Shader linking i guess

This commit is contained in:
2026-04-12 14:52:33 +03:00
parent 79ceac1005
commit 457b455042
38 changed files with 12534 additions and 114 deletions

View File

@@ -0,0 +1,105 @@
#include "tier2/fileformats/json.h"
#include "tier2/ifilesystem.h"
#include "tier0/commandline.h"
#include "tier0/mem.h"
#include "helper.h"
#define EXTERNAL "../../external/"
#define GRAMMAR EXTERNAL"SPIRV-Headers/include/spirv/unified1/spirv.core.grammar.json"
#define OUTPUT "rtlinker_gen.cpp"
DECLARE_BUILD_STAGE(SpirvOperandsGen)
{
if (!filesystem2->ShouldRecompile(GRAMMAR, OUTPUT))
return 0;
if (!filesystem2->ShouldRecompile(__FILE__, OUTPUT))
return 0;
IFileHandle *pHandle = filesystem->Open(GRAMMAR, FILEMODE_READ);
if (pHandle == NULL)
return 0;
const char *szContents = filesystem->ReadString(pHandle);
filesystem->Close(pHandle);
pHandle = filesystem->Open(OUTPUT, FILEMODE_WRITE);
IJSONValue *pRoot = JSONManager()->ReadString(szContents);
IJSONArray *instructions = pRoot->GetObject()->GetValue("instructions")->GetArray();
filesystem->PrintF( pHandle, "#include \"rtlinker_gen.h\"\n");
filesystem->PrintF( pHandle, "int SpvGetOperandCount( int op )\n{\nswitch ( op ) {\n");
for ( int i = 0; i < instructions->GetCount(); i++)
{
IJSONObject *op = instructions->GetParameter(i)->GetObject();
if (op->GetValue("operands"))
filesystem->PrintF( pHandle, "case %.0f: return %u;\n", op->GetValue("opcode")->GetNumberValue(), op->GetValue("operands")->GetArray()->GetCount());
}
filesystem->PrintF( pHandle, "default: break;\n}\nreturn 0;\n}\n");
filesystem->PrintF( pHandle, "void SpvGetOperands( int op, ESpirvOperandType *pTypes )\n{\nswitch ( op ) {\n");
for ( int i = 0; i < instructions->GetCount(); i++)
{
IJSONObject *op = instructions->GetParameter(i)->GetObject();
if (op->GetValue("operands"))
{
IJSONArray *operands = op->GetValue("operands")->GetArray();
filesystem->PrintF( pHandle, "case %.0f:\n", op->GetValue("opcode")->GetNumberValue());
for ( int o = 0; o < operands->GetCount(); o++ )
{
CUtlString type = operands->GetParameter(o)->GetObject()->GetValue("kind")->GetStringValue();
if (type == "IdRef")
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirv_RefId;\n",o);
else if (type == "IdResult")
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirv_ResultId;\n",o);
else if (type == "IdResultType")
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirv_ResultTypeId;\n",o);
else if (type == "IdScope")
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirv_ScopeId;\n",o);
else if (type == "IdMemorySemantics")
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirv_MemorySemanticsId;\n",o);
}
filesystem->PrintF( pHandle, "break;\n");
}
}
filesystem->PrintF( pHandle, "default: break;\n}\n");
filesystem->PrintF( pHandle, "}\n");
filesystem->PrintF( pHandle, "void SpvGetOperandFlags( int op, ESpirvOperandFlags *pTypes )\n{\nswitch ( op ) {\n");
for ( int i = 0; i < instructions->GetCount(); i++)
{
IJSONObject *op = instructions->GetParameter(i)->GetObject();
if (op->GetValue("operands"))
{
IJSONArray *operands = op->GetValue("operands")->GetArray();
filesystem->PrintF( pHandle, "case %.0f:\n", op->GetValue("opcode")->GetNumberValue());
for ( int o = 0; o < operands->GetCount(); o++ )
{
IJSONValue *q = operands->GetParameter(o)->GetObject()->GetValue("quantifier");
if (q == 0)
{
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirvOperandFlags_None;\n",o);
continue;
}
CUtlString type = q->GetStringValue();
if (type == NULL)
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirvOperandFlags_None;\n",o);
if (type == "?")
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirvOperandFlags_Optional;\n",o);
else if (type == "*")
filesystem->PrintF( pHandle, "pTypes[%u] = k_ESpirvOperandFlags_Array;\n",o);
}
filesystem->PrintF( pHandle, "break;\n");
}
}
filesystem->PrintF( pHandle, "default: break;\n}\n");
filesystem->PrintF( pHandle, "}\n");
filesystem->Close( pHandle );
V_free((void*)szContents);
return 0;
}

View File

@@ -23,7 +23,7 @@ static const char *s_vkDeviceExtensions[] = {
#undef REQUIRED_EXTENSION
#undef OPTIONAL_EXTENSION
SupportedVulkanExtensions_t g_vkAvailableExtensions;
SupportedVulkanExtensions_t g_vkAvailableExtensions = {};
uint32_t g_iDrawFamily;
@@ -458,7 +458,9 @@ public:
IBuffer *CreateBufferAligned( uint32_t nSize, uint32_t nAlignment, VkBufferUsageFlags2 eUsage );
virtual IShader *CreateShader( const char *szName ) override;
virtual void DestroyShader( IShader *pShader ) override;
virtual IRayTracingShader *CreateRayShader( const char *szName ) override;
virtual IComputeShader *CreateComputeShader( const char *szName ) override;
virtual void DestroyShader( IBaseShader *pShader ) override;
virtual IMaterial *CreateMaterial( IShader *pShader ) override;
virtual void DestroyMaterial( IMaterial *pMaterial ) override;
@@ -593,7 +595,21 @@ IShader *CVkRenderContext::CreateShader( const char *szName )
return pShader;
}
void CVkRenderContext::DestroyShader( IShader *pShader )
IRayTracingShader *CVkRenderContext::CreateRayShader( const char *szName )
{
CVkRayTracingShader *pShader = new CVkRayTracingShader();
VkGraphicsPipelineCreateInfo stPipelineCreateInfo = {};
ICompiledShaderManager *pCompiledShaderManager = (ICompiledShaderManager*)CreateInterface(COMPILED_SHADER_MANAGER_INTERFACE_VERSION, NULL);
pCompiledShaderManager->ReadFromFile(&pShader->m_shader, szName);
pShader->m_hDevice = s_vkDevice;
return pShader;
}
IComputeShader *CVkRenderContext::CreateComputeShader( const char *szName )
{
}
void CVkRenderContext::DestroyShader( IBaseShader *pShader )
{
delete pShader;
}

View File

@@ -0,0 +1,249 @@
#include "rtlinker.h"
#define SPV_ENABLE_UTILITY_CODE
#include "spirv/unified1/spirv.h"
#include "rtlinker_gen.h"
#include "tier2/ifilesystem.h"
#include "tier1/utlstring.h"
#define MINI_SPIRV_IMPLEMENTATION
#include "../minispv/minispv.h"
class CSpirvModule
{
CUtlVector<SpvCapability> m_capabilities;
CUtlVector<CUtlString> m_extensions;
CUtlVector<CUtlString> m_instructionImports;
SpvAddressingModel m_addressingModel;
SpvMemoryModel m_memoryModel;
CUtlVector<CUtlString> m_entryPoints;
};
void CVkShaderLinker::SetMainSpirv( uint32_t size, uint32_t *data )
{
m_main = (SpirvShader_t){size,data};
}
void CVkShaderLinker::AddSpirv( uint32_t size, uint32_t *data )
{
m_shaders.AppendTail((SpirvShader_t){size,data});
}
#define SET_LAST(a) if ( a > last ) last = a;
void CVkShaderLinker::Build()
{
mspv_module *mod = mspv_read_module(m_main.m_size, m_main.m_data);
uint32_t last = 0;
uint32_t current = 0;
for ( int i = 0; i < mod->types.count; i++ )
{
SET_LAST(mod->types.data[i].id);
}
for ( int i = 0; i < mod->ext_instructions.count; i++ )
{
SET_LAST(mod->ext_instructions.data[i].id);
}
for ( int i = 0; i < mod->variables.count; i++ )
{
SET_LAST(mod->variables.data[i].result);
SET_LAST(mod->variables.data[i].resulttype);
}
for ( int i = 0; i < mod->functions.count; i++ )
{
SET_LAST(mod->functions.data[i].result);
mspv_function &f = mod->functions.data[i];
for ( int u = 0; u < f.instructions.len; )
{
SpvOp op = (SpvOp)(f.instructions.data[u]&0xFFFF);
uint32_t uOpLen = f.instructions.data[u]>>16;
uint32_t uOpCount = SpvGetOperandCount(op);
if (uOpCount == 0)
{
u+=uOpLen;
continue;
}
ESpirvOperandType *peOps = (ESpirvOperandType *)V_malloc(uOpCount*sizeof(ESpirvOperandType));
ESpirvOperandFlags *peFlags = (ESpirvOperandFlags *)V_malloc(uOpCount*sizeof(ESpirvOperandFlags));
SpvGetOperands(op, peOps);
SpvGetOperandFlags(op, peFlags);
for ( int c = 0, uParam = 0; (c < uOpCount) && (c < uOpLen-1); c++ )
{
switch (peOps[c])
{
case k_ESpirv_RefId:
case k_ESpirv_ResultId:
case k_ESpirv_ResultTypeId:
case k_ESpirv_ScopeId:
case k_ESpirv_MemorySemanticsId:
if (peFlags[uParam]==k_ESpirvOperandFlags_None)
{
uParam++;
}
SET_LAST(f.instructions.data[u+c+1]);
break;
default:
break;
}
}
u+=uOpLen;
V_free(peOps);
}
}
current = last;
/* now we can combine shaders*/
CUtlVector<uint32_t> functions = {};
for (auto &shader: m_shaders)
{
mspv_module *s = mspv_read_module(shader.m_size, shader.m_data);
for ( int i = 0; i < s->capabilities.count; i++ )
{
mspv_array_push(mod->capabilities, s->capabilities.data[i]);
}
for ( int i = 0; i < s->extensions.count; i++ )
{
mspv_array_push(mod->extensions, s->extensions.data[i]);
}
for ( int i = 0; i < s->ext_instructions.count; i++ )
{
SET_LAST(s->ext_instructions.data[i].id);
}
for ( int i = 0; i < s->entry_points.count; i++ )
{
functions.AppendTail(s->entry_points.data[i].id+current);
SET_LAST(s->entry_points.data[i].id+current);
}
for ( int i = 0; i < s->variables.count; i++ )
{
s->variables.data[i].result+=current;
s->variables.data[i].resulttype+=current;
SET_LAST(s->variables.data[i].result)
SET_LAST(s->variables.data[i].resulttype)
mspv_array_push(mod->variables, s->variables.data[i]);
}
for ( int i = 0; i < s->types.count; i++ )
{
s->types.data[i].id+=current;
mspv_data_view &dv = s->types.data[i].dv;
SET_LAST(s->types.data[i].id);
SpvOp op = (SpvOp)(dv.data[0]&0xFFFF);
uint32_t uOpLen = dv.data[0]>>16;
uint32_t uOpCount = SpvGetOperandCount(op);
if (uOpCount == 0)
{
continue;
}
ESpirvOperandType *peOps = (ESpirvOperandType *)V_malloc(uOpCount*sizeof(ESpirvOperandType));
ESpirvOperandFlags *peFlags = (ESpirvOperandFlags *)V_malloc(uOpCount*sizeof(ESpirvOperandFlags));
SpvGetOperands(op, peOps);
SpvGetOperandFlags(op, peFlags);
/* shift the stuff */
for ( int c = 0, uParam = 0; (c < uOpCount) && (c < uOpLen-1); c++ )
{
switch (peOps[uParam])
{
case k_ESpirv_RefId:
case k_ESpirv_ResultId:
case k_ESpirv_ResultTypeId:
case k_ESpirv_ScopeId:
case k_ESpirv_MemorySemanticsId:
if (peFlags[uParam]==k_ESpirvOperandFlags_None)
{
dv.data[c+1]+=current;
uParam++;
}
if (peFlags[uParam]==k_ESpirvOperandFlags_Array)
{
dv.data[c+1]+=current;
};
SET_LAST(dv.data[c+1]);
break;
default:
break;
}
}
V_free(peFlags);
V_free(peOps);
mspv_array_push(mod->types, s->types.data[i]);
}
for ( int i = 0; i < s->functions.count; i++ )
{
s->functions.data[i].result+=current;
SET_LAST(s->functions.data[i].result);
mspv_function &f = s->functions.data[i];
for ( int u = 0; u < f.instructions.len; )
{
SpvOp op = (SpvOp)(f.instructions.data[u]&0xFFFF);
uint32_t uOpLen = f.instructions.data[u]>>16;
uint32_t uOpCount = SpvGetOperandCount(op);
if (uOpCount == 0)
{
u+=uOpLen;
continue;
}
ESpirvOperandType *peOps = (ESpirvOperandType *)V_malloc(uOpCount*sizeof(ESpirvOperandType));
SpvGetOperands(op, peOps);
/* shift the stuff */
for ( int c = 0; c < uOpCount && c < (uOpLen-1); c++ )
{
switch (peOps[c])
{
case k_ESpirv_RefId:
case k_ESpirv_ResultId:
case k_ESpirv_ResultTypeId:
case k_ESpirv_ScopeId:
case k_ESpirv_MemorySemanticsId:
f.instructions.data[u+c+1]+=current;
SET_LAST(f.instructions.data[u+c+1]);
break;
default:
break;
}
}
u+=uOpLen;
V_free(peOps);
}
mspv_array_push(mod->functions, s->functions.data[i]);
}
current = last;
}
mspv_spv spv = mspv_write_module(mod);
mspv_close_module(mod);
m_out.m_data = spv.data;
m_out.m_size = spv.count;
IFileHandle *ph = filesystem->Open("a.txt", FILEMODE_WRITE);
filesystem->Write(ph, spv.data, spv.count*4);
filesystem->Close(ph);
mspv_array_destroy(spv);
}
uint32_t CVkShaderLinker::GetSize()
{
return m_out.m_size;
}
uint32_t *CVkShaderLinker::GetData()
{
return m_out.m_data;
}

View File

@@ -0,0 +1,28 @@
#ifndef VULKAN_RT_COMPILER_H
#define VULKAN_RT_COMPILER_H
#include "tier1/utlvector.h"
class CVkShaderLinker
{
public:
void SetMainSpirv( uint32_t size, uint32_t *data );
void AddSpirv( uint32_t size, uint32_t *data );
void Build();
uint32_t GetSize();
uint32_t *GetData();
private:
struct SpirvShader_t
{
uint32_t m_size;
uint32_t *m_data;
};
CUtlVector<SpirvShader_t> m_shaders;
SpirvShader_t m_main;
SpirvShader_t m_out;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
#include "rtlinker_shared.h"
int SpvGetOperandCount( int op );
void SpvGetOperands( int op, ESpirvOperandType *pTypes );
void SpvGetOperandFlags( int op, ESpirvOperandFlags *pTypes );

View File

@@ -0,0 +1,25 @@
#ifndef RTLINKER_SHARED_H
#define RTLINKER_SHARED_H
enum ESpirvOperandType
{
k_ESpirv_Unknown = 0,
k_ESpirv_ResultId,
k_ESpirv_ResultTypeId,
k_ESpirv_RefId,
k_ESpirv_MemorySemanticsId,
k_ESpirv_ScopeId,
k_ESpirv_LiteralBool,
k_ESpirv_LiteralInt,
k_ESpirv_LiteralFloat,
};
enum ESpirvOperandFlags
{
k_ESpirvOperandFlags_None,
k_ESpirvOperandFlags_Optional,
k_ESpirvOperandFlags_Array,
};
#endif

View File

@@ -0,0 +1,68 @@
#include "vulkan_state.h"
#include "rtlinker.h"
#include "materialsystem/compiledshadermgr.h"
uint32_t CVkRayTracingShader::GetMissShaderBinding( const char *szName )
{
}
uint32_t CVkRayTracingShader::GetClosestHitShaderBinding( const char *szName )
{
}
uint32_t CVkRayTracingShader::GetCallableShaderBinding( const char *szName )
{
}
void CVkRayTracingShader::AddShader( const char *szName, const char *szPath )
{
ICompiledShaderManager *pCompiledShaderManager = (ICompiledShaderManager*)CreateInterface(COMPILED_SHADER_MANAGER_INTERFACE_VERSION, NULL);
CCompiledShader shader = {};
pCompiledShaderManager->ReadFromFile(&shader, szPath);
m_callableShaders.AppendTail( {szName, shader} );
}
void CVkRayTracingShader::RemoveShader( const char *szName )
{
}
void CVkRayTracingShader::Build()
{
if (g_vkAvailableExtensions.bIsSupported_VK_KHR_RAY_TRACING_PIPELINE)
BuildTrace();
else
BuildCompute();
}
void CVkRayTracingShader::BuildCompute()
{
CVkShaderLinker linker = {};
ShaderObject_t *pShader;
pShader = m_shader.FindShaderObject(SHADER_BACKEND_SPIRV_VULKAN, SHADER_STAGE_RAYGEN_SOFTWARE);
if (!pShader)
return;
linker.SetMainSpirv(m_shader.GetLumpSize(pShader->m_nDataLump)/4,
(uint32_t*)m_shader.GetLumpPtr(pShader->m_nDataLump));
for ( auto s: m_callableShaders )
{
pShader = s.m_shader.FindShaderObject(SHADER_BACKEND_SPIRV_VULKAN, SHADER_STAGE_CALLABLE_SOFTWARE);
if (!pShader)
continue;
linker.AddSpirv(s.m_shader.GetLumpSize(pShader->m_nDataLump)/4,
(uint32_t*)s.m_shader.GetLumpPtr(pShader->m_nDataLump));
}
linker.Build();
}
void CVkRayTracingShader::BuildTrace()
{
}

View File

@@ -7,6 +7,7 @@
#include "vk_mem_alloc.h"
#include "tier0/platform.h"
#include "tier1/utlvector.h"
#include "tier1/utlstring.h"
#include "tier2/iappsystem.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/shaderinternals.h"
@@ -268,7 +269,7 @@ public:
virtual void AddOutputImage( int iImageIndex, EImageFormat eFormat ) override;
virtual void SetDepthImage( EImageFormat eFormat ) override;
virtual void SetMultisampling( EMultisampleType eFormat ) override;
virtual void DisablePixelShader( bool bDisable) override;
virtual void DisablePixelShader( bool bDisable ) override;
virtual void Build() override;
VkPipeline m_hPipeline = NULL;
@@ -285,7 +286,57 @@ private:
EMultisampleType m_eMultiSampling;
VkFormat m_eDepthFormat;
bool m_bIsFragmentEnabled;
};
class CVkComputeShader : public IComputeShader
{
public:
virtual void Build() override;
void BuildCompute();
void BuildTrace();
VkDevice m_hDevice;
CCompiledShader m_shader;
VkPipeline m_hPipeline = NULL;
VkPipelineLayout m_hPipelineLayout;
CUtlVector<VkDescriptorSetLayout> m_setLayouts;
CUtlVector<VulkanDescriptor_t> m_bindings;
private:
struct ShaderBinding_t
{
CUtlString m_szName;
CCompiledShader m_shader;
};
CUtlVector<ShaderBinding_t> m_callableShaders = {};
};
class CVkRayTracingShader : public IRayTracingShader
{
public:
virtual uint32_t GetMissShaderBinding( const char *szName ) override;
virtual uint32_t GetClosestHitShaderBinding( const char *szName ) override;
virtual uint32_t GetCallableShaderBinding( const char *szName ) override;
virtual void AddShader( const char *szName, const char *szPath ) override;
virtual void RemoveShader( const char *szName ) override;
virtual void Build() override;
void BuildCompute();
void BuildTrace();
VkDevice m_hDevice;
CCompiledShader m_shader;
VkPipeline m_hPipeline = NULL;
VkPipelineLayout m_hPipelineLayout;
CUtlVector<VkDescriptorSetLayout> m_setLayouts;
CUtlVector<VulkanDescriptor_t> m_bindings;
private:
struct ShaderBinding_t
{
CUtlString m_szName;
CCompiledShader m_shader;
};
CUtlVector<ShaderBinding_t> m_callableShaders = {};
};
class CVkTextureArray: public ITextureArray