Improved fragment id shader code

- Deleted WriteClearValues and replace with QueryPostModValues
- Add support for earlier GLSL versions and fix logic for creating primitive id program
- Changed to only run per fragment queries on events with multiple fragments
This commit is contained in:
Bruce He
2022-11-09 22:18:05 -05:00
committed by Baldur Karlsson
parent f6102a48a4
commit c0b931eb15
9 changed files with 388 additions and 151 deletions
+1
View File
@@ -433,6 +433,7 @@ set(data
data/glsl/pixelhistory_mscopy.comp
data/glsl/pixelhistory_mscopy_depth.comp
data/glsl/pixelhistory_primid.frag
data/glsl/pixelhistory_primid_legacy.frag
data/glsl/shaderdebug_sample.vert
data/glsl/texdisplay.frag
data/glsl/texremap.frag
+1
View File
@@ -66,6 +66,7 @@ DECLARE_EMBED(glsl_gles_texsample_h);
DECLARE_EMBED(glsl_pixelhistory_mscopy_comp);
DECLARE_EMBED(glsl_pixelhistory_mscopy_depth_comp);
DECLARE_EMBED(glsl_pixelhistory_primid_frag);
DECLARE_EMBED(glsl_pixelhistory_primid_legacy_frag);
DECLARE_EMBED(glsl_shaderdebug_sample_vert);
DECLARE_EMBED(glsl_texremap_frag);
DECLARE_EMBED(glsl_discard_frag);
+1 -1
View File
@@ -28,5 +28,5 @@ IO_LOCATION(0) out vec4 color_out;
void main(void)
{
color_out = intBitsToFloat(gl_PrimitiveID).xxxx;
color_out = vec4(intBitsToFloat(gl_PrimitiveID));
}
@@ -0,0 +1,32 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2020-2022 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "glsl_globals.h"
IO_LOCATION(0) out vec4 color_out;
void main(void)
{
color_out = vec4(float(gl_PrimitiveID));
}
+1
View File
@@ -156,6 +156,7 @@ RESOURCE_glsl_histogram_comp TYPE_EMBED "glsl/histogram.comp"
RESOURCE_glsl_pixelhistory_mscopy_comp TYPE_EMBED "glsl/pixelhistory_mscopy.comp"
RESOURCE_glsl_pixelhistory_mscopy_depth_comp TYPE_EMBED "glsl/pixelhistory_mscopy_depth.comp"
RESOURCE_glsl_pixelhistory_primid_frag TYPE_EMBED "glsl/pixelhistory_primid.frag"
RESOURCE_glsl_pixelhistory_primid_legacy_frag TYPE_EMBED "glsl/pixelhistory_primid_legacy.frag"
RESOURCE_glsl_glsl_ubos_h TYPE_EMBED "glsl/glsl_ubos.h"
RESOURCE_glsl_gl_texsample_h TYPE_EMBED "glsl/gl_texsample.h"
RESOURCE_glsl_vk_texsample_h TYPE_EMBED "glsl/vk_texsample.h"
+1
View File
@@ -65,6 +65,7 @@
#define RESOURCE_glsl_vk_depthms2buffer_comp 448
#define RESOURCE_glsl_vk_buffer2ms_comp 449
#define RESOURCE_glsl_vk_depthbuf2ms_frag 450
#define RESOURCE_glsl_pixelhistory_primid_legacy_frag 451
// Next default values for new objects
//
+347 -150
View File
@@ -45,6 +45,7 @@ struct GLPixelHistoryResources
GLuint dsImage;
GLuint frameBuffer;
GLuint primitiveIdFragmentShader;
GLuint primitiveIdFragmentShaderSPIRV;
std::unordered_map<GLuint, GLuint> programs;
};
@@ -64,6 +65,193 @@ enum class PerFragmentQueryType
PrimitiveId
};
GLuint CreatePrimitiveIdProgram(GLuint Program, GLuint Pipeline, GLuint fragShader,
GLuint fragShaderSPIRV, WrappedOpenGL *driver, GLReplay *replay)
{
WrappedOpenGL &drv = *driver;
ContextPair &ctx = drv.GetCtx();
GLuint primitiveIdProgram = drv.glCreateProgram();
// these are the shaders to attach, and the programs to copy details from
GLuint shaders[4] = {0};
GLuint programs[4] = {0};
// temporary programs created as needed if the original program was created with
// glCreateShaderProgramv and we don't have a shader to attach
GLuint tmpShaders[4] = {0};
// the reflection for the vertex shader, used to copy vertex bindings
ShaderReflection *vsRefl = NULL;
bool HasSPIRVShaders = false;
bool HasGLSLShaders = false;
if(Program == 0)
{
if(Pipeline == 0)
{
return false;
}
else
{
ResourceId id = driver->GetResourceManager()->GetResID(ProgramPipeRes(ctx, Pipeline));
const WrappedOpenGL::PipelineData &pipeDetails = driver->m_Pipelines[id];
// fetch the corresponding shaders and programs for each stage
for(size_t i = 0; i < 4; i++)
{
if(pipeDetails.stageShaders[i] != ResourceId())
{
const WrappedOpenGL::ShaderData &shadDetails =
driver->m_Shaders[pipeDetails.stageShaders[i]];
if(shadDetails.reflection->encoding == ShaderEncoding::SPIRV)
HasSPIRVShaders = true;
else
HasGLSLShaders = true;
programs[i] =
driver->GetResourceManager()->GetCurrentResource(pipeDetails.stagePrograms[i]).name;
shaders[i] =
driver->GetResourceManager()->GetCurrentResource(pipeDetails.stageShaders[i]).name;
if(pipeDetails.stagePrograms[i] == pipeDetails.stageShaders[i])
{
const WrappedOpenGL::ProgramData &progDetails =
driver->m_Programs[pipeDetails.stagePrograms[i]];
if(progDetails.shaderProgramUnlinkable)
{
rdcarray<const char *> sources;
sources.reserve(shadDetails.sources.size());
for(const rdcstr &s : shadDetails.sources)
sources.push_back(s.c_str());
shaders[i] = tmpShaders[i] = drv.glCreateShader(ShaderEnum(i));
drv.glShaderSource(tmpShaders[i], (GLsizei)sources.size(), sources.data(), NULL);
drv.glCompileShader(tmpShaders[i]);
GLint status = 0;
drv.glGetShaderiv(tmpShaders[i], eGL_COMPILE_STATUS, &status);
if(status == 0)
{
char buffer[1024] = {};
drv.glGetShaderInfoLog(tmpShaders[i], 1024, NULL, buffer);
RDCERR("Trying to create primitive id program, couldn't compile shader:\n%s", buffer);
}
}
}
if(i == 0)
vsRefl = replay->GetShader(ResourceId(), pipeDetails.stageShaders[i], ShaderEntryPoint());
}
}
}
}
else
{
const WrappedOpenGL::ProgramData &progDetails =
driver->m_Programs[driver->GetResourceManager()->GetResID(ProgramRes(ctx, Program))];
// fetch any and all non-fragment shader shaders
for(size_t i = 0; i < 4; i++)
{
if(progDetails.stageShaders[i] != ResourceId())
{
programs[i] = Program;
shaders[i] =
driver->GetResourceManager()->GetCurrentResource(progDetails.stageShaders[i]).name;
const WrappedOpenGL::ShaderData &shadDetails = driver->m_Shaders[progDetails.stageShaders[i]];
if(shadDetails.reflection->encoding == ShaderEncoding::SPIRV)
HasSPIRVShaders = true;
else
HasGLSLShaders = true;
if(i == 0)
vsRefl = replay->GetShader(ResourceId(), progDetails.stageShaders[0], ShaderEntryPoint());
}
}
}
if(HasGLSLShaders && HasSPIRVShaders)
RDCERR("Unsupported - mixed GLSL and SPIR-V shaders in pipeline");
// attach the shaders
for(size_t i = 0; i < 4; i++)
if(shaders[i])
drv.glAttachShader(primitiveIdProgram, shaders[i]);
if(HasSPIRVShaders)
{
RDCASSERT(fragShaderSPIRV);
drv.glAttachShader(primitiveIdProgram, fragShaderSPIRV);
}
else
{
drv.glAttachShader(primitiveIdProgram, fragShader);
}
// copy the vertex attribs over from the source program
if(vsRefl && programs[0] && !HasSPIRVShaders)
CopyProgramAttribBindings(programs[0], primitiveIdProgram, vsRefl);
// link the overlay program
drv.glLinkProgram(primitiveIdProgram);
// detach the shaders
for(size_t i = 0; i < 4; i++)
if(shaders[i])
drv.glDetachShader(primitiveIdProgram, shaders[i]);
if(HasSPIRVShaders)
drv.glDetachShader(primitiveIdProgram, fragShaderSPIRV);
else
drv.glDetachShader(primitiveIdProgram, fragShader);
// delete any temporaries
for(size_t i = 0; i < 4; i++)
if(tmpShaders[i])
drv.glDeleteShader(tmpShaders[i]);
// check that the link succeeded
char buffer[1024] = {};
GLint status = 0;
drv.glGetProgramiv(primitiveIdProgram, eGL_LINK_STATUS, &status);
if(status == 0)
{
drv.glGetProgramInfoLog(primitiveIdProgram, 1024, NULL, buffer);
RDCERR("Error linking primitive id program: %s", buffer);
return false;
}
// copy the uniform values over from the source program. This is redundant but harmless if the
// same program is bound to multiple stages. It's just inefficient
{
PerStageReflections dstStages;
driver->FillReflectionArray(ProgramRes(ctx, primitiveIdProgram), dstStages);
for(size_t i = 0; i < 4; i++)
{
if(programs[i])
{
PerStageReflections stages;
driver->FillReflectionArray(ProgramRes(ctx, programs[i]), stages);
CopyProgramUniforms(stages, programs[i], dstStages, primitiveIdProgram);
}
}
}
// return HasSPIRVShaders;
return primitiveIdProgram;
}
GLuint GetPrimitiveIdProgram(WrappedOpenGL *driver, GLReplay *replay,
GLPixelHistoryResources &resources, GLuint currentProgram)
{
@@ -73,69 +261,19 @@ GLuint GetPrimitiveIdProgram(WrappedOpenGL *driver, GLReplay *replay,
return programIterator->second;
}
GLuint newProgram;
GLRenderState rs;
rs.FetchState(driver);
GLint numAttachedShaders;
driver->glGetProgramiv(currentProgram, eGL_ATTACHED_SHADERS, &numAttachedShaders);
newProgram = driver->glCreateProgram();
GLuint *attachedShaders = new GLuint[numAttachedShaders];
driver->glGetAttachedShaders(currentProgram, numAttachedShaders, &numAttachedShaders,
attachedShaders);
ShaderReflection *vsRefl = NULL;
for(int i = 0; i < numAttachedShaders; ++i)
{
GLint shaderType;
driver->glGetShaderiv(attachedShaders[i], eGL_SHADER_TYPE, &shaderType);
if(shaderType != eGL_FRAGMENT_SHADER)
{
driver->glAttachShader(newProgram, attachedShaders[i]);
}
if(shaderType == eGL_VERTEX_SHADER)
{
vsRefl = replay->GetShader(ResourceId(), driver->GetResourceManager()->GetResID(
ShaderRes(driver->GetCtx(), attachedShaders[i])),
ShaderEntryPoint());
}
}
delete[] attachedShaders;
driver->glAttachShader(newProgram, resources.primitiveIdFragmentShader);
if(vsRefl)
{
CopyProgramAttribBindings(currentProgram, newProgram, vsRefl);
}
driver->glLinkProgram(newProgram);
char buffer[1024] = {};
GLint status = 0;
driver->glGetProgramiv(newProgram, eGL_LINK_STATUS, &status);
if(status == 0)
{
GL.glGetProgramInfoLog(newProgram, 1024, NULL, buffer);
RDCERR("Shader error: %s", buffer);
}
resources.programs[currentProgram] = newProgram;
PerStageReflections dstStages;
driver->FillReflectionArray(ProgramRes(driver->GetCtx(), newProgram), dstStages);
PerStageReflections stages;
driver->FillReflectionArray(ProgramRes(driver->GetCtx(), newProgram), stages);
CopyProgramUniforms(stages, currentProgram, dstStages, newProgram);
GLuint newProgram = CreatePrimitiveIdProgram(
rs.Program.name, rs.Pipeline.name, resources.primitiveIdFragmentShader,
resources.primitiveIdFragmentShaderSPIRV, driver, replay);
return newProgram;
}
bool PixelHistorySetupResources(WrappedOpenGL *driver, GLPixelHistoryResources &resources,
const TextureDescription &desc, const Subresource &sub,
uint32_t numEvents)
uint32_t numEvents, GLuint glslVersion)
{
// Allocate a framebuffer that will render to the textures
driver->glGenFramebuffers(1, &resources.frameBuffer);
@@ -156,15 +294,24 @@ bool PixelHistorySetupResources(WrappedOpenGL *driver, GLPixelHistoryResources &
desc.msSamp, 1);
driver->glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, resources.dsImage, 0);
// The pixel history primitive ID Fragment Shader requires at least version 420.
// This is because it requires scalars to be swizzled something enabled
// in version 420. We also require intBitsToFloat which is introduced in
// version 330.
int GLSLVersion = 420;
rdcstr fs = GenerateGLSLShader(GetEmbeddedResource(glsl_pixelhistory_primid_frag),
ShaderType::GLSL, GLSLVersion);
resources.primitiveIdFragmentShader = CreateShader(eGL_FRAGMENT_SHADER, fs);
// If the GLSL version is greater than or equal to 330, we can use IntBitsToFloat, otherwise we
// need to write the float value directly.
rdcstr glslSource;
if(glslVersion >= 330)
{
glslSource = GenerateGLSLShader(GetEmbeddedResource(glsl_pixelhistory_primid_frag),
ShaderType::GLSL, glslVersion);
}
else
{
glslSource = GenerateGLSLShader(GetEmbeddedResource(glsl_pixelhistory_primid_legacy_frag),
ShaderType::GLSL, glslVersion);
}
// SPIR-V shaders are always generated as desktop GL 430, for ease
rdcstr spirvSource = GenerateGLSLShader(GetEmbeddedResource(glsl_pixelhistory_primid_frag),
ShaderType::GLSPIRV, 430);
resources.primitiveIdFragmentShaderSPIRV = CreateSPIRVShader(eGL_FRAGMENT_SHADER, spirvSource);
resources.primitiveIdFragmentShader = CreateShader(eGL_FRAGMENT_SHADER, glslSource);
return true;
}
@@ -175,6 +322,7 @@ bool PixelHistoryDestroyResources(WrappedOpenGL *driver, const GLPixelHistoryRes
driver->glDeleteTextures(1, &resources.dsImage);
driver->glDeleteFramebuffers(1, &resources.frameBuffer);
driver->glDeleteShader(resources.primitiveIdFragmentShader);
driver->glDeleteShader(resources.primitiveIdFragmentShaderSPIRV);
for(const std::pair<const GLuint, GLuint> &resourceProgram : resources.programs)
{
@@ -195,7 +343,7 @@ rdcarray<EventUsage> QueryModifyingEvents(WrappedOpenGL *driver, GLPixelHistoryR
driver->ReplayLog(0, events[0].eventId, eReplay_WithoutDraw);
// execute the occlusion queries
for(size_t i = 0; i < events.size(); ++i)
for(size_t i = 0; i < events.size(); i++)
{
if(!(events[i].usage == ResourceUsage::Clear || isDirectWrite(events[i].usage)))
{
@@ -220,7 +368,7 @@ rdcarray<EventUsage> QueryModifyingEvents(WrappedOpenGL *driver, GLPixelHistoryR
}
}
// read back the occlusion queries and generate the list of potentially modifying events
for(size_t i = 0; i < events.size(); ++i)
for(size_t i = 0; i < events.size(); i++)
{
if(events[i].usage == ResourceUsage::Clear || isDirectWrite(events[i].usage))
{
@@ -251,9 +399,48 @@ rdcarray<EventUsage> QueryModifyingEvents(WrappedOpenGL *driver, GLPixelHistoryR
return modEvents;
}
void QueryPostModPixelValues(WrappedOpenGL *driver, GLPixelHistoryResources &resources,
const rdcarray<EventUsage> &modEvents, int x, int y,
rdcarray<PixelModification> &history)
{
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
driver->glClear(eGL_COLOR_BUFFER_BIT | eGL_DEPTH_BUFFER_BIT | eGL_STENCIL_BUFFER_BIT);
driver->ReplayLog(0, modEvents[0].eventId, eReplay_WithoutDraw);
for(size_t i = 0; i < modEvents.size(); i++)
{
GLint savedReadFramebuffer, savedDrawFramebuffer;
driver->glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, &savedDrawFramebuffer);
driver->glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &savedReadFramebuffer);
// bind our own framebuffer to save the pixel values
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
driver->ReplayLog(modEvents[i].eventId, modEvents[i].eventId, eReplay_Full);
// read the post mod pixel value into the history event
ModificationValue modValue;
PixelValue pixelValue;
driver->glReadPixels(x, y, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)pixelValue.floatValue.data());
driver->glReadPixels(x, y, 1, 1, eGL_DEPTH_COMPONENT, eGL_FLOAT, (void *)&modValue.depth);
driver->glReadPixels(x, y, 1, 1, eGL_STENCIL_INDEX, eGL_INT, (void *)&modValue.stencil);
modValue.col = pixelValue;
history[i].postMod = modValue;
// restore the capture's framebuffer
driver->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, savedDrawFramebuffer);
driver->glBindFramebuffer(eGL_READ_FRAMEBUFFER, savedReadFramebuffer);
if(i < modEvents.size() - 1)
{
driver->ReplayLog(modEvents[i].eventId + 1, modEvents[i + 1].eventId, eReplay_WithoutDraw);
}
}
}
std::map<uint32_t, uint32_t> QueryNumFragmentsByEvent(WrappedOpenGL *driver,
GLPixelHistoryResources &resources,
const rdcarray<EventUsage> &modEvents, int x,
const rdcarray<EventUsage> &modEvents,
rdcarray<PixelModification> &history, int x,
int y)
{
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
@@ -264,30 +451,45 @@ std::map<uint32_t, uint32_t> QueryNumFragmentsByEvent(WrappedOpenGL *driver,
for(size_t i = 0; i < modEvents.size(); ++i)
{
if(!isDirectWrite(modEvents[i].usage) && modEvents[i].usage != ResourceUsage::Clear)
{
GLint savedReadFramebuffer, savedDrawFramebuffer;
driver->glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, &savedDrawFramebuffer);
driver->glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &savedReadFramebuffer);
// bind our own framebuffer to save the pixel values
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
driver->glStencilOp(eGL_INCR, eGL_INCR, eGL_INCR);
driver->glStencilMask(0xff);
driver->glClearStencil(0);
driver->glClear(eGL_STENCIL_BUFFER_BIT);
driver->glEnable(eGL_STENCIL_TEST);
driver->ReplayLog(modEvents[i].eventId, modEvents[i].eventId, eReplay_Full);
GLint savedReadFramebuffer, savedDrawFramebuffer;
driver->glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, &savedDrawFramebuffer);
driver->glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &savedReadFramebuffer);
// bind our own framebuffer to save the pixel values
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
driver->glStencilOp(eGL_INCR, eGL_INCR, eGL_INCR);
driver->glStencilMask(0xff); // default for 1 byte
driver->glStencilFunc(eGL_ALWAYS, 0, 0xff);
driver->glClearStencil(0);
driver->glClear(eGL_STENCIL_BUFFER_BIT);
driver->glEnable(eGL_STENCIL_TEST);
// depth test enable
driver->glEnable(eGL_DEPTH_TEST);
driver->glDepthFunc(eGL_ALWAYS);
driver->glDepthMask(GL_TRUE);
driver->glDisable(eGL_BLEND);
// replay start
driver->ReplayLog(modEvents[i].eventId, modEvents[i].eventId, eReplay_OnlyDraw);
// read and get number of fragments
uint32_t numFragments;
driver->glReadPixels(x, y, 1, 1, eGL_STENCIL_INDEX, eGL_INT, (void *)&numFragments);
uint32_t numFragments;
ModificationValue modValue;
PixelValue pixelValue;
eventFragments.emplace(modEvents[i].eventId, numFragments);
driver->glReadPixels(x, y, 1, 1, eGL_STENCIL_INDEX, eGL_INT, (void *)&numFragments);
driver->glReadPixels(x, y, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)pixelValue.floatValue.data());
driver->glReadPixels(x, y, 1, 1, eGL_DEPTH_COMPONENT, eGL_FLOAT, (void *)&modValue.depth);
modValue.col = pixelValue;
// restore the capture's framebuffer
driver->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, savedDrawFramebuffer);
driver->glBindFramebuffer(eGL_READ_FRAMEBUFFER, savedReadFramebuffer);
}
// We're not reading the stencil value here, so use the postMod instead.
// Shaders don't actually output stencil values, those are determined by the stencil op.
modValue.stencil = history[i].postMod.stencil;
history[i].shaderOut = modValue;
eventFragments.emplace(modEvents[i].eventId, numFragments);
// restore the capture's framebuffer
driver->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, savedDrawFramebuffer);
driver->glBindFramebuffer(eGL_READ_FRAMEBUFFER, savedReadFramebuffer);
if(i < modEvents.size() - 1)
{
@@ -397,15 +599,13 @@ void QueryPerFragmentValues(WrappedOpenGL *driver, GLReplay *replay,
GLPixelHistoryResources &resources, const EventUsage &modEvent, int x,
int y, rdcarray<PixelModification> &history,
const std::map<uint32_t, uint32_t> &eventFragments,
PerFragmentQueryType queryType)
PerFragmentQueryType queryType, bool usingLegacyPrimitiveId,
uint32_t numFragments)
{
driver->ReplayLog(0, modEvent.eventId - 1, eReplay_Full);
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
driver->glReadBuffer(eGL_COLOR_ATTACHMENT0);
auto it = eventFragments.find(modEvent.eventId);
uint32_t numFragments = (it != eventFragments.end()) ? it->second : 0;
driver->glEnable(eGL_SCISSOR_TEST);
driver->glScissor(x, y, 1, 1);
@@ -433,6 +633,8 @@ void QueryPerFragmentValues(WrappedOpenGL *driver, GLReplay *replay,
});
RDCASSERT(historyIndex != history.end());
GLint currentProgram = 0;
if(queryType == PerFragmentQueryType::PostMod)
{
if(historyIndex != history.begin())
@@ -464,8 +666,6 @@ void QueryPerFragmentValues(WrappedOpenGL *driver, GLReplay *replay,
driver->glClearColor(0.84f, 0.17f, 0.2f, 0.49f);
driver->glClear(eGL_COLOR_BUFFER_BIT);
GLint currentProgram;
driver->glGetIntegerv(eGL_CURRENT_PROGRAM, &currentProgram);
driver->glUseProgram(GetPrimitiveIdProgram(driver, replay, resources, currentProgram));
@@ -476,19 +676,32 @@ void QueryPerFragmentValues(WrappedOpenGL *driver, GLReplay *replay,
ModificationValue modValue;
PixelValue pixelValue;
modValue.stencil = 0;
// Set the stencil function so only jth fragment will pass.
driver->glStencilFunc(eGL_EQUAL, (int)j, 0xff);
driver->glClear(eGL_STENCIL_BUFFER_BIT);
driver->ReplayLog(modEvent.eventId, modEvent.eventId, eReplay_Full);
driver->ReplayLog(modEvent.eventId, modEvent.eventId, eReplay_OnlyDraw);
if(queryType == PerFragmentQueryType::PrimitiveId)
{
int primitiveIds[4];
driver->glReadPixels(x, y, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)primitiveIds);
if(usingLegacyPrimitiveId)
{
float primitiveIds[4];
driver->glReadPixels(x, y, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)primitiveIds);
RDCASSERT(primitiveIds[0] == primitiveIds[1] && primitiveIds[0] == primitiveIds[2] &&
primitiveIds[0] == primitiveIds[3]);
historyIndex->primitiveID = primitiveIds[0];
RDCASSERT(primitiveIds[0] == primitiveIds[1] && primitiveIds[0] == primitiveIds[2] &&
primitiveIds[0] == primitiveIds[3]);
historyIndex->primitiveID = int(primitiveIds[0]);
}
else
{
int primitiveIds[4];
driver->glReadPixels(x, y, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)primitiveIds);
RDCASSERT(primitiveIds[0] == primitiveIds[1] && primitiveIds[0] == primitiveIds[2] &&
primitiveIds[0] == primitiveIds[3]);
historyIndex->primitiveID = primitiveIds[0];
}
}
else
{
@@ -508,43 +721,11 @@ void QueryPerFragmentValues(WrappedOpenGL *driver, GLReplay *replay,
}
++historyIndex;
}
}
void WriteClearValues(WrappedOpenGL *driver, GLPixelHistoryResources &resources,
const EventUsage clearEvent, int x, int y, rdcarray<PixelModification> &history)
{
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
driver->glClear(eGL_COLOR_BUFFER_BIT | eGL_DEPTH_BUFFER_BIT | eGL_STENCIL_BUFFER_BIT);
driver->ReplayLog(0, clearEvent.eventId - 1, eReplay_WithoutDraw);
GLint savedReadFramebuffer, savedDrawFramebuffer;
driver->glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, &savedDrawFramebuffer);
driver->glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, &savedReadFramebuffer);
// bind our own framebuffer to save the pixel values
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
driver->ReplayLog(clearEvent.eventId, clearEvent.eventId, eReplay_Full);
// read the post mod pixel value into the history event
ModificationValue modValue;
PixelValue pixelValue;
driver->glReadPixels(x, y, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)pixelValue.floatValue.data());
driver->glReadPixels(x, y, 1, 1, eGL_DEPTH_COMPONENT, eGL_FLOAT, (void *)&modValue.depth);
driver->glReadPixels(x, y, 1, 1, eGL_STENCIL_INDEX, eGL_INT, (void *)&modValue.stencil);
modValue.col = pixelValue;
PixelModification referenceHistory;
referenceHistory.eventId = clearEvent.eventId;
auto historyIndex =
std::lower_bound(history.begin(), history.end(), referenceHistory,
[](const PixelModification &h1, const PixelModification &h2) -> bool {
return h1.eventId < h2.eventId;
});
historyIndex->postMod = modValue;
// restore the capture's framebuffer
driver->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, savedDrawFramebuffer);
driver->glBindFramebuffer(eGL_READ_FRAMEBUFFER, savedReadFramebuffer);
if(queryType == PerFragmentQueryType::PrimitiveId)
{
driver->glUseProgram(currentProgram);
}
}
bool depthTestPassed(int depthFunc, float shaderOutputDepth, float depthInBuffer)
@@ -560,19 +741,28 @@ bool depthTestPassed(int depthFunc, float shaderOutputDepth, float depthInBuffer
case eGL_GEQUAL: return shaderOutputDepth >= depthInBuffer;
case eGL_ALWAYS: return true;
default: RDCASSERT(0);
default: RDCERR("Unexpected depth function: %d", depthFunc);
}
return false;
}
void CalculateFragmentDepthTests(WrappedOpenGL *driver, GLPixelHistoryResources &resources,
const rdcarray<EventUsage> &modEvents,
rdcarray<PixelModification> &history)
rdcarray<PixelModification> &history,
const std::map<uint32_t, uint32_t> &eventFragments)
{
driver->ReplayLog(0, modEvents[0].eventId, eReplay_WithoutDraw);
size_t historyIndex = 0;
for(size_t i = 0; i < modEvents.size(); ++i)
{
// We only need to calculate the depth test for events with multiple fragments.
auto it = eventFragments.find(modEvents[i].eventId);
uint32_t numFragments = (it != eventFragments.end()) ? it->second : 0;
if(numFragments <= 1)
{
continue;
}
for(; historyIndex < history.size() && modEvents[i].eventId == history[historyIndex].eventId;
++historyIndex)
{
@@ -649,7 +839,11 @@ rdcarray<PixelModification> GLReplay::PixelHistory(rdcarray<EventUsage> events,
MakeCurrentReplayContext(&m_ReplayCtx);
PixelHistorySetupResources(m_pDriver, resources, textureDesc, sub, (uint32_t)events.size());
int glslVersion = DebugData.glslVersion;
bool usingLegacyPrimitveId = glslVersion < 330;
PixelHistorySetupResources(m_pDriver, resources, textureDesc, sub, (uint32_t)events.size(),
glslVersion);
rdcarray<EventUsage> modEvents =
QueryModifyingEvents(m_pDriver, resources, events, x, flippedY, history);
@@ -661,8 +855,10 @@ rdcarray<PixelModification> GLReplay::PixelHistory(rdcarray<EventUsage> events,
}
QueryFailedTests(m_pDriver, resources, modEvents, x, flippedY, history);
QueryPostModPixelValues(m_pDriver, resources, modEvents, x, flippedY, history);
std::map<uint32_t, uint32_t> eventFragments =
QueryNumFragmentsByEvent(m_pDriver, resources, modEvents, x, flippedY);
QueryNumFragmentsByEvent(m_pDriver, resources, modEvents, history, x, flippedY);
// copy history entries to create one history per fragment
for(size_t h = 0; h < history.size();)
@@ -686,18 +882,19 @@ rdcarray<PixelModification> GLReplay::PixelHistory(rdcarray<EventUsage> events,
for(const EventUsage &modEvent : modEvents)
{
if(modEvent.usage == ResourceUsage::Clear)
{
WriteClearValues(m_pDriver, resources, modEvent, x, flippedY, history);
}
else
auto it = eventFragments.find(modEvent.eventId);
uint32_t numFragments = (it != eventFragments.end()) ? it->second : 0;
if(numFragments > 1)
{
QueryPerFragmentValues(m_pDriver, this, resources, modEvent, x, flippedY, history,
eventFragments, PerFragmentQueryType::ShaderOut);
eventFragments, PerFragmentQueryType::ShaderOut, usingLegacyPrimitveId,
numFragments);
QueryPerFragmentValues(m_pDriver, this, resources, modEvent, x, flippedY, history,
eventFragments, PerFragmentQueryType::PrimitiveId);
eventFragments, PerFragmentQueryType::PrimitiveId,
usingLegacyPrimitveId, numFragments);
QueryPerFragmentValues(m_pDriver, this, resources, modEvent, x, flippedY, history,
eventFragments, PerFragmentQueryType::PostMod);
eventFragments, PerFragmentQueryType::PostMod, usingLegacyPrimitveId,
numFragments);
}
}
@@ -707,7 +904,7 @@ rdcarray<PixelModification> GLReplay::PixelHistory(rdcarray<EventUsage> events,
history[i].preMod = history[i - 1].postMod;
}
CalculateFragmentDepthTests(m_pDriver, resources, modEvents, history);
CalculateFragmentDepthTests(m_pDriver, resources, modEvents, history, eventFragments);
PixelHistoryDestroyResources(m_pDriver, resources);
return history;
+1
View File
@@ -700,6 +700,7 @@
<None Include="data\glsl\pixelhistory_mscopy.comp" />
<None Include="data\glsl\pixelhistory_mscopy_depth.comp" />
<None Include="data\glsl\pixelhistory_primid.frag" />
<None Include="data\glsl\pixelhistory_primid_legacy.frag" />
<None Include="data\glsl\quadresolve.frag" />
<None Include="data\glsl\quadwrite.frag" />
<None Include="data\glsl\shaderdebug_sample.vert" />
+3
View File
@@ -1030,6 +1030,9 @@
<None Include="data\glsl\pixelhistory_primid.frag">
<Filter>Resources\glsl</Filter>
</None>
<None Include="data\glsl\pixelhistory_primid_legacy.frag">
<Filter>Resources\glsl</Filter>
</None>
<None Include="data\glsl\quadresolve.frag">
<Filter>Resources\glsl</Filter>
</None>