mirror of https://github.com/mosra/magnum.git
12 changed files with 364 additions and 5 deletions
@ -0,0 +1,116 @@ |
|||||||
|
#ifndef Magnum_Vk_Implementation_spirvPatching_h |
||||||
|
#define Magnum_Vk_Implementation_spirvPatching_h |
||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <Corrade/Containers/ArrayTuple.h> |
||||||
|
|
||||||
|
#include "Magnum/Math/Functions.h" |
||||||
|
|
||||||
|
/* All code in this file should be self-contained, with no link-time dependency
|
||||||
|
on ShaderTools */ |
||||||
|
#include "Magnum/ShaderTools/Implementation/spirv.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Vk { namespace Implementation { namespace { |
||||||
|
|
||||||
|
/* This kinda throws const-correctness through the window -- the the SPIR-V
|
||||||
|
utils work on const data, but this function actually does mutate them */ |
||||||
|
bool spirvPatchSwiftShaderConflictingMultiEntrypointLocations(Containers::ArrayView<const UnsignedInt> data) { |
||||||
|
/* Find vertex/fragment entrypoints and count how many is there in total */ |
||||||
|
UnsignedInt entrypointCount = 0; |
||||||
|
Containers::Optional<ShaderTools::Implementation::SpirvEntrypoint> vertexEntryPoint, fragmentEntryPoint; |
||||||
|
while(Containers::Optional<ShaderTools::Implementation::SpirvEntrypoint> entrypoint = ShaderTools::Implementation::spirvNextEntrypoint(data)) { |
||||||
|
++entrypointCount; |
||||||
|
if(entrypoint->executionModel == SpvExecutionModelVertex) |
||||||
|
vertexEntryPoint = *entrypoint; |
||||||
|
else if(entrypoint->executionModel == SpvExecutionModelFragment) |
||||||
|
fragmentEntryPoint = *entrypoint; |
||||||
|
} |
||||||
|
|
||||||
|
/* If there aren't both entrypoints, this bug doesn't affect the shader. If
|
||||||
|
there are more, we won't attempt anything -- right now SwiftShader |
||||||
|
doesn't support geom/tess shaders, so the only possibility is that the |
||||||
|
module is a library of multiple different vertex / fragment |
||||||
|
implementations and that's too frightening as any patching would most |
||||||
|
likely break things *really bad*. */ |
||||||
|
if(entrypointCount > 2 || !vertexEntryPoint || !fragmentEntryPoint) |
||||||
|
return false; |
||||||
|
|
||||||
|
/* Get locations and storage classes for all entrypoint interfaces */ |
||||||
|
Containers::ArrayView<ShaderTools::Implementation::SpirvEntrypointInterface> vertexInterface, fragmentInterface; |
||||||
|
Containers::ArrayTuple interfaceData{ |
||||||
|
{Containers::ValueInit, vertexEntryPoint->interfaces.size(), vertexInterface}, |
||||||
|
{Containers::ValueInit, fragmentEntryPoint->interfaces.size(), fragmentInterface} |
||||||
|
}; |
||||||
|
spirvEntrypointInterface(data, *vertexEntryPoint, vertexInterface); |
||||||
|
spirvEntrypointInterface(data, *fragmentEntryPoint, fragmentInterface); |
||||||
|
|
||||||
|
/* Calculate the max location so we know what to change to */ |
||||||
|
UnsignedInt maxLocation = 0; |
||||||
|
for(const ShaderTools::Implementation::SpirvEntrypointInterface& i: vertexInterface) |
||||||
|
if(i.location) maxLocation = Math::max(maxLocation, *i.location); |
||||||
|
for(const ShaderTools::Implementation::SpirvEntrypointInterface& i: fragmentInterface) |
||||||
|
if(i.location) maxLocation = Math::max(maxLocation, *i.location); |
||||||
|
|
||||||
|
/* For all vertex outputs check if there are fragment outputs with the same
|
||||||
|
locations */ |
||||||
|
for(const ShaderTools::Implementation::SpirvEntrypointInterface& vertexOutput: vertexInterface) { |
||||||
|
/* Ignore what's not an output or what doesn't have a location (for
|
||||||
|
example a builtin) */ |
||||||
|
if(!vertexOutput.storageClass || *vertexOutput.storageClass != SpvStorageClassOutput || !vertexOutput.location) |
||||||
|
continue; |
||||||
|
|
||||||
|
for(const ShaderTools::Implementation::SpirvEntrypointInterface& fragmentOutput: fragmentInterface) { |
||||||
|
/* Ignore what's not an output or what doesn't have a location (for
|
||||||
|
example a builtin) */ |
||||||
|
if(!fragmentOutput.storageClass || *fragmentOutput.storageClass != SpvStorageClassOutput || !fragmentOutput.location) continue; |
||||||
|
|
||||||
|
/* The same location used, we need to remap. Use the next highest
|
||||||
|
unused location and change also the corresponding fragment |
||||||
|
input, if there's any. */ |
||||||
|
if(*vertexOutput.location == *fragmentOutput.location) { |
||||||
|
const UnsignedInt newLocation = ++maxLocation; |
||||||
|
for(const ShaderTools::Implementation::SpirvEntrypointInterface& fragmentInput: fragmentInterface) { |
||||||
|
if(*fragmentInput.storageClass != SpvStorageClassInput) |
||||||
|
continue; |
||||||
|
if(*fragmentInput.location == *vertexOutput.location) { |
||||||
|
/** @todo ugly! */ |
||||||
|
*const_cast<UnsignedInt*>(fragmentInput.location) = newLocation; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
/** @todo ugly! */ |
||||||
|
*const_cast<UnsignedInt*>(vertexOutput.location) = newLocation; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
#!/bin/bash |
||||||
|
|
||||||
|
for i in $(ls *.spvasm); do |
||||||
|
magnum-shaderconverter $i ${i%asm} |
||||||
|
done |
||||||
Binary file not shown.
@ -0,0 +1,53 @@ |
|||||||
|
OpCapability Shader |
||||||
|
OpMemoryModel Logical GLSL450 |
||||||
|
OpEntryPoint Vertex %ver "ver" %position %color %gl_Position %interpolatedColorOut %interpolatedTexCoordsOut %interpolatedNormalOut %unused |
||||||
|
OpEntryPoint Fragment %fra "fra" %interpolatedColorIn %interpolatedTexCoordsIn %interpolatedNormalIn %fragmentColor %weight |
||||||
|
|
||||||
|
OpDecorate %gl_Position BuiltIn Position |
||||||
|
OpDecorate %position Location 0 |
||||||
|
OpDecorate %color Location 1 |
||||||
|
OpDecorate %fragmentColor Location 0 |
||||||
|
OpDecorate %weight Location 1 |
||||||
|
|
||||||
|
OpDecorate %interpolatedColorOut Location 0 |
||||||
|
OpDecorate %interpolatedColorIn Location 0 |
||||||
|
|
||||||
|
OpDecorate %interpolatedTexCoordsOut Location 1 |
||||||
|
OpDecorate %interpolatedTexCoordsIn Location 1 |
||||||
|
|
||||||
|
OpDecorate %interpolatedNormalOut Location 2 |
||||||
|
OpDecorate %interpolatedNormalIn Location 2 |
||||||
|
|
||||||
|
OpDecorate %unused Location 3 |
||||||
|
|
||||||
|
%float = OpTypeFloat 32 |
||||||
|
%v2float = OpTypeVector %float 2 |
||||||
|
%v3float = OpTypeVector %float 3 |
||||||
|
%v4float = OpTypeVector %float 4 |
||||||
|
|
||||||
|
%_ptr_Output_float = OpTypePointer Output %float |
||||||
|
%weight = OpVariable %_ptr_Output_float Output |
||||||
|
|
||||||
|
%_ptr_Input_v2float = OpTypePointer Input %v2float |
||||||
|
%interpolatedTexCoordsIn = OpVariable %_ptr_Input_v2float Input |
||||||
|
|
||||||
|
%_ptr_Output_v2float = OpTypePointer Output %v2float |
||||||
|
%interpolatedTexCoordsOut = OpVariable %_ptr_Input_v2float Output |
||||||
|
|
||||||
|
%_ptr_Input_v3float = OpTypePointer Input %v3float |
||||||
|
%interpolatedNormalIn = OpVariable %_ptr_Input_v3float Input |
||||||
|
|
||||||
|
%_ptr_Output_v3float = OpTypePointer Output %v3float |
||||||
|
%interpolatedNormalOut = OpVariable %_ptr_Input_v3float Output |
||||||
|
|
||||||
|
%_ptr_Input_v4float = OpTypePointer Input %v4float |
||||||
|
%position = OpVariable %_ptr_Input_v4float Input |
||||||
|
%color = OpVariable %_ptr_Input_v4float Input |
||||||
|
%interpolatedColorIn = OpVariable %_ptr_Input_v4float Input |
||||||
|
|
||||||
|
%_ptr_Output_v4float = OpTypePointer Output %v4float |
||||||
|
%interpolatedColorOut = OpVariable %_ptr_Output_v4float Output |
||||||
|
%gl_Position = OpVariable %_ptr_Output_v4float Output |
||||||
|
%fragmentColor = OpVariable %_ptr_Output_v4float Output |
||||||
|
|
||||||
|
%unused = OpVariable %_ptr_Output_float Output |
||||||
Loading…
Reference in new issue