diff --git a/renderdoc/driver/d3d12/d3d12_postvs.cpp b/renderdoc/driver/d3d12/d3d12_postvs.cpp index 2c19fcd6b..fbc36dc59 100644 --- a/renderdoc/driver/d3d12/d3d12_postvs.cpp +++ b/renderdoc/driver/d3d12/d3d12_postvs.cpp @@ -24,6 +24,7 @@ #include #include "driver/dxgi/dxgi_common.h" +#include "replay/replay_driver.h" #include "strings/string_utils.h" #include "d3d12_command_list.h" #include "d3d12_command_queue.h" @@ -734,47 +735,12 @@ void D3D12Replay::InitPostVSBuffers(uint32_t eventId) for(uint64_t i = 1; numPosComponents == 4 && i < numPrims; 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 + i * stride); - if(fabs(pos->w - pos0->w) > 0.01f && fabs(pos->z - pos0->z) > 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 || c == 0.0f) - continue; - - if(-c / m <= 0.000001f) - continue; - - nearp = -c / m; - farp = c / (1 - m); - - found = true; + DeriveNearFar(*pos, *pos0, nearp, farp, found); + if(found) break; - } } // if we didn't find anything, all z's and w's were identical. @@ -1324,47 +1290,12 @@ void D3D12Replay::InitPostVSBuffers(uint32_t eventId) for(UINT64 i = 1; numPosComponents == 4 && i < numVerts; 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 + i * stride); - if(fabs(pos->w - pos0->w) > 0.01f && fabs(pos->z - pos0->z) > 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 || c == 0.0f) - continue; - - if(-c / m <= 0.000001f) - continue; - - nearp = -c / m; - farp = c / (1 - m); - - found = true; + DeriveNearFar(*pos, *pos0, nearp, farp, found); + if(found) break; - } } // if we didn't find anything, all z's and w's were identical. diff --git a/renderdoc/driver/vulkan/vk_postvs.cpp b/renderdoc/driver/vulkan/vk_postvs.cpp index 62a72b787..f47e7fc20 100644 --- a/renderdoc/driver/vulkan/vk_postvs.cpp +++ b/renderdoc/driver/vulkan/vk_postvs.cpp @@ -28,6 +28,7 @@ #include "core/settings.h" #include "driver/shaders/spirv/spirv_editor.h" #include "driver/shaders/spirv/spirv_op_helpers.h" +#include "replay/replay_driver.h" #include "vk_core.h" #include "vk_debug.h" #include "vk_replay.h" @@ -2811,50 +2812,14 @@ void VulkanReplay::FetchVSOut(uint32_t eventId, VulkanRenderState &state) // and position is the first value for(uint32_t i = 1; - refl->outputSignature[0].systemValue == ShaderBuiltin::Position && i < numVerts; i++) + refl->outputSignature[0].systemValue == ShaderBuiltin::Position && !found && i < numVerts; 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 + i * bufStride); - // skip invalid vertices (w=0) - if(pos->w != 0.0f && fabs(pos->w - pos0->w) > 0.01f && fabs(pos->z - pos0->z) > 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 || c == 0.0f) - continue; - - if(-c / m <= 0.000001f) - continue; - - nearp = -c / m; - farp = c / (1 - m); - - found = true; + DeriveNearFar(*pos, *pos0, nearp, farp, found); + if(found) break; - } } // if we didn't find anything, all z's and w's were identical. @@ -3408,50 +3373,10 @@ void VulkanReplay::FetchTessGSOut(uint32_t eventId, VulkanRenderState &state) if(readbackoffset == 0) memcpy(&pos0, data.data(), sizeof(pos0)); - for(uint32_t i = 0; i < data.size() / xfbStride; i++) + for(uint32_t i = 0; !found && i < data.size() / xfbStride; 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 *)(data.data() + xfbStride * i); - - // skip invalid vertices (w=0) - if(pos->w != 0.0f && fabs(pos->w - pos0.w) > 0.01f && fabs(pos->z - pos0.z) > 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 || c == 0.0f) - continue; - - if(-c / m <= 0.000001f) - continue; - - nearp = -c / m; - farp = c / (1 - m); - - found = true; - - break; - } + DeriveNearFar(*pos, pos0, nearp, farp, found); } if(found) diff --git a/renderdoc/replay/replay_driver.cpp b/renderdoc/replay/replay_driver.cpp index 199ea355a..952e84aba 100644 --- a/renderdoc/replay/replay_driver.cpp +++ b/renderdoc/replay/replay_driver.cpp @@ -23,6 +23,8 @@ ******************************************************************************/ #include "replay_driver.h" +#include +#include #include "compressonator/CMP_Core.h" #include "maths/formatpacking.h" #include "maths/half_convert.h" @@ -1802,3 +1804,45 @@ bytebuf GetDiscardPattern(DiscardType type, const ResourceFormat &fmt, uint32_t return ret; } + +void DeriveNearFar(Vec4f pos, Vec4f pos0, float &nearp, float &farp, bool &found) +{ + ////////////////////////////////////////////////////////////////////////////////// + // 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 + + // skip invalid vertices (w=0) + if(pos.w != 0.0f && fabsf(pos.w - pos0.w) > 0.01f && fabsf(pos.z - pos0.z) > 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 || c == 0.0f) + return; + + if(-c / m <= 0.000001f) + return; + + nearp = -c / m; + farp = c / (1 - m); + + found = true; + } +} diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index c2f50c9ce..76153af25 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -369,3 +369,5 @@ static constexpr uint32_t DiscardPatternHeight = 8; // returns a pattern to fill the texture with bytebuf GetDiscardPattern(DiscardType type, const ResourceFormat &fmt, uint32_t rowPitch = 1, bool invert = false); + +void DeriveNearFar(Vec4f pos, Vec4f pos0, float &nearp, float &farp, bool &found);