mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-25 22:25:07 +00:00
feat(shader): Refactor shader compilation process to use BgfxShaderCompiler and streamline error handling
This commit is contained in:
@@ -208,6 +208,8 @@ target_include_directories(shaderc_local PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_deps/glslang"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_deps/glslang/Include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/bgfx_deps/glslang/glslang/Public")
|
||||
target_include_directories(shaderc_local PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
if(TARGET bgfx::bx)
|
||||
target_link_libraries(shaderc_local PUBLIC bgfx::bx)
|
||||
endif()
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint8_t kShaderBinVersion = 11;
|
||||
constexpr uint32_t kChunkMagicVsh = BX_MAKEFOURCC('V', 'S', 'H', kShaderBinVersion);
|
||||
constexpr uint32_t kChunkMagicFsh = BX_MAKEFOURCC('F', 'S', 'H', kShaderBinVersion);
|
||||
constexpr uint32_t kChunkMagicCsh = BX_MAKEFOURCC('C', 'S', 'H', kShaderBinVersion);
|
||||
|
||||
// Writer that captures binary output into a std::vector<uint8_t>
|
||||
class MemoryWriter : public bx::FileWriter
|
||||
{
|
||||
@@ -30,6 +35,28 @@ private:
|
||||
std::vector<uint8_t> m_buffer;
|
||||
};
|
||||
|
||||
uint32_t ChunkMagicForType(char shaderType) {
|
||||
switch (shaderType) {
|
||||
case 'v':
|
||||
return kChunkMagicVsh;
|
||||
case 'f':
|
||||
return kChunkMagicFsh;
|
||||
case 'c':
|
||||
return kChunkMagicCsh;
|
||||
default:
|
||||
return kChunkMagicFsh;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteShaderHeader(MemoryWriter& writer, char shaderType) {
|
||||
bx::ErrorAssert err;
|
||||
const uint32_t magic = ChunkMagicForType(shaderType);
|
||||
const uint32_t hash = 0;
|
||||
bx::write(&writer, magic, &err);
|
||||
bx::write(&writer, hash, &err);
|
||||
bx::write(&writer, hash, &err);
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
|
||||
int shaderc_compile_from_memory(const char* source, size_t source_len, const char* profile,
|
||||
@@ -53,25 +80,27 @@ int shaderc_compile_from_memory(const char* source, size_t source_len, const cha
|
||||
opts.shaderType = 'f';
|
||||
}
|
||||
|
||||
opts.profile = "glsl";
|
||||
// Use SPIR-V target by default (matches CLI's typical default for desktop)
|
||||
const uint32_t spirvVersion = 1010;
|
||||
|
||||
MemoryWriter writer;
|
||||
bx::ErrorAssert err;
|
||||
bx::WriterI* messageWriter = &writer; // reuse writer for messages as well
|
||||
MemoryWriter shaderWriter;
|
||||
MemoryWriter messageWriter;
|
||||
bx::WriterI* messageOut = &messageWriter;
|
||||
|
||||
const std::string code(source, source_len);
|
||||
|
||||
bool ok = bgfx::compileSPIRVShader(opts, spirvVersion, code, &writer, messageWriter);
|
||||
WriteShaderHeader(shaderWriter, opts.shaderType);
|
||||
bool ok = bgfx::compileSPIRVShader(opts, spirvVersion, code, &shaderWriter, messageOut);
|
||||
if (!ok) {
|
||||
// capture any message buffer
|
||||
const auto& msg = writer.data();
|
||||
const auto& msg = messageWriter.data();
|
||||
std::string s(msg.begin(), msg.end());
|
||||
if (out_error) *out_error = strdup(s.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
const auto& out = writer.data();
|
||||
const auto& out = shaderWriter.data();
|
||||
if (out.empty()) {
|
||||
if (out_error) *out_error = strdup("shaderc: empty output");
|
||||
return -1;
|
||||
@@ -120,20 +149,27 @@ int shaderc_compile_from_memory_with_target(const char* source, size_t source_le
|
||||
opts.shaderType = 'f';
|
||||
}
|
||||
|
||||
MemoryWriter writer;
|
||||
bx::ErrorAssert err;
|
||||
bx::WriterI* messageWriter = &writer;
|
||||
if (0 == std::strcmp(target, "spirv")) {
|
||||
opts.profile = "glsl";
|
||||
}
|
||||
|
||||
MemoryWriter shaderWriter;
|
||||
MemoryWriter messageWriter;
|
||||
bx::WriterI* messageOut = &messageWriter;
|
||||
const std::string code(source, source_len);
|
||||
|
||||
bool ok = false;
|
||||
uint32_t version = 1010;
|
||||
// Dispatch based on target language (in-process supports SPIR-V/MSL/HLSL only).
|
||||
if (0 == std::strcmp(target, "spirv")) {
|
||||
ok = bgfx::compileSPIRVShader(opts, version, code, &writer, messageWriter);
|
||||
WriteShaderHeader(shaderWriter, opts.shaderType);
|
||||
ok = bgfx::compileSPIRVShader(opts, version, code, &shaderWriter, messageOut);
|
||||
} else if (0 == std::strcmp(target, "msl") || 0 == std::strcmp(target, "metal")) {
|
||||
ok = bgfx::compileMetalShader(opts, version, code, &writer, messageWriter);
|
||||
WriteShaderHeader(shaderWriter, opts.shaderType);
|
||||
ok = bgfx::compileMetalShader(opts, version, code, &shaderWriter, messageOut);
|
||||
} else if (0 == std::strcmp(target, "hlsl")) {
|
||||
ok = bgfx::compileHLSLShader(opts, version, code, &writer, messageWriter);
|
||||
WriteShaderHeader(shaderWriter, opts.shaderType);
|
||||
ok = bgfx::compileHLSLShader(opts, version, code, &shaderWriter, messageOut);
|
||||
} else {
|
||||
if (out_error) {
|
||||
*out_error = strdup("shaderc: target not supported by in-process compiler");
|
||||
@@ -142,13 +178,13 @@ int shaderc_compile_from_memory_with_target(const char* source, size_t source_le
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
const auto& msg = writer.data();
|
||||
const auto& msg = messageWriter.data();
|
||||
std::string s(msg.begin(), msg.end());
|
||||
if (out_error) *out_error = strdup(s.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
const auto& out = writer.data();
|
||||
const auto& out = shaderWriter.data();
|
||||
if (out.empty()) {
|
||||
if (out_error) *out_error = strdup("shaderc: empty output");
|
||||
return -1;
|
||||
|
||||
@@ -27,7 +27,7 @@ BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow") // warning: declaration of 'u
|
||||
#include <spirv-tools/optimizer.hpp>
|
||||
BX_PRAGMA_DIAGNOSTIC_POP()
|
||||
|
||||
namespace bgfx
|
||||
namespace shaderc_local
|
||||
{
|
||||
struct TinyStlAllocator
|
||||
{
|
||||
@@ -35,16 +35,16 @@ namespace bgfx
|
||||
static void static_deallocate(void* _ptr, size_t /*_bytes*/);
|
||||
};
|
||||
|
||||
} // namespace bgfx
|
||||
} // namespace shaderc_local
|
||||
|
||||
#define TINYSTL_ALLOCATOR bgfx::TinyStlAllocator
|
||||
#include <tinystl/allocator.h>
|
||||
#include <tinystl/string.h>
|
||||
#include <tinystl/unordered_map.h>
|
||||
#include <tinystl/vector.h>
|
||||
#define TINYSTL_ALLOCATOR shaderc_local::TinyStlAllocator
|
||||
#include <TINYSTL/allocator.h>
|
||||
#include <TINYSTL/string.h>
|
||||
#include <TINYSTL/unordered_map.h>
|
||||
#include <TINYSTL/vector.h>
|
||||
namespace stl = tinystl;
|
||||
|
||||
#include "../../src/shader.h"
|
||||
#include "../src/shader.h"
|
||||
|
||||
namespace bgfx { namespace metal
|
||||
{
|
||||
|
||||
@@ -27,10 +27,10 @@ BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow") // warning: declaration of 'u
|
||||
#include <spirv-tools/optimizer.hpp>
|
||||
BX_PRAGMA_DIAGNOSTIC_POP()
|
||||
|
||||
namespace bgfx
|
||||
namespace shaderc_local
|
||||
{
|
||||
static bx::DefaultAllocator s_allocator;
|
||||
bx::AllocatorI* g_allocator = &s_allocator;
|
||||
static bx::AllocatorI* g_allocator = &s_allocator;
|
||||
|
||||
struct TinyStlAllocator
|
||||
{
|
||||
@@ -50,18 +50,18 @@ namespace bgfx
|
||||
bx::free(g_allocator, _ptr);
|
||||
}
|
||||
}
|
||||
} // namespace bgfx
|
||||
} // namespace shaderc_local
|
||||
|
||||
#define TINYSTL_ALLOCATOR bgfx::TinyStlAllocator
|
||||
#include <tinystl/allocator.h>
|
||||
#include <tinystl/string.h>
|
||||
#include <tinystl/unordered_map.h>
|
||||
#include <tinystl/vector.h>
|
||||
#define TINYSTL_ALLOCATOR shaderc_local::TinyStlAllocator
|
||||
#include <TINYSTL/allocator.h>
|
||||
#include <TINYSTL/string.h>
|
||||
#include <TINYSTL/unordered_map.h>
|
||||
#include <TINYSTL/vector.h>
|
||||
namespace stl = tinystl;
|
||||
|
||||
#include "../../src/shader.h"
|
||||
#include "../../src/shader_spirv.h"
|
||||
#include "../../3rdparty/khronos/vulkan-local/vulkan.h"
|
||||
#include "../src/shader.h"
|
||||
#include "../src/shader_spirv.h"
|
||||
#include "../../bgfx_deps/khronos/vulkan-local/vulkan.h"
|
||||
|
||||
namespace bgfx { namespace spirv
|
||||
{
|
||||
@@ -462,20 +462,25 @@ namespace bgfx { namespace spirv
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool useHlslInput = (0 == bx::strCmp(_options.profile.c_str(), "hlsl"));
|
||||
|
||||
glslang::TProgram* program = new glslang::TProgram;
|
||||
glslang::TShader* shader = new glslang::TShader(stage);
|
||||
|
||||
EShMessages messages = EShMessages(0
|
||||
| EShMsgDefault
|
||||
| EShMsgReadHlsl
|
||||
| EShMsgVulkanRules
|
||||
| EShMsgSpvRules
|
||||
| EShMsgDebugInfo
|
||||
| (useHlslInput ? EShMsgReadHlsl : 0)
|
||||
);
|
||||
|
||||
shader->setEntryPoint("main");
|
||||
shader->setAutoMapBindings(true);
|
||||
shader->setEnvInput(glslang::EShSourceHlsl, stage, glslang::EShClientVulkan, s_GLSL_VULKAN_CLIENT_VERSION);
|
||||
shader->setEnvInput(useHlslInput ? glslang::EShSourceHlsl : glslang::EShSourceGlsl,
|
||||
stage,
|
||||
glslang::EShClientVulkan,
|
||||
s_GLSL_VULKAN_CLIENT_VERSION);
|
||||
shader->setEnvClient(glslang::EShClientVulkan, getGlslangTargetVulkanVersion(_version, _messageWriter));
|
||||
shader->setEnvTarget(glslang::EShTargetSpv, getGlslangTargetSpirvVersion(_version, _messageWriter));
|
||||
|
||||
@@ -554,7 +559,7 @@ namespace bgfx { namespace spirv
|
||||
{
|
||||
program->buildReflection();
|
||||
|
||||
if (_firstPass)
|
||||
if (_firstPass && useHlslInput)
|
||||
{
|
||||
// first time through, we just find unused uniforms and get rid of them
|
||||
std::string output;
|
||||
@@ -896,7 +901,8 @@ namespace bgfx { namespace spirv
|
||||
|
||||
bool compileSPIRVShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter)
|
||||
{
|
||||
return spirv::compile(_options, _version, _code, _shaderWriter, _messageWriter, true);
|
||||
const bool useHlslInput = (0 == bx::strCmp(_options.profile.c_str(), "hlsl"));
|
||||
return spirv::compile(_options, _version, _code, _shaderWriter, _messageWriter, useHlslInput);
|
||||
}
|
||||
|
||||
} // namespace bgfx
|
||||
|
||||
@@ -9,6 +9,78 @@ namespace bgfx {
|
||||
|
||||
bool g_verbose = false;
|
||||
|
||||
Options::Options()
|
||||
: shaderType(' ')
|
||||
, disasm(false)
|
||||
, raw(false)
|
||||
, preprocessOnly(false)
|
||||
, depends(false)
|
||||
, debugInformation(false)
|
||||
, avoidFlowControl(false)
|
||||
, noPreshader(false)
|
||||
, partialPrecision(false)
|
||||
, preferFlowControl(false)
|
||||
, backwardsCompatibility(false)
|
||||
, warningsAreErrors(false)
|
||||
, keepIntermediate(false)
|
||||
, optimize(false)
|
||||
, optimizationLevel(3) {
|
||||
}
|
||||
|
||||
void Options::dump() {
|
||||
BX_TRACE("Options:\n"
|
||||
"\t shaderType: %c\n"
|
||||
"\t platform: %s\n"
|
||||
"\t profile: %s\n"
|
||||
"\t inputFile: %s\n"
|
||||
"\t outputFile: %s\n"
|
||||
"\t disasm: %s\n"
|
||||
"\t raw: %s\n"
|
||||
"\t preprocessOnly: %s\n"
|
||||
"\t depends: %s\n"
|
||||
"\t debugInformation: %s\n"
|
||||
"\t avoidFlowControl: %s\n"
|
||||
"\t noPreshader: %s\n"
|
||||
"\t partialPrecision: %s\n"
|
||||
"\t preferFlowControl: %s\n"
|
||||
"\t backwardsCompatibility: %s\n"
|
||||
"\t warningsAreErrors: %s\n"
|
||||
"\t keepIntermediate: %s\n"
|
||||
"\t optimize: %s\n"
|
||||
"\t optimizationLevel: %d\n",
|
||||
shaderType,
|
||||
platform.c_str(),
|
||||
profile.c_str(),
|
||||
inputFilePath.c_str(),
|
||||
outputFilePath.c_str(),
|
||||
disasm ? "true" : "false",
|
||||
raw ? "true" : "false",
|
||||
preprocessOnly ? "true" : "false",
|
||||
depends ? "true" : "false",
|
||||
debugInformation ? "true" : "false",
|
||||
avoidFlowControl ? "true" : "false",
|
||||
noPreshader ? "true" : "false",
|
||||
partialPrecision ? "true" : "false",
|
||||
preferFlowControl ? "true" : "false",
|
||||
backwardsCompatibility ? "true" : "false",
|
||||
warningsAreErrors ? "true" : "false",
|
||||
keepIntermediate ? "true" : "false",
|
||||
optimize ? "true" : "false",
|
||||
optimizationLevel);
|
||||
|
||||
for (size_t ii = 0; ii < includeDirs.size(); ++ii) {
|
||||
BX_TRACE("\t include :%s\n", includeDirs[ii].c_str());
|
||||
}
|
||||
|
||||
for (size_t ii = 0; ii < defines.size(); ++ii) {
|
||||
BX_TRACE("\t define :%s\n", defines[ii].c_str());
|
||||
}
|
||||
|
||||
for (size_t ii = 0; ii < dependencies.size(); ++ii) {
|
||||
BX_TRACE("\t dependency :%s\n", dependencies[ii].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int32_t writef(bx::WriterI* _writer, const char* _format, ...) {
|
||||
va_list argList;
|
||||
va_start(argList, _format);
|
||||
|
||||
73
src/bgfx_tools/src/shader.h
Normal file
73
src/bgfx_tools/src/shader.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2011-2025 Branimir Karadzic. All rights reserved.
|
||||
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
#ifndef BGFX_SHADER_H
|
||||
#define BGFX_SHADER_H
|
||||
|
||||
#include <bx/readerwriter.h>
|
||||
|
||||
namespace bgfx
|
||||
{
|
||||
BX_ERROR_RESULT(kShaderInvalidHeader, BX_MAKEFOURCC('S', 'H', 0, 1) );
|
||||
BX_ERROR_RESULT(kShaderInvalidInstruction, BX_MAKEFOURCC('S', 'H', 0, 2) );
|
||||
|
||||
struct DescriptorType
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
StorageBuffer,
|
||||
StorageImage,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
DescriptorType::Enum idToDescriptorType(uint16_t _id);
|
||||
uint16_t descriptorTypeToId(DescriptorType::Enum _type);
|
||||
|
||||
struct TextureComponentType
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Float,
|
||||
Int,
|
||||
Uint,
|
||||
Depth,
|
||||
UnfilterableFloat,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
TextureComponentType::Enum idToTextureComponentType(uint8_t _id);
|
||||
uint8_t textureComponentTypeToId(TextureComponentType::Enum _type);
|
||||
|
||||
struct TextureDimension
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Dimension1D,
|
||||
Dimension2D,
|
||||
Dimension2DArray,
|
||||
DimensionCube,
|
||||
DimensionCubeArray,
|
||||
Dimension3D,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
TextureDimension::Enum idToTextureDimension(uint8_t _id);
|
||||
uint8_t textureDimensionToId(TextureDimension::Enum _dim);
|
||||
|
||||
///
|
||||
void disassemble(bx::WriterI* _writer, bx::ReaderSeekerI* _reader, bx::Error* _err = NULL);
|
||||
|
||||
///
|
||||
void disassemble(bx::WriterI* _writer, const void* _data, uint32_t _size, bx::Error* _err = NULL);
|
||||
|
||||
} // namespace bgfx
|
||||
|
||||
#endif // BGFX_SHADER_H
|
||||
659
src/bgfx_tools/src/shader_spirv.h
Normal file
659
src/bgfx_tools/src/shader_spirv.h
Normal file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* Copyright 2011-2025 Branimir Karadzic. All rights reserved.
|
||||
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
#ifndef BGFX_SHADER_SPIRV_H
|
||||
#define BGFX_SHADER_SPIRV_H
|
||||
|
||||
#include <bx/readerwriter.h>
|
||||
|
||||
#define SPV_CHUNK_HEADER BX_MAKEFOURCC(0x03, 0x02, 0x23, 0x07)
|
||||
|
||||
namespace bgfx
|
||||
{
|
||||
constexpr uint8_t kSpirvVertexBinding = 0;
|
||||
constexpr uint8_t kSpirvFragmentBinding = 1;
|
||||
constexpr uint8_t kSpirvBindShift = 2;
|
||||
constexpr uint8_t kSpirvSamplerShift = 16;
|
||||
|
||||
constexpr uint8_t kSpirvOldVertexBinding = 0;
|
||||
constexpr uint8_t kSpirvOldFragmentBinding = 48;
|
||||
constexpr uint8_t kSpirvOldFragmentShift = 48;
|
||||
constexpr uint8_t kSpirvOldBufferShift = 16;
|
||||
constexpr uint8_t kSpirvOldImageShift = 32;
|
||||
constexpr uint8_t kSpirvOldTextureShift = 16;
|
||||
|
||||
// Reference(s):
|
||||
// - https://web.archive.org/web/20181126035927/https://www.khronos.org/registry/spir-v/specs/1.0/SPIRV.html
|
||||
//
|
||||
struct SpvOpcode
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Nop,
|
||||
Undef,
|
||||
SourceContinued,
|
||||
Source,
|
||||
SourceExtension,
|
||||
Name,
|
||||
MemberName,
|
||||
String,
|
||||
Line,
|
||||
Invalid9,
|
||||
Extension,
|
||||
ExtInstImport,
|
||||
ExtInst,
|
||||
Invalid13,
|
||||
MemoryModel,
|
||||
EntryPoint,
|
||||
ExecutionMode,
|
||||
Capability,
|
||||
Invalid18,
|
||||
TypeVoid,
|
||||
TypeBool,
|
||||
TypeInt,
|
||||
TypeFloat,
|
||||
TypeVector,
|
||||
TypeMatrix,
|
||||
TypeImage,
|
||||
TypeSampler,
|
||||
TypeSampledImage,
|
||||
TypeArray,
|
||||
TypeRuntimeArray,
|
||||
TypeStruct,
|
||||
TypeOpaque,
|
||||
TypePointer,
|
||||
TypeFunction,
|
||||
TypeEvent,
|
||||
TypeDeviceEvent,
|
||||
TypeReserveId,
|
||||
TypeQueue,
|
||||
TypePipe,
|
||||
TypeForwardPointer,
|
||||
Invalid40,
|
||||
ConstantTrue,
|
||||
ConstantFalse,
|
||||
Constant,
|
||||
ConstantComposite,
|
||||
ConstantSampler,
|
||||
ConstantNull,
|
||||
Invalid47,
|
||||
SpecConstantTrue,
|
||||
SpecConstantFalse,
|
||||
SpecConstant,
|
||||
SpecConstantComposite,
|
||||
SpecConstantOp,
|
||||
Invalid53,
|
||||
Function,
|
||||
FunctionParameter,
|
||||
FunctionEnd,
|
||||
FunctionCall,
|
||||
Invalid58,
|
||||
Variable,
|
||||
ImageTexelPointer,
|
||||
Load,
|
||||
Store,
|
||||
CopyMemory,
|
||||
CopyMemorySized,
|
||||
AccessChain,
|
||||
InBoundsAccessChain,
|
||||
PtrAccessChain,
|
||||
ArrayLength,
|
||||
GenericPtrMemSemantics,
|
||||
InBoundsPtrAccessChain,
|
||||
Decorate,
|
||||
MemberDecorate,
|
||||
DecorationGroup,
|
||||
GroupDecorate,
|
||||
GroupMemberDecorate,
|
||||
Invalid76,
|
||||
VectorExtractDynamic,
|
||||
VectorInsertDynamic,
|
||||
VectorShuffle,
|
||||
CompositeConstruct,
|
||||
CompositeExtract,
|
||||
CompositeInsert,
|
||||
CopyObject,
|
||||
Transpose,
|
||||
Invalid85,
|
||||
SampledImage,
|
||||
ImageSampleImplicitLod,
|
||||
ImageSampleExplicitLod,
|
||||
ImageSampleDrefImplicitLod,
|
||||
ImageSampleDrefExplicitLod,
|
||||
ImageSampleProjImplicitLod,
|
||||
ImageSampleProjExplicitLod,
|
||||
ImageSampleProjDrefImplicitLod,
|
||||
ImageSampleProjDrefExplicitLod,
|
||||
ImageFetch,
|
||||
ImageGather,
|
||||
ImageDrefGather,
|
||||
ImageRead,
|
||||
ImageWrite,
|
||||
Image,
|
||||
ImageQueryFormat,
|
||||
ImageQueryOrder,
|
||||
ImageQuerySizeLod,
|
||||
ImageQuerySize,
|
||||
ImageQueryLod,
|
||||
ImageQueryLevels,
|
||||
ImageQuerySamples,
|
||||
Invalid108,
|
||||
ConvertFToU,
|
||||
ConvertFToS,
|
||||
ConvertSToF,
|
||||
ConvertUToF,
|
||||
UConvert,
|
||||
SConvert,
|
||||
FConvert,
|
||||
QuantizeToF16,
|
||||
ConvertPtrToU,
|
||||
SatConvertSToU,
|
||||
SatConvertUToS,
|
||||
ConvertUToPtr,
|
||||
PtrCastToGeneric,
|
||||
GenericCastToPtr,
|
||||
GenericCastToPtrExplicit,
|
||||
Bitcast,
|
||||
Invalid125,
|
||||
SNegate,
|
||||
FNegate,
|
||||
IAdd,
|
||||
FAdd,
|
||||
ISub,
|
||||
FSub,
|
||||
IMul,
|
||||
FMul,
|
||||
UDiv,
|
||||
SDiv,
|
||||
FDiv,
|
||||
UMod,
|
||||
SRem,
|
||||
SMod,
|
||||
FRem,
|
||||
FMod,
|
||||
VectorTimesScalar,
|
||||
MatrixTimesScalar,
|
||||
VectorTimesMatrix,
|
||||
MatrixTimesVector,
|
||||
MatrixTimesMatrix,
|
||||
OuterProduct,
|
||||
Dot,
|
||||
IAddCarry,
|
||||
ISubBorrow,
|
||||
UMulExtended,
|
||||
SMulExtended,
|
||||
Invalid153,
|
||||
Any,
|
||||
All,
|
||||
IsNan,
|
||||
IsInf,
|
||||
IsFinite,
|
||||
IsNormal,
|
||||
SignBitSet,
|
||||
LessOrGreater,
|
||||
Ordered,
|
||||
Unordered,
|
||||
LogicalEqual,
|
||||
LogicalNotEqual,
|
||||
LogicalOr,
|
||||
LogicalAnd,
|
||||
LogicalNot,
|
||||
Select,
|
||||
IEqual,
|
||||
INotEqual,
|
||||
UGreaterThan,
|
||||
SGreaterThan,
|
||||
UGreaterThanEqual,
|
||||
SGreaterThanEqual,
|
||||
ULessThan,
|
||||
SLessThan,
|
||||
ULessThanEqual,
|
||||
SLessThanEqual,
|
||||
FOrdEqual,
|
||||
FUnordEqual,
|
||||
FOrdNotEqual,
|
||||
FUnordNotEqual,
|
||||
FOrdLessThan,
|
||||
FUnordLessThan,
|
||||
FOrdGreaterThan,
|
||||
FUnordGreaterThan,
|
||||
FOrdLessThanEqual,
|
||||
FUnordLessThanEqual,
|
||||
FOrdGreaterThanEqual,
|
||||
FUnordGreaterThanEqual,
|
||||
Invalid192,
|
||||
Invalid193,
|
||||
ShiftRightLogical,
|
||||
ShiftRightArithmetic,
|
||||
ShiftLeftLogical,
|
||||
BitwiseOr,
|
||||
BitwiseXor,
|
||||
BitwiseAnd,
|
||||
Not,
|
||||
BitFieldInsert,
|
||||
BitFieldSExtract,
|
||||
BitFieldUExtract,
|
||||
BitReverse,
|
||||
BitCount,
|
||||
Invalid206,
|
||||
DPdx,
|
||||
DPdy,
|
||||
Fwidth,
|
||||
DPdxFine,
|
||||
DPdyFine,
|
||||
FwidthFine,
|
||||
DPdxCoarse,
|
||||
DPdyCoarse,
|
||||
FwidthCoarse,
|
||||
Invalid216,
|
||||
Invalid217,
|
||||
EmitVertex,
|
||||
EndPrimitive,
|
||||
EmitStreamVertex,
|
||||
EndStreamPrimitive,
|
||||
Invalid222,
|
||||
Invalid223,
|
||||
ControlBarrier,
|
||||
MemoryBarrier,
|
||||
Invalid226,
|
||||
AtomicLoad,
|
||||
AtomicStore,
|
||||
AtomicExchange,
|
||||
AtomicCompareExchange,
|
||||
AtomicCompareExchangeWeak,
|
||||
AtomicIIncrement,
|
||||
AtomicIDecrement,
|
||||
AtomicIAdd,
|
||||
AtomicISub,
|
||||
AtomicSMin,
|
||||
AtomicUMin,
|
||||
AtomicSMax,
|
||||
AtomicUMax,
|
||||
AtomicAnd,
|
||||
AtomicOr,
|
||||
AtomicXor,
|
||||
Invalid243,
|
||||
Invalid244,
|
||||
Phi,
|
||||
LoopMerge,
|
||||
SelectionMerge,
|
||||
Label,
|
||||
Branch,
|
||||
BranchConditional,
|
||||
Switch,
|
||||
Kill,
|
||||
Return,
|
||||
ReturnValue,
|
||||
Unreachable,
|
||||
LifetimeStart,
|
||||
LifetimeStop,
|
||||
Invalid258,
|
||||
GroupAsyncCopy,
|
||||
GroupWaitEvents,
|
||||
GroupAll,
|
||||
GroupAny,
|
||||
GroupBroadcast,
|
||||
GroupIAdd,
|
||||
GroupFAdd,
|
||||
GroupFMin,
|
||||
GroupUMin,
|
||||
GroupSMin,
|
||||
GroupFMax,
|
||||
GroupUMax,
|
||||
GroupSMax,
|
||||
Invalid272,
|
||||
Invalid273,
|
||||
ReadPipe,
|
||||
WritePipe,
|
||||
ReservedReadPipe,
|
||||
ReservedWritePipe,
|
||||
ReserveReadPipePackets,
|
||||
ReserveWritePipePackets,
|
||||
CommitReadPipe,
|
||||
CommitWritePipe,
|
||||
IsValidReserveId,
|
||||
GetNumPipePackets,
|
||||
GetMaxPipePackets,
|
||||
GroupReserveReadPipePackets,
|
||||
GroupReserveWritePipePackets,
|
||||
GroupCommitReadPipe,
|
||||
GroupCommitWritePipe,
|
||||
Invalid289,
|
||||
Invalid290,
|
||||
EnqueueMarker,
|
||||
EnqueueKernel,
|
||||
GetKernelNDrangeSubGroupCount,
|
||||
GetKernelNDrangeMaxSubGroupSize,
|
||||
GetKernelWorkGroupSize,
|
||||
GetKernelPreferredWorkGroupSizeMultiple,
|
||||
RetainEvent,
|
||||
ReleaseEvent,
|
||||
CreateUserEvent,
|
||||
IsValidEvent,
|
||||
SetUserEventStatus,
|
||||
CaptureEventProfilingInfo,
|
||||
GetDefaultQueue,
|
||||
BuildNDRange,
|
||||
ImageSparseSampleImplicitLod,
|
||||
ImageSparseSampleExplicitLod,
|
||||
ImageSparseSampleDrefImplicitLod,
|
||||
ImageSparseSampleDrefExplicitLod,
|
||||
ImageSparseSampleProjImplicitLod,
|
||||
ImageSparseSampleProjExplicitLod,
|
||||
ImageSparseSampleProjDrefImplicitLod,
|
||||
ImageSparseSampleProjDrefExplicitLod,
|
||||
ImageSparseFetch,
|
||||
ImageSparseGather,
|
||||
ImageSparseDrefGather,
|
||||
ImageSparseTexelsResident,
|
||||
NoLine,
|
||||
AtomicFlagTestAndSet,
|
||||
AtomicFlagClear,
|
||||
ImageSparseRead,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
const char* getName(SpvOpcode::Enum _opcode);
|
||||
|
||||
struct SpvBuiltin
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Position,
|
||||
PointSize,
|
||||
ClipDistance,
|
||||
CullDistance,
|
||||
VertexId,
|
||||
InstanceId,
|
||||
PrimitiveId,
|
||||
InvocationId,
|
||||
Layer,
|
||||
ViewportIndex,
|
||||
TessLevelOuter,
|
||||
TessLevelInner,
|
||||
TessCoord,
|
||||
PatchVertices,
|
||||
FragCoord,
|
||||
PointCoord,
|
||||
FrontFacing,
|
||||
SampleId,
|
||||
SamplePosition,
|
||||
SampleMask,
|
||||
FragDepth,
|
||||
HelperInvocation,
|
||||
NumWorkgroups,
|
||||
WorkgroupSize,
|
||||
WorkgroupId,
|
||||
LocalInvocationId,
|
||||
GlobalInvocationId,
|
||||
LocalInvocationIndex,
|
||||
WorkDim,
|
||||
GlobalSize,
|
||||
EnqueuedWorkgroupSize,
|
||||
GlobalOffset,
|
||||
GlobalLinearId,
|
||||
SubgroupSize,
|
||||
SubgroupMaxSize,
|
||||
NumSubgroups,
|
||||
NumEnqueuedSubgroups,
|
||||
SubgroupId,
|
||||
SubgroupLocalInvocationId,
|
||||
VertexIndex,
|
||||
InstanceIndex,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
const char* getName(SpvBuiltin::Enum _enum);
|
||||
|
||||
struct SpvExecutionModel
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Vertex,
|
||||
TessellationControl,
|
||||
TessellationEvaluation,
|
||||
Geometry,
|
||||
Fragment,
|
||||
GLCompute,
|
||||
Kernel,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct SpvAddressingModel
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Logical,
|
||||
Physical32,
|
||||
Physical64,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct SpvMemoryModel
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Simple,
|
||||
GLSL450,
|
||||
OpenCL,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
struct SpvStorageClass
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
UniformConstant,
|
||||
Input,
|
||||
Uniform,
|
||||
Output,
|
||||
Workgroup,
|
||||
CrossWorkgroup,
|
||||
Private,
|
||||
Function,
|
||||
Generic,
|
||||
PushConstant,
|
||||
AtomicCounter,
|
||||
Image,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
const char* getName(SpvStorageClass::Enum _enum);
|
||||
|
||||
struct SpvResourceDim
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
Texture1D,
|
||||
Texture2D,
|
||||
Texture3D,
|
||||
TextureCube,
|
||||
TextureRect,
|
||||
Buffer,
|
||||
SubpassData,
|
||||
};
|
||||
};
|
||||
|
||||
struct SpvDecoration
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
RelaxedPrecision,
|
||||
SpecId,
|
||||
Block,
|
||||
BufferBlock,
|
||||
RowMajor,
|
||||
ColMajor,
|
||||
ArrayStride,
|
||||
MatrixStride,
|
||||
GLSLShared,
|
||||
GLSLPacked,
|
||||
CPacked,
|
||||
BuiltIn,
|
||||
Unknown12,
|
||||
NoPerspective,
|
||||
Flat,
|
||||
Patch,
|
||||
Centroid,
|
||||
Sample,
|
||||
Invariant,
|
||||
Restrict,
|
||||
Aliased,
|
||||
Volatile,
|
||||
Constant,
|
||||
Coherent,
|
||||
NonWritable,
|
||||
NonReadable,
|
||||
Uniform,
|
||||
Unknown27,
|
||||
SaturatedConversion,
|
||||
Stream,
|
||||
Location,
|
||||
Component,
|
||||
Index,
|
||||
Binding,
|
||||
DescriptorSet,
|
||||
Offset,
|
||||
XfbBuffer,
|
||||
XfbStride,
|
||||
FuncParamAttr,
|
||||
FPRoundingMode,
|
||||
FPFastMathMode,
|
||||
LinkageAttributes,
|
||||
NoContraction,
|
||||
InputAttachmentIndex,
|
||||
Alignment,
|
||||
|
||||
Count
|
||||
};
|
||||
};
|
||||
|
||||
const char* getName(SpvDecoration::Enum _enum);
|
||||
|
||||
struct SpvOperand
|
||||
{
|
||||
SpvOperand() { /* not pod */ }
|
||||
|
||||
enum Enum
|
||||
{
|
||||
AccessQualifier,
|
||||
AddressingModel,
|
||||
Base,
|
||||
Capability,
|
||||
Component,
|
||||
ComponentType,
|
||||
Composite,
|
||||
Condition,
|
||||
Coordinate,
|
||||
Decoration,
|
||||
Dim,
|
||||
Dref,
|
||||
ElementType,
|
||||
ExecutionModel,
|
||||
Function,
|
||||
FunctionControl,
|
||||
Id,
|
||||
IdRep,
|
||||
ImageFormat,
|
||||
ImageOperands,
|
||||
LinkageType,
|
||||
LiteralNumber,
|
||||
LiteralRep,
|
||||
LiteralString,
|
||||
Matrix,
|
||||
MemoryAccess,
|
||||
MemoryModel,
|
||||
Object,
|
||||
Pointer,
|
||||
SampledType,
|
||||
SampledImage,
|
||||
SamplerAddressingMode,
|
||||
SamplerFilterMode,
|
||||
Scalar,
|
||||
SourceLanguage,
|
||||
StorageClass,
|
||||
StructureType,
|
||||
Vector,
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
Enum type;
|
||||
uint32_t data;
|
||||
|
||||
stl::string literalString;
|
||||
};
|
||||
|
||||
struct SpvInstruction
|
||||
{
|
||||
SpvInstruction() { /* not pod */ }
|
||||
|
||||
SpvOpcode::Enum opcode;
|
||||
uint16_t length;
|
||||
uint16_t numOperands;
|
||||
|
||||
uint32_t type;
|
||||
uint32_t result;
|
||||
bool hasType;
|
||||
bool hasResult;
|
||||
|
||||
SpvOperand operand[32];
|
||||
};
|
||||
|
||||
int32_t read(bx::ReaderI* _reader, SpvInstruction& _instruction, bx::Error* _err);
|
||||
int32_t write(bx::WriterI* _writer, const SpvInstruction& _instruction, bx::Error* _err);
|
||||
int32_t toString(char* _out, int32_t _size, const SpvInstruction& _instruction);
|
||||
|
||||
struct SpvShader
|
||||
{
|
||||
SpvShader() { /* not pod */ }
|
||||
|
||||
stl::vector<uint8_t> byteCode;
|
||||
};
|
||||
|
||||
int32_t read(bx::ReaderSeekerI* _reader, SpvShader& _shader, bx::Error* _err);
|
||||
int32_t write(bx::WriterI* _writer, const SpvShader& _shader, bx::Error* _err);
|
||||
|
||||
typedef bool (*SpvParseFn)(uint32_t _offset, const SpvInstruction& _instruction, void* _userData);
|
||||
void parse(const SpvShader& _src, SpvParseFn _fn, void* _userData, bx::Error* _err = NULL);
|
||||
|
||||
typedef void (*SpvFilterFn)(SpvInstruction& _instruction, void* _userData);
|
||||
void filter(SpvShader& _dst, const SpvShader& _src, SpvFilterFn _fn, void* _userData, bx::Error* _err = NULL);
|
||||
|
||||
struct SpirV
|
||||
{
|
||||
SpirV() { /* not pod */ }
|
||||
|
||||
struct Header
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t generator;
|
||||
uint32_t bound;
|
||||
uint32_t schema;
|
||||
};
|
||||
|
||||
Header header;
|
||||
SpvShader shader;
|
||||
};
|
||||
|
||||
int32_t read(bx::ReaderSeekerI* _reader, SpirV& _spirv, bx::Error* _err);
|
||||
int32_t write(bx::WriterSeekerI* _writer, const SpirV& _spirv, bx::Error* _err);
|
||||
|
||||
} // namespace bgfx
|
||||
|
||||
#endif // BGFX_SHADER_SPIRV_H
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "bgfx_graphics_backend.hpp"
|
||||
#include "bgfx_shader_compiler.hpp"
|
||||
#include "../interfaces/i_pipeline_compiler_service.hpp"
|
||||
#include <stb_image.h>
|
||||
|
||||
@@ -677,67 +678,18 @@ bgfx::ShaderHandle BgfxGraphicsBackend::CreateShader(const std::string& label,
|
||||
logger_->Trace("BgfxGraphicsBackend", "CreateShader",
|
||||
"label=" + label +
|
||||
", renderer=" + RendererTypeName(rendererType) +
|
||||
", sourceLength=" + std::to_string(source.size()));
|
||||
", sourceLength=" + std::to_string(source.size()) +
|
||||
", compiler=BgfxShaderCompiler");
|
||||
}
|
||||
|
||||
// For OpenGL, bgfx expects raw GLSL source (no wrapper needed)
|
||||
// For Vulkan/Metal/DX, bgfx expects SPIRV wrapped in binary format
|
||||
const bool isOpenGL = (rendererType == bgfx::RendererType::OpenGL ||
|
||||
rendererType == bgfx::RendererType::OpenGLES);
|
||||
|
||||
if (isOpenGL) {
|
||||
// For OpenGL: Just copy GLSL source directly
|
||||
const uint32_t sourceSize = static_cast<uint32_t>(source.size());
|
||||
const bgfx::Memory* mem = bgfx::copy(source.c_str(), sourceSize + 1); // +1 for null terminator
|
||||
|
||||
bgfx::ShaderHandle handle = bgfx::createShader(mem);
|
||||
if (!bgfx::isValid(handle) && logger_) {
|
||||
logger_->Error("bgfx::createShader failed for " + label +
|
||||
" (renderer=" + RendererTypeName(rendererType) + ")");
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
// Use PipelineCompilerService to compile shader via bgfx_tools
|
||||
std::string tempInputPath = "/tmp/" + label + (isVertex ? ".vert.glsl" : ".frag.glsl");
|
||||
std::string tempOutputPath = "/tmp/" + label + (isVertex ? ".vert.bin" : ".frag.bin");
|
||||
// Write source to tempInputPath
|
||||
{
|
||||
std::ofstream ofs(tempInputPath);
|
||||
ofs << source;
|
||||
}
|
||||
std::vector<std::string> args;
|
||||
// Add any required args for bgfx_tools/shaderc here (e.g., profile, macros)
|
||||
bool success = pipelineCompiler_ && pipelineCompiler_->Compile(tempInputPath, tempOutputPath, args);
|
||||
if (!success) {
|
||||
std::string error = pipelineCompiler_ ? pipelineCompiler_->GetLastError().value_or("") : "No compiler service";
|
||||
BgfxShaderCompiler compiler(logger_, pipelineCompiler_);
|
||||
bgfx::ShaderHandle handle = compiler.CompileShader(label, source, isVertex, {}, {});
|
||||
if (!bgfx::isValid(handle)) {
|
||||
if (logger_) {
|
||||
logger_->Error("PipelineCompilerService failed: " + label + "\n" + error);
|
||||
logger_->Error("BgfxGraphicsBackend::CreateShader failed for " + label +
|
||||
" (renderer=" + RendererTypeName(rendererType) + ")");
|
||||
}
|
||||
throw std::runtime_error("PipelineCompilerService failed: " + label + "\n" + error);
|
||||
}
|
||||
// Read compiled binary
|
||||
std::ifstream ifs(tempOutputPath, std::ios::binary | std::ios::ate);
|
||||
if (!ifs) {
|
||||
if (logger_) {
|
||||
logger_->Error("Failed to read compiled shader: " + tempOutputPath);
|
||||
}
|
||||
throw std::runtime_error("Failed to read compiled shader: " + tempOutputPath);
|
||||
}
|
||||
std::streamsize size = ifs.tellg();
|
||||
ifs.seekg(0, std::ios::beg);
|
||||
std::vector<char> buffer(size);
|
||||
if (!ifs.read(buffer.data(), size)) {
|
||||
if (logger_) {
|
||||
logger_->Error("Failed to read compiled shader data: " + tempOutputPath);
|
||||
}
|
||||
throw std::runtime_error("Failed to read compiled shader data: " + tempOutputPath);
|
||||
}
|
||||
const bgfx::Memory* mem = bgfx::copy(buffer.data(), static_cast<uint32_t>(size));
|
||||
bgfx::ShaderHandle handle = bgfx::createShader(mem);
|
||||
if (!bgfx::isValid(handle) && logger_) {
|
||||
logger_->Error("bgfx::createShader failed for " + label + " (renderer=" + RendererTypeName(rendererType) + ", binSize=" + std::to_string(size) + ")");
|
||||
throw std::runtime_error("BgfxGraphicsBackend::CreateShader failed for " + label);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user