Use XFB to get postvs data (not post gs/tess yet), and render

This commit is contained in:
baldurk
2015-01-26 13:07:24 +00:00
parent 846a83d6b1
commit 9c9c92b08f
9 changed files with 723 additions and 97 deletions
+9 -15
View File
@@ -3707,25 +3707,19 @@ void D3D11DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark)
}
}
PostVSData D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventID)
{
auto idx = std::make_pair(frameID, eventID);
if(m_PostVSData.find(idx) != m_PostVSData.end())
return m_PostVSData[idx];
RDCWARN("Post VS Buffers not initialised!");
PostVSData empty;
RDCEraseEl(empty);
return empty;
}
MeshFormat D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage)
{
MeshFormat ret;
PostVSData postvs;
RDCEraseEl(postvs);
auto idx = std::make_pair(frameID, eventID);
if(m_PostVSData.find(idx) != m_PostVSData.end())
postvs = m_PostVSData[idx];
PostVSData postvs = GetPostVSBuffers(frameID, eventID);
PostVSData::StageData s = postvs.GetStage(stage);
MeshFormat ret;
if(s.useIndices && s.idxBuf)
ret.idxbuf = ((WrappedID3D11Buffer *)s.idxBuf)->GetResourceID();
else
-1
View File
@@ -113,7 +113,6 @@ class D3D11DebugManager
int GetHeight() { return m_height; }
void InitPostVSBuffers(uint32_t frameID, uint32_t eventID);
PostVSData GetPostVSBuffers(uint32_t frameID, uint32_t eventID);
MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage);
uint32_t GetStructCount(ID3D11UnorderedAccessView *uav);
+580 -57
View File
@@ -33,6 +33,8 @@
#include "serialise/string_utils.h"
#include <algorithm>
GLuint GLReplay::CreateCShaderProgram(const char *csSrc)
{
if(m_pDriver == NULL) return 0;
@@ -215,7 +217,7 @@ void GLReplay::InitDebugData()
gl.glGenBuffers(1, &DebugData.outlineStripVB);
gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.outlineStripVB);
gl.glBufferData(eGL_ARRAY_BUFFER, sizeof(data), data, eGL_STATIC_DRAW);
gl.glNamedBufferDataEXT(DebugData.outlineStripVB, sizeof(data), data, eGL_STATIC_DRAW);
gl.glGenVertexArrays(1, &DebugData.outlineStripVAO);
gl.glBindVertexArray(DebugData.outlineStripVAO);
@@ -246,7 +248,7 @@ void GLReplay::InitDebugData()
for(size_t i=0; i < ARRAY_COUNT(DebugData.UBOs); i++)
{
gl.glBindBuffer(eGL_UNIFORM_BUFFER, DebugData.UBOs[i]);
gl.glBufferData(eGL_UNIFORM_BUFFER, 512, NULL, eGL_DYNAMIC_DRAW);
gl.glNamedBufferDataEXT(DebugData.UBOs[i], 512, NULL, eGL_DYNAMIC_DRAW);
RDCCOMPILE_ASSERT(sizeof(texdisplay) < 512, "texdisplay UBO too large");
RDCCOMPILE_ASSERT(sizeof(FontUniforms) < 512, "texdisplay UBO too large");
RDCCOMPILE_ASSERT(sizeof(HistogramCBufferData) < 512, "texdisplay UBO too large");
@@ -408,6 +410,18 @@ void GLReplay::InitDebugData()
gl.glEnableVertexAttribArray(0);
DebugData.replayQuadProg = CreateShaderProgram(DebugData.blitvsSource.c_str(), DebugData.genericfsSource.c_str());
MakeCurrentReplayContext(&m_ReplayCtx);
gl.glGenTransformFeedbacks(1, &DebugData.feedbackObj);
gl.glGenBuffers(1, &DebugData.feedbackBuffer);
gl.glGenQueries(1, &DebugData.feedbackQuery);
gl.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, DebugData.feedbackObj);
gl.glBindBuffer(eGL_TRANSFORM_FEEDBACK_BUFFER, DebugData.feedbackBuffer);
gl.glNamedBufferStorageEXT(DebugData.feedbackBuffer, 32*1024*1024, NULL, GL_MAP_READ_BIT);
gl.glBindBufferBase(eGL_TRANSFORM_FEEDBACK_BUFFER, 0, DebugData.feedbackBuffer);
gl.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, 0);
}
void GLReplay::DeleteDebugData()
@@ -416,6 +430,16 @@ void GLReplay::DeleteDebugData()
WrappedOpenGL &gl = *m_pDriver;
for(auto it=m_PostVSData.begin(); it != m_PostVSData.end(); ++it)
{
gl.glDeleteBuffers(1, &it->second.vsout.buf);
gl.glDeleteBuffers(1, &it->second.vsout.idxBuf);
gl.glDeleteBuffers(1, &it->second.gsout.buf);
gl.glDeleteBuffers(1, &it->second.gsout.idxBuf);
}
m_PostVSData.clear();
gl.glDeleteProgram(DebugData.blitProg);
for(int i=0; i < 3; i++)
@@ -459,6 +483,10 @@ void GLReplay::DeleteDebugData()
gl.glDeleteBuffers(1, &DebugData.minmaxResult);
gl.glDeleteBuffers(1, &DebugData.histogramBuf);
gl.glDeleteTransformFeedbacks(1, &DebugData.feedbackObj);
gl.glDeleteBuffers(1, &DebugData.feedbackBuffer);
gl.glDeleteQueries(1, &DebugData.feedbackQuery);
gl.glDeleteVertexArrays(1, &DebugData.meshVAO);
gl.glDeleteVertexArrays(1, &DebugData.axisVAO);
gl.glDeleteVertexArrays(1, &DebugData.frustumVAO);
@@ -1548,6 +1576,450 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overl
return m_pDriver->GetResourceManager()->GetID(TextureRes(ctx, DebugData.overlayTex));
}
void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID)
{
auto idx = std::make_pair(frameID, eventID);
if(m_PostVSData.find(idx) != m_PostVSData.end())
return;
MakeCurrentReplayContext(&m_ReplayCtx);
void *ctx = m_ReplayCtx.ctx;
WrappedOpenGL &gl = *m_pDriver;
GLResourceManager *rm = m_pDriver->GetResourceManager();
GLRenderState rs(&gl.GetHookset(), NULL, READING);
rs.FetchState(ctx, &gl);
GLuint elArrayBuffer = 0;
if(rs.VAO)
gl.glGetIntegerv(eGL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint *)&elArrayBuffer);
// reflection structures
ShaderReflection *vsRefl = NULL;
ShaderReflection *tesRefl = NULL;
ShaderReflection *gsRefl = NULL;
// non-program used separable programs of each shader.
// we'll add our feedback varings to these programs, relink,
// and combine into a pipeline for use.
GLuint vsProg = 0;
GLuint tcsProg = 0;
GLuint tesProg = 0;
GLuint gsProg = 0;
// these are the 'real' programs with uniform values that we need
// to copy over to our separable programs.
GLuint vsProgSrc = 0;
GLuint tcsProgSrc = 0;
GLuint tesProgSrc = 0;
GLuint gsProgSrc = 0;
if(rs.Program == 0)
{
if(rs.Pipeline == 0)
{
return;
}
else
{
ResourceId id = rm->GetID(ProgramPipeRes(ctx, rs.Pipeline));
auto &pipeDetails = m_pDriver->m_Pipelines[id];
if(pipeDetails.stageShaders[0] != ResourceId())
{
vsRefl = GetShader(pipeDetails.stageShaders[0]);
vsProg = m_pDriver->m_Shaders[pipeDetails.stageShaders[0]].prog;
vsProgSrc = rm->GetCurrentResource(pipeDetails.stagePrograms[0]).name;
}
if(pipeDetails.stageShaders[1] != ResourceId())
{
tcsProg = m_pDriver->m_Shaders[pipeDetails.stageShaders[1]].prog;
tcsProgSrc = rm->GetCurrentResource(pipeDetails.stagePrograms[1]).name;
}
if(pipeDetails.stageShaders[2] != ResourceId())
{
tesRefl = GetShader(pipeDetails.stageShaders[2]);
tesProg = m_pDriver->m_Shaders[pipeDetails.stageShaders[2]].prog;
tesProgSrc = rm->GetCurrentResource(pipeDetails.stagePrograms[2]).name;
}
if(pipeDetails.stageShaders[3] != ResourceId())
{
gsRefl = GetShader(pipeDetails.stageShaders[3]);
gsProg = m_pDriver->m_Shaders[pipeDetails.stageShaders[3]].prog;
gsProgSrc = rm->GetCurrentResource(pipeDetails.stagePrograms[3]).name;
}
}
}
else
{
auto &progDetails = m_pDriver->m_Programs[rm->GetID(ProgramRes(ctx, rs.Program))];
if(progDetails.stageShaders[0] != ResourceId())
{
vsRefl = GetShader(progDetails.stageShaders[0]);
vsProg = m_pDriver->m_Shaders[progDetails.stageShaders[0]].prog;
}
if(progDetails.stageShaders[1] != ResourceId())
{
tcsProg = m_pDriver->m_Shaders[progDetails.stageShaders[1]].prog;
}
if(progDetails.stageShaders[2] != ResourceId())
{
tesRefl = GetShader(progDetails.stageShaders[2]);
tesProg = m_pDriver->m_Shaders[progDetails.stageShaders[2]].prog;
}
if(progDetails.stageShaders[3] != ResourceId())
{
gsRefl = GetShader(progDetails.stageShaders[3]);
gsProg = m_pDriver->m_Shaders[progDetails.stageShaders[3]].prog;
}
vsProgSrc = tcsProgSrc = tesProgSrc = gsProgSrc = rs.Program;
}
if(vsRefl == NULL)
{
// no vertex shader bound (no vertex processing - compute only program
// or no program bound, for a clear etc)
m_PostVSData[idx] = GLPostVSData();
return;
}
const FetchDrawcall *drawcall = m_pDriver->GetDrawcall(frameID, eventID);
if(drawcall->numIndices == 0)
{
// draw is 0 length, nothing to do
m_PostVSData[idx] = GLPostVSData();
return;
}
GLenum gsOutputType = eGL_NONE;
if(gsProg)
gl.glGetProgramiv(gsProg, eGL_GEOMETRY_OUTPUT_TYPE, (GLint *)&gsOutputType);
vector<const char *> varyings;
// we don't want to do any work, so just discard before rasterizing
gl.glEnable(eGL_RASTERIZER_DISCARD);
varyings.clear();
uint32_t stride = 0;
uint32_t posoffset = ~0U;
for(int32_t i=0; i < vsRefl->OutputSig.count; i++)
{
varyings.push_back(vsRefl->OutputSig[i].varName.elems);
if(!strcmp(vsRefl->OutputSig[i].varName.elems, "gl_Position"))
posoffset = stride;
stride += sizeof(float)*vsRefl->OutputSig[i].compCount;
}
gl.glTransformFeedbackVaryings(vsProg, (GLsizei)varyings.size(), &varyings[0], eGL_INTERLEAVED_ATTRIBS);
// relink separable program with varyings
gl.glLinkProgram(vsProg);
GLint status = 0;
gl.glGetProgramiv(vsProg, eGL_LINK_STATUS, &status);
if(status == 0)
{
char buffer[1025] = {0};
gl.glGetProgramInfoLog(vsProg, 1024, NULL, buffer);
RDCERR("Link error making xfb vs program: %s", buffer);
m_PostVSData[idx] = GLPostVSData();
return;
}
// make a pipeline to contain just the vertex shader
GLuint vsFeedbackPipe = 0;
gl.glGenProgramPipelines(1, &vsFeedbackPipe);
// bind the separable vertex program to it
gl.glUseProgramStages(vsFeedbackPipe, eGL_VERTEX_SHADER_BIT, vsProg);
// copy across any uniform values, bindings etc from the real program containing
// the vertex stage
CopyProgramUniforms(gl.GetHookset(), vsProgSrc, vsProg);
// bind our program and do the feedback draw
gl.glUseProgram(0);
gl.glBindProgramPipeline(vsFeedbackPipe);
gl.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, DebugData.feedbackObj);
// need to rebind this here because of an AMD bug that seems to ignore the buffer
// bindings in the feedback object - or at least it errors if the default feedback
// object has no buffers bound. Fortunately the state is still object-local so
// we don't have to restore the buffer binding on the default feedback object.
gl.glBindBufferBase(eGL_TRANSFORM_FEEDBACK_BUFFER, 0, DebugData.feedbackBuffer);
GLuint idxBuf = 0;
gl.glBeginQuery(eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, DebugData.feedbackQuery);
gl.glBeginTransformFeedback(eGL_POINTS);
if((drawcall->flags & eDraw_UseIBuffer) == 0)
{
gl.glDrawArrays(eGL_POINTS, drawcall->vertexOffset, drawcall->numIndices);
}
else // drawcall is indexed
{
ResourceId idxId = rm->GetID(BufferRes(NULL, elArrayBuffer));
vector<byte> idxdata = GetBufferData(idxId, drawcall->indexOffset*drawcall->indexByteWidth, drawcall->numIndices*drawcall->indexByteWidth);
vector<uint32_t> indices;
uint8_t *idx8 = (uint8_t *) &idxdata[0];
uint16_t *idx16 = (uint16_t *)&idxdata[0];
uint32_t *idx32 = (uint32_t *)&idxdata[0];
// only read as many indices as were available in the buffer
uint32_t numIndices = RDCMIN(uint32_t(idxdata.size()/drawcall->indexByteWidth), drawcall->numIndices);
// grab all unique vertex indices referenced
for(uint32_t i=0; i < numIndices; i++)
{
uint32_t i32 = 0;
if(drawcall->indexByteWidth == 1) i32 = uint32_t(idx8 [i]);
else if(drawcall->indexByteWidth == 2) i32 = uint32_t(idx16[i]);
else if(drawcall->indexByteWidth == 4) i32 = idx32[i];
auto it = std::lower_bound(indices.begin(), indices.end(), i32);
if(it != indices.end() && *it == i32)
continue;
indices.insert(it, i32);
}
// An index buffer could be something like: 500, 501, 502, 501, 503, 502
// in which case we can't use the existing index buffer without filling 499 slots of vertex
// data with padding. Instead we rebase the indices based on the smallest vertex so it becomes
// 0, 1, 2, 1, 3, 2 and then that matches our stream-out'd buffer.
//
// Since we want the indices to be preserved in order to easily match up inputs to outputs,
// but shifted, fill in gaps in our streamout vertex buffer with the lowest index value.
// (use the lowest index value so that even the gaps are a 'valid' vertex, rather than
// potentially garbage data).
uint32_t minindex = indices.empty() ? 0 : indices[0];
// indices[] contains ascending unique vertex indices referenced. Fill gaps with minindex
for(size_t i=1; i < indices.size(); i++)
{
if(indices[i]-1 > indices[i-1])
{
size_t gapsize = size_t( (indices[i]-1) - indices[i-1] );
indices.insert(indices.begin()+i, gapsize, minindex);
i += gapsize;
}
}
// generate a temporary index buffer with our 'unique index set' indices,
// so we can transform feedback each referenced vertex once
GLuint indexSetBuffer = 0;
gl.glGenBuffers(1, &indexSetBuffer);
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, indexSetBuffer);
gl.glNamedBufferStorageEXT(indexSetBuffer, sizeof(uint32_t)*indices.size(), &indices[0], 0);
gl.glDrawElementsBaseVertex(eGL_POINTS, (GLsizei)indices.size(), eGL_UNSIGNED_INT, NULL, drawcall->vertexOffset);
// delete the buffer, we don't need it anymore
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, elArrayBuffer);
gl.glDeleteBuffers(1, &indexSetBuffer);
// rebase existing index buffer to point from 0 onwards (which will index into our
// stream-out'd vertex buffer)
if(drawcall->indexByteWidth == 1)
{
for(uint32_t i=0; i < numIndices; i++)
idx8[i] -= uint8_t(minindex&0xff);
}
else if(drawcall->indexByteWidth == 2)
{
for(uint32_t i=0; i < numIndices; i++)
idx16[i] -= uint16_t(minindex&0xffff);
}
else
{
for(uint32_t i=0; i < numIndices; i++)
idx32[i] -= minindex;
}
// make the index buffer that can be used to render this postvs data - the original
// indices, rebased with minindex being 0 (since we transform feedback to the start
// of our feedback buffer).
gl.glGenBuffers(1, &idxBuf);
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, idxBuf);
gl.glNamedBufferStorageEXT(idxBuf, (GLsizeiptr)idxdata.size(), &idxdata[0], 0);
// restore previous element array buffer binding
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, elArrayBuffer);
}
gl.glEndTransformFeedback();
gl.glEndQuery(eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
// this should be the same as the draw size
GLuint primsWritten = 0;
gl.glGetQueryObjectuiv(DebugData.feedbackQuery, eGL_QUERY_RESULT, &primsWritten);
// get buffer data from buffer attached to feedback object
float *data = (float *)gl.glMapNamedBufferEXT(DebugData.feedbackBuffer, eGL_READ_ONLY);
// create a buffer with this data, for future use (typed to ARRAY_BUFFER so we
// can render from it to display previews).
GLuint vsoutBuffer = 0;
gl.glGenBuffers(1, &vsoutBuffer);
gl.glBindBuffer(eGL_ARRAY_BUFFER, vsoutBuffer);
gl.glNamedBufferStorageEXT(vsoutBuffer, stride*primsWritten, data, 0);
byte *byteData = (byte *)data;
float nearp = 0.0f;
float farp = 0.0f;
Vec4f *pos0 = (Vec4f *)(byteData + posoffset);
for(GLuint i=1; posoffset != ~0U && i < primsWritten; i++)
{
//////////////////////////////////////////////////////////////////////////////////
// derive near/far, assuming a standard perspective matrix
//
// the transformation from from pre-projection {Z,W} to post-projection {Z,W}
// is linear. So we can say Zpost = Zpre*m + c . Here we assume Wpre = 1
// and we know Wpost = Zpre from the perspective matrix.
// we can then see from the perspective matrix that
// m = F/(F-N)
// c = -(F*N)/(F-N)
//
// with re-arranging and substitution, we then get:
// N = -c/m
// F = c/(1-m)
//
// so if we can derive m and c then we can determine N and F. We can do this with
// two points, and we pick them reasonably distinct on z to reduce floating-point
// error
Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride);
if(fabs(pos->w - pos0->w) > 0.01f)
{
Vec2f A(pos0->w, pos0->z);
Vec2f B(pos->w, pos->z);
float m = (B.y-A.y)/(B.x-A.x);
float c = B.y - B.x*m;
if(m == 1.0f) continue;
nearp = -c/m;
farp = c/(1-m);
break;
}
}
gl.glUnmapNamedBufferEXT(DebugData.feedbackBuffer);
// store everything out to the PostVS data cache
m_PostVSData[idx].vsin.topo = drawcall->topology;
m_PostVSData[idx].vsout.buf = vsoutBuffer;
m_PostVSData[idx].vsout.posOffset = posoffset;
m_PostVSData[idx].vsout.vertStride = stride;
m_PostVSData[idx].vsout.nearPlane = nearp;
m_PostVSData[idx].vsout.farPlane = farp;
m_PostVSData[idx].vsout.useIndices = (drawcall->flags & eDraw_UseIBuffer) > 0;
m_PostVSData[idx].vsout.numVerts = drawcall->numIndices;
m_PostVSData[idx].vsout.idxBuf = 0;
m_PostVSData[idx].vsout.idxByteWidth = drawcall->indexByteWidth;
if(m_PostVSData[idx].vsout.useIndices && idxBuf)
{
m_PostVSData[idx].vsout.idxBuf = idxBuf;
}
m_PostVSData[idx].vsout.topo = drawcall->topology;
// set vsProg back to no varyings, for future use
gl.glTransformFeedbackVaryings(vsProg, 0, NULL, eGL_INTERLEAVED_ATTRIBS);
gl.glLinkProgram(vsProg);
GLuint lastFeedbackPipe = 0;
// delete temporary pipelines we made
gl.glDeleteProgramPipelines(1, &vsFeedbackPipe);
if(lastFeedbackPipe) gl.glDeleteProgramPipelines(1, &lastFeedbackPipe);
// restore replay state we trashed
gl.glUseProgram(rs.Program);
gl.glBindProgramPipeline(rs.Pipeline);
gl.glBindBuffer(eGL_ARRAY_BUFFER, rs.BufferBindings[GLRenderState::eBufIdx_Array]);
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, elArrayBuffer);
gl.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, rs.FeedbackObj);
if(!rs.Enabled[GLRenderState::eEnabled_RasterizerDiscard])
gl.glDisable(eGL_RASTERIZER_DISCARD);
else
gl.glEnable(eGL_RASTERIZER_DISCARD);
}
MeshFormat GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage)
{
GLPostVSData postvs;
RDCEraseEl(postvs);
auto idx = std::make_pair(frameID, eventID);
if(m_PostVSData.find(idx) != m_PostVSData.end())
postvs = m_PostVSData[idx];
GLPostVSData::StageData s = postvs.GetStage(stage);
MeshFormat ret;
if(s.useIndices && s.idxBuf)
ret.idxbuf = m_pDriver->GetResourceManager()->GetID(BufferRes(NULL, s.idxBuf));
else
ret.idxbuf = ResourceId();
ret.idxoffs = 0;
ret.idxByteWidth = s.idxByteWidth;
if(s.buf)
ret.buf = m_pDriver->GetResourceManager()->GetID(BufferRes(NULL, s.buf));
else
ret.buf = ResourceId();
ret.offset = s.posOffset;
ret.stride = s.vertStride;
ret.compCount = 4;
ret.compByteWidth = 4;
ret.compType = eCompType_Float;
ret.specialFormat = eSpecial_Unknown;
ret.showAlpha = false;
ret.topo = s.topo;
ret.numVerts = s.numVerts;
ret.unproject = true;
ret.nearPlane = s.nearPlane;
ret.farPlane = s.farPlane;
return ret;
}
FloatVector GLReplay::InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool &valid)
{
FloatVector ret(0.0f, 0.0f, 0.0f, 1.0f);
@@ -1666,6 +2138,92 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
gl.glBindVertexArray(DebugData.meshVAO);
const MeshFormat *fmts[2] = { &cfg.position, &cfg.second };
GLenum topo = MakeGLPrimitiveTopology(cfg.position.topo);
GLuint prog = DebugData.meshProg;
if(cfg.solidShadeMode == eShade_Lit)
{
// pick program with GS for per-face lighting
prog = DebugData.meshgsProg;
}
GLint colLoc = gl.glGetUniformLocation(prog, "RENDERDOC_GenericFS_Color");
GLint mvpLoc = gl.glGetUniformLocation(prog, "ModelViewProj");
GLint fmtLoc = gl.glGetUniformLocation(prog, "Mesh_DisplayFormat");
GLint sizeLoc = gl.glGetUniformLocation(prog, "PointSpriteSize");
GLint homogLoc = gl.glGetUniformLocation(prog, "HomogenousInput");
gl.glUseProgram(prog);
gl.glEnable(eGL_FRAMEBUFFER_SRGB);
if(cfg.position.unproject)
{
// the derivation of the projection matrix might not be right (hell, it could be an
// orthographic projection). But it'll be close enough likely.
Matrix4f guessProj = Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect);
if(cfg.ortho)
{
guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane);
}
guessProjInv = guessProj.Inverse();
ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
}
gl.glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, ModelViewProj.Data());
gl.glUniform1ui(homogLoc, cfg.position.unproject);
gl.glUniform2f(sizeLoc, 0.0f, 0.0f);
if(!secondaryDraws.empty())
{
gl.glUniform4fv(colLoc, 1, &cfg.prevMeshColour.x);
gl.glUniform1ui(fmtLoc, MESHDISPLAY_SOLID);
gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_LINE);
// secondary draws have to come from gl_Position which is float4
gl.glVertexAttribFormat(0, 4, eGL_FLOAT, GL_FALSE, 0);
gl.glEnableVertexAttribArray(0);
gl.glDisableVertexAttribArray(1);
for(size_t i=0; i < secondaryDraws.size(); i++)
{
const MeshFormat &fmt = secondaryDraws[i];
if(fmt.buf != ResourceId())
{
GLuint vb = m_pDriver->GetResourceManager()->GetCurrentResource(fmt.buf).name;
gl.glBindVertexBuffer(0, vb, fmt.offset, fmt.stride);
GLenum topo = MakeGLPrimitiveTopology(fmt.topo);
if(fmt.idxbuf != ResourceId())
{
GLuint ib = m_pDriver->GetResourceManager()->GetCurrentResource(fmt.idxbuf).name;
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib);
GLenum idxtype = eGL_UNSIGNED_BYTE;
if(fmt.idxByteWidth == 2)
idxtype = eGL_UNSIGNED_SHORT;
else if(fmt.idxByteWidth == 4)
idxtype = eGL_UNSIGNED_INT;
gl.glDrawElements(topo, fmt.numVerts, idxtype, (const void *)(fmt.idxoffs));
}
else
{
gl.glDrawArrays(topo, 0, fmt.numVerts);
}
}
}
}
for(uint32_t i=0; i < 2; i++)
{
@@ -1743,52 +2301,13 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
gl.glVertexAttribLFormat(i, fmts[i]->compCount, eGL_DOUBLE, 0);
}
gl.glBindVertexBuffer(i, m_pDriver->GetResourceManager()->GetCurrentResource(fmts[i]->buf).name, fmts[i]->offset, fmts[i]->stride);
GLuint vb = m_pDriver->GetResourceManager()->GetCurrentResource(fmts[i]->buf).name;
gl.glBindVertexBuffer(i, vb, fmts[i]->offset, fmts[i]->stride);
}
// enable position attribute
gl.glEnableVertexAttribArray(0);
GLenum topo = MakeGLPrimitiveTopology(cfg.position.topo);
GLuint prog = DebugData.meshProg;
if(cfg.solidShadeMode == eShade_Lit)
{
// pick program with GS for per-face lighting
prog = DebugData.meshgsProg;
}
GLint colLoc = gl.glGetUniformLocation(prog, "RENDERDOC_GenericFS_Color");
GLint mvpLoc = gl.glGetUniformLocation(prog, "ModelViewProj");
GLint fmtLoc = gl.glGetUniformLocation(prog, "Mesh_DisplayFormat");
GLint sizeLoc = gl.glGetUniformLocation(prog, "PointSpriteSize");
GLint homogLoc = gl.glGetUniformLocation(prog, "HomogenousInput");
gl.glUseProgram(prog);
gl.glEnable(eGL_FRAMEBUFFER_SRGB);
if(cfg.position.unproject)
{
// the derivation of the projection matrix might not be right (hell, it could be an
// orthographic projection). But it'll be close enough likely.
Matrix4f guessProj = Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect);
if(cfg.ortho)
{
guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane);
}
guessProjInv = guessProj.Inverse();
ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
}
gl.glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, ModelViewProj.Data());
gl.glUniform1i(homogLoc, 0);
gl.glUniform2f(sizeLoc, 0.0f, 0.0f);
gl.glDisableVertexAttribArray(1);
// solid render
if(cfg.solidShadeMode != eShade_None && topo != eGL_PATCHES)
@@ -1805,7 +2324,8 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
gl.glUniformMatrix4fv(invProjLoc, 1, GL_FALSE, InvProj.Data());
}
gl.glEnableVertexAttribArray(1);
if(cfg.second.buf != ResourceId())
gl.glEnableVertexAttribArray(1);
float wireCol[] = { 0.8f, 0.8f, 0.0f, 1.0f };
gl.glUniform4fv(colLoc, 1, wireCol);
@@ -1825,7 +2345,8 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
else if(cfg.position.idxByteWidth == 4)
idxtype = eGL_UNSIGNED_INT;
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name);
GLuint ib = m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name;
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib);
gl.glDrawElements(topo, cfg.position.numVerts, idxtype, (const void *)(cfg.position.idxoffs));
}
else
@@ -1833,7 +2354,7 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
gl.glDrawArrays(topo, 0, cfg.position.numVerts);
}
gl.glEnableVertexAttribArray(0);
gl.glDisableVertexAttribArray(1);
if(cfg.solidShadeMode == eShade_Lit)
{
@@ -1846,7 +2367,7 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
gl.glUseProgram(prog);
gl.glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, ModelViewProj.Data());
gl.glUniform1i(homogLoc, 0);
gl.glUniform1ui(homogLoc, cfg.position.unproject);
gl.glUniform2f(sizeLoc, 0.0f, 0.0f);
}
}
@@ -1857,6 +2378,12 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
if(cfg.solidShadeMode == eShade_None || cfg.wireframeDraw || topo == eGL_PATCHES)
{
float wireCol[] = { 0.0f, 0.0f, 0.0f, 1.0f };
if(!secondaryDraws.empty())
{
wireCol[0] = cfg.currentMeshColour.x;
wireCol[1] = cfg.currentMeshColour.y;
wireCol[2] = cfg.currentMeshColour.z;
}
gl.glUniform4fv(colLoc, 1, wireCol);
gl.glUniform1ui(fmtLoc, MESHDISPLAY_SOLID);
@@ -1871,7 +2398,8 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
else if(cfg.position.idxByteWidth == 4)
idxtype = eGL_UNSIGNED_INT;
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name);
GLuint ib = m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name;
gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib);
gl.glDrawElements(topo != eGL_PATCHES ? topo : eGL_POINTS, cfg.position.numVerts, idxtype, (const void *)(cfg.position.idxoffs));
}
else
@@ -1906,7 +2434,6 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
float wireCol[] = { 1.0f, 1.0f, 1.0f, 1.0f };
gl.glUniform4fv(colLoc, 1, wireCol);
ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
gl.glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, ModelViewProj.Data());
gl.glDrawArrays(eGL_LINES, 0, 24);
@@ -2280,15 +2807,11 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
// if data is from post transform, it will be in clipspace
if(cfg.position.unproject)
{
ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
gl.glUniform1i(homogLoc, 1);
}
else
{
ModelViewProj = projMat.Mul(camMat);
gl.glUniform1i(homogLoc, 0);
}
gl.glUniform1ui(homogLoc, cfg.position.unproject);
gl.glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, ModelViewProj.Data());
@@ -2318,7 +2841,7 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshF
gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer);
gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(Vec4f)*adjacentPrimVertices.size(), &adjacentPrimVertices[0]);
gl.glDrawArrays(primTopo, 0, adjacentPrimVertices.size());
gl.glDrawArrays(primTopo, 0, (GLsizei)adjacentPrimVertices.size());
}
////////////////////////////////////////////////////////////////
+48 -2
View File
@@ -1880,10 +1880,10 @@ void WrappedOpenGL::DebugSnoop(GLenum source, GLenum type, GLuint id, GLenum sev
{
if(type != eGL_DEBUG_TYPE_PERFORMANCE && type != eGL_DEBUG_TYPE_OTHER)
{
if(m_DebugMsgContext != "")
RDCLOG("Debug Message context: \"%s\"", m_DebugMsgContext.c_str());
RDCLOG("Got a Debug message from %s, type %s, ID %d, severity %s:\n'%s'",
ToStr::Get(source).c_str(), ToStr::Get(type).c_str(), id, ToStr::Get(severity).c_str(), message);
if(m_DebugMsgContext != "")
RDCLOG("Debug Message context: \"%s\"", m_DebugMsgContext.c_str());
}
if(m_State == WRITING_CAPFRAME &&
@@ -3123,6 +3123,52 @@ FetchAPIEvent WrappedOpenGL::GetEvent(uint32_t eventID)
return m_Events[0];
}
const FetchDrawcall *WrappedOpenGL::GetDrawcall(const FetchDrawcall *draw, uint32_t eventID)
{
if(draw == NULL) return NULL;
if(draw->eventID == eventID) return draw;
int32_t count = draw->children.count;
for(int32_t i=0; i < count; i++)
{
const FetchDrawcall *cur = &draw->children.elems[i];
const FetchDrawcall *next = i+1 < count ? &draw->children.elems[i+1] : NULL;
if(next && next->eventID <= eventID)
continue;
cur = GetDrawcall(cur, eventID);
if(cur)
return cur;
}
return NULL;
}
const FetchDrawcall *WrappedOpenGL::GetDrawcall(uint32_t frameID, uint32_t eventID)
{
if(frameID >= m_FrameRecord.size())
return NULL;
int32_t count = m_FrameRecord[frameID].drawcallList.count;
for(int32_t i=0; i < count; i++)
{
const FetchDrawcall *cur = &m_FrameRecord[frameID].drawcallList.elems[i];
const FetchDrawcall *next = i+1 < count ? &m_FrameRecord[frameID].drawcallList.elems[i+1] : NULL;
if(next && next->eventID <= eventID)
continue;
cur = GetDrawcall(cur, eventID);
if(cur)
return cur;
}
return NULL;
}
void WrappedOpenGL::ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType)
{
RDCASSERT(frameID < (uint32_t)m_FrameRecord.size());
+4
View File
@@ -150,6 +150,8 @@ class WrappedOpenGL
vector<FetchFrameRecord> m_FrameRecord;
const FetchDrawcall *GetDrawcall(const FetchDrawcall *draw, uint32_t eventID);
static const char *GetChunkName(uint32_t idx);
// replay
@@ -371,6 +373,8 @@ class WrappedOpenGL
vector<FetchFrameRecord> &GetFrameRecord() { return m_FrameRecord; }
FetchAPIEvent GetEvent(uint32_t eventID);
const FetchDrawcall *GetDrawcall(uint32_t frameID, uint32_t eventID);
void CreateContext(GLWindowingData winData, void *shareContext, GLInitParams initParams, bool core);
void DeleteContext(void *contextHandle);
void ActivateContext(GLWindowingData winData);
+5 -17
View File
@@ -336,13 +336,16 @@ vector<byte> GLReplay::GetBufferData(ResourceId buff, uint32_t offset, uint32_t
ret.resize(len);
WrappedOpenGL &gl = *m_pDriver;
MakeCurrentReplayContext(m_DebugCtx);
GLuint oldbuf = 0;
gl.glGetIntegerv(eGL_COPY_READ_BUFFER_BINDING, (GLint *)&oldbuf);
gl.glBindBuffer(eGL_COPY_READ_BUFFER, buf.resource.name);
gl.glGetBufferSubData(eGL_COPY_READ_BUFFER, (GLintptr)offset, (GLsizeiptr)len, &ret[0]);
gl.glBindBuffer(eGL_COPY_READ_BUFFER, oldbuf);
return ret;
}
@@ -2159,11 +2162,6 @@ void GLReplay::FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector
#pragma endregion
void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID)
{
GLNOTIMP("GLReplay::InitPostVSBuffers");
}
vector<EventUsage> GLReplay::GetUsage(ResourceId id)
{
GLNOTIMP("GetUsage");
@@ -2185,16 +2183,6 @@ void GLReplay::FreeCustomShader(ResourceId id)
RDCUNIMPLEMENTED("FreeCustomShader");
}
MeshFormat GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage)
{
MeshFormat ret;
RDCEraseEl(ret);
GLNOTIMP("GLReplay::GetPostVSBuffers");
return ret;
}
byte *GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize)
{
RDCUNIMPLEMENTED("GetTextureData");
+46
View File
@@ -32,6 +32,45 @@
class WrappedOpenGL;
struct GLPostVSData
{
struct StageData
{
GLuint buf;
PrimitiveTopology topo;
uint32_t numVerts;
uint32_t posOffset;
uint32_t vertStride;
bool useIndices;
GLuint idxBuf;
uint32_t idxByteWidth;
float nearPlane;
float farPlane;
} vsin, vsout, gsout;
GLPostVSData()
{
RDCEraseEl(vsin);
RDCEraseEl(vsout);
RDCEraseEl(gsout);
}
const StageData &GetStage(MeshDataStage type)
{
if(type == eMeshDataStage_VSOut)
return vsout;
else if(type == eMeshDataStage_GSOut)
return gsout;
else
RDCERR("Unexpected mesh data stage!");
return vsin;
}
};
class GLReplay : public IReplayDriver
{
public:
@@ -216,6 +255,10 @@ class GLReplay : public IReplayDriver
GLuint outlineStripVB;
GLuint outlineStripVAO;
GLuint feedbackObj;
GLuint feedbackQuery;
GLuint feedbackBuffer;
GLuint pickPixelTex;
GLuint pickPixelFBO;
@@ -243,6 +286,9 @@ class GLReplay : public IReplayDriver
vector<byte> data;
vector<uint32_t> indices;
} m_HighlightCache;
// <frame,event> -> data
std::map<std::pair<uint32_t,uint32_t>, GLPostVSData> m_PostVSData;
void InitDebugData();
void DeleteDebugData();
+9 -5
View File
@@ -162,15 +162,16 @@ void CheckVertexOutputUses(vector<string> sources, bool &pointSizeUsed, bool &cl
// little utility function that if necessary emulates glCreateShaderProgramv functionality but using glCompileShaderIncludeARB
static GLuint CreateSepProgram(const GLHookSet &gl, GLenum type, GLsizei numSources, const char **sources, GLsizei numPaths, const char **paths)
{
if(paths == NULL)
return gl.glCreateShaderProgramv(type, numSources, sources);
// definition of glCreateShaderProgramv from the spec
GLuint shader = gl.glCreateShader(type);
if(shader)
{
gl.glShaderSource(shader, numSources, sources, NULL);
gl.glCompileShaderIncludeARB(shader, numPaths, paths, NULL);
if(paths == NULL)
gl.glCompileShader(shader);
else
gl.glCompileShaderIncludeARB(shader, numPaths, paths, NULL);
GLuint program = gl.glCreateProgram();
if(program)
@@ -184,7 +185,10 @@ static GLuint CreateSepProgram(const GLHookSet &gl, GLenum type, GLsizei numSour
{
gl.glAttachShader(program, shader);
gl.glLinkProgram(program);
gl.glDetachShader(program, shader);
// we deliberately leave the shaders attached so this program can be re-linked.
// they will be cleaned up when the program is deleted
// gl.glDetachShader(program, shader);
}
}
gl.glDeleteShader(shader);
@@ -77,6 +77,8 @@ void WrappedOpenGL::glGenBuffers(GLsizei n, GLuint *buffers)
else
{
GetResourceManager()->AddLiveResource(id, res);
m_Buffers[id].resource = res;
m_Buffers[id].curType = eGL_NONE;
}
}
}
@@ -241,6 +243,10 @@ void WrappedOpenGL::glBindBuffer(GLenum target, GLuint buffer)
GetResourceManager()->MarkDirtyResource(r->GetResourceID());
}
}
else
{
m_Buffers[GetResourceManager()->GetID(BufferRes(GetCtx(), buffer))].curType = target;
}
}
bool WrappedOpenGL::Serialise_glNamedBufferStorageEXT(GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags)
@@ -310,6 +316,10 @@ void WrappedOpenGL::glNamedBufferStorageEXT(GLuint buffer, GLsizeiptr size, cons
record->Length = (int32_t)size;
}
}
else
{
m_Buffers[GetResourceManager()->GetID(BufferRes(GetCtx(), buffer))].size = size;
}
}
void WrappedOpenGL::glBufferStorage(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags)
@@ -343,6 +353,10 @@ void WrappedOpenGL::glBufferStorage(GLenum target, GLsizeiptr size, const void *
record->Length = (int32_t)size;
}
}
else
{
RDCERR("Internal buffers should be allocated via dsa interfaces");
}
}
bool WrappedOpenGL::Serialise_glNamedBufferDataEXT(GLuint buffer, GLsizeiptr size, const void *data, GLenum usage)
@@ -478,6 +492,10 @@ void WrappedOpenGL::glNamedBufferDataEXT(GLuint buffer, GLsizeiptr size, const v
record->usage = usage;
}
}
else
{
m_Buffers[GetResourceManager()->GetID(BufferRes(GetCtx(), buffer))].size = size;
}
}
void WrappedOpenGL::glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
@@ -578,6 +596,10 @@ void WrappedOpenGL::glBufferData(GLenum target, GLsizeiptr size, const void *dat
record->usage = usage;
}
}
else
{
RDCERR("Internal buffers should be allocated via dsa interfaces");
}
}
bool WrappedOpenGL::Serialise_glNamedBufferSubDataEXT(GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data)