From ad2b26b238973cb606aec46d40114cf02a71da77 Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 2 Nov 2014 20:59:36 +0000 Subject: [PATCH] Implement texture histogram for OpenGL --- renderdoc/data/glsl/histogram.comp | 163 +++++++++++++++++++++++++++++ renderdoc/driver/gl/gl_debug.cpp | 113 ++++++++++++++++++++ renderdoc/driver/gl/gl_replay.h | 2 + 3 files changed, 278 insertions(+) diff --git a/renderdoc/data/glsl/histogram.comp b/renderdoc/data/glsl/histogram.comp index 97a4113f9..98d0c6126 100644 --- a/renderdoc/data/glsl/histogram.comp +++ b/renderdoc/data/glsl/histogram.comp @@ -241,3 +241,166 @@ void main() } #endif // #if RENDERDOC_ResultMinMaxCS + +#if RENDERDOC_HistogramCS + +layout(binding=0) writeonly buffer minmaxresultdest +{ + uint result[HGRAM_NUM_BUCKETS]; +} dest; + +layout (local_size_x = HGRAM_TILES_PER_BLOCK, local_size_y = HGRAM_TILES_PER_BLOCK) in; + +void main() +{ + uvec3 tid = gl_LocalInvocationID; + uvec3 gid = gl_WorkGroupID; + + int texType = SHADER_RESTYPE; + + uvec3 texDim = uvec3(HistogramTextureResolution); + + uint blocksX = uint(ceil(float(texDim.x)/float(HGRAM_PIXELS_PER_TILE*HGRAM_TILES_PER_BLOCK))); + + uvec2 topleft = (gid.xy*HGRAM_TILES_PER_BLOCK + tid.xy)*HGRAM_PIXELS_PER_TILE; + + int i=0; + + for(uint y=topleft.y; y < min(texDim.y, topleft.y + HGRAM_PIXELS_PER_TILE); y++) + { + for(uint x=topleft.x; x < min(texDim.x, topleft.x + HGRAM_PIXELS_PER_TILE); x++) + { + uint bucketIdx = HGRAM_NUM_BUCKETS+1; + +#if UINT_TEX + { + uvec4 data = SampleTextureUInt4(vec2(x, y), texType, false, + HistogramMip, HistogramSlice); + // HistogramSample, texDim + + float divisor = 0.0f; + uint sum = 0; + if((HistogramChannels & 0x1) > 0) + { + sum += data.x; + divisor += 1.0f; + } + if((HistogramChannels & 0x2) > 0) + { + sum += data.y; + divisor += 1.0f; + } + if((HistogramChannels & 0x4) > 0) + { + sum += data.z; + divisor += 1.0f; + } + if((HistogramChannels & 0x8) > 0) + { + sum += data.w; + divisor += 1.0f; + } + + if(divisor > 0.0f) + { + float val = float(sum)/divisor; + + float normalisedVal = (val - HistogramMin)/(HistogramMax - HistogramMin); + + if(normalisedVal < 0.0f) + normalisedVal = 2.0f; + + bucketIdx = uint(floor(normalisedVal*HGRAM_NUM_BUCKETS)); + } + } +#elif SINT_TEX + { + ivec4 data = SampleTextureSInt4(vec2(x, y), texType, false, + HistogramMip, HistogramSlice); + // HistogramSample, texDim + + float divisor = 0.0f; + int sum = 0; + if((HistogramChannels & 0x1) > 0) + { + sum += data.x; + divisor += 1.0f; + } + if((HistogramChannels & 0x2) > 0) + { + sum += data.y; + divisor += 1.0f; + } + if((HistogramChannels & 0x4) > 0) + { + sum += data.z; + divisor += 1.0f; + } + if((HistogramChannels & 0x8) > 0) + { + sum += data.w; + divisor += 1.0f; + } + + if(divisor > 0.0f) + { + float val = float(sum)/divisor; + + float normalisedVal = (val - HistogramMin)/(HistogramMax - HistogramMin); + + if(normalisedVal < 0.0f) + normalisedVal = 2.0f; + + bucketIdx = uint(floor(normalisedVal*HGRAM_NUM_BUCKETS)); + } + } +#else + { + vec4 data = SampleTextureFloat4(vec2(x, y), texType, false, false, + HistogramMip, HistogramSlice); + // HistogramSample, texDim + + float divisor = 0.0f; + float sum = 0.0f; + if((HistogramChannels & 0x1) > 0) + { + sum += data.x; + divisor += 1.0f; + } + if((HistogramChannels & 0x2) > 0) + { + sum += data.y; + divisor += 1.0f; + } + if((HistogramChannels & 0x4) > 0) + { + sum += data.z; + divisor += 1.0f; + } + if((HistogramChannels & 0x8) > 0) + { + sum += data.w; + divisor += 1.0f; + } + + if(divisor > 0.0f) + { + float val = sum/divisor; + + float normalisedVal = (val - HistogramMin)/(HistogramMax - HistogramMin); + + if(normalisedVal < 0.0f) + normalisedVal = 2.0f; + + bucketIdx = uint(floor(normalisedVal*HGRAM_NUM_BUCKETS)); + } + } +#endif + + if(bucketIdx >= 0 && bucketIdx < HGRAM_NUM_BUCKETS) + atomicAdd(dest.result[bucketIdx], 1U); + } + } +} + +#endif //#if RENDERDOC_HistogramCS diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 908ea74dd..f1364fe0e 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -254,6 +254,17 @@ void GLReplay::InitDebugData() DebugData.minmaxTileProgram[idx] = CreateCShaderProgram(glsl.c_str()); } + { + string glsl = glslheader; + glsl += string("#define SHADER_RESTYPE ") + ToStr::Get(t) + "\n"; + glsl += string("#define UINT_TEX ") + (i == 1 ? "1" : "0") + "\n"; + glsl += string("#define SINT_TEX ") + (i == 2 ? "1" : "0") + "\n"; + glsl += string("#define RENDERDOC_HistogramCS 1\n"); + glsl += histogramglsl; + + DebugData.histogramProgram[idx] = CreateCShaderProgram(glsl.c_str()); + } + if(t == 1) { string glsl = glslheader; @@ -270,6 +281,7 @@ void GLReplay::InitDebugData() gl.glGenBuffers(1, &DebugData.minmaxTileResult); gl.glGenBuffers(1, &DebugData.minmaxResult); + gl.glGenBuffers(1, &DebugData.histogramBuf); const uint32_t maxTexDim = 16384; const uint32_t blockPixSize = HGRAM_PIXELS_PER_TILE*HGRAM_TILES_PER_BLOCK; @@ -279,6 +291,7 @@ void GLReplay::InitDebugData() gl.glNamedBufferStorageEXT(DebugData.minmaxTileResult, byteSize, NULL, 0); gl.glNamedBufferStorageEXT(DebugData.minmaxResult, sizeof(Vec4f)*2, NULL, GL_MAP_READ_BIT); + gl.glNamedBufferStorageEXT(DebugData.histogramBuf, sizeof(uint32_t)*HGRAM_NUM_BUCKETS, NULL, GL_MAP_READ_BIT); } MakeCurrentReplayContext(&m_ReplayCtx); @@ -400,6 +413,106 @@ bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uin bool GLReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool channels[4], vector &histogram) { + if(minval >= maxval) return false; + + if(m_pDriver->m_Textures.find(texid) == m_pDriver->m_Textures.end()) + return false; + + auto &texDetails = m_pDriver->m_Textures[texid]; + + FetchTexture details = GetTexture(texid); + + const GLHookSet &gl = m_pDriver->GetHookset(); + + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); + HistogramCBufferData *cdata = (HistogramCBufferData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(HistogramCBufferData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + + cdata->HistogramTextureResolution.x = (float)RDCMAX(details.width>>mip, 1U); + cdata->HistogramTextureResolution.y = (float)RDCMAX(details.height>>mip, 1U); + cdata->HistogramTextureResolution.z = (float)RDCMAX(details.depth>>mip, 1U); + cdata->HistogramSlice = (float)sliceFace; + cdata->HistogramMip = mip; + cdata->HistogramSample = (int)RDCCLAMP(sample, 0U, details.msSamp-1); + if(sample == ~0U) cdata->HistogramSample = -int(details.msSamp); + cdata->HistogramMin = minval; + cdata->HistogramMax = maxval; + cdata->HistogramChannels = 0; + if(channels[0]) cdata->HistogramChannels |= 0x1; + if(channels[1]) cdata->HistogramChannels |= 0x2; + if(channels[2]) cdata->HistogramChannels |= 0x4; + if(channels[3]) cdata->HistogramChannels |= 0x8; + cdata->HistogramFlags = 0; + + int texSlot = 0; + int intIdx = 0; + + switch (texDetails.curType) + { + case eGL_TEXTURE_1D: + texSlot = RESTYPE_TEX1D; + break; + default: + RDCWARN("Unexpected texture type"); + case eGL_TEXTURE_2D: + texSlot = RESTYPE_TEX2D; + break; + case eGL_TEXTURE_3D: + texSlot = RESTYPE_TEX3D; + break; + case eGL_TEXTURE_CUBE_MAP: + texSlot = RESTYPE_TEXCUBE; + break; + case eGL_TEXTURE_1D_ARRAY: + texSlot = RESTYPE_TEX1DARRAY; + break; + case eGL_TEXTURE_2D_ARRAY: + texSlot = RESTYPE_TEX2DARRAY; + break; + case eGL_TEXTURE_CUBE_MAP_ARRAY: + texSlot = RESTYPE_TEXCUBEARRAY; + break; + } + + if(details.format.compType == eCompType_UInt) + { + texSlot |= TEXDISPLAY_UINT_TEX; + intIdx = 1; + } + if(details.format.compType == eCompType_SInt) + { + texSlot |= TEXDISPLAY_SINT_TEX; + intIdx = 2; + } + + if(details.dimension == 3) + cdata->HistogramSlice = float(sliceFace)/float(details.depth); + + int blocksX = (int)ceil(cdata->HistogramTextureResolution.x/float(HGRAM_PIXELS_PER_TILE*HGRAM_TILES_PER_BLOCK)); + int blocksY = (int)ceil(cdata->HistogramTextureResolution.y/float(HGRAM_PIXELS_PER_TILE*HGRAM_TILES_PER_BLOCK)); + + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + gl.glActiveTexture((RDCGLenum)(eGL_TEXTURE0 + texSlot)); + gl.glBindTexture(texDetails.curType, texDetails.resource.name); + gl.glBindSampler(texSlot, DebugData.pointSampler); + + gl.glBindBufferBase(eGL_SHADER_STORAGE_BUFFER, 0, DebugData.histogramBuf); + + GLuint zero = 0; + gl.glClearBufferData(eGL_SHADER_STORAGE_BUFFER, eGL_R32UI, eGL_RED, eGL_UNSIGNED_INT, &zero); + + gl.glUseProgram(DebugData.histogramProgram[texSlot]); + gl.glDispatchCompute(blocksX, blocksY, 1); + + gl.glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + + histogram.clear(); + histogram.resize(HGRAM_NUM_BUCKETS); + + gl.glBindBuffer(eGL_COPY_READ_BUFFER, DebugData.histogramBuf); + gl.glGetBufferSubData(eGL_COPY_READ_BUFFER, 0, sizeof(uint32_t)*HGRAM_NUM_BUCKETS, &histogram[0]); + return true; } diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index d3b4b04aa..0695e5243 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -178,8 +178,10 @@ class GLReplay : public IReplayDriver // min/max data GLuint minmaxTileResult; // tile result buffer GLuint minmaxResult; // Vec4f[2] final result buffer + GLuint histogramBuf; // uint32_t * num buckets buffer GLuint minmaxResultProgram[3]; // float/uint/sint tile result -> final result program GLuint minmaxTileProgram[32]; // RESTYPE indexed (see debuguniforms.h, 1d/2d/3d etc | uint/sint) src tex -> tile result buf program + GLuint histogramProgram[32]; // RESTYPE indexed (see debuguniforms.h, 1d/2d/3d etc | uint/sint) src tex -> histogram result buf program // program that does a blit of texture from input to output, // no transformation or scaling