Files
funnygame/materialsystem/vulkan/rtlinker.cpp
2026-04-12 14:52:33 +03:00

250 lines
6.1 KiB
C++

#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;
}