Add WIP OpenGL Pixel History code for PostMod pixel value

The OpenGL Pixel History feature is hidden behind the OpenGL_PixelHistory config toggle.
For now, we only run an occlusion query and then replay the events
and read back the pixel values to return to the UI.
This commit is contained in:
Orson Baines
2022-06-10 23:43:51 -04:00
committed by Baldur Karlsson
parent 7d9a1a05b8
commit 8684585330
5 changed files with 232 additions and 8 deletions
+1
View File
@@ -6,6 +6,7 @@ set(sources
gl_postvs.cpp
gl_overlay.cpp
gl_outputwindow.cpp
gl_pixelhistory.cpp
gl_rendermesh.cpp
gl_rendertexture.cpp
gl_rendertext.cpp
+225
View File
@@ -0,0 +1,225 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2019-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 "gl_driver.h"
#include "gl_replay.h"
namespace
{
bool isDirectWrite(ResourceUsage usage)
{
return ((usage >= ResourceUsage::VS_RWResource && usage <= ResourceUsage::CS_RWResource) ||
usage == ResourceUsage::CopyDst || usage == ResourceUsage::Copy ||
usage == ResourceUsage::Resolve || usage == ResourceUsage::ResolveDst ||
usage == ResourceUsage::GenMips);
}
struct GLPixelHistoryResources
{
// Used for offscreen rendering for draw call events.
GLuint colorImage;
GLuint dsImage;
GLuint frameBuffer;
GLuint occlusionQuery;
};
bool PixelHistorySetupResources(WrappedOpenGL *driver, GLPixelHistoryResources &resources,
const TextureDescription &desc, const Subresource &sub,
uint32_t numEvents)
{
// Allocate a framebuffer that will render to the textures
driver->glGenFramebuffers(1, &resources.frameBuffer);
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
// Allocate a texture for the pixel history colour values
driver->glGenTextures(1, &resources.colorImage);
driver->glBindTexture(eGL_TEXTURE_2D, resources.colorImage);
driver->CreateTextureImage(resources.colorImage, eGL_RGBA32F, eGL_NONE, eGL_NONE, eGL_TEXTURE_2D,
2, desc.width >> sub.mip, desc.height >> sub.mip, 1, desc.msSamp, 1);
driver->glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, resources.colorImage, 0);
// Allocate a texture for the pixel history depth/stencil values
driver->glGenTextures(1, &resources.dsImage);
driver->glBindTexture(eGL_TEXTURE_2D, resources.dsImage);
driver->CreateTextureImage(resources.dsImage, eGL_DEPTH32F_STENCIL8, eGL_NONE, eGL_NONE,
eGL_TEXTURE_2D, 2, desc.width >> sub.mip, desc.height >> sub.mip, 1,
desc.msSamp, 1);
driver->glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, resources.dsImage, 0);
driver->glGenQueries(1, &resources.occlusionQuery);
return true;
}
bool PixelHistoryDestroyResources(WrappedOpenGL *driver, const GLPixelHistoryResources &resources)
{
driver->glDeleteTextures(1, &resources.colorImage);
driver->glDeleteTextures(1, &resources.dsImage);
driver->glDeleteFramebuffers(1, &resources.frameBuffer);
driver->glDeleteQueries(1, &resources.occlusionQuery);
return true;
}
rdcarray<EventUsage> QueryModifyingEvents(WrappedOpenGL *driver, GLPixelHistoryResources &resources,
const rdcarray<EventUsage> &events, int x, int y)
{
driver->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
driver->ReplayLog(0, events[0].eventId, eReplay_WithoutDraw);
rdcarray<EventUsage> modEvents;
for(size_t i = 0; i < events.size(); i++)
{
if(events[i].usage == ResourceUsage::Clear || isDirectWrite(events[i].usage))
{
modEvents.push_back(events[i]);
}
else
{
driver->glBindFramebuffer(eGL_FRAMEBUFFER, resources.frameBuffer);
driver->glDisable(eGL_DEPTH_TEST);
driver->glDisable(eGL_STENCIL_TEST);
driver->glEnable(eGL_SCISSOR_TEST);
driver->glScissor(x, y, 1, 1);
driver->glBeginQuery(eGL_ANY_SAMPLES_PASSED, resources.occlusionQuery);
driver->ReplayLog(events[i].eventId, events[i].eventId, eReplay_OnlyDraw);
int result;
driver->glGetQueryObjectiv(resources.occlusionQuery, eGL_QUERY_RESULT, &result);
if(result)
{
modEvents.push_back(events[i]);
}
}
if(i < events.size() - 1)
{
driver->ReplayLog(events[i].eventId + 1, events[i + 1].eventId, eReplay_WithoutDraw);
}
}
return modEvents;
}
void QueryPostModPixelValues(WrappedOpenGL *driver, GLPixelHistoryResources &resources,
const rdcarray<EventUsage> &modEvents, int x, int y,
rdcarray<PixelModification> &history)
{
driver->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
driver->ReplayLog(0, modEvents[0].eventId, eReplay_WithoutDraw);
for(size_t i = 0; i < modEvents.size(); i++)
{
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
PixelModification mod;
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;
RDCEraseEl(mod);
mod.eventId = modEvents[i].eventId;
mod.postMod = modValue;
history.push_back(mod);
if(i < modEvents.size() - 1)
{
driver->ReplayLog(modEvents[i].eventId + 1, modEvents[i + 1].eventId, eReplay_WithoutDraw);
}
}
}
};
rdcarray<PixelModification> GLReplay::PixelHistory(rdcarray<EventUsage> events, ResourceId target,
uint32_t x, uint32_t y, const Subresource &sub,
CompType typeCast)
{
rdcarray<PixelModification> history;
if(events.empty())
return history;
TextureDescription textureDesc = GetTexture(target);
if(textureDesc.format.type == ResourceFormatType::Undefined)
return history;
// When RenderDoc passes in the y, the value being passed in is with the Y axis starting from the
// top
// However, we need to have it starting from the bottom, so flip it by subtracting y from the
// height.
uint32_t flippedY = textureDesc.height - y - 1;
rdcstr regionName = StringFormat::Fmt(
"PixelHistory: pixel: (%u, %u) on %s subresource (%u, %u, %u) cast to %s with %zu events", x,
flippedY, ToStr(target).c_str(), sub.mip, sub.slice, sub.sample, ToStr(typeCast).c_str(),
events.size());
RDCDEBUG("%s", regionName.c_str());
uint32_t sampleIdx = sub.sample;
if(sampleIdx > textureDesc.msSamp)
sampleIdx = 0;
uint32_t sampleMask = ~0U;
if(sampleIdx < 32)
sampleMask = 1U << sampleIdx;
bool multisampled = (textureDesc.msSamp > 1);
if(sampleIdx == ~0U || !multisampled)
sampleIdx = 0;
GLPixelHistoryResources resources;
MakeCurrentReplayContext(&m_ReplayCtx);
PixelHistorySetupResources(m_pDriver, resources, textureDesc, sub, (uint32_t)events.size());
rdcarray<EventUsage> modEvents = QueryModifyingEvents(m_pDriver, resources, events, x, flippedY);
if(modEvents.empty())
{
return history;
}
QueryPostModPixelValues(m_pDriver, resources, modEvents, x, flippedY, history);
// copy the postMod to next history's preMod
for(size_t i = 1; i < history.size(); ++i)
{
history[i].preMod = history[i - 1].postMod;
}
PixelHistoryDestroyResources(m_pDriver, resources);
return history;
}
+2 -8
View File
@@ -41,6 +41,7 @@
RDOC_CONFIG(bool, OpenGL_HardwareCounters, true,
"Enable support for IHV-specific hardware counters on OpenGL.");
RDOC_CONFIG(bool, OpenGL_PixelHistory, false, "Enable Pixel History on OpenGL (WIP).");
static const char *SPIRVDisassemblyTarget = "SPIR-V (RenderDoc)";
@@ -218,6 +219,7 @@ APIProperties GLReplay::GetAPIProperties()
ret.degraded = m_Degraded;
ret.vendor = m_DriverInfo.vendor;
ret.shadersMutable = true;
ret.pixelHistory = OpenGL_PixelHistory();
return ret;
}
@@ -3725,14 +3727,6 @@ rdcarray<EventUsage> GLReplay::GetUsage(ResourceId id)
return m_pDriver->GetUsage(id);
}
rdcarray<PixelModification> GLReplay::PixelHistory(rdcarray<EventUsage> events, ResourceId target,
uint32_t x, uint32_t y, const Subresource &sub,
CompType typeCast)
{
GLNOTIMP("GLReplay::PixelHistory");
return {};
}
ShaderDebugTrace *GLReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t view)
{
+1
View File
@@ -153,6 +153,7 @@
<ClCompile Include="gl_debug.cpp" />
<ClCompile Include="gl_driver.cpp" />
<ClCompile Include="gl_hooks.cpp" />
<ClCompile Include="gl_pixelhistory.cpp" />
<ClCompile Include="wgl_hooks.cpp" />
<ClCompile Include="gl_initstate.cpp" />
<ClCompile Include="gl_manager.cpp" />
@@ -260,6 +260,9 @@
<ClCompile Include="glx_fake_vk_hooks.cpp">
<Filter>Platform Interfaces\Linux</Filter>
</ClCompile>
<ClCompile Include="gl_pixelhistory.cpp">
<Filter>Replay</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cgl_platform_helpers.mm">