diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index c43c508de..be63611da 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -736,8 +736,8 @@ void TextureViewer::RT_FetchCurrentPixel(IReplayController *r, uint32_t x, uint3 if(m_TexDisplay.flipY) y = (texptr->height - 1) - y; - x = qMax(0U, x >> m_TexDisplay.subresource.mip); - y = qMax(0U, y >> m_TexDisplay.subresource.mip); + x = qMax(0U, MipCoordFromBase(x, texptr->width)); + y = qMax(0U, MipCoordFromBase(y, texptr->height)); ResourceId id = m_TexDisplay.resourceId; Subresource sub = m_TexDisplay.subresource; @@ -965,11 +965,12 @@ void TextureViewer::UI_UpdateStatusText() ui->pickSwatch->setPalette(Pal); } - int y = m_CurHoverPixel.y() >> (int)m_TexDisplay.subresource.mip; - uint32_t mipWidth = qMax(1U, tex.width >> (int)m_TexDisplay.subresource.mip); uint32_t mipHeight = qMax(1U, tex.height >> (int)m_TexDisplay.subresource.mip); + int x = MipCoordFromBase(m_CurHoverPixel.x(), tex.width); + int y = MipCoordFromBase(m_CurHoverPixel.y(), tex.height); + if(ShouldFlipForGL()) y = (int)(mipHeight - 1) - y; if(m_TexDisplay.flipY) @@ -977,7 +978,6 @@ void TextureViewer::UI_UpdateStatusText() y = qMax(0, y); - int x = m_CurHoverPixel.x() >> (int)m_TexDisplay.subresource.mip; float invWidth = 1.0f / mipWidth; float invHeight = 1.0f / mipHeight; @@ -1004,8 +1004,8 @@ void TextureViewer::UI_UpdateStatusText() if(m_PickedPoint.x() >= 0) { - x = m_PickedPoint.x() >> (int)m_TexDisplay.subresource.mip; - y = m_PickedPoint.y() >> (int)m_TexDisplay.subresource.mip; + x = MipCoordFromBase(m_PickedPoint.x(), tex.width); + y = MipCoordFromBase(m_PickedPoint.y(), tex.height); if(ShouldFlipForGL()) y = (int)(mipHeight - 1) - y; if(m_TexDisplay.flipY) @@ -2151,8 +2151,8 @@ void TextureViewer::GotoLocation(uint32_t x, uint32_t y) if(tex == NULL) return; - x = qMin(x << m_TexDisplay.subresource.mip, uint32_t(tex->width - 1)); - y = qMin(y << m_TexDisplay.subresource.mip, uint32_t(tex->height - 1)); + x = qMin(BaseCoordFromMip(x, tex->width), uint32_t(tex->width - 1)); + y = qMin(BaseCoordFromMip(y, tex->height), uint32_t(tex->height - 1)); m_PickedPoint = QPoint(x, y); @@ -3796,8 +3796,8 @@ rdcpair TextureViewer::GetPickedLocation() { QPoint p = m_PickedPoint; - p.setX(p.x() >> (int)m_TexDisplay.subresource.mip); - p.setY(p.y() >> (int)m_TexDisplay.subresource.mip); + p.setX(MipCoordFromBase(p.x(), texptr->width)); + p.setY(MipCoordFromBase(p.y(), texptr->height)); uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.subresource.mip); @@ -3820,8 +3820,8 @@ void TextureViewer::ShowGotoPopup() { QPoint p = m_PickedPoint; - p.setX(p.x() >> (int)m_TexDisplay.subresource.mip); - p.setY(p.y() >> (int)m_TexDisplay.subresource.mip); + p.setX(MipCoordFromBase(p.x(), texptr->width)); + p.setY(MipCoordFromBase(p.y(), texptr->height)); uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.subresource.mip); @@ -3969,11 +3969,11 @@ void TextureViewer::on_debugPixelContext_clicked() if(m_PickedPoint.x() < 0 || m_PickedPoint.y() < 0) return; - int x = m_PickedPoint.x() >> (int)m_TexDisplay.subresource.mip; - int y = m_PickedPoint.y() >> (int)m_TexDisplay.subresource.mip; - TextureDescription *texptr = GetCurrentTexture(); + int x = MipCoordFromBase(m_PickedPoint.x(), texptr->width); + int y = MipCoordFromBase(m_PickedPoint.y(), texptr->height); + uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.subresource.mip); if(m_TexDisplay.flipY) @@ -4035,8 +4035,8 @@ void TextureViewer::on_pixelHistory_clicked() ANALYTIC_SET(UIFeatures.PixelHistory, true); - int x = m_PickedPoint.x() >> (int)m_TexDisplay.subresource.mip; - int y = m_PickedPoint.y() >> (int)m_TexDisplay.subresource.mip; + int x = MipCoordFromBase(m_PickedPoint.x(), texptr->width); + int y = MipCoordFromBase(m_PickedPoint.y(), texptr->height); uint32_t mipHeight = qMax(1U, texptr->height >> (int)m_TexDisplay.subresource.mip); @@ -4417,6 +4417,34 @@ QString TextureViewer::getShaderPath(const QString &filename) const return path; } +uint32_t TextureViewer::MipCoordFromBase(int coord, uint32_t dim) +{ + const uint32_t mip = m_TexDisplay.subresource.mip; + const uint32_t mipDim = qMax(1U, dim >> mip); + + // for mip levels where we more than half (e.g. 15x15 to 7x7) the coord can't be shifted by the + // mip. + // e.g. if the top level is 960x540 an x coordinate of 950 would be shifted by 7 down to 7, but + // mip 7 is 7x4 so the max x co-ordinate is 6. Instead we need to get the float value on the top + // mip, multiply by the mip dimension, and floor it + + float coordf = float(coord) / float(dim); + + return uint32_t(mipDim * coordf); +} + +uint32_t TextureViewer::BaseCoordFromMip(int coord, uint32_t dim) +{ + const uint32_t mip = m_TexDisplay.subresource.mip; + uint32_t mipDim = qMax(1U, dim >> mip); + + // reverse of the above conversion + + float coordf = float(coord) / float(mipDim); + + return uint32_t(dim * coordf); +} + void TextureViewer::on_customCreate_clicked() { QString filename = ui->customShader->currentText(); diff --git a/qrenderdoc/Windows/TextureViewer.h b/qrenderdoc/Windows/TextureViewer.h index 2a5a93d75..e49617fe9 100644 --- a/qrenderdoc/Windows/TextureViewer.h +++ b/qrenderdoc/Windows/TextureViewer.h @@ -307,6 +307,8 @@ private: void ShowGotoPopup(); bool ShouldFlipForGL(); + uint32_t MipCoordFromBase(int coord, uint32_t dim); + uint32_t BaseCoordFromMip(int coord, uint32_t dim); void UI_UpdateFittedScale(); void UI_SetScale(float s); diff --git a/renderdoc/data/hlsl/histogram.hlsl b/renderdoc/data/hlsl/histogram.hlsl index 0f3007e8d..600b1e7a4 100644 --- a/renderdoc/data/hlsl/histogram.hlsl +++ b/renderdoc/data/hlsl/histogram.hlsl @@ -61,8 +61,8 @@ RWBuffer MinMaxDestInt : register(u2); { for(uint x = topleft.x; x < min(texDim.x, topleft.x + HGRAM_PIXELS_PER_TILE); x++) { - uint4 data = SampleTextureUInt4(texType, float2(x, y) / float2(texDim.xy), HistogramSlice, - HistogramMip, HistogramSample, texDim); + uint4 data = SampleTextureUInt4(texType, float2(x + 0.1f, y + 0.1f) / float2(texDim.xy), + HistogramSlice, HistogramMip, HistogramSample, texDim); if(i == 0) { @@ -91,8 +91,8 @@ RWBuffer MinMaxDestInt : register(u2); { for(uint x = topleft.x; x < min(texDim.x, topleft.x + HGRAM_PIXELS_PER_TILE); x++) { - int4 data = SampleTextureInt4(texType, float2(x, y) / float2(texDim.xy), HistogramSlice, - HistogramMip, HistogramSample, texDim); + int4 data = SampleTextureInt4(texType, float2(x + 0.1f, y + 0.1f) / float2(texDim.xy), + HistogramSlice, HistogramMip, HistogramSample, texDim); if(i == 0) { @@ -121,9 +121,10 @@ RWBuffer MinMaxDestInt : register(u2); { for(uint x = topleft.x; x < min(texDim.x, topleft.x + HGRAM_PIXELS_PER_TILE); x++) { - float4 data = SampleTextureFloat4(texType, false, float2(x, y) / float2(texDim.xy), - HistogramSlice, HistogramMip, HistogramSample, texDim, - HistogramYUVDownsampleRate, HistogramYUVAChannels); + float4 data = + SampleTextureFloat4(texType, false, float2(x + 0.1f, y + 0.1f) / float2(texDim.xy), + HistogramSlice, HistogramMip, HistogramSample, texDim, + HistogramYUVDownsampleRate, HistogramYUVAChannels); if(i == 0) { @@ -238,8 +239,8 @@ RWBuffer HistogramDest : register(u0); #if UINT_TEX { - uint4 data = SampleTextureUInt4(texType, float2(x, y) / float2(texDim.xy), HistogramSlice, - HistogramMip, HistogramSample, texDim); + uint4 data = SampleTextureUInt4(texType, float2(x + 0.1f, y + 0.1f) / float2(texDim.xy), + HistogramSlice, HistogramMip, HistogramSample, texDim); if((HistogramChannels & 0x1) == 0) data.x = uint(HistogramMax + 1); @@ -268,8 +269,8 @@ RWBuffer HistogramDest : register(u0); } #elif SINT_TEX { - int4 data = SampleTextureInt4(texType, float2(x, y) / float2(texDim.xy), HistogramSlice, - HistogramMip, HistogramSample, texDim); + int4 data = SampleTextureInt4(texType, float2(x + 0.1f, y + 0.1f) / float2(texDim.xy), + HistogramSlice, HistogramMip, HistogramSample, texDim); if((HistogramChannels & 0x1) == 0) data.x = int(HistogramMax + 1); @@ -298,9 +299,10 @@ RWBuffer HistogramDest : register(u0); } #else { - float4 data = SampleTextureFloat4(texType, false, float2(x, y) / float2(texDim.xy), - HistogramSlice, HistogramMip, HistogramSample, texDim, - HistogramYUVDownsampleRate, HistogramYUVAChannels); + float4 data = + SampleTextureFloat4(texType, false, float2(x + 0.1f, y + 0.1f) / float2(texDim.xy), + HistogramSlice, HistogramMip, HistogramSample, texDim, + HistogramYUVDownsampleRate, HistogramYUVAChannels); if((HistogramChannels & 0x1) == 0) data.x = float(HistogramMax + 1); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index e615d57dd..10e476ef7 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1704,8 +1704,47 @@ void D3D11Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Su texDisplay.resourceId = texture; texDisplay.typeCast = typeCast; texDisplay.rawOutput = true; - texDisplay.xOffset = -float(x << sub.mip); - texDisplay.yOffset = -float(y << sub.mip); + + uint32_t texWidth = 1, texHeight = 1; + + auto it1 = WrappedID3D11Texture1D::m_TextureList.find(texture); + auto it2 = WrappedID3D11Texture2D1::m_TextureList.find(texture); + auto it3 = WrappedID3D11Texture3D1::m_TextureList.find(texture); + if(it1 != WrappedID3D11Texture1D::m_TextureList.end()) + { + WrappedID3D11Texture1D *wrapTex1D = (WrappedID3D11Texture1D *)it1->second.m_Texture; + + D3D11_TEXTURE1D_DESC desc1d = {0}; + wrapTex1D->GetDesc(&desc1d); + + texWidth = desc1d.Width; + } + else if(it2 != WrappedID3D11Texture2D1::m_TextureList.end()) + { + WrappedID3D11Texture2D1 *wrapTex2D = (WrappedID3D11Texture2D1 *)it2->second.m_Texture; + + D3D11_TEXTURE2D_DESC desc2d = {0}; + wrapTex2D->GetDesc(&desc2d); + + texWidth = desc2d.Width; + texHeight = desc2d.Height; + } + else if(it3 != WrappedID3D11Texture3D1::m_TextureList.end()) + { + WrappedID3D11Texture3D1 *wrapTex3D = (WrappedID3D11Texture3D1 *)it3->second.m_Texture; + + D3D11_TEXTURE3D_DESC desc3d = {0}; + wrapTex3D->GetDesc(&desc3d); + + texWidth = desc3d.Width; + texHeight = desc3d.Height; + } + + uint32_t mipWidth = RDCMAX(1U, texWidth >> sub.mip); + uint32_t mipHeight = RDCMAX(1U, texHeight >> sub.mip); + + texDisplay.xOffset = -(float(x) / float(mipWidth)) * texWidth; + texDisplay.yOffset = -(float(y) / float(mipHeight)) * texHeight; RenderTextureInternal(texDisplay, eTexDisplay_None); } diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 880701c5e..d1db7c0ff 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -2580,8 +2580,19 @@ void D3D12Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Su texDisplay.resourceId = texture; texDisplay.typeCast = typeCast; texDisplay.rawOutput = true; - texDisplay.xOffset = -float(x << sub.mip); - texDisplay.yOffset = -float(y << sub.mip); + + ID3D12Resource *resource = m_pDevice->GetResourceList()[texture]; + + if(resource) + { + D3D12_RESOURCE_DESC desc = resource->GetDesc(); + + uint32_t mipWidth = RDCMAX(1U, UINT(desc.Width >> sub.mip)); + uint32_t mipHeight = RDCMAX(1U, desc.Height >> sub.mip); + + texDisplay.xOffset = -(float(x) / float(mipWidth)) * desc.Width; + texDisplay.yOffset = -(float(y) / float(mipHeight)) * desc.Height; + } m_OutputViewport = {0, 0, 1, 1, 0.0f, 1.0f}; RenderTextureInternal(GetDebugManager()->GetCPUHandle(PICK_PIXEL_RTV), texDisplay, diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index f0e723f24..74229b097 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -1620,14 +1620,20 @@ void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subre texDisplay.xOffset = -float(x << sub.mip); texDisplay.yOffset = -float(y << sub.mip); + auto &texDetails = m_pDriver->m_Textures[texDisplay.resourceId]; + + uint32_t mipWidth = RDCMAX(1U, (uint32_t)texDetails.width >> sub.mip); + uint32_t mipHeight = RDCMAX(1U, (uint32_t)texDetails.height >> sub.mip); + + texDisplay.xOffset = -(float(x) / float(mipWidth)) * texDetails.width; + texDisplay.yOffset = -(float(y) / float(mipHeight)) * texDetails.height; + RenderTextureInternal(texDisplay, eTexDisplay_MipShift); drv.glReadPixels(0, 0, 1, 1, eGL_RGBA, eGL_FLOAT, (void *)pixel); if(!HasExt[ARB_gpu_shader5]) { - auto &texDetails = m_pDriver->m_Textures[texDisplay.resourceId]; - if(IsSIntFormat(texDetails.internalFormat)) { int32_t casted[4] = { @@ -1647,8 +1653,6 @@ void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subre } { - auto &texDetails = m_pDriver->m_Textures[texture]; - // need to read stencil separately as GL can't read both depth and stencil // at the same time. if(texDetails.internalFormat == eGL_DEPTH24_STENCIL8 || diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 6632c70d7..0053bd25d 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -2406,8 +2406,12 @@ void VulkanReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const S texDisplay.resourceId = texture; texDisplay.typeCast = typeCast; texDisplay.rawOutput = true; - texDisplay.xOffset = -float(x << sub.mip); - texDisplay.yOffset = -float(y << sub.mip); + + uint32_t mipWidth = RDCMAX(1U, iminfo.extent.width >> sub.mip); + uint32_t mipHeight = RDCMAX(1U, iminfo.extent.height >> sub.mip); + + texDisplay.xOffset = -(float(x) / float(mipWidth)) * iminfo.extent.width; + texDisplay.yOffset = -(float(y) / float(mipHeight)) * iminfo.extent.height; // only render green (stencil) in second pass if(pass == 1) diff --git a/renderdoc/replay/replay_controller.h b/renderdoc/replay/replay_controller.h index 7da2f8cb5..ca1fbe823 100644 --- a/renderdoc/replay/replay_controller.h +++ b/renderdoc/replay/replay_controller.h @@ -97,6 +97,8 @@ private: bool dirty; } m_MainOutput; + rdcpair m_TextureDim = {0, 0}; + ResourceId m_OverlayResourceId; ResourceId m_CustomShaderResourceId; diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index e58061c4a..ea32a551e 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -202,6 +202,15 @@ void ReplayOutput::SetTextureDisplay(const TextureDisplay &o) m_CustomDirty = true; m_RenderData.texDisplay = o; m_MainOutput.dirty = true; + + m_TextureDim = {0, 0}; + for(size_t t = 0; t < m_pController->m_Textures.size(); t++) + { + if(m_pController->m_Textures[t].resourceId == m_RenderData.texDisplay.resourceId) + { + m_TextureDim = {m_pController->m_Textures[t].width, m_pController->m_Textures[t].height}; + } + } } void ReplayOutput::SetMeshDisplay(const MeshDisplay &o) @@ -593,11 +602,25 @@ void ReplayOutput::DisplayContext() int x = (int)m_ContextX; int y = (int)m_ContextY; - x >>= disp.subresource.mip; - x <<= disp.subresource.mip; + if(m_TextureDim.first > 0 && m_TextureDim.second > 0) + { + rdcpair mipDim = {RDCMAX(1U, m_TextureDim.first >> disp.subresource.mip), + RDCMAX(1U, m_TextureDim.second >> disp.subresource.mip)}; - y >>= disp.subresource.mip; - y <<= disp.subresource.mip; + x = int((float(x) / float(m_TextureDim.first)) * mipDim.first); + x = int((float(x) / float(mipDim.first)) * m_TextureDim.first); + + y = int((float(y) / float(m_TextureDim.second)) * mipDim.second); + y = int((float(y) / float(mipDim.second)) * m_TextureDim.second); + } + else + { + x >>= disp.subresource.mip; + x <<= disp.subresource.mip; + + y >>= disp.subresource.mip; + y <<= disp.subresource.mip; + } disp.xOffset = -(float)x * disp.scale; disp.yOffset = -(float)y * disp.scale;