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