Factor out near/far derivation into common driver code

This commit is contained in:
baldurk
2023-11-16 16:48:44 +00:00
parent b0c97182f6
commit 54fdac1d44
4 changed files with 57 additions and 155 deletions
+5 -74
View File
@@ -24,6 +24,7 @@
#include <algorithm>
#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.
+6 -81
View File
@@ -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)
+44
View File
@@ -23,6 +23,8 @@
******************************************************************************/
#include "replay_driver.h"
#include <float.h>
#include <math.h>
#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;
}
}
+2
View File
@@ -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);