Add support for ARB_gl_spirv. Closes #767

This commit is contained in:
baldurk
2018-06-19 20:48:30 +01:00
parent d7db77cd12
commit dc8347262e
16 changed files with 615 additions and 322 deletions
+3
View File
@@ -1772,6 +1772,9 @@ enum class GLChunk : uint32_t
glMaxShaderCompilerThreadsARB,
glMaxShaderCompilerThreadsKHR,
glSpecializeShader,
glSpecializeShaderARB,
Max,
};
+8 -1
View File
@@ -77,6 +77,7 @@ void WrappedOpenGL::BuildGLExtensions()
m_GLExtensions.push_back("GL_ARB_geometry_shader4");
m_GLExtensions.push_back("GL_ARB_get_program_binary");
m_GLExtensions.push_back("GL_ARB_get_texture_sub_image");
m_GLExtensions.push_back("GL_ARB_gl_spirv");
m_GLExtensions.push_back("GL_ARB_gpu_shader_fp64");
m_GLExtensions.push_back("GL_ARB_gpu_shader5");
m_GLExtensions.push_back("GL_ARB_half_float_pixel");
@@ -135,6 +136,7 @@ void WrappedOpenGL::BuildGLExtensions()
m_GLExtensions.push_back("GL_ARB_shading_language_packing");
m_GLExtensions.push_back("GL_ARB_shadow");
m_GLExtensions.push_back("GL_ARB_shadow_ambient");
m_GLExtensions.push_back("GL_ARB_spirv_extensions");
m_GLExtensions.push_back("GL_ARB_stencil_texturing");
m_GLExtensions.push_back("GL_ARB_sync");
m_GLExtensions.push_back("GL_ARB_tessellation_shader");
@@ -3917,6 +3919,12 @@ bool WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk)
// Just in case it gets exported and imported, completely ignore it.
return true;
case GLChunk::glShaderBinary: return Serialise_glShaderBinary(ser, 0, NULL, eGL_NONE, NULL, 0);
case GLChunk::glSpecializeShaderARB:
case GLChunk::glSpecializeShader:
return Serialise_glSpecializeShader(ser, 0, NULL, 0, NULL, NULL);
// these functions are not currently serialised - they do nothing on replay and are not
// serialised for information (it would be harmless and perhaps useful for the user to see
// where and how they're called).
@@ -4198,7 +4206,6 @@ bool WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk)
case GLChunk::glActiveShaderProgram:
case GLChunk::glActiveShaderProgramEXT:
case GLChunk::glProgramBinary:
case GLChunk::glShaderBinary:
case GLChunk::glReleaseShaderCompiler:
case GLChunk::glFrameTerminatorGREMEDY:
case GLChunk::glDiscardFramebufferEXT:
+19 -1
View File
@@ -308,7 +308,21 @@ private:
GLuint prog;
int version;
void Compile(WrappedOpenGL &gl, ResourceId id, GLuint realShader);
// used for if the application actually uploaded SPIR-V
std::vector<uint32_t> spirvWords;
// the parameters passed to glSpecializeShader
std::string entryPoint;
std::vector<uint32_t> specIDs;
std::vector<uint32_t> specValues;
// pre-calculated bindpoint mapping for SPIR-V shaders. NOT valid for normal GLSL shaders
ShaderBindpointMapping mapping;
void ProcessCompilation(WrappedOpenGL &gl, ResourceId id, GLuint realShader);
void ProcessSPIRVCompilation(WrappedOpenGL &gl, ResourceId id, GLuint realShader,
const GLchar *pEntryPoint, GLuint numSpecializationConstants,
const GLuint *pConstantIndex, const GLuint *pConstantValue);
};
struct ProgramData
@@ -2241,6 +2255,10 @@ public:
GLsizei samples);
void glFramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget,
GLuint texture, GLint level, GLsizei samples);
IMPLEMENT_FUNCTION_SERIALISED(void, glSpecializeShader, GLuint shader, const GLchar *pEntryPoint,
GLuint numSpecializationConstants, const GLuint *pConstantIndex,
const GLuint *pConstantValue);
};
class ScopedDebugContext
+2
View File
@@ -662,6 +662,8 @@ struct GLHookSet
// ARB_parallel_shader_compile
PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR; // aliases glMaxShaderCompilerThreadsARB
// ARB_gl_spirv
PFNGLSPECIALIZESHADERPROC glSpecializeShader; // aliases glSpecializeShaderARB
// EXT_direct_state_access below here. We only include the functions relevant for core 3.2+ GL,
// not any
+4 -4
View File
@@ -1082,6 +1082,8 @@
HookExtensionAlias(PFNGLREADNPIXELSPROC, glReadnPixels, glReadnPixelsARB); \
HookExtensionAlias(PFNGLREADNPIXELSPROC, glReadnPixels, glReadnPixelsEXT); \
HookExtension(PFNGLTEXTUREBARRIERPROC, glTextureBarrier); \
HookExtension(PFNGLSPECIALIZESHADERPROC, glSpecializeShader); \
HookExtensionAlias(PFNGLSPECIALIZESHADERPROC, glSpecializeShader, glSpecializeShaderARB); \
HookExtension(PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC, glMultiDrawArraysIndirectCount); \
HookExtensionAlias(PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC, glMultiDrawArraysIndirectCount, glMultiDrawArraysIndirectCountARB); \
HookExtension(PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC, glMultiDrawElementsIndirectCount); \
@@ -2342,6 +2344,8 @@
HookAliasWrapper8(void, glReadnPixelsEXT, glReadnPixels, GLint, x, GLint, y, GLsizei, width, GLsizei, height, GLenum, format, GLenum, type, GLsizei, bufSize, void *, data); \
HookWrapper8(void, glReadnPixels, GLint, x, GLint, y, GLsizei, width, GLsizei, height, GLenum, format, GLenum, type, GLsizei, bufSize, void *, data); \
HookWrapper0(void, glTextureBarrier); \
HookAliasWrapper5(void, glSpecializeShaderARB, glSpecializeShader, GLuint, shader, const GLchar *, pEntryPoint, GLuint, numSpecializationConstants, const GLuint *, pConstantIndex, const GLuint *, pConstantValue); \
HookWrapper5(void, glSpecializeShader, GLuint, shader, const GLchar *, pEntryPoint, GLuint, numSpecializationConstants, const GLuint *, pConstantIndex, const GLuint *, pConstantValue); \
HookAliasWrapper5(void, glMultiDrawArraysIndirectCountARB, glMultiDrawArraysIndirectCount, GLenum, mode, const void *, indirect, GLintptr, drawcount, GLsizei, maxdrawcount, GLsizei, stride); \
HookWrapper5(void, glMultiDrawArraysIndirectCount, GLenum, mode, const void *, indirect, GLintptr, drawcount, GLsizei, maxdrawcount, GLsizei, stride); \
HookAliasWrapper6(void, glMultiDrawElementsIndirectCountARB, glMultiDrawElementsIndirectCount, GLenum, mode, GLenum, type, const void *, indirect, GLintptr, drawcount, GLsizei, maxdrawcount, GLsizei, stride); \
@@ -2491,7 +2495,6 @@
// unsupported entry points - used for dummy functions
#define DefineUnsupportedDummies() \
HookWrapper5(void, glSpecializeShader, GLuint, shader, const GLchar *, pEntryPoint, GLuint, numSpecializationConstants, const GLuint *, pConstantIndex, const GLuint *, pConstantValue); \
HookWrapper8(void, glPrimitiveBoundingBoxARB, GLfloat, minX, GLfloat, minY, GLfloat, minZ, GLfloat, minW, GLfloat, maxX, GLfloat, maxY, GLfloat, maxZ, GLfloat, maxW); \
HookWrapper1(GLuint64, glGetTextureHandleARB, GLuint, texture); \
HookWrapper2(GLuint64, glGetTextureSamplerHandleARB, GLuint, texture, GLuint, sampler); \
@@ -2511,7 +2514,6 @@
HookWrapper3(void, glGetVertexAttribLui64vARB, GLuint, index, GLenum, pname, GLuint64EXT *, params); \
HookWrapper3(GLsync, glCreateSyncFromCLeventARB, struct _cl_context *, context, struct _cl_event *, event, GLbitfield, flags); \
HookWrapper5(void, glFramebufferTextureFaceARB, GLenum, target, GLenum, attachment, GLuint, texture, GLint, level, GLenum, face); \
HookWrapper5(void, glSpecializeShaderARB, GLuint, shader, const GLchar *, pEntryPoint, GLuint, numSpecializationConstants, const GLuint *, pConstantIndex, const GLuint *, pConstantValue); \
HookWrapper2(void, glUniform1i64ARB, GLint, location, GLint64, x); \
HookWrapper3(void, glUniform2i64ARB, GLint, location, GLint64, x, GLint64, y); \
HookWrapper4(void, glUniform3i64ARB, GLint, location, GLint64, x, GLint64, y, GLint64, z); \
@@ -4470,7 +4472,6 @@
#define CheckUnsupported() \
HandleUnsupported(PFNGLSPECIALIZESHADERPROC, glSpecializeShader); \
HandleUnsupported(PFNGLPRIMITIVEBOUNDINGBOXARBPROC, glPrimitiveBoundingBoxARB); \
HandleUnsupported(PFNGLGETTEXTUREHANDLEARBPROC, glGetTextureHandleARB); \
HandleUnsupported(PFNGLGETTEXTURESAMPLERHANDLEARBPROC, glGetTextureSamplerHandleARB); \
@@ -4490,7 +4491,6 @@
HandleUnsupported(PFNGLGETVERTEXATTRIBLUI64VARBPROC, glGetVertexAttribLui64vARB); \
HandleUnsupported(PFNGLCREATESYNCFROMCLEVENTARBPROC, glCreateSyncFromCLeventARB); \
HandleUnsupported(PFNGLFRAMEBUFFERTEXTUREFACEARBPROC, glFramebufferTextureFaceARB); \
HandleUnsupported(PFNGLSPECIALIZESHADERARBPROC, glSpecializeShaderARB); \
HandleUnsupported(PFNGLUNIFORM1I64ARBPROC, glUniform1i64ARB); \
HandleUnsupported(PFNGLUNIFORM2I64ARBPROC, glUniform2i64ARB); \
HandleUnsupported(PFNGLUNIFORM3I64ARBPROC, glUniform3i64ARB); \
+27 -8
View File
@@ -1104,15 +1104,34 @@ bool GLResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceId r
}
}
char **srcs = new char *[shadDetails.sources.size()];
for(size_t s = 0; s < shadDetails.sources.size(); s++)
srcs[s] = (char *)shadDetails.sources[s].c_str();
gl.glShaderSource(shad, (GLsizei)shadDetails.sources.size(), srcs, NULL);
if(!shadDetails.sources.empty())
{
char **srcs = new char *[shadDetails.sources.size()];
for(size_t s = 0; s < shadDetails.sources.size(); s++)
srcs[s] = (char *)shadDetails.sources[s].c_str();
gl.glShaderSource(shad, (GLsizei)shadDetails.sources.size(), srcs, NULL);
SAFE_DELETE_ARRAY(srcs);
gl.glCompileShader(shad);
gl.glAttachShader(initProg, shad);
gl.glDeleteShader(shad);
SAFE_DELETE_ARRAY(srcs);
gl.glCompileShader(shad);
gl.glAttachShader(initProg, shad);
gl.glDeleteShader(shad);
}
else if(!shadDetails.spirvWords.empty())
{
gl.glShaderBinary(1, &shad, eGL_SHADER_BINARY_FORMAT_SPIR_V, shadDetails.spirvWords.data(),
(GLsizei)shadDetails.spirvWords.size() * sizeof(uint32_t));
gl.glSpecializeShader(shad, shadDetails.entryPoint.c_str(),
(GLuint)shadDetails.specIDs.size(), shadDetails.specIDs.data(),
shadDetails.specValues.data());
gl.glAttachShader(initProg, shad);
gl.glDeleteShader(shad);
}
else
{
RDCERR("Unexpectedly empty shader in program initial state!");
}
}
// Some drivers optimize out uniforms if they dont change any active vertex shader outputs.
+71 -8
View File
@@ -847,6 +847,7 @@ void GLReplay::SavePipelineState()
};
ShaderReflection *refls[6] = {NULL};
ShaderBindpointMapping *mappings[6] = {NULL};
bool spirv[6] = {false};
for(int i = 0; i < 6; i++)
{
@@ -879,10 +880,25 @@ void GLReplay::SavePipelineState()
if(pipeDetails.stageShaders[i] != ResourceId())
{
curProg = rm->GetCurrentResource(pipeDetails.stagePrograms[i]).name;
stages[i]->reflection = refls[i] =
GetShader(pipeDetails.stageShaders[i], ShaderEntryPoint());
GetBindpointMapping(gl.GetHookset(), curProg, (int)i, refls[i],
stages[i]->bindpointMapping);
auto &shaderDetails = m_pDriver->m_Shaders[pipeDetails.stageShaders[i]];
if(shaderDetails.prog == 0)
stages[i]->reflection = refls[i] = NULL;
else
stages[i]->reflection = refls[i] = &shaderDetails.reflection;
if(!shaderDetails.spirvWords.empty())
{
stages[i]->bindpointMapping = shaderDetails.mapping;
spirv[i] = true;
}
else
{
GetBindpointMapping(gl.GetHookset(), curProg, (int)i, refls[i],
stages[i]->bindpointMapping);
}
mappings[i] = &stages[i]->bindpointMapping;
stages[i]->programResourceId = rm->GetOriginalID(pipeDetails.stagePrograms[i]);
@@ -906,8 +922,24 @@ void GLReplay::SavePipelineState()
{
if(progDetails.stageShaders[i] != ResourceId())
{
stages[i]->reflection = refls[i] = GetShader(progDetails.stageShaders[i], ShaderEntryPoint());
GetBindpointMapping(gl.GetHookset(), curProg, (int)i, refls[i], stages[i]->bindpointMapping);
auto &shaderDetails = m_pDriver->m_Shaders[progDetails.stageShaders[i]];
if(shaderDetails.prog == 0)
stages[i]->reflection = refls[i] = NULL;
else
stages[i]->reflection = refls[i] = &shaderDetails.reflection;
if(!shaderDetails.spirvWords.empty())
{
stages[i]->bindpointMapping = shaderDetails.mapping;
spirv[i] = true;
}
else
{
GetBindpointMapping(gl.GetHookset(), curProg, (int)i, refls[i],
stages[i]->bindpointMapping);
}
mappings[i] = &stages[i]->bindpointMapping;
stages[i]->programResourceId = rm->GetOriginalID(id);
@@ -923,7 +955,13 @@ void GLReplay::SavePipelineState()
// !!!NOTE!!! This function will MODIFY the refls[] binding arrays.
// See inside this function for what it does and why.
for(size_t i = 0; i < ARRAY_COUNT(refls); i++)
{
// don't resort if it's SPIR-V
if(spirv[i])
continue;
ResortBindings(refls[i], mappings[i]);
}
RDCEraseEl(pipe.transformFeedback);
@@ -1987,8 +2025,33 @@ void GLReplay::FillCBufferVariables(ResourceId shader, string entryPoint, uint32
const ConstantBlock &cblock = shaderDetails.reflection.constantBlocks[cbufSlot];
FillCBufferVariables(gl, curProg, cblock.bufferBacked ? true : false, "", cblock.variables,
outvars, data);
if(shaderDetails.spirvWords.empty())
{
FillCBufferVariables(gl, curProg, cblock.bufferBacked ? true : false, "", cblock.variables,
outvars, data);
}
else
{
if(shaderDetails.mapping.constantBlocks[cbufSlot].bindset == SpecializationConstantBindSet)
{
std::vector<SpecConstant> specconsts;
for(size_t i = 0; i < shaderDetails.specIDs.size(); i++)
{
SpecConstant spec;
spec.specID = shaderDetails.specIDs[i];
spec.data.resize(sizeof(shaderDetails.specValues[i]));
memcpy(&spec.data[0], &shaderDetails.specValues[i], spec.data.size());
specconsts.push_back(spec);
}
FillSpecConstantVariables(cblock.variables, outvars, specconsts);
}
else
{
SPIRVFillCBufferVariables(cblock.variables, outvars, data, 0);
}
}
}
void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip,
@@ -54,12 +54,78 @@ std::string DoStringise(const GLshaderbitfield &el)
END_BITFIELD_STRINGISE();
}
void WrappedOpenGL::ShaderData::Compile(WrappedOpenGL &gl, ResourceId id, GLuint realShader)
void WrappedOpenGL::ShaderData::ProcessSPIRVCompilation(WrappedOpenGL &gl, ResourceId id,
GLuint realShader, const GLchar *pEntryPoint,
GLuint numSpecializationConstants,
const GLuint *pConstantIndex,
const GLuint *pConstantValue)
{
reflection.resourceId = id;
reflection.entryPoint = pEntryPoint;
reflection.stage = MakeShaderStage(type);
reflection.encoding = ShaderEncoding::SPIRV;
reflection.rawBytes.assign((byte *)spirv.spirv.data(), spirv.spirv.size() * sizeof(uint32_t));
// we discard this too, because we don't need it - we don't do any SPIR-V patching in GL
SPIRVPatchData patchData;
spirv.MakeReflection(ShaderStage(ShaderIdx(type)), pEntryPoint, reflection, mapping, patchData);
version = 460;
entryPoint = pEntryPoint;
if(numSpecializationConstants > 0)
{
specIDs.assign(pConstantIndex, pConstantIndex + numSpecializationConstants);
specValues.assign(pConstantValue, pConstantValue + numSpecializationConstants);
}
const GLHookSet &real = gl.GetHookset();
GLuint sepshader = real.glCreateShader(type);
if(sepshader)
{
real.glShaderBinary(1, &sepshader, eGL_SHADER_BINARY_FORMAT_SPIR_V, reflection.rawBytes.data(),
(GLsizei)reflection.rawBytes.size());
real.glSpecializeShader(sepshader, pEntryPoint, numSpecializationConstants, pConstantIndex,
pConstantValue);
GLint compiled = 0;
real.glGetShaderiv(sepshader, eGL_COMPILE_STATUS, &compiled);
if(compiled)
{
prog = real.glCreateProgram();
real.glAttachShader(prog, sepshader);
real.glProgramParameteri(prog, eGL_PROGRAM_SEPARABLE, GL_TRUE);
real.glLinkProgram(prog);
gl.glGetProgramiv(prog, eGL_LINK_STATUS, &compiled);
if(!compiled)
{
RDCERR("Re-compiled but couldn't link SPIR-V program");
}
}
else
{
RDCERR("Couldn't re-compile SPIR-V shader");
}
real.glDeleteShader(sepshader);
}
}
void WrappedOpenGL::ShaderData::ProcessCompilation(WrappedOpenGL &gl, ResourceId id, GLuint realShader)
{
bool pointSizeUsed = false, clipDistanceUsed = false;
if(type == eGL_VERTEX_SHADER)
CheckVertexOutputUses(sources, pointSizeUsed, clipDistanceUsed);
entryPoint = "main";
string concatenated;
for(size_t i = 0; i < sources.size(); i++)
@@ -374,7 +440,8 @@ bool WrappedOpenGL::Serialise_glCompileShader(SerialiserType &ser, GLuint shader
m_Real.glCompileShader(shader.name);
m_Shaders[liveId].Compile(*this, GetResourceManager()->GetOriginalID(liveId), shader.name);
m_Shaders[liveId].ProcessCompilation(*this, GetResourceManager()->GetOriginalID(liveId),
shader.name);
AddResourceInitChunk(shader);
}
@@ -403,7 +470,7 @@ void WrappedOpenGL::glCompileShader(GLuint shader)
else
{
ResourceId id = GetResourceManager()->GetID(ShaderRes(GetCtx(), shader));
m_Shaders[id].Compile(*this, id, shader);
m_Shaders[id].ProcessCompilation(*this, id, shader);
}
}
@@ -606,7 +673,7 @@ bool WrappedOpenGL::Serialise_glCreateShaderProgramv(SerialiserType &ser, GLenum
shadDetails.sources.swap(src);
shadDetails.prog = sepprog;
shadDetails.Compile(*this, Program, 0);
shadDetails.ProcessCompilation(*this, Program, 0);
GetResourceManager()->AddLiveResource(Program, res);
@@ -670,7 +737,7 @@ GLuint WrappedOpenGL::glCreateShaderProgramv(GLenum type, GLsizei count, const G
shadDetails.sources.swap(src);
shadDetails.prog = sepprog;
shadDetails.Compile(*this, id, 0);
shadDetails.ProcessCompilation(*this, id, 0);
}
return real;
@@ -1178,15 +1245,62 @@ void WrappedOpenGL::glValidateProgramPipeline(GLuint pipeline)
m_Real.glValidateProgramPipeline(pipeline);
}
template <typename SerialiserType>
bool WrappedOpenGL::Serialise_glShaderBinary(SerialiserType &ser, GLsizei count,
const GLuint *shaders, GLenum binaryformat,
const void *binary, GLsizei length)
{
SERIALISE_ELEMENT(count);
SERIALISE_ELEMENT_LOCAL(shader, ShaderRes(GetCtx(), shaders[0]));
SERIALISE_ELEMENT(binaryformat);
SERIALISE_ELEMENT_ARRAY(binary, length);
SERIALISE_ELEMENT(length);
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading())
{
ResourceId liveId = GetResourceManager()->GetID(shader);
m_Real.glShaderBinary(1, &shader.name, binaryformat, binary, length);
m_Shaders[liveId].spirvWords.assign((uint32_t *)binary, (uint32_t *)((byte *)binary + length));
AddResourceInitChunk(shader);
}
return true;
}
void WrappedOpenGL::glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat,
const void *binary, GLsizei length)
{
// deliberately don't forward on this call when writing, since we want to coax the app into
// providing non-binary shaders.
// conditionally forward on this call when capturing, since we want to coax the app into
// providing non-binary shaders unless it's a format we understand: SPIR-V.
if(IsReplayMode(m_State))
{
m_Real.glShaderBinary(count, shaders, binaryformat, binary, length);
}
else if(IsCaptureMode(m_State) && binaryformat == eGL_SHADER_BINARY_FORMAT_SPIR_V)
{
SERIALISE_TIME_CALL(m_Real.glShaderBinary(count, shaders, binaryformat, binary, length));
for(GLsizei i = 0; i < count; i++)
{
GLResourceRecord *record =
GetResourceManager()->GetResourceRecord(ShaderRes(GetCtx(), shaders[i]));
RDCASSERTMSG("Couldn't identify object passed to function. Mismatched or bad GLuint?", record,
shaders[i]);
if(record)
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(gl_CurChunk);
Serialise_glShaderBinary(ser, 1, shaders + i, binaryformat, binary, length);
record->AddChunk(scope.Get());
}
}
}
}
void WrappedOpenGL::glProgramBinary(GLuint program, GLenum binaryFormat, const void *binary,
@@ -1588,7 +1702,7 @@ bool WrappedOpenGL::Serialise_glCompileShaderIncludeARB(SerialiserType &ser, GLu
m_Real.glCompileShaderIncludeARB(shader.name, count, path, NULL);
shadDetails.Compile(*this, GetResourceManager()->GetOriginalID(liveId), shader.name);
shadDetails.ProcessCompilation(*this, GetResourceManager()->GetOriginalID(liveId), shader.name);
AddResourceInitChunk(shader);
}
@@ -1627,7 +1741,7 @@ void WrappedOpenGL::glCompileShaderIncludeARB(GLuint shader, GLsizei count,
for(int32_t i = 0; i < count; i++)
shadDetails.includepaths.push_back(path[i]);
shadDetails.Compile(*this, id, shader);
shadDetails.ProcessCompilation(*this, id, shader);
}
}
@@ -1717,7 +1831,63 @@ void WrappedOpenGL::glMaxShaderCompilerThreadsKHR(GLuint count)
m_Real.glMaxShaderCompilerThreadsKHR(count);
}
template <typename SerialiserType>
bool WrappedOpenGL::Serialise_glSpecializeShader(SerialiserType &ser, GLuint shaderHandle,
const GLchar *pEntryPoint,
GLuint numSpecializationConstants,
const GLuint *pConstantIndex,
const GLuint *pConstantValue)
{
SERIALISE_ELEMENT_LOCAL(shader, ShaderRes(GetCtx(), shaderHandle));
SERIALISE_ELEMENT(pEntryPoint);
SERIALISE_ELEMENT(numSpecializationConstants);
SERIALISE_ELEMENT_ARRAY(pConstantIndex, numSpecializationConstants);
SERIALISE_ELEMENT_ARRAY(pConstantValue, numSpecializationConstants);
SERIALISE_CHECK_READ_ERRORS();
if(IsReplayingAndReading())
{
ResourceId liveId = GetResourceManager()->GetID(shader);
m_Real.glSpecializeShader(shader.name, pEntryPoint, numSpecializationConstants, pConstantIndex,
pConstantValue);
ParseSPIRV(m_Shaders[liveId].spirvWords.data(), m_Shaders[liveId].spirvWords.size(),
m_Shaders[liveId].spirv);
m_Shaders[liveId].ProcessSPIRVCompilation(*this, GetResourceManager()->GetOriginalID(liveId),
shader.name, pEntryPoint, numSpecializationConstants,
pConstantIndex, pConstantValue);
AddResourceInitChunk(shader);
}
return true;
}
void WrappedOpenGL::glSpecializeShader(GLuint shader, const GLchar *pEntryPoint,
GLuint numSpecializationConstants,
const GLuint *pConstantIndex, const GLuint *pConstantValue)
{
SERIALISE_TIME_CALL(m_Real.glSpecializeShader(shader, pEntryPoint, numSpecializationConstants,
pConstantIndex, pConstantValue));
if(IsCaptureMode(m_State))
{
GLResourceRecord *record = GetResourceManager()->GetResourceRecord(ShaderRes(GetCtx(), shader));
RDCASSERTMSG("Couldn't identify object passed to function. Mismatched or bad GLuint?", record,
shader);
if(record)
{
USE_SCRATCH_SERIALISER();
SCOPED_SERIALISE_CHUNK(gl_CurChunk);
Serialise_glSpecializeShader(ser, shader, pEntryPoint, numSpecializationConstants,
pConstantIndex, pConstantValue);
record->AddChunk(scope.Get());
}
}
}
INSTANTIATE_FUNCTION_SERIALISED(void, glCreateShader, GLenum type, GLuint shader);
@@ -1757,3 +1927,8 @@ INSTANTIATE_FUNCTION_SERIALISED(void, glCompileShaderIncludeARB, GLuint shaderHa
INSTANTIATE_FUNCTION_SERIALISED(void, glNamedStringARB, GLenum type, GLint namelen,
const GLchar *nameStr, GLint stringlen, const GLchar *valStr);
INSTANTIATE_FUNCTION_SERIALISED(void, glDeleteNamedStringARB, GLint namelen, const GLchar *nameStr);
INSTANTIATE_FUNCTION_SERIALISED(void, glShaderBinary, GLsizei count, const GLuint *shaders,
GLenum binaryformat, const void *binary, GLsizei length);
INSTANTIATE_FUNCTION_SERIALISED(void, glSpecializeShader, GLuint shader, const GLchar *pEntryPoint,
GLuint numSpecializationConstants, const GLuint *pConstantIndex,
const GLuint *pConstantValue);
@@ -48,3 +48,231 @@ void ShutdownSPIRVCompiler()
glslang::FinalizeProcess();
}
}
void SPIRVFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
vector<ShaderVariable> &outvars, const bytebuf &data,
size_t baseOffset)
{
for(size_t v = 0; v < invars.size(); v++)
{
std::string basename = invars[v].name;
uint32_t rows = invars[v].type.descriptor.rows;
uint32_t cols = invars[v].type.descriptor.columns;
uint32_t elems = RDCMAX(1U, invars[v].type.descriptor.elements);
bool rowMajor = invars[v].type.descriptor.rowMajorStorage != 0;
bool isArray = elems > 1;
size_t dataOffset =
baseOffset + invars[v].reg.vec * sizeof(float) * 4 + invars[v].reg.comp * sizeof(float);
if(!invars[v].type.members.empty() || (rows == 0 && cols == 0))
{
ShaderVariable var;
var.name = basename;
var.rows = var.columns = 0;
var.type = VarType::Float;
var.rowMajor = rowMajor;
vector<ShaderVariable> varmembers;
if(isArray)
{
for(uint32_t i = 0; i < elems; i++)
{
ShaderVariable vr;
vr.name = StringFormat::Fmt("%s[%u]", basename.c_str(), i);
vr.rows = vr.columns = 0;
vr.type = VarType::Float;
vr.rowMajor = rowMajor;
vector<ShaderVariable> mems;
SPIRVFillCBufferVariables(invars[v].type.members, mems, data, dataOffset);
dataOffset += invars[v].type.descriptor.arrayByteStride;
vr.isStruct = true;
vr.members = mems;
varmembers.push_back(vr);
}
var.isStruct = false;
}
else
{
var.isStruct = true;
SPIRVFillCBufferVariables(invars[v].type.members, varmembers, data, dataOffset);
}
{
var.members = varmembers;
outvars.push_back(var);
}
continue;
}
size_t outIdx = outvars.size();
outvars.resize(outvars.size() + 1);
{
outvars[outIdx].name = basename;
outvars[outIdx].rows = 1;
outvars[outIdx].type = invars[v].type.descriptor.type;
outvars[outIdx].isStruct = false;
outvars[outIdx].columns = cols;
outvars[outIdx].rowMajor = rowMajor;
size_t elemByteSize = 4;
if(outvars[outIdx].type == VarType::Double)
elemByteSize = 8;
ShaderVariable &var = outvars[outIdx];
if(!isArray)
{
outvars[outIdx].rows = rows;
if(dataOffset < data.size())
{
const byte *d = &data[dataOffset];
RDCASSERT(rows <= 4 && rows * cols <= 16, rows, cols);
if(!rowMajor)
{
uint32_t tmp[16] = {0};
for(uint32_t c = 0; c < cols; c++)
{
size_t srcoffs = 4 * elemByteSize * c;
size_t dstoffs = rows * elemByteSize * c;
memcpy((byte *)(tmp) + dstoffs, d + srcoffs,
RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * rows));
}
// transpose
for(size_t r = 0; r < rows; r++)
for(size_t c = 0; c < cols; c++)
outvars[outIdx].value.uv[r * cols + c] = tmp[c * rows + r];
}
else
{
for(uint32_t r = 0; r < rows; r++)
{
size_t srcoffs = 4 * elemByteSize * r;
size_t dstoffs = cols * elemByteSize * r;
memcpy((byte *)(&outvars[outIdx].value.uv[0]) + dstoffs, d + srcoffs,
RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * cols));
}
}
}
}
else
{
var.name = outvars[outIdx].name;
var.rows = 0;
var.columns = 0;
bool isMatrix = rows > 1 && cols > 1;
vector<ShaderVariable> varmembers;
varmembers.resize(elems);
std::string base = outvars[outIdx].name;
// primary is the 'major' direction
// so we copy secondaryDim number of primaryDim-sized elements
uint32_t primaryDim = cols;
uint32_t secondaryDim = rows;
if(isMatrix && rowMajor)
{
primaryDim = rows;
secondaryDim = cols;
}
for(uint32_t e = 0; e < elems; e++)
{
varmembers[e].name = StringFormat::Fmt("%s[%u]", base.c_str(), e);
varmembers[e].rows = rows;
varmembers[e].type = invars[v].type.descriptor.type;
varmembers[e].isStruct = false;
varmembers[e].columns = cols;
varmembers[e].rowMajor = rowMajor;
size_t rowDataOffset = dataOffset;
dataOffset += invars[v].type.descriptor.arrayByteStride;
if(rowDataOffset < data.size())
{
const byte *d = &data[rowDataOffset];
// each primary element (row or column) is stored in a float4.
// we copy some padding here, but that will come out in the wash
// when we transpose
for(uint32_t s = 0; s < secondaryDim; s++)
{
uint32_t matStride = primaryDim;
if(matStride == 3)
matStride = 4;
memcpy(&(varmembers[e].value.uv[primaryDim * s]), d + matStride * elemByteSize * s,
RDCMIN(data.size() - rowDataOffset, elemByteSize * primaryDim));
}
if(!rowMajor)
{
ShaderVariable tmp = varmembers[e];
// transpose
for(size_t ri = 0; ri < rows; ri++)
for(size_t ci = 0; ci < cols; ci++)
varmembers[e].value.uv[ri * cols + ci] = tmp.value.uv[ci * rows + ri];
}
}
}
{
var.isStruct = false;
var.members = varmembers;
}
}
}
}
}
void FillSpecConstantVariables(const rdcarray<ShaderConstant> &invars,
std::vector<ShaderVariable> &outvars,
const std::vector<SpecConstant> &specInfo)
{
outvars.resize(invars.size());
for(size_t v = 0; v < invars.size(); v++)
{
outvars[v].rows = invars[v].type.descriptor.rows;
outvars[v].columns = invars[v].type.descriptor.columns;
outvars[v].isStruct = !invars[v].type.members.empty();
RDCASSERT(!outvars[v].isStruct);
outvars[v].name = invars[v].name;
outvars[v].type = invars[v].type.descriptor.type;
outvars[v].value.uv[0] = (invars[v].defaultValue & 0xFFFFFFFF);
outvars[v].value.uv[1] = ((invars[v].defaultValue >> 32) & 0xFFFFFFFF);
}
// find any actual values specified
for(size_t i = 0; i < specInfo.size(); i++)
{
for(size_t v = 0; v < invars.size(); v++)
{
if(specInfo[i].specID == invars[v].reg.vec)
{
memcpy(outvars[v].value.uv, specInfo[i].data.data(),
RDCMIN(specInfo[i].data.size(), sizeof(outvars[v].value.uv)));
break;
}
}
}
}
@@ -143,3 +143,19 @@ struct SPVModule
string CompileSPIRV(const SPIRVCompilationSettings &settings, const vector<string> &sources,
vector<uint32_t> &spirv);
void ParseSPIRV(uint32_t *spirv, size_t spirvLength, SPVModule &module);
void SPIRVFillCBufferVariables(const rdcarray<ShaderConstant> &invars,
vector<ShaderVariable> &outvars, const bytebuf &data,
size_t baseOffset);
static const uint32_t SpecializationConstantBindSet = 1234567;
struct SpecConstant
{
uint32_t specID;
std::vector<byte> data;
};
void FillSpecConstantVariables(const rdcarray<ShaderConstant> &invars,
std::vector<ShaderVariable> &outvars,
const std::vector<SpecConstant> &specInfo);
@@ -4394,7 +4394,7 @@ void SPVModule::MakeReflection(ShaderStage stage, const string &entryPoint,
// set something crazy so this doesn't overlap with a real buffer binding
// also identify this as specialization constant data
bindmap.bindset = 123456; // magic constants :(
bindmap.bindset = SpecializationConstantBindSet;
bindmap.bind = -1;
bindmap.arraySize = 1;
bindmap.used = true;
+7 -11
View File
@@ -172,17 +172,14 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk
if(pCreateInfo->pStages[i].pSpecializationInfo)
{
shad.specdata.resize(pCreateInfo->pStages[i].pSpecializationInfo->dataSize);
memcpy(&shad.specdata[0], pCreateInfo->pStages[i].pSpecializationInfo->pData,
shad.specdata.size());
const byte *data = (const byte *)pCreateInfo->pStages[i].pSpecializationInfo->pData;
const VkSpecializationMapEntry *maps = pCreateInfo->pStages[i].pSpecializationInfo->pMapEntries;
for(uint32_t s = 0; s < pCreateInfo->pStages[i].pSpecializationInfo->mapEntryCount; s++)
{
Shader::SpecInfo spec;
SpecConstant spec;
spec.specID = maps[s].constantID;
spec.data = &shad.specdata[maps[s].offset];
spec.size = maps[s].size;
spec.data.assign(data + maps[s].offset, data + maps[s].offset + maps[s].size);
// ignore maps[s].size, assume it's enough for the type
shad.specialization.push_back(spec);
}
@@ -423,16 +420,15 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk
if(pCreateInfo->stage.pSpecializationInfo)
{
shad.specdata.resize(pCreateInfo->stage.pSpecializationInfo->dataSize);
memcpy(&shad.specdata[0], pCreateInfo->stage.pSpecializationInfo->pData, shad.specdata.size());
const byte *data = (const byte *)pCreateInfo->stage.pSpecializationInfo->pData;
const VkSpecializationMapEntry *maps = pCreateInfo->stage.pSpecializationInfo->pMapEntries;
for(uint32_t s = 0; s < pCreateInfo->stage.pSpecializationInfo->mapEntryCount; s++)
{
Shader::SpecInfo spec;
SpecConstant spec;
spec.specID = maps[s].constantID;
spec.data = &shad.specdata[maps[s].offset];
spec.size = maps[s].size;
spec.data.assign(data + maps[s].offset, data + maps[s].offset + maps[s].size);
// ignore maps[s].size, assume it's enough for the type
shad.specialization.push_back(spec);
}
}
+1 -8
View File
@@ -138,14 +138,7 @@ struct VulkanCreationInfo
ShaderBindpointMapping *mapping;
SPIRVPatchData *patchData;
vector<byte> specdata;
struct SpecInfo
{
uint32_t specID;
byte *data;
size_t size;
};
vector<SpecInfo> specialization;
vector<SpecConstant> specialization;
};
Shader shaders[6];
+11 -232
View File
@@ -834,8 +834,7 @@ void VulkanReplay::SavePipelineState()
for(size_t s = 0; s < p.shaders[i].specialization.size(); s++)
{
stage.specialization[s].specializationId = p.shaders[i].specialization[s].specID;
stage.specialization[s].data.assign(p.shaders[i].specialization[s].data,
p.shaders[i].specialization[s].size);
stage.specialization[s].data = p.shaders[i].specialization[s].data;
}
}
}
@@ -911,8 +910,7 @@ void VulkanReplay::SavePipelineState()
for(size_t s = 0; s < p.shaders[i].specialization.size(); s++)
{
stages[i]->specialization[s].specializationId = p.shaders[i].specialization[s].specID;
stages[i]->specialization[s].data.assign(p.shaders[i].specialization[s].data,
p.shaders[i].specialization[s].size);
stages[i]->specialization[s].data = p.shaders[i].specialization[s].data;
}
}
@@ -1472,201 +1470,6 @@ void VulkanReplay::SavePipelineState()
}
}
void VulkanReplay::FillCBufferVariables(rdcarray<ShaderConstant> invars,
vector<ShaderVariable> &outvars, const bytebuf &data,
size_t baseOffset)
{
for(size_t v = 0; v < invars.size(); v++)
{
std::string basename = invars[v].name;
uint32_t rows = invars[v].type.descriptor.rows;
uint32_t cols = invars[v].type.descriptor.columns;
uint32_t elems = RDCMAX(1U, invars[v].type.descriptor.elements);
bool rowMajor = invars[v].type.descriptor.rowMajorStorage != 0;
bool isArray = elems > 1;
size_t dataOffset =
baseOffset + invars[v].reg.vec * sizeof(Vec4f) + invars[v].reg.comp * sizeof(float);
if(!invars[v].type.members.empty() || (rows == 0 && cols == 0))
{
ShaderVariable var;
var.name = basename;
var.rows = var.columns = 0;
var.type = VarType::Float;
var.rowMajor = rowMajor;
vector<ShaderVariable> varmembers;
if(isArray)
{
for(uint32_t i = 0; i < elems; i++)
{
ShaderVariable vr;
vr.name = StringFormat::Fmt("%s[%u]", basename.c_str(), i);
vr.rows = vr.columns = 0;
vr.type = VarType::Float;
vr.rowMajor = rowMajor;
vector<ShaderVariable> mems;
FillCBufferVariables(invars[v].type.members, mems, data, dataOffset);
dataOffset += invars[v].type.descriptor.arrayByteStride;
vr.isStruct = true;
vr.members = mems;
varmembers.push_back(vr);
}
var.isStruct = false;
}
else
{
var.isStruct = true;
FillCBufferVariables(invars[v].type.members, varmembers, data, dataOffset);
}
{
var.members = varmembers;
outvars.push_back(var);
}
continue;
}
size_t outIdx = outvars.size();
outvars.resize(outvars.size() + 1);
{
outvars[outIdx].name = basename;
outvars[outIdx].rows = 1;
outvars[outIdx].type = invars[v].type.descriptor.type;
outvars[outIdx].isStruct = false;
outvars[outIdx].columns = cols;
outvars[outIdx].rowMajor = rowMajor;
size_t elemByteSize = 4;
if(outvars[outIdx].type == VarType::Double)
elemByteSize = 8;
ShaderVariable &var = outvars[outIdx];
if(!isArray)
{
outvars[outIdx].rows = rows;
if(dataOffset < data.size())
{
const byte *d = &data[dataOffset];
RDCASSERT(rows <= 4 && rows * cols <= 16, rows, cols);
if(!rowMajor)
{
uint32_t tmp[16] = {0};
for(uint32_t c = 0; c < cols; c++)
{
size_t srcoffs = 4 * elemByteSize * c;
size_t dstoffs = rows * elemByteSize * c;
memcpy((byte *)(tmp) + dstoffs, d + srcoffs,
RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * rows));
}
// transpose
for(size_t r = 0; r < rows; r++)
for(size_t c = 0; c < cols; c++)
outvars[outIdx].value.uv[r * cols + c] = tmp[c * rows + r];
}
else
{
for(uint32_t r = 0; r < rows; r++)
{
size_t srcoffs = 4 * elemByteSize * r;
size_t dstoffs = cols * elemByteSize * r;
memcpy((byte *)(&outvars[outIdx].value.uv[0]) + dstoffs, d + srcoffs,
RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * cols));
}
}
}
}
else
{
var.name = outvars[outIdx].name;
var.rows = 0;
var.columns = 0;
bool isMatrix = rows > 1 && cols > 1;
vector<ShaderVariable> varmembers;
varmembers.resize(elems);
std::string base = outvars[outIdx].name;
// primary is the 'major' direction
// so we copy secondaryDim number of primaryDim-sized elements
uint32_t primaryDim = cols;
uint32_t secondaryDim = rows;
if(isMatrix && rowMajor)
{
primaryDim = rows;
secondaryDim = cols;
}
for(uint32_t e = 0; e < elems; e++)
{
varmembers[e].name = StringFormat::Fmt("%s[%u]", base.c_str(), e);
varmembers[e].rows = rows;
varmembers[e].type = invars[v].type.descriptor.type;
varmembers[e].isStruct = false;
varmembers[e].columns = cols;
varmembers[e].rowMajor = rowMajor;
size_t rowDataOffset = dataOffset;
dataOffset += invars[v].type.descriptor.arrayByteStride;
if(rowDataOffset < data.size())
{
const byte *d = &data[rowDataOffset];
// each primary element (row or column) is stored in a float4.
// we copy some padding here, but that will come out in the wash
// when we transpose
for(uint32_t s = 0; s < secondaryDim; s++)
{
uint32_t matStride = primaryDim;
if(matStride == 3)
matStride = 4;
memcpy(&(varmembers[e].value.uv[primaryDim * s]), d + matStride * elemByteSize * s,
RDCMIN(data.size() - rowDataOffset, elemByteSize * primaryDim));
}
if(!rowMajor)
{
ShaderVariable tmp = varmembers[e];
// transpose
for(size_t ri = 0; ri < rows; ri++)
for(size_t ci = 0; ci < cols; ci++)
varmembers[e].value.uv[ri * cols + ci] = tmp.value.uv[ci * rows + ri];
}
}
}
{
var.isStruct = false;
var.members = varmembers;
}
}
}
}
}
void VulkanReplay::FillCBufferVariables(ResourceId shader, string entryPoint, uint32_t cbufSlot,
vector<ShaderVariable> &outvars, const bytebuf &data)
{
@@ -1695,29 +1498,17 @@ void VulkanReplay::FillCBufferVariables(ResourceId shader, string entryPoint, ui
if(c.bufferBacked)
{
FillCBufferVariables(c.variables, outvars, data, 0);
SPIRVFillCBufferVariables(c.variables, outvars, data, 0);
}
else
{
// very specialised (and rather ugly) path to display specialization constants
// magic constant here matches the one generated in SPVModule::MakeReflection(
if(mapping.constantBlocks[c.bindPoint].bindset == 123456)
// specialised path to display specialization constants
if(mapping.constantBlocks[c.bindPoint].bindset == SpecializationConstantBindSet)
{
outvars.resize(c.variables.size());
for(size_t v = 0; v < c.variables.size(); v++)
{
outvars[v].rows = c.variables[v].type.descriptor.rows;
outvars[v].columns = c.variables[v].type.descriptor.columns;
outvars[v].isStruct = !c.variables[v].type.members.empty();
RDCASSERT(!outvars[v].isStruct);
outvars[v].name = c.variables[v].name;
outvars[v].type = c.variables[v].type.descriptor.type;
outvars[v].value.uv[0] = (c.variables[v].defaultValue & 0xFFFFFFFF);
outvars[v].value.uv[1] = ((c.variables[v].defaultValue >> 32) & 0xFFFFFFFF);
}
ResourceId pipeline = m_pDriver->m_RenderState.graphics.pipeline;
// TODO we shouldn't be looking up the pipeline here, this query should work regardless.
ResourceId pipeline = refl.stage == ShaderStage::Compute
? m_pDriver->m_RenderState.compute.pipeline
: m_pDriver->m_RenderState.graphics.pipeline;
if(pipeline != ResourceId())
{
auto pipeIt = m_pDriver->m_CreationInfo.m_Pipeline.find(pipeline);
@@ -1727,19 +1518,7 @@ void VulkanReplay::FillCBufferVariables(ResourceId shader, string entryPoint, ui
auto specInfo =
pipeIt->second.shaders[it->second.m_Reflections[entryPoint].stageIndex].specialization;
// find any actual values specified
for(size_t i = 0; i < specInfo.size(); i++)
{
for(size_t v = 0; v < c.variables.size(); v++)
{
if(specInfo[i].specID == c.variables[v].reg.vec)
{
memcpy(outvars[v].value.uv, specInfo[i].data,
RDCMIN(specInfo[i].size, sizeof(outvars[v].value.uv)));
break;
}
}
}
FillSpecConstantVariables(c.variables, outvars, specInfo);
}
}
}
@@ -1748,7 +1527,7 @@ void VulkanReplay::FillCBufferVariables(ResourceId shader, string entryPoint, ui
bytebuf pushdata;
pushdata.resize(sizeof(m_pDriver->m_RenderState.pushconsts));
memcpy(&pushdata[0], m_pDriver->m_RenderState.pushconsts, pushdata.size());
FillCBufferVariables(c.variables, outvars, pushdata, 0);
SPIRVFillCBufferVariables(c.variables, outvars, pushdata, 0);
}
}
}
-3
View File
@@ -331,9 +331,6 @@ private:
void CreateTexImageView(VkImageAspectFlags aspectFlags, VkImage liveIm,
VulkanCreationInfo::Image &iminfo);
void FillCBufferVariables(rdcarray<ShaderConstant>, vector<ShaderVariable> &outvars,
const bytebuf &data, size_t baseOffset);
VulkanDebugManager *GetDebugManager();
VulkanResourceManager *GetResourceManager();
+33 -36
View File
@@ -268,20 +268,27 @@ void VulkanShaderCache::MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &p
static VkPipelineShaderStageCreateInfo stages[6];
static VkSpecializationInfo specInfo[6];
static vector<VkSpecializationMapEntry> specMapEntries;
static std::vector<byte> specdata;
size_t specEntries = 0;
size_t specSize = 0;
for(uint32_t i = 0; i < 6; i++)
if(pipeInfo.shaders[i].module != ResourceId())
if(!pipeInfo.shaders[i].specialization.empty())
specEntries += pipeInfo.shaders[i].specialization.size();
{
specEntries += pipeInfo.shaders[i].specialization.size();
for(size_t s = 0; s < pipeInfo.shaders[i].specialization.size(); s++)
specSize += pipeInfo.shaders[i].specialization[s].data.size();
}
specMapEntries.resize(specEntries);
specdata.resize(specSize);
VkSpecializationMapEntry *entry = &specMapEntries[0];
uint32_t stageCount = 0;
specSize = 0;
// reserve space for spec constants
for(uint32_t i = 0; i < 6; i++)
{
if(pipeInfo.shaders[i].module != ResourceId())
@@ -299,27 +306,20 @@ void VulkanShaderCache::MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &p
specInfo[i].pMapEntries = entry;
specInfo[i].mapEntryCount = (uint32_t)pipeInfo.shaders[i].specialization.size();
byte *minDataPtr = NULL;
byte *maxDataPtr = NULL;
for(size_t s = 0; s < pipeInfo.shaders[i].specialization.size(); s++)
{
entry[s].constantID = pipeInfo.shaders[i].specialization[s].specID;
entry[s].size = pipeInfo.shaders[i].specialization[s].size;
entry[s].size = pipeInfo.shaders[i].specialization[s].data.size();
entry[s].offset = (uint32_t)specSize;
if(minDataPtr == NULL)
minDataPtr = pipeInfo.shaders[i].specialization[s].data;
else
minDataPtr = RDCMIN(minDataPtr, pipeInfo.shaders[i].specialization[s].data);
specSize += entry[s].size;
maxDataPtr = RDCMAX(minDataPtr, pipeInfo.shaders[i].specialization[s].data + entry[s].size);
memcpy(&specdata[0] + entry[s].offset, pipeInfo.shaders[i].specialization[s].data.data(),
entry[s].size);
}
for(size_t s = 0; s < pipeInfo.shaders[i].specialization.size(); s++)
entry[s].offset = (uint32_t)(pipeInfo.shaders[i].specialization[s].data - minDataPtr);
specInfo[i].dataSize = (maxDataPtr - minDataPtr);
specInfo[i].pData = (const void *)minDataPtr;
specInfo[i].dataSize = specdata.size();
specInfo[i].pData = specdata.data();
entry += specInfo[i].mapEntryCount;
}
@@ -531,13 +531,17 @@ void VulkanShaderCache::MakeComputePipelineInfo(VkComputePipelineCreateInfo &pip
VkPipelineShaderStageCreateInfo stage; // Returned by value
static VkSpecializationInfo specInfo;
static vector<VkSpecializationMapEntry> specMapEntries;
static std::vector<byte> specdata;
const uint32_t i = 5; // Compute stage
RDCASSERT(pipeInfo.shaders[i].module != ResourceId());
size_t specEntries = 0;
if(!pipeInfo.shaders[i].specialization.empty())
specEntries += pipeInfo.shaders[i].specialization.size();
size_t specEntries = pipeInfo.shaders[i].specialization.size();
size_t specSize = 0;
for(size_t s = 0; s < pipeInfo.shaders[i].specialization.size(); s++)
specSize += pipeInfo.shaders[i].specialization[s].data.size();
specdata.resize(specSize);
specMapEntries.resize(specEntries);
VkSpecializationMapEntry *entry = &specMapEntries[0];
@@ -550,35 +554,28 @@ void VulkanShaderCache::MakeComputePipelineInfo(VkComputePipelineCreateInfo &pip
stage.pSpecializationInfo = NULL;
stage.flags = VK_SHADER_STAGE_COMPUTE_BIT;
specSize = 0;
if(!pipeInfo.shaders[i].specialization.empty())
{
stage.pSpecializationInfo = &specInfo;
specInfo.pMapEntries = entry;
specInfo.mapEntryCount = (uint32_t)pipeInfo.shaders[i].specialization.size();
byte *minDataPtr = NULL;
byte *maxDataPtr = NULL;
for(size_t s = 0; s < pipeInfo.shaders[i].specialization.size(); s++)
{
entry[s].constantID = pipeInfo.shaders[i].specialization[s].specID;
entry[s].size = pipeInfo.shaders[i].specialization[s].size;
entry[s].size = pipeInfo.shaders[i].specialization[s].data.size();
entry[s].offset = (uint32_t)specSize;
if(minDataPtr == NULL)
minDataPtr = pipeInfo.shaders[i].specialization[s].data;
else
minDataPtr = RDCMIN(minDataPtr, pipeInfo.shaders[i].specialization[s].data);
specSize += entry[s].size;
maxDataPtr = RDCMAX(minDataPtr, pipeInfo.shaders[i].specialization[s].data + entry[s].size);
memcpy(&specdata[0] + entry[s].offset, pipeInfo.shaders[i].specialization[s].data.data(),
entry[s].size);
}
for(size_t s = 0; s < pipeInfo.shaders[i].specialization.size(); s++)
entry[s].offset = (uint32_t)(pipeInfo.shaders[i].specialization[s].data - minDataPtr);
specInfo.dataSize = (maxDataPtr - minDataPtr);
specInfo.pData = (const void *)minDataPtr;
entry += specInfo.mapEntryCount;
specInfo.dataSize = specdata.size();
specInfo.pData = specdata.data();
}
VkComputePipelineCreateInfo ret = {