mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-13 13:30:44 +00:00
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:
committed by
Baldur Karlsson
parent
7d9a1a05b8
commit
8684585330
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user