diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index cb3930959..9931d5ef2 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -235,11 +235,11 @@ void TextureViewer::OnEventSelected(uint32_t eventID) TextureDisplay &d = m_TexDisplay; - if(m_Core->APIProps().pipelineType == ePipelineState_D3D11) + if(m_Core->APIProps().pipelineType == eGraphicsAPI_D3D11) { d.texid = m_Core->CurD3D11PipelineState.m_OM.RenderTargets[0].Resource; } - else if(m_Core->APIProps().pipelineType == ePipelineState_OpenGL) + else if(m_Core->APIProps().pipelineType == eGraphicsAPI_OpenGL) { d.texid = m_Core->CurGLPipelineState.m_FB.m_DrawFBO.Color[0].Obj; } diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 09edda0e7..4b9fc1aec 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -140,12 +140,12 @@ public: } vector GetTextures() { return m_Proxy->GetTextures(); } FetchTexture GetTexture(ResourceId id) { return m_Proxy->GetTexture(m_TextureID); } - byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize) { - return m_Proxy->GetTextureData(m_TextureID, arrayIdx, mip, typeHint, resolve, forceRGBA8unorm, - blackPoint, whitePoint, dataSize); + return m_Proxy->GetTextureData(m_TextureID, arrayIdx, mip, forDiskSave, typeHint, resolve, + forceRGBA8unorm, blackPoint, whitePoint, dataSize); } // handle a couple of operations ourselves to return a simple fake log diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index 171986f9f..875b2a0c6 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -1719,7 +1719,8 @@ void ReplayProxy::EnsureTexCached(ResourceId texid, uint32_t arrayIdx, uint32_t ResourceId proxyid = m_ProxyTextureIds[texid]; size_t size; - byte *data = GetTextureData(texid, arrayIdx, mip, eCompType_None, false, false, 0.0f, 0.0f, size); + byte *data = + GetTextureData(texid, arrayIdx, mip, false, eCompType_None, false, false, 0.0f, 0.0f, size); if(data) m_Proxy->SetProxyTextureData(proxyid, arrayIdx, mip, data, size); @@ -1818,7 +1819,7 @@ bool ReplayProxy::Tick(int type, Serialiser *incomingPacket) case eReplayProxy_GetTextureData: { size_t dummy; - GetTextureData(ResourceId(), 0, 0, eCompType_None, false, false, 0.0f, 0.0f, dummy); + GetTextureData(ResourceId(), 0, 0, false, eCompType_None, false, false, 0.0f, 0.0f, dummy); break; } case eReplayProxy_InitPostVS: InitPostVSBuffers(0); break; @@ -1892,13 +1893,15 @@ APIProperties ReplayProxy::GetAPIProperties() { if(!SendReplayCommand(eReplayProxy_GetAPIProperties)) return ret; - - APIProperties local = m_Proxy->GetAPIProperties(); - ret.localRenderer = local.localRenderer; } m_FromReplaySerialiser->Serialise("", ret); + if(!m_RemoteServer) + ret.localRenderer = m_Proxy->GetAPIProperties().localRenderer; + + m_APIProps = ret; + return ret; } @@ -2291,13 +2294,14 @@ void ReplayProxy::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, } } -byte *ReplayProxy::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +byte *ReplayProxy::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize) { m_ToReplaySerialiser->Serialise("", tex); m_ToReplaySerialiser->Serialise("", arrayIdx); m_ToReplaySerialiser->Serialise("", mip); + m_ToReplaySerialiser->Serialise("", forDiskSave); m_ToReplaySerialiser->Serialise("", typeHint); m_ToReplaySerialiser->Serialise("", resolve); m_ToReplaySerialiser->Serialise("", forceRGBA8unorm); @@ -2306,8 +2310,8 @@ byte *ReplayProxy::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi if(m_RemoteServer) { - byte *data = m_Remote->GetTextureData(tex, arrayIdx, mip, typeHint, resolve, forceRGBA8unorm, - blackPoint, whitePoint, dataSize); + byte *data = m_Remote->GetTextureData(tex, arrayIdx, mip, forDiskSave, typeHint, resolve, + forceRGBA8unorm, blackPoint, whitePoint, dataSize); byte *compressed = new byte[LZ4_COMPRESSBOUND(dataSize)]; diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 273254d88..07147508b 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -103,6 +103,8 @@ public: m_FromReplaySerialiser = NULL; m_ToReplaySerialiser = new Serialiser(NULL, Serialiser::WRITING, false); m_RemoteHasResolver = false; + + GetAPIProperties(); } ReplayProxy(Network::Socket *sock, IRemoteDriver *remote) @@ -224,6 +226,15 @@ public: if(cfg.texid == ResourceId() || m_ProxyTextureIds[cfg.texid] == ResourceId()) return false; cfg.texid = m_ProxyTextureIds[cfg.texid]; + + // due to OpenGL having origin bottom-left compared to the rest of the world, + // we need to flip going in or out of GL. + if((m_APIProps.pipelineType == eGraphicsAPI_OpenGL) != + (m_APIProps.localRenderer == eGraphicsAPI_OpenGL)) + { + cfg.FlipY = !cfg.FlipY; + } + return m_Proxy->RenderTexture(cfg); } @@ -238,7 +249,22 @@ public: EnsureTexCached(texture, sliceFace, mip); if(texture == ResourceId() || m_ProxyTextureIds[texture] == ResourceId()) return; - m_Proxy->PickPixel(m_ProxyTextureIds[texture], x, y, sliceFace, mip, sample, typeHint, pixel); + + texture = m_ProxyTextureIds[texture]; + + // due to OpenGL having origin bottom-left compared to the rest of the world, + // we need to flip going in or out of GL. + // This is a bit more annoying here as we don't have a bool to flip, we need to + // manually adjust y + if((m_APIProps.pipelineType == eGraphicsAPI_OpenGL) != + (m_APIProps.localRenderer == eGraphicsAPI_OpenGL)) + { + FetchTexture tex = m_Proxy->GetTexture(texture); + uint32_t mipHeight = RDCMAX(1U, tex.height >> mip); + y = (mipHeight - 1) - y; + } + + m_Proxy->PickPixel(texture, x, y, sliceFace, mip, sample, typeHint, pixel); } } @@ -393,7 +419,7 @@ public: vector &outvars, const vector &data); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector &retData); - byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); @@ -510,6 +536,8 @@ private: bool m_RemoteHasResolver; + APIProperties m_APIProps; + D3D11PipelineState m_D3D11PipelineState; GLPipelineState m_GLPipelineState; VulkanPipelineState m_VulkanPipelineState; diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index 05a4a89b6..361e98c09 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -2519,9 +2519,9 @@ void D3D11DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, ui } byte *D3D11DebugManager::GetTextureData(ResourceId id, uint32_t arrayIdx, uint32_t mip, - FormatComponentType typeHint, bool resolve, - bool forceRGBA8unorm, float blackPoint, float whitePoint, - size_t &dataSize) + bool forDiskSave, FormatComponentType typeHint, + bool resolve, bool forceRGBA8unorm, float blackPoint, + float whitePoint, size_t &dataSize) { ID3D11Resource *dummyTex = NULL; diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index dabdb802e..0ae3eca65 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -127,7 +127,7 @@ public: void GetBufferData(ID3D11Buffer *buff, uint64_t offset, uint64_t length, vector &retData, bool unwrap); - byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index b5c9ef216..98be6fbdc 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1450,12 +1450,13 @@ void D3D11Replay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, m_pDevice->GetDebugManager()->GetBufferData(buff, offset, len, retData); } -byte *D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +byte *D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize) { - return m_pDevice->GetDebugManager()->GetTextureData( - tex, arrayIdx, mip, typeHint, resolve, forceRGBA8unorm, blackPoint, whitePoint, dataSize); + return m_pDevice->GetDebugManager()->GetTextureData(tex, arrayIdx, mip, forDiskSave, typeHint, + resolve, forceRGBA8unorm, blackPoint, + whitePoint, dataSize); } void D3D11Replay::ReplaceResource(ResourceId from, ResourceId to) diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 01753418b..a6ee70b65 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -106,7 +106,7 @@ public: MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector &retData); - byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index deafc3969..8faea9237 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -388,7 +388,7 @@ void D3D12Replay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, { } -byte *D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +byte *D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize) { diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index ce2c80d9a..0db21f09d 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -101,7 +101,7 @@ public: MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector &retData); - byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 2d82f3047..b2ff47029 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -2216,7 +2216,7 @@ void GLReplay::FillCBufferVariables(ResourceId shader, string entryPoint, uint32 outvars, data); } -byte *GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +byte *GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize) { @@ -2487,62 +2487,72 @@ byte *GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, m_pDriver->glGetTexImage(target, (GLint)mip, fmt, type, ret); - // need to vertically flip the image now to get conventional row ordering - // we either do this when copying out the slice of interest, or just - // on its own - size_t rowSize = GetByteSize(width, 1, 1, fmt, type); - byte *src, *dst; + // if we're saving to disk we make the decision to vertically flip any non-compressed + // images. This is a bit arbitrary, but really origin top-left is common for all disk + // formats so we do this flip from bottom-left origin. We only do this for saving to + // disk so that if we're transferring over the network etc for remote replay, the image + // order is consistent (and we just need to take care to apply an extra vertical flip + // for display when proxying). - // for arrays just extract the slice we're interested in. - if(texType == eGL_TEXTURE_2D_ARRAY || texType == eGL_TEXTURE_1D_ARRAY || - texType == eGL_TEXTURE_CUBE_MAP_ARRAY) + if(forDiskSave) { - dataSize = GetByteSize(width, height, 1, fmt, type); - byte *slice = new byte[dataSize]; + // need to vertically flip the image now to get conventional row ordering + // we either do this when copying out the slice of interest, or just + // on its own + size_t rowSize = GetByteSize(width, 1, 1, fmt, type); + byte *src, *dst; - // src points to the last row in the array slice image - src = (ret + dataSize * arrayIdx) + (height - 1) * rowSize; - dst = slice; - - // we do memcpy + vertical flip - // memcpy(slice, ret + dataSize*arrayIdx, dataSize); - - for(GLsizei i = 0; i < height; i++) + // for arrays just extract the slice we're interested in. + if(texType == eGL_TEXTURE_2D_ARRAY || texType == eGL_TEXTURE_1D_ARRAY || + texType == eGL_TEXTURE_CUBE_MAP_ARRAY) { - memcpy(dst, src, rowSize); + dataSize = GetByteSize(width, height, 1, fmt, type); + byte *slice = new byte[dataSize]; - dst += rowSize; - src -= rowSize; - } + // src points to the last row in the array slice image + src = (ret + dataSize * arrayIdx) + (height - 1) * rowSize; + dst = slice; - delete[] ret; + // we do memcpy + vertical flip + // memcpy(slice, ret + dataSize*arrayIdx, dataSize); - ret = slice; - } - else - { - byte *row = new byte[rowSize]; - - size_t sliceSize = GetByteSize(width, height, 1, fmt, type); - - // invert all slices in a 3D texture - for(GLsizei d = 0; d < depth; d++) - { - dst = ret + d * sliceSize; - src = dst + (height - 1) * rowSize; - - for(GLsizei i = 0; i> 1; i++) + for(GLsizei i = 0; i < height; i++) { - memcpy(row, src, rowSize); - memcpy(src, dst, rowSize); - memcpy(dst, row, rowSize); + memcpy(dst, src, rowSize); dst += rowSize; src -= rowSize; } - } - delete[] row; + delete[] ret; + + ret = slice; + } + else + { + byte *row = new byte[rowSize]; + + size_t sliceSize = GetByteSize(width, height, 1, fmt, type); + + // invert all slices in a 3D texture + for(GLsizei d = 0; d < depth; d++) + { + dst = ret + d * sliceSize; + src = dst + (height - 1) * rowSize; + + for(GLsizei i = 0; i> 1; i++) + { + memcpy(row, src, rowSize); + memcpy(src, dst, rowSize); + memcpy(dst, row, rowSize); + + dst += rowSize; + src -= rowSize; + } + } + + delete[] row; + } } } diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 8d07a6a84..9ba562cf6 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -151,7 +151,7 @@ public: MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector &ret); - byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index e3853d9c9..0f59925a4 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -4568,7 +4568,7 @@ MeshFormat VulkanReplay::GetPostVSBuffers(uint32_t eventID, uint32_t instID, Mes return GetDebugManager()->GetPostVSBuffers(eventID, instID, stage); } -byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, +byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize) { diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index c6fc2d0d7..b1ae58f2d 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -186,7 +186,7 @@ public: MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector &retData); - byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index 58db5ad62..f902ee042 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -88,7 +88,7 @@ public: virtual void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector &retData) = 0; - virtual byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + virtual byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool forDiskSave, FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize) = 0; diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index 4d5b1beca..d31bb17d8 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -483,8 +483,8 @@ bool ReplayRenderer::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t } size_t sz = 0; - byte *bytes = - m_pDevice->GetTextureData(liveId, arrayIdx, mip, eCompType_None, false, false, 0.0f, 0.0f, sz); + byte *bytes = m_pDevice->GetTextureData(liveId, arrayIdx, mip, false, eCompType_None, false, + false, 0.0f, 0.0f, sz); if(sz == 0 || bytes == NULL) create_array_uninit(*data, 0); @@ -745,7 +745,7 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) size_t datasize = 0; byte *bytes = - m_pDevice->GetTextureData(liveid, slice, mip, sd.typeHint, resolveSamples, downcast, + m_pDevice->GetTextureData(liveid, slice, mip, true, sd.typeHint, resolveSamples, downcast, sd.comp.blackPoint, sd.comp.whitePoint, datasize); if(bytes == NULL)