mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Implement mesh picking for D3D12
This commit is contained in:
@@ -2318,10 +2318,9 @@ uint32_t D3D11DebugManager::PickVertex(uint32_t eventID, const MeshDisplay &cfg,
|
||||
Vec3f testDir = (cameraToWorldFarPosition - cameraToWorldNearPosition);
|
||||
testDir.Normalise();
|
||||
|
||||
/* Calculate the ray direction first in the regular way (above), so we can use the
|
||||
the output for testing if the ray we are picking is negative or not. This is similar
|
||||
to checking against the forward direction of the camera, but more robust
|
||||
*/
|
||||
// Calculate the ray direction first in the regular way (above), so we can use the
|
||||
// the output for testing if the ray we are picking is negative or not. This is similar
|
||||
// to checking against the forward direction of the camera, but more robust
|
||||
if(cfg.position.unproject)
|
||||
{
|
||||
Matrix4f inversePickMVPGuess = pickMVPProj.Inverse();
|
||||
@@ -2358,27 +2357,27 @@ uint32_t D3D11DebugManager::PickVertex(uint32_t eventID, const MeshDisplay &cfg,
|
||||
{
|
||||
cbuf.MeshMode = MESH_TRIANGLE_LIST;
|
||||
break;
|
||||
};
|
||||
}
|
||||
case eTopology_TriangleStrip:
|
||||
{
|
||||
cbuf.MeshMode = MESH_TRIANGLE_STRIP;
|
||||
break;
|
||||
};
|
||||
}
|
||||
case eTopology_TriangleList_Adj:
|
||||
{
|
||||
cbuf.MeshMode = MESH_TRIANGLE_LIST_ADJ;
|
||||
break;
|
||||
};
|
||||
}
|
||||
case eTopology_TriangleStrip_Adj:
|
||||
{
|
||||
cbuf.MeshMode = MESH_TRIANGLE_STRIP_ADJ;
|
||||
break;
|
||||
};
|
||||
}
|
||||
default: // points, lines, patchlists, unknown
|
||||
{
|
||||
cbuf.MeshMode = MESH_OTHER;
|
||||
isTriangleMesh = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11Buffer *vb = NULL, *ib = NULL;
|
||||
|
||||
@@ -200,6 +200,9 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
m_WrappedDevice->CreateRenderTargetView(m_PickPixelTex, NULL, m_PickPixelRTV);
|
||||
}
|
||||
|
||||
m_PickVB = NULL;
|
||||
m_PickSize = 0;
|
||||
|
||||
{
|
||||
D3D12_RESOURCE_DESC soBufDesc;
|
||||
soBufDesc.Alignment = 0;
|
||||
@@ -516,6 +519,44 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
|
||||
SAFE_RELEASE(root);
|
||||
|
||||
rootSig.clear();
|
||||
|
||||
// 0: CBV
|
||||
param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
param.Descriptor.ShaderRegister = 0;
|
||||
param.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE;
|
||||
|
||||
rootSig.push_back(param);
|
||||
|
||||
// 0: SRVs
|
||||
srvrange.NumDescriptors = 2;
|
||||
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
param.DescriptorTable.pDescriptorRanges = &srvrange;
|
||||
param.DescriptorTable.NumDescriptorRanges = 1;
|
||||
|
||||
rootSig.push_back(param);
|
||||
|
||||
// 0: UAV
|
||||
uavrange.NumDescriptors = 1;
|
||||
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
param.DescriptorTable.pDescriptorRanges = &uavrange;
|
||||
param.DescriptorTable.NumDescriptorRanges = 1;
|
||||
|
||||
rootSig.push_back(param);
|
||||
|
||||
root = MakeRootSig(rootSig);
|
||||
|
||||
RDCASSERT(root);
|
||||
|
||||
hr = m_WrappedDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(),
|
||||
__uuidof(ID3D12RootSignature),
|
||||
(void **)&m_MeshPickRootSig);
|
||||
|
||||
SAFE_RELEASE(root);
|
||||
|
||||
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.6f);
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc;
|
||||
@@ -688,6 +729,26 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
D3D12_COMPUTE_PIPELINE_STATE_DESC compPipeDesc;
|
||||
RDCEraseEl(compPipeDesc);
|
||||
|
||||
compPipeDesc.pRootSignature = m_MeshPickRootSig;
|
||||
|
||||
ID3DBlob *meshPickCS;
|
||||
|
||||
GetShaderBlob(meshhlsl.c_str(), "RENDERDOC_MeshPickCS", D3DCOMPILE_WARNINGS_ARE_ERRORS, "cs_5_0",
|
||||
&meshPickCS);
|
||||
|
||||
RDCASSERT(meshPickCS);
|
||||
|
||||
compPipeDesc.CS.BytecodeLength = meshPickCS->GetBufferSize();
|
||||
compPipeDesc.CS.pShaderBytecode = meshPickCS->GetBufferPointer();
|
||||
|
||||
hr = m_WrappedDevice->CreateComputePipelineState(&compPipeDesc, __uuidof(ID3D12PipelineState),
|
||||
(void **)&m_MeshPickPipe);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create m_MeshPickPipe! 0x%08x", hr);
|
||||
}
|
||||
|
||||
compPipeDesc.pRootSignature = m_HistogramRootSig;
|
||||
|
||||
RDCEraseEl(m_TileMinMaxPipe);
|
||||
@@ -770,6 +831,60 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
SAFE_RELEASE(QOResolvePS);
|
||||
SAFE_RELEASE(CheckerboardPS);
|
||||
|
||||
{
|
||||
D3D12_RESOURCE_DESC pickResultDesc = {};
|
||||
pickResultDesc.Alignment = 0;
|
||||
pickResultDesc.DepthOrArraySize = 1;
|
||||
pickResultDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
pickResultDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
pickResultDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
pickResultDesc.Height = 1;
|
||||
pickResultDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
pickResultDesc.MipLevels = 1;
|
||||
pickResultDesc.SampleDesc.Count = 1;
|
||||
pickResultDesc.SampleDesc.Quality = 0;
|
||||
// add an extra 64 bytes for the counter at the start
|
||||
pickResultDesc.Width = m_MaxMeshPicks * sizeof(Vec4f) + 64;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(
|
||||
&heapProps, D3D12_HEAP_FLAG_NONE, &pickResultDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
NULL, __uuidof(ID3D12Resource), (void **)&m_PickResultBuf);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create tile buffer for min/max, HRESULT: 0x%08x", hr);
|
||||
}
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
||||
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
uavDesc.Buffer.CounterOffsetInBytes = 0;
|
||||
// start with elements after the counter
|
||||
uavDesc.Buffer.FirstElement = 64 / sizeof(Vec4f);
|
||||
uavDesc.Buffer.NumElements = m_MaxMeshPicks;
|
||||
uavDesc.Buffer.StructureByteStride = sizeof(Vec4f);
|
||||
|
||||
m_WrappedDevice->CreateUnorderedAccessView(m_PickResultBuf, m_PickResultBuf, &uavDesc,
|
||||
GetCPUHandle(PICK_RESULT_UAV));
|
||||
|
||||
// this UAV is used for clearing everything back to 0
|
||||
|
||||
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
|
||||
uavDesc.Buffer.FirstElement = 0;
|
||||
uavDesc.Buffer.NumElements = m_MaxMeshPicks + 64 / sizeof(Vec4f);
|
||||
uavDesc.Buffer.StructureByteStride = 0;
|
||||
|
||||
m_WrappedDevice->CreateUnorderedAccessView(m_PickResultBuf, NULL, &uavDesc,
|
||||
GetCPUHandle(PICK_RESULT_CLEAR_UAV));
|
||||
}
|
||||
|
||||
{
|
||||
const uint64_t maxTexDim = 16384;
|
||||
const uint64_t blockPixSize = HGRAM_PIXELS_PER_TILE * HGRAM_TILES_PER_BLOCK;
|
||||
@@ -1210,6 +1325,11 @@ D3D12DebugManager::~D3D12DebugManager()
|
||||
|
||||
SAFE_RELEASE(m_PickPixelTex);
|
||||
|
||||
SAFE_RELEASE(m_MeshPickRootSig);
|
||||
SAFE_RELEASE(m_MeshPickPipe);
|
||||
SAFE_RELEASE(m_PickResultBuf);
|
||||
SAFE_RELEASE(m_PickVB);
|
||||
|
||||
SAFE_RELEASE(m_SOBuffer);
|
||||
SAFE_RELEASE(m_SOStagingBuffer);
|
||||
|
||||
@@ -2024,6 +2144,354 @@ void D3D12DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, ui
|
||||
m_ReadbackBuffer->Unmap(0, &range);
|
||||
}
|
||||
|
||||
uint32_t D3D12DebugManager::PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x,
|
||||
uint32_t y)
|
||||
{
|
||||
if(cfg.position.numVerts == 0)
|
||||
return ~0U;
|
||||
|
||||
struct MeshPickData
|
||||
{
|
||||
Vec3f RayPos;
|
||||
uint32_t PickIdx;
|
||||
|
||||
Vec3f RayDir;
|
||||
uint32_t PickNumVerts;
|
||||
|
||||
Vec2f PickCoords;
|
||||
Vec2f PickViewport;
|
||||
|
||||
uint32_t MeshMode;
|
||||
uint32_t PickUnproject;
|
||||
Vec2f Padding;
|
||||
|
||||
Matrix4f PickMVP;
|
||||
|
||||
} cbuf;
|
||||
|
||||
cbuf.PickCoords = Vec2f((float)x, (float)y);
|
||||
cbuf.PickViewport = Vec2f((float)GetWidth(), (float)GetHeight());
|
||||
cbuf.PickIdx = cfg.position.idxByteWidth ? 1 : 0;
|
||||
cbuf.PickNumVerts = cfg.position.numVerts;
|
||||
cbuf.PickUnproject = cfg.position.unproject ? 1 : 0;
|
||||
|
||||
Matrix4f projMat =
|
||||
Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(GetWidth()) / float(GetHeight()));
|
||||
|
||||
Matrix4f camMat = cfg.cam ? cfg.cam->GetMatrix() : Matrix4f::Identity();
|
||||
|
||||
Matrix4f pickMVP = projMat.Mul(camMat);
|
||||
|
||||
ResourceFormat resFmt;
|
||||
resFmt.compByteWidth = cfg.position.compByteWidth;
|
||||
resFmt.compCount = cfg.position.compCount;
|
||||
resFmt.compType = cfg.position.compType;
|
||||
resFmt.special = false;
|
||||
if(cfg.position.specialFormat != eSpecial_Unknown)
|
||||
{
|
||||
resFmt.special = true;
|
||||
resFmt.specialFormat = cfg.position.specialFormat;
|
||||
}
|
||||
|
||||
Matrix4f pickMVPProj;
|
||||
if(cfg.position.unproject)
|
||||
{
|
||||
// the derivation of the projection matrix might not be right (hell, it could be an
|
||||
// orthographic projection). But it'll be close enough likely.
|
||||
Matrix4f guessProj =
|
||||
Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect);
|
||||
|
||||
if(cfg.ortho)
|
||||
guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane);
|
||||
|
||||
pickMVPProj = projMat.Mul(camMat.Mul(guessProj.Inverse()));
|
||||
}
|
||||
|
||||
Vec3f rayPos;
|
||||
Vec3f rayDir;
|
||||
// convert mouse pos to world space ray
|
||||
{
|
||||
Matrix4f inversePickMVP = pickMVP.Inverse();
|
||||
|
||||
float pickX = ((float)x) / ((float)GetWidth());
|
||||
float pickXCanonical = RDCLERP(-1.0f, 1.0f, pickX);
|
||||
|
||||
float pickY = ((float)y) / ((float)GetHeight());
|
||||
// flip the Y axis
|
||||
float pickYCanonical = RDCLERP(1.0f, -1.0f, pickY);
|
||||
|
||||
Vec3f cameraToWorldNearPosition =
|
||||
inversePickMVP.Transform(Vec3f(pickXCanonical, pickYCanonical, -1), 1);
|
||||
|
||||
Vec3f cameraToWorldFarPosition =
|
||||
inversePickMVP.Transform(Vec3f(pickXCanonical, pickYCanonical, 1), 1);
|
||||
|
||||
Vec3f testDir = (cameraToWorldFarPosition - cameraToWorldNearPosition);
|
||||
testDir.Normalise();
|
||||
|
||||
// Calculate the ray direction first in the regular way (above), so we can use the
|
||||
// the output for testing if the ray we are picking is negative or not. This is similar
|
||||
// to checking against the forward direction of the camera, but more robust
|
||||
if(cfg.position.unproject)
|
||||
{
|
||||
Matrix4f inversePickMVPGuess = pickMVPProj.Inverse();
|
||||
|
||||
Vec3f nearPosProj = inversePickMVPGuess.Transform(Vec3f(pickXCanonical, pickYCanonical, -1), 1);
|
||||
|
||||
Vec3f farPosProj = inversePickMVPGuess.Transform(Vec3f(pickXCanonical, pickYCanonical, 1), 1);
|
||||
|
||||
rayDir = (farPosProj - nearPosProj);
|
||||
rayDir.Normalise();
|
||||
|
||||
if(testDir.z < 0)
|
||||
{
|
||||
rayDir = -rayDir;
|
||||
}
|
||||
rayPos = nearPosProj;
|
||||
}
|
||||
else
|
||||
{
|
||||
rayDir = testDir;
|
||||
rayPos = cameraToWorldNearPosition;
|
||||
}
|
||||
}
|
||||
|
||||
cbuf.RayPos = rayPos;
|
||||
cbuf.RayDir = rayDir;
|
||||
|
||||
cbuf.PickMVP = cfg.position.unproject ? pickMVPProj : pickMVP;
|
||||
|
||||
bool isTriangleMesh = true;
|
||||
switch(cfg.position.topo)
|
||||
{
|
||||
case eTopology_TriangleList:
|
||||
{
|
||||
cbuf.MeshMode = MESH_TRIANGLE_LIST;
|
||||
break;
|
||||
}
|
||||
case eTopology_TriangleStrip:
|
||||
{
|
||||
cbuf.MeshMode = MESH_TRIANGLE_STRIP;
|
||||
break;
|
||||
}
|
||||
case eTopology_TriangleList_Adj:
|
||||
{
|
||||
cbuf.MeshMode = MESH_TRIANGLE_LIST_ADJ;
|
||||
break;
|
||||
}
|
||||
case eTopology_TriangleStrip_Adj:
|
||||
{
|
||||
cbuf.MeshMode = MESH_TRIANGLE_STRIP_ADJ;
|
||||
break;
|
||||
}
|
||||
default: // points, lines, patchlists, unknown
|
||||
{
|
||||
cbuf.MeshMode = MESH_OTHER;
|
||||
isTriangleMesh = false;
|
||||
}
|
||||
}
|
||||
|
||||
ID3D12Resource *vb = NULL, *ib = NULL;
|
||||
DXGI_FORMAT ifmt = cfg.position.idxByteWidth == 4 ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
|
||||
|
||||
if(cfg.position.buf != ResourceId())
|
||||
vb = m_WrappedDevice->GetResourceManager()->GetCurrentAs<ID3D12Resource>(cfg.position.buf);
|
||||
|
||||
if(cfg.position.idxbuf != ResourceId())
|
||||
ib = m_WrappedDevice->GetResourceManager()->GetCurrentAs<ID3D12Resource>(cfg.position.idxbuf);
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
// most IB/VBs will not be available as SRVs. So, we copy into our own buffers.
|
||||
// In the case of VB we also tightly pack and unpack the data. IB can just be
|
||||
// read as R16 or R32 via the SRV so it is just a straight copy
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC sdesc = {};
|
||||
sdesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
||||
sdesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
sdesc.Format = ifmt;
|
||||
|
||||
if(cfg.position.idxByteWidth && ib)
|
||||
{
|
||||
sdesc.Buffer.NumElements = cfg.position.numVerts;
|
||||
m_WrappedDevice->CreateShaderResourceView(ib, &sdesc, GetCPUHandle(PICK_IB_SRV));
|
||||
}
|
||||
else
|
||||
{
|
||||
sdesc.Buffer.NumElements = 4;
|
||||
m_WrappedDevice->CreateShaderResourceView(NULL, &sdesc, GetCPUHandle(PICK_IB_SRV));
|
||||
}
|
||||
|
||||
sdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
|
||||
if(vb)
|
||||
{
|
||||
if(m_PickVB == NULL || m_PickSize < cfg.position.numVerts)
|
||||
{
|
||||
SAFE_RELEASE(m_PickVB);
|
||||
|
||||
m_PickSize = cfg.position.numVerts;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC vbDesc;
|
||||
vbDesc.Alignment = 0;
|
||||
vbDesc.DepthOrArraySize = 1;
|
||||
vbDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
vbDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
vbDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
vbDesc.Height = 1;
|
||||
vbDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
vbDesc.MipLevels = 1;
|
||||
vbDesc.SampleDesc.Count = 1;
|
||||
vbDesc.SampleDesc.Quality = 0;
|
||||
vbDesc.Width = sizeof(Vec4f) * cfg.position.numVerts;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &vbDesc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_PickVB);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create pick vertex buffer: %08x", hr);
|
||||
return ~0U;
|
||||
}
|
||||
|
||||
sdesc.Buffer.NumElements = cfg.position.numVerts;
|
||||
m_WrappedDevice->CreateShaderResourceView(m_PickVB, &sdesc, GetCPUHandle(PICK_VB_SRV));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sdesc.Buffer.NumElements = 4;
|
||||
m_WrappedDevice->CreateShaderResourceView(NULL, &sdesc, GetCPUHandle(PICK_VB_SRV));
|
||||
}
|
||||
|
||||
// unpack and linearise the data
|
||||
{
|
||||
FloatVector *vbData = new FloatVector[cfg.position.numVerts];
|
||||
|
||||
vector<byte> oldData;
|
||||
GetBufferData(vb, cfg.position.offset, 0, oldData);
|
||||
|
||||
byte *data = &oldData[0];
|
||||
byte *dataEnd = data + oldData.size();
|
||||
|
||||
bool valid = true;
|
||||
|
||||
for(uint32_t i = 0; i < cfg.position.numVerts; i++)
|
||||
vbData[i] = InterpretVertex(data, i, cfg, dataEnd, false, valid);
|
||||
|
||||
FillBuffer(m_PickVB, 0, vbData, sizeof(Vec4f) * cfg.position.numVerts);
|
||||
|
||||
delete[] vbData;
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList *list = m_WrappedDevice->GetNewList();
|
||||
|
||||
list->SetPipelineState(m_MeshPickPipe);
|
||||
|
||||
list->SetComputeRootSignature(m_MeshPickRootSig);
|
||||
|
||||
list->SetDescriptorHeaps(1, &cbvsrvuavHeap);
|
||||
|
||||
list->SetComputeRootConstantBufferView(0, UploadConstants(&cbuf, sizeof(cbuf)));
|
||||
list->SetComputeRootDescriptorTable(1, GetGPUHandle(PICK_IB_SRV));
|
||||
list->SetComputeRootDescriptorTable(2, GetGPUHandle(PICK_RESULT_UAV));
|
||||
|
||||
list->Dispatch(cfg.position.numVerts / 1024 + 1, 1, 1);
|
||||
|
||||
list->Close();
|
||||
m_WrappedDevice->ExecuteLists();
|
||||
|
||||
vector<byte> results;
|
||||
GetBufferData(m_PickResultBuf, 0, 0, results);
|
||||
|
||||
list = m_WrappedDevice->GetNewList();
|
||||
|
||||
UINT zeroes[4] = {0, 0, 0, 0};
|
||||
list->ClearUnorderedAccessViewUint(GetGPUHandle(PICK_RESULT_CLEAR_UAV),
|
||||
GetCPUHandle(PICK_RESULT_CLEAR_UAV), m_PickResultBuf, zeroes,
|
||||
0, NULL);
|
||||
|
||||
list->Close();
|
||||
|
||||
byte *data = &results[0];
|
||||
|
||||
uint32_t numResults = *(uint32_t *)data;
|
||||
|
||||
if(numResults > 0)
|
||||
{
|
||||
if(isTriangleMesh)
|
||||
{
|
||||
struct PickResult
|
||||
{
|
||||
uint32_t vertid;
|
||||
Vec3f intersectionPoint;
|
||||
};
|
||||
|
||||
PickResult *pickResults = (PickResult *)(data + 64);
|
||||
|
||||
PickResult *closest = pickResults;
|
||||
|
||||
// distance from raycast hit to nearest worldspace position of the mouse
|
||||
float closestPickDistance = (closest->intersectionPoint - rayPos).Length();
|
||||
|
||||
// min with size of results buffer to protect against overflows
|
||||
for(uint32_t i = 1; i < RDCMIN(m_MaxMeshPicks, numResults); i++)
|
||||
{
|
||||
float pickDistance = (pickResults[i].intersectionPoint - rayPos).Length();
|
||||
if(pickDistance < closestPickDistance)
|
||||
{
|
||||
closest = pickResults + i;
|
||||
}
|
||||
}
|
||||
|
||||
return closest->vertid;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct PickResult
|
||||
{
|
||||
uint32_t vertid;
|
||||
uint32_t idx;
|
||||
float len;
|
||||
float depth;
|
||||
};
|
||||
|
||||
PickResult *pickResults = (PickResult *)(data + 64);
|
||||
|
||||
PickResult *closest = pickResults;
|
||||
|
||||
// min with size of results buffer to protect against overflows
|
||||
for(uint32_t i = 1; i < RDCMIN(m_MaxMeshPicks, numResults); i++)
|
||||
{
|
||||
// We need to keep the picking order consistent in the face
|
||||
// of random buffer appends, when multiple vertices have the
|
||||
// identical position (e.g. if UVs or normals are different).
|
||||
//
|
||||
// We could do something to try and disambiguate, but it's
|
||||
// never going to be intuitive, it's just going to flicker
|
||||
// confusingly.
|
||||
if(pickResults[i].len < closest->len ||
|
||||
(pickResults[i].len == closest->len && pickResults[i].depth < closest->depth) ||
|
||||
(pickResults[i].len == closest->len && pickResults[i].depth == closest->depth &&
|
||||
pickResults[i].vertid < closest->vertid))
|
||||
closest = pickResults + i;
|
||||
}
|
||||
|
||||
return closest->vertid;
|
||||
}
|
||||
}
|
||||
|
||||
return ~0U;
|
||||
}
|
||||
|
||||
void D3D12DebugManager::FillCBufferVariables(const string &prefix, size_t &offset, bool flatten,
|
||||
const vector<DXBC::CBufferVariable> &invars,
|
||||
vector<ShaderVariable> &outvars,
|
||||
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
|
||||
void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip,
|
||||
uint32_t sample, FormatComponentType typeHint, float pixel[4]);
|
||||
uint32_t PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y);
|
||||
|
||||
void FillCBufferVariables(const vector<DXBC::CBufferVariable> &invars,
|
||||
vector<ShaderVariable> &outvars, bool flattenVec4s,
|
||||
@@ -163,6 +164,11 @@ private:
|
||||
OVERDRAW_SRV,
|
||||
OVERDRAW_UAV,
|
||||
STREAM_OUT_UAV,
|
||||
|
||||
PICK_IB_SRV,
|
||||
PICK_VB_SRV,
|
||||
PICK_RESULT_UAV,
|
||||
PICK_RESULT_CLEAR_UAV,
|
||||
};
|
||||
|
||||
enum RTVSlot
|
||||
@@ -255,6 +261,9 @@ private:
|
||||
ID3D12Resource *m_PickPixelTex;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE m_PickPixelRTV;
|
||||
|
||||
ID3D12RootSignature *m_MeshPickRootSig;
|
||||
ID3D12PipelineState *m_MeshPickPipe;
|
||||
|
||||
ID3D12RootSignature *m_HistogramRootSig;
|
||||
// one per texture type, one per int/uint/float
|
||||
ID3D12PipelineState *m_TileMinMaxPipe[10][3];
|
||||
@@ -363,6 +372,11 @@ private:
|
||||
|
||||
map<uint64_t, MeshDisplayPipelines> m_CachedMeshPipelines;
|
||||
|
||||
static const uint32_t m_MaxMeshPicks = 500;
|
||||
ID3D12Resource *m_PickVB;
|
||||
uint32_t m_PickSize;
|
||||
ID3D12Resource *m_PickResultBuf;
|
||||
|
||||
static const int m_SOBufferSize = 32 * 1024 * 1024;
|
||||
ID3D12Resource *m_SOBuffer;
|
||||
ID3D12Resource *m_SOStagingBuffer;
|
||||
|
||||
@@ -1469,6 +1469,11 @@ MeshFormat D3D12Replay::GetPostVSBuffers(uint32_t eventID, uint32_t instID, Mesh
|
||||
return m_pDevice->GetDebugManager()->GetPostVSBuffers(eventID, instID, stage);
|
||||
}
|
||||
|
||||
uint32_t D3D12Replay::PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y)
|
||||
{
|
||||
return m_pDevice->GetDebugManager()->PickVertex(eventID, cfg, x, y);
|
||||
}
|
||||
|
||||
uint64_t D3D12Replay::MakeOutputWindow(WindowingSystem system, void *data, bool depth)
|
||||
{
|
||||
return m_pDevice->GetDebugManager()->MakeOutputWindow(system, data, depth);
|
||||
@@ -1673,11 +1678,6 @@ ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventID, uint32_t groupid[3],
|
||||
return ShaderDebugTrace();
|
||||
}
|
||||
|
||||
uint32_t D3D12Replay::PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y)
|
||||
{
|
||||
return ~0U;
|
||||
}
|
||||
|
||||
ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip,
|
||||
uint32_t arrayIdx, uint32_t sampleIdx,
|
||||
FormatComponentType typeHint)
|
||||
|
||||
Reference in New Issue
Block a user