summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp
diff options
context:
space:
mode:
author Julian Sikorski <belegdol+github@gmail.com>2019-10-13 13:50:38 +0200
committer R. Belmont <rb6502@users.noreply.github.com>2019-10-13 07:50:38 -0400
commit0837e7451a84f95c29dbdb9bd6b8b931fee1635d (patch)
tree626bcbd250a7fbebdf5958a288d2f438d4f9fb5a /3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp
parentc913ccb59d713ce0b91135520719ac5385e54358 (diff)
WIP: sync bgfx, bx and bimg with latest upstream (#5723)
* Sync with bgfx upstream revision b91d0b6 * Sync with bx upstream revision d60912b * Sync with bimg upstream revision bd81f60 * Add astc-codec decoder * Rename VertexDecl to VertexLayout * Rename UniformType enum Int1 to Sampler. * Add NVN stub * Fix unused-const-variable error on macOS * Drop redundant explicit language parameters buildoptions_cpp are only applied to c++ files and buildoptions_objcpp are only applied to objective c++ files. As such, hardcoding -x offers no benefit while preventing overrides (such as one needed by 3rdparty/bgfx/src/renderer_vk.cpp on macOS) from working. * Re-introduce -x c++ in places where C code is compiled as C++ to prevent clang from throwing a warning * Build bgfx as Objective-C++ on macOS It is needed due to included headers * Enable Direct3D12 and Vulkan bgfx rendering backends * Enable building of spirv shaders * Properly escape /c in cmd call * Comment out dx12 bgfx renderer * Honor VERBOSE setting during shaders build * Only invert hlsl shader XYZ_TO_sRGB matrix for opengl * Add spirv shaders * OpenGL ES needs transposed matrix too * Metal needs transposed matrix as well
Diffstat (limited to '3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp')
-rw-r--r--3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp490
1 files changed, 430 insertions, 60 deletions
diff --git a/3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp b/3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp
index 1f2e165de0b..c1227f44f3d 100644
--- a/3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp
+++ b/3rdparty/bgfx/tools/shaderc/shaderc_spirv.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
+ * Copyright 2011-2019 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
@@ -14,6 +14,10 @@ BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow") // warning: declaration of 'u
#include <ResourceLimits.h>
#include <SPIRV/SPVRemapper.h>
#include <SPIRV/GlslangToSpv.h>
+#define SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+#include <spirv_msl.hpp>
+#include <spirv_reflect.hpp>
+#include <spirv-tools/optimizer.hpp>
BX_PRAGMA_DIAGNOSTIC_POP()
namespace bgfx
@@ -49,6 +53,7 @@ namespace bgfx
namespace stl = tinystl;
#include "../../src/shader_spirv.h"
+#include "../../3rdparty/khronos/vulkan/vulkan.h"
namespace bgfx { namespace spirv
{
@@ -539,11 +544,6 @@ namespace bgfx { namespace spirv
}
}
-// static void printError(spv_message_level_t, const char*, const spv_position_t&, const char* _message)
-// {
-// fprintf(stderr, "%s\n", _message);
-// }
-
static const char* s_attribName[] =
{
"a_position",
@@ -567,6 +567,39 @@ namespace bgfx { namespace spirv
};
BX_STATIC_ASSERT(bgfx::Attrib::Count == BX_COUNTOF(s_attribName) );
+ int32_t extractStageNumber(const std::string _strLine)
+ {
+ bx::StringView found = bx::findIdentifierMatch(_strLine.c_str(), "register");
+ const char* ptr = found.getPtr() + found.getLength();
+ const char* start = NULL;
+ const char* end = NULL;
+
+ while (*ptr != ')'
+ && ptr < _strLine.c_str() + _strLine.size() )
+ {
+ if (*ptr >= '0' && *ptr <= '9')
+ {
+ if (start == NULL)
+ {
+ start = ptr;
+ }
+
+ end = ptr;
+ }
+
+ ptr++;
+ }
+
+ BX_CHECK(start != NULL && end != NULL, "cannot find register number");
+
+ bx::StringView numberString(start, end - start + 1);
+ int32_t regNumber = -1;
+ bx::fromString(&regNumber, numberString);
+ BX_CHECK(regNumber >= 0, "register number should be semi-positive integer");
+
+ return regNumber;
+ }
+
bgfx::Attrib::Enum toAttribEnum(const bx::StringView& _name)
{
for (uint8_t ii = 0; ii < Attrib::Count; ++ii)
@@ -580,6 +613,56 @@ namespace bgfx { namespace spirv
return bgfx::Attrib::Count;
}
+ static const char* s_samplerTypes[] =
+ {
+ "BgfxSampler2D",
+ "BgfxISampler2D",
+ "BgfxUSampler2D",
+ "BgfxSampler2DArray",
+ "BgfxSampler2DShadow",
+ "BgfxSampler2DArrayShadow",
+ "BgfxSampler3D",
+ "BgfxISampler3D",
+ "BgfxUSampler3D",
+ "BgfxSamplerCube",
+ "BgfxSamplerCubeShadow",
+ "BgfxSampler2DMS",
+ };
+
+ static uint16_t writeUniformArray(bx::WriterI* _writer, const UniformArray& uniforms, bool isFragmentShader)
+ {
+ uint16_t size = 0;
+
+ uint16_t count = static_cast<uint16_t>(uniforms.size());
+ bx::write(_writer, count);
+
+ uint32_t fragmentBit = isFragmentShader ? BGFX_UNIFORM_FRAGMENTBIT : 0;
+ for (uint16_t ii = 0; ii < count; ++ii)
+ {
+ const Uniform& un = uniforms[ii];
+
+ if (un.type != UniformType::Sampler)
+ size = bx::max(size, (uint16_t)(un.regIndex + un.regCount*16));
+
+ uint8_t nameSize = (uint8_t)un.name.size();
+ bx::write(_writer, nameSize);
+ bx::write(_writer, un.name.c_str(), nameSize);
+ bx::write(_writer, uint8_t(un.type | fragmentBit));
+ bx::write(_writer, un.num);
+ bx::write(_writer, un.regIndex);
+ bx::write(_writer, un.regCount);
+
+ BX_TRACE("%s, %s, %d, %d, %d"
+ , un.name.c_str()
+ , getUniformTypeName(un.type)
+ , un.num
+ , un.regIndex
+ , un.regCount
+ );
+ }
+ return size;
+ }
+
static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _writer, bool _firstPass)
{
BX_UNUSED(_version);
@@ -591,7 +674,7 @@ namespace bgfx { namespace spirv
EShLanguage stage = getLang(_options.shaderType);
if (EShLangCount == stage)
{
- fprintf(stderr, "Error: Unknown shader type '%c'.\n", _options.shaderType);
+ bx::printf("Error: Unknown shader type '%c'.\n", _options.shaderType);
return false;
}
glslang::TShader* shader = new glslang::TShader(stage);
@@ -604,6 +687,13 @@ namespace bgfx { namespace spirv
);
shader->setEntryPoint("main");
+ shader->setAutoMapBindings(true);
+ uint32_t bindingOffset = (stage == EShLanguage::EShLangFragment ? 48 : 0);
+ shader->setShiftBinding(glslang::EResUbo, bindingOffset);
+ shader->setShiftBinding(glslang::EResTexture, bindingOffset + 16);
+ shader->setShiftBinding(glslang::EResSampler, bindingOffset + 32);
+ shader->setShiftBinding(glslang::EResSsbo, bindingOffset + 16);
+ shader->setShiftBinding(glslang::EResImage, bindingOffset + 32);
const char* shaderStrings[] = { _code.c_str() };
shader->setStrings(
@@ -650,7 +740,7 @@ namespace bgfx { namespace spirv
printCode(_code.c_str(), line, start, end, column);
- fprintf(stderr, "%s\n", log);
+ bx::printf("%s\n", log);
}
}
else
@@ -666,19 +756,16 @@ namespace bgfx { namespace spirv
const char* log = program->getInfoLog();
if (NULL != log)
{
- fprintf(stderr, "%s\n", log);
+ bx::printf("%s\n", log);
}
}
else
{
- uint16_t size = 0;
-
program->buildReflection();
+ std::map<std::string, uint32_t> stageMap;
if (_firstPass)
{
- const size_t strLength = bx::strLen("uniform");
-
// first time through, we just find unused uniforms and get rid of them
std::string output;
bx::Error err;
@@ -696,14 +783,9 @@ namespace bgfx { namespace spirv
{
bool found = false;
- for (int32_t ii = 0, num = program->getNumLiveUniformVariables(); ii < num; ++ii)
+ for (uint32_t ii = 0; ii < BX_COUNTOF(s_samplerTypes); ++ii)
{
- // matching lines like: uniform u_name;
- // we want to replace "uniform" with "static" so that it's no longer
- // included in the uniform blob that the application must upload
- // we can't just remove them, because unused functions might still reference
- // them and cause a compile error when they're gone
- if (!bx::findIdentifierMatch(strLine.c_str(), program->getUniformName(ii) ).isEmpty() )
+ if (!bx::findIdentifierMatch(strLine.c_str(), s_samplerTypes[ii]).isEmpty())
{
found = true;
break;
@@ -712,7 +794,24 @@ namespace bgfx { namespace spirv
if (!found)
{
- strLine = strLine.replace(index, strLength, "static");
+ for (int32_t ii = 0, num = program->getNumLiveUniformVariables(); ii < num; ++ii)
+ {
+ // matching lines like: uniform u_name;
+ // we want to replace "uniform" with "static" so that it's no longer
+ // included in the uniform blob that the application must upload
+ // we can't just remove them, because unused functions might still reference
+ // them and cause a compile error when they're gone
+ if (!bx::findIdentifierMatch(strLine.c_str(), program->getUniformName(ii)).isEmpty())
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ strLine = strLine.replace(index, 7 /* uniform */, "static");
}
}
@@ -723,12 +822,114 @@ namespace bgfx { namespace spirv
// recompile with the unused uniforms converted to statics
return compile(_options, _version, output.c_str(), _writer, false);
}
+ else
+ {
+ // second time, find sampler state and get its stage index
+ bx::Error err;
+ LineReader reader(_code.c_str());
+ while (err.isOk())
+ {
+ char str[4096];
+ int32_t len = bx::read(&reader, str, BX_COUNTOF(str), &err);
+ if (err.isOk())
+ {
+ std::string strLine(str, len);
+ size_t index = strLine.find("uniform ");
+ if (index != std::string::npos)
+ {
+ if (!bx::findIdentifierMatch(strLine.c_str(), "SamplerState").isEmpty() ||
+ !bx::findIdentifierMatch(strLine.c_str(), "SamplerComparisonState").isEmpty())
+ {
+ int32_t regNumber = extractStageNumber(strLine);
+
+ bx::StringView found = bx::findIdentifierMatch(strLine.c_str(), "SamplerState");
+
+ if (found.isEmpty() )
+ {
+ found = bx::findIdentifierMatch(
+ strLine.c_str()
+ , "SamplerComparisonState"
+ );
+ }
+
+ const char* ptr = found.getPtr() + found.getLength();
+ const char* start = NULL;
+ const char* end = NULL;
+ while (ptr < strLine.c_str() + strLine.size())
+ {
+ if (*ptr != ' ')
+ {
+ if (start == NULL)
+ {
+ start = ptr;
+ }
+
+ end = ptr;
+ }
+ else if (start != NULL)
+ {
+ break;
+ }
+
+ ptr++;
+ }
+
+ BX_CHECK(start != NULL && end != NULL, "sampler name cannot be found");
+
+ std::string samplerName(start, end - start + 1);
+ stageMap[samplerName] = regNumber;
+ }
+ }
+ else if (!bx::findIdentifierMatch(strLine.c_str(), "StructuredBuffer").isEmpty()
+ || !bx::findIdentifierMatch(strLine.c_str(), "RWStructuredBuffer").isEmpty() )
+ {
+ int32_t regNumber = extractStageNumber(strLine);
+
+ const char* ptr = strLine.c_str();
+ const char* start = NULL;
+ const char* end = NULL;
+ while (ptr < strLine.c_str() + strLine.size())
+ {
+ if (*ptr == '>')
+ {
+ start = ptr + 1;
+ while (*start == ' ')
+ {
+ start++;
+ }
+ }
+
+ if (*ptr == ':')
+ {
+ end = ptr - 1;
+ while (*end == ' ')
+ {
+ end--;
+ }
+ }
+
+ if (start != NULL && end != NULL)
+ {
+ break;
+ }
+
+ ptr++;
+ }
+
+ BX_CHECK(start != NULL && end != NULL, "sampler name cannot be found");
+
+ std::string bufferName(start, end - start + 1);
+ stageMap[bufferName] = regNumber;
+ }
+ }
+ }
+ }
+
+ UniformArray uniforms;
{
uint16_t count = (uint16_t)program->getNumLiveUniformVariables();
- bx::write(_writer, count);
- uint32_t fragmentBit = _options.shaderType == 'f' ? BGFX_UNIFORM_FRAGMENTBIT : 0;
for (uint16_t ii = 0; ii < count; ++ii)
{
Uniform un;
@@ -742,43 +943,32 @@ namespace bgfx { namespace spirv
switch (program->getUniformType(ii))
{
case 0x1404: // GL_INT:
- un.type = UniformType::Int1;
+ un.type = UniformType::Sampler;
break;
+
case 0x8B52: // GL_FLOAT_VEC4:
un.type = UniformType::Vec4;
break;
+
case 0x8B5B: // GL_FLOAT_MAT3:
un.type = UniformType::Mat3;
un.regCount *= 3;
break;
+
case 0x8B5C: // GL_FLOAT_MAT4:
un.type = UniformType::Mat4;
un.regCount *= 4;
break;
+
default:
un.type = UniformType::End;
break;
}
- size += un.regCount*16;
-
- uint8_t nameSize = (uint8_t)un.name.size();
- bx::write(_writer, nameSize);
- bx::write(_writer, un.name.c_str(), nameSize);
- bx::write(_writer, uint8_t(un.type | fragmentBit));
- bx::write(_writer, un.num);
- bx::write(_writer, un.regIndex);
- bx::write(_writer, un.regCount);
-
- BX_TRACE("%s, %s, %d, %d, %d"
- , un.name.c_str()
- , getUniformTypeName(un.type)
- , un.num
- , un.regIndex
- , un.regCount
- );
+ uniforms.push_back(un);
}
}
+
if (g_verbose)
{
program->dumpReflection();
@@ -794,35 +984,215 @@ namespace bgfx { namespace spirv
glslang::GlslangToSpv(*intermediate, spirv, &options);
- bx::Error err;
- bx::WriterI* writer = bx::getDebugOut();
- bx::MemoryReader reader(spirv.data(), uint32_t(spirv.size()*4) );
- disassemble(writer, &reader, &err);
+ spvtools::Optimizer opt(SPV_ENV_VULKAN_1_0);
+
+ auto print_msg_to_stderr = [](
+ spv_message_level_t
+ , const char*
+ , const spv_position_t&
+ , const char* m
+ )
+ {
+ bx::printf("Error: %s\n", m);
+ };
+
+ opt.SetMessageConsumer(print_msg_to_stderr);
- uint32_t shaderSize = (uint32_t)spirv.size()*sizeof(uint32_t);
- bx::write(_writer, shaderSize);
- bx::write(_writer, spirv.data(), shaderSize);
- uint8_t nul = 0;
- bx::write(_writer, nul);
+ opt.RegisterLegalizationPasses();
- //
- const uint8_t numAttr = (uint8_t)program->getNumLiveAttributes();
- bx::write(_writer, numAttr);
+ spvtools::ValidatorOptions validatorOptions;
+ validatorOptions.SetBeforeHlslLegalization(true);
- for (uint8_t ii = 0; ii < numAttr; ++ii)
+ if (!opt.Run(
+ spirv.data()
+ , spirv.size()
+ , &spirv
+ , validatorOptions
+ , false
+ ) )
{
- bgfx::Attrib::Enum attr = toAttribEnum(program->getAttributeName(ii) );
- if (bgfx::Attrib::Count != attr)
+ compiled = false;
+ }
+ else
+ {
+ bx::Error err;
+ bx::WriterI* writer = bx::getDebugOut();
+ bx::MemoryReader reader(spirv.data(), uint32_t(spirv.size()*4) );
+ disassemble(writer, &reader, &err);
+
+ spirv_cross::CompilerReflection refl(spirv);
+ spirv_cross::ShaderResources resourcesrefl = refl.get_shader_resources();
+
+ // Loop through the separate_images, and extract the uniform names:
+ for (auto &resource : resourcesrefl.separate_images)
+ {
+ std::string name = refl.get_name(resource.id);
+ if (name.size() > 7
+ && 0 == bx::strCmp(name.c_str() + name.length() - 7, "Texture") )
+ {
+ auto uniform_name = name.substr(0, name.length() - 7);
+
+ Uniform un;
+ un.name = uniform_name;
+ un.type = UniformType::Sampler;
+
+ uint32_t texture_binding_index = refl.get_decoration(resource.id, spv::Decoration::DecorationBinding);
+ uint32_t sampler_binding_index = 0;
+ std::string sampler_name;
+
+ for (auto& sampler_resource : resourcesrefl.separate_samplers)
+ {
+ sampler_name = refl.get_name(sampler_resource.id);
+ if (sampler_name.size() > 7
+ && !bx::strFind(sampler_name.c_str(), uniform_name.c_str()).isEmpty()
+ && (0 == bx::strCmp(sampler_name.c_str() + name.length() - 7, "Sampler") ||
+ 0 == bx::strCmp(sampler_name.c_str() + name.length() - 7, "SamplerComparison")
+ ) )
+ {
+ sampler_binding_index = refl.get_decoration(sampler_resource.id, spv::Decoration::DecorationBinding);
+ break;
+ }
+ }
+
+ un.num = stageMap[sampler_name]; // want to write stage index
+ un.regIndex = texture_binding_index; // for sampled image binding index
+ un.regCount = sampler_binding_index; // for sampler binding index
+
+ uniforms.push_back(un);
+ }
+ }
+
+ // Loop through the separate_images, and extract the uniform names:
+ for (auto &resource : resourcesrefl.storage_images)
+ {
+ std::string name = refl.get_name(resource.id);
+
+ if (name.size() > 7
+ && 0 == bx::strCmp(name.c_str() + name.length() - 7, "Texture") )
+ {
+ auto uniform_name = name.substr(0, name.length() - 7);
+ uint32_t binding_index = refl.get_decoration(resource.id, spv::Decoration::DecorationBinding);
+ std::string sampler_name = uniform_name + "Sampler";
+
+ Uniform un;
+ un.name = uniform_name;
+ un.type = UniformType::End;
+ un.num = stageMap[sampler_name]; // want to write stage index
+ un.regIndex = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; // for descriptor type
+ un.regCount = binding_index; // for image binding index
+
+ uniforms.push_back(un);
+ }
+ }
+
+ // Loop through the storage buffer, and extract the uniform names:
+ for (auto& resource : resourcesrefl.storage_buffers)
{
- bx::write(_writer, bgfx::attribToId(attr) );
+ std::string name = refl.get_name(resource.id);
+
+ for (auto& uniform : uniforms)
+ {
+ if (!bx::strFind(uniform.name.c_str(), name.c_str()).isEmpty())
+ {
+ uint32_t binding_index = refl.get_decoration(resource.id, spv::Decoration::DecorationBinding);
+ uniform.name = name;
+ uniform.type = UniformType::End;
+ uniform.num = stageMap[name];
+ uniform.regIndex = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ uniform.regCount = binding_index;
+ break;
+ }
+ }
+ }
+
+ uint16_t size = writeUniformArray( _writer, uniforms, _options.shaderType == 'f');
+
+ if (_version == BX_MAKEFOURCC('M', 'T', 'L', 0) )
+ {
+ if (g_verbose)
+ {
+ glslang::SpirvToolsDisassemble(std::cout, spirv);
+ }
+
+ spirv_cross::CompilerMSL msl(std::move(spirv));
+
+ spirv_cross::ShaderResources resources = msl.get_shader_resources();
+
+ spirv_cross::SmallVector<spirv_cross::EntryPoint> entryPoints = msl.get_entry_points_and_stages();
+ if (!entryPoints.empty() )
+ {
+ msl.rename_entry_point(
+ entryPoints[0].name
+ , "xlatMtlMain"
+ , entryPoints[0].execution_model
+ );
+ }
+
+ for (auto &resource : resources.uniform_buffers)
+ {
+ msl.set_name(resource.id, "_mtl_u");
+ }
+
+ for (auto &resource : resources.storage_buffers)
+ {
+ unsigned binding = msl.get_decoration(resource.id, spv::DecorationBinding);
+ msl.set_decoration(resource.id, spv::DecorationBinding, binding + 1);
+ }
+
+ for (auto &resource : resources.separate_images)
+ {
+ std::string name = msl.get_name(resource.id);
+ if (name.size() > 7
+ && 0 == bx::strCmp(name.c_str() + name.length() - 7, "Texture") )
+ {
+ msl.set_name(resource.id, name.substr(0, name.length() - 7));
+ }
+ }
+
+ std::string source = msl.compile();
+
+ if ('c' == _options.shaderType)
+ {
+ for (int i = 0; i < 3; ++i)
+ {
+ uint16_t dim = (uint16_t)msl.get_execution_mode_argument(spv::ExecutionMode::ExecutionModeLocalSize, i);
+ bx::write(_writer, dim);
+ }
+ }
+
+ uint32_t shaderSize = (uint32_t)source.size();
+ bx::write(_writer, shaderSize);
+ bx::write(_writer, source.c_str(), shaderSize);
+ uint8_t nul = 0;
+ bx::write(_writer, nul);
}
else
{
- bx::write(_writer, uint16_t(UINT16_MAX) );
+ uint32_t shaderSize = (uint32_t)spirv.size() * sizeof(uint32_t);
+ bx::write(_writer, shaderSize);
+ bx::write(_writer, spirv.data(), shaderSize);
+ uint8_t nul = 0;
+ bx::write(_writer, nul);
}
- }
- bx::write(_writer, size);
+ const uint8_t numAttr = (uint8_t)program->getNumLiveAttributes();
+ bx::write(_writer, numAttr);
+
+ for (uint8_t ii = 0; ii < numAttr; ++ii)
+ {
+ bgfx::Attrib::Enum attr = toAttribEnum(program->getAttributeName(ii) );
+ if (bgfx::Attrib::Count != attr)
+ {
+ bx::write(_writer, bgfx::attribToId(attr) );
+ }
+ else
+ {
+ bx::write(_writer, uint16_t(UINT16_MAX) );
+ }
+ }
+
+ bx::write(_writer, size);
+ }
}
}