mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-07 07:11:06 +00:00
Add support for ARB_gl_spirv. Closes #767
This commit is contained in:
@@ -1772,6 +1772,9 @@ enum class GLChunk : uint32_t
|
||||
glMaxShaderCompilerThreadsARB,
|
||||
glMaxShaderCompilerThreadsKHR,
|
||||
|
||||
glSpecializeShader,
|
||||
glSpecializeShaderARB,
|
||||
|
||||
Max,
|
||||
};
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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); \
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user