Implement pixel picking on D3D12

This commit is contained in:
baldurk
2016-09-19 18:23:07 +02:00
parent ece0725d8e
commit 45551e58cc
3 changed files with 233 additions and 13 deletions
+204 -6
View File
@@ -157,6 +157,77 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
RDCERR("Couldn't create sampler descriptor heap! 0x%08x", hr);
}
{
D3D12_RESOURCE_DESC pickPixelDesc = {};
pickPixelDesc.Alignment = 0;
pickPixelDesc.DepthOrArraySize = 1;
pickPixelDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
pickPixelDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
pickPixelDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
pickPixelDesc.Height = 1;
pickPixelDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
pickPixelDesc.MipLevels = 1;
pickPixelDesc.SampleDesc.Count = 1;
pickPixelDesc.SampleDesc.Quality = 0;
pickPixelDesc.Width = 1;
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, &pickPixelDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL,
__uuidof(ID3D12Resource), (void **)&m_PickPixelTex);
if(FAILED(hr))
{
RDCERR("Failed to create rendering texture for pixel picking, HRESULT: 0x%08x", hr);
return;
}
m_PickPixelRTV = rtvHeap->GetCPUDescriptorHandleForHeapStart();
m_PickPixelRTV.ptr +=
FIXED_RTV_PICK_PIXEL *
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
m_WrappedDevice->CreateRenderTargetView(m_PickPixelTex, NULL, m_PickPixelRTV);
}
{
D3D12_RESOURCE_DESC readbackDesc;
readbackDesc.Alignment = 0;
readbackDesc.DepthOrArraySize = 1;
readbackDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
readbackDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
readbackDesc.Format = DXGI_FORMAT_UNKNOWN;
readbackDesc.Height = 1;
readbackDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
readbackDesc.MipLevels = 1;
readbackDesc.SampleDesc.Count = 1;
readbackDesc.SampleDesc.Quality = 0;
readbackDesc.Width = m_ReadbackSize;
D3D12_HEAP_PROPERTIES heapProps;
heapProps.Type = D3D12_HEAP_TYPE_READBACK;
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, &readbackDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
__uuidof(ID3D12Resource), (void **)&m_ReadbackBuffer);
if(FAILED(hr))
{
RDCERR("Failed to create readback buffer, HRESULT: 0x%08x", hr);
return;
}
}
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.2f);
// create fixed samplers, point and linear
@@ -312,6 +383,18 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
RDCERR("Couldn't create m_TexDisplayPipe! 0x%08x", hr);
}
pipeDesc.RTVFormats[0] = DXGI_FORMAT_R32G32B32A32_FLOAT;
hr = m_WrappedDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState),
(void **)&m_TexDisplayF32Pipe);
if(FAILED(hr))
{
RDCERR("Couldn't create m_TexDisplayF32Pipe! 0x%08x", hr);
}
pipeDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
pipeDesc.PS.BytecodeLength = CheckerboardPS->GetBufferSize();
pipeDesc.PS.pShaderBytecode = CheckerboardPS->GetBufferPointer();
@@ -628,10 +711,15 @@ D3D12DebugManager::~D3D12DebugManager()
SAFE_RELEASE(m_TexDisplayBlendPipe);
SAFE_RELEASE(m_TexDisplayPipe);
SAFE_RELEASE(m_TexDisplayF32Pipe);
SAFE_RELEASE(m_TexDisplayRootSig);
SAFE_RELEASE(m_CheckerboardPipe);
SAFE_RELEASE(m_PickPixelTex);
SAFE_RELEASE(m_ReadbackBuffer);
m_WrappedDevice->InternalRelease();
if(RenderDoc::Inst().GetCrashHandler())
@@ -957,6 +1045,8 @@ uint64_t D3D12DebugManager::MakeOutputWindow(WindowingSystem system, void *data,
outw.bbIdx = 0;
outw.rtv = rtvHeap->GetCPUDescriptorHandleForHeapStart();
outw.rtv.ptr += FIXED_RTV_COUNT *
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
outw.rtv.ptr += SIZE_T(m_OutputWindowID) *
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
@@ -1199,6 +1289,103 @@ void D3D12DebugManager::FreeRTV(D3D12_CPU_DESCRIPTOR_HANDLE handle)
D3D12NOTIMP("Not freeing RTV's - will run out");
}
void D3D12DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace,
uint32_t mip, uint32_t sample, FormatComponentType typeHint,
float pixel[4])
{
int oldW = GetWidth(), oldH = GetHeight();
SetOutputDimensions(1, 1, DXGI_FORMAT_R32G32B32A32_FLOAT);
{
TextureDisplay texDisplay;
texDisplay.Red = texDisplay.Green = texDisplay.Blue = texDisplay.Alpha = true;
texDisplay.HDRMul = -1.0f;
texDisplay.linearDisplayAsGamma = true;
texDisplay.FlipY = false;
texDisplay.mip = mip;
texDisplay.sampleIdx = sample;
texDisplay.CustomShader = ResourceId();
texDisplay.sliceFace = sliceFace;
texDisplay.rangemin = 0.0f;
texDisplay.rangemax = 1.0f;
texDisplay.scale = 1.0f;
texDisplay.texid = texture;
texDisplay.typeHint = typeHint;
texDisplay.rawoutput = true;
texDisplay.offx = -float(x);
texDisplay.offy = -float(y);
RenderTextureInternal(m_PickPixelRTV, texDisplay, false);
}
ID3D12GraphicsCommandList *list = m_WrappedDevice->GetNewList();
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Transition.pResource = m_PickPixelTex;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
list->ResourceBarrier(1, &barrier);
D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {};
src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
src.pResource = m_PickPixelTex;
src.SubresourceIndex = 0;
dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
dst.pResource = m_ReadbackBuffer;
dst.PlacedFootprint.Offset = 0;
dst.PlacedFootprint.Footprint.Width = sizeof(Vec4f);
dst.PlacedFootprint.Footprint.Height = 1;
dst.PlacedFootprint.Footprint.Depth = 1;
dst.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
dst.PlacedFootprint.Footprint.RowPitch = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL);
std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
list->ResourceBarrier(1, &barrier);
list->Close();
m_WrappedDevice->ExecuteLists();
m_WrappedDevice->FlushLists();
D3D12_RANGE range = {0, sizeof(Vec4f)};
float *pix = NULL;
HRESULT hr = m_ReadbackBuffer->Map(0, &range, (void **)&pix);
if(FAILED(hr))
{
RDCERR("Failed to map picking stage tex %08x", hr);
}
if(pix == NULL)
{
RDCERR("Failed to map pick-pixel staging texture.");
}
else
{
pixel[0] = pix[0];
pixel[1] = pix[1];
pixel[2] = pix[2];
pixel[3] = pix[3];
}
SetOutputDimensions(oldW, oldH, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
range.End = 0;
if(SUCCEEDED(hr))
m_ReadbackBuffer->Unmap(0, &range);
}
void D3D12DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark)
{
DebugVertexCBuffer vertexData;
@@ -1377,6 +1564,12 @@ void D3D12DebugManager::RenderTextInternal(ID3D12GraphicsCommandList *list, floa
}
bool D3D12DebugManager::RenderTexture(TextureDisplay cfg, bool blendAlpha)
{
return RenderTextureInternal(m_OutputWindows[m_CurrentOutputWindow].rtv, cfg, blendAlpha);
}
bool D3D12DebugManager::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, TextureDisplay cfg,
bool blendAlpha)
{
DebugVertexCBuffer vertexData;
DebugPixelCBufferData pixelData;
@@ -1586,28 +1779,33 @@ bool D3D12DebugManager::RenderTexture(TextureDisplay cfg, bool blendAlpha)
barriers.push_back(b);
}
OutputWindow &outw = m_OutputWindows[m_CurrentOutputWindow];
{
ID3D12GraphicsCommandList *list = m_WrappedDevice->GetNewList();
if(!barriers.empty())
list->ResourceBarrier((UINT)barriers.size(), &barriers[0]);
list->OMSetRenderTargets(1, &outw.rtv, TRUE, NULL);
list->OMSetRenderTargets(1, &rtv, TRUE, NULL);
D3D12_VIEWPORT viewport = {0, 0, (float)outw.width, (float)outw.height, 0.0f, 1.0f};
D3D12_VIEWPORT viewport = {0, 0, (float)m_width, (float)m_height, 0.0f, 1.0f};
list->RSSetViewports(1, &viewport);
D3D12_RECT scissor = {0, 0, outw.width, outw.height};
D3D12_RECT scissor = {0, 0, m_width, m_height};
list->RSSetScissorRects(1, &scissor);
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
if(cfg.rawoutput || !blendAlpha || cfg.CustomShader != ResourceId())
list->SetPipelineState(m_TexDisplayPipe);
{
if(m_BBFmtIdx == RGBA32_BACKBUFFER)
list->SetPipelineState(m_TexDisplayF32Pipe);
else
list->SetPipelineState(m_TexDisplayPipe);
}
else
{
list->SetPipelineState(m_TexDisplayBlendPipe);
}
list->SetGraphicsRootSignature(m_TexDisplayRootSig);
+22 -1
View File
@@ -58,6 +58,8 @@ public:
m_BBFmtIdx = BGRA8_BACKBUFFER;
else if(fmt == DXGI_FORMAT_R16G16B16A16_FLOAT)
m_BBFmtIdx = RGBA16_BACKBUFFER;
else if(fmt == DXGI_FORMAT_R32G32B32A32_FLOAT)
m_BBFmtIdx = RGBA32_BACKBUFFER;
else
m_BBFmtIdx = RGBA8_BACKBUFFER;
}
@@ -68,6 +70,9 @@ public:
void RenderCheckerboard(Vec3f light, Vec3f dark);
bool RenderTexture(TextureDisplay cfg, bool blendAlpha);
void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip,
uint32_t sample, FormatComponentType typeHint, float pixel[4]);
D3D12_CPU_DESCRIPTOR_HANDLE AllocRTV();
void FreeRTV(D3D12_CPU_DESCRIPTOR_HANDLE handle);
@@ -106,12 +111,20 @@ private:
// index in SRV heap
static const int FONT_SRV = 128;
enum
{
FIXED_RTV_PICK_PIXEL,
FIXED_RTV_CUSTOM_SHADER,
FIXED_RTV_COUNT,
};
// indices for the pipelines, for the three possible backbuffer formats
enum
{
BGRA8_BACKBUFFER = 0,
RGBA8_BACKBUFFER,
RGBA16_BACKBUFFER,
RGBA32_BACKBUFFER,
FMTNUM_BACKBUFFER,
} m_BBFmtIdx;
@@ -154,12 +167,20 @@ private:
ID3D12Resource *m_GenericPSCbuffer;
ID3D12PipelineState *m_TexDisplayPipe;
ID3D12PipelineState *m_TexDisplayF32Pipe;
ID3D12PipelineState *m_TexDisplayBlendPipe;
ID3D12RootSignature *m_TexDisplayRootSig;
ID3D12PipelineState *m_CheckerboardPipe;
ID3D12Resource *m_PickPixelTex;
D3D12_CPU_DESCRIPTOR_HANDLE m_PickPixelRTV;
ID3D12Resource *m_ReadbackBuffer;
static const uint32_t m_ReadbackSize = 8 * 1024 * 1024;
static const uint32_t m_ShaderCacheMagic = 0xbaafd1d1;
static const uint32_t m_ShaderCacheVersion = 1;
@@ -167,11 +188,11 @@ private:
map<uint32_t, ID3DBlob *> m_ShaderCache;
void RenderTextInternal(ID3D12GraphicsCommandList *list, float x, float y, const char *text);
bool RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, TextureDisplay cfg, bool blendAlpha);
string GetShaderBlob(const char *source, const char *entry, const uint32_t compileFlags,
const char *profile, ID3DBlob **srcblob);
static ID3DBlob *MakeRootSig(const vector<D3D12_ROOT_PARAMETER> &rootSig);
int m_width, m_height;
uint64_t m_OutputWindowID;
+7 -6
View File
@@ -243,6 +243,13 @@ bool D3D12Replay::RenderTexture(TextureDisplay cfg)
return m_pDevice->GetDebugManager()->RenderTexture(cfg, true);
}
void D3D12Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace,
uint32_t mip, uint32_t sample, FormatComponentType typeHint,
float pixel[4])
{
m_pDevice->GetDebugManager()->PickPixel(texture, x, y, sliceFace, mip, sample, typeHint, pixel);
}
uint64_t D3D12Replay::MakeOutputWindow(WindowingSystem system, void *data, bool depth)
{
return m_pDevice->GetDebugManager()->MakeOutputWindow(system, data, depth);
@@ -461,12 +468,6 @@ uint32_t D3D12Replay::PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint3
return ~0U;
}
void D3D12Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace,
uint32_t mip, uint32_t sample, FormatComponentType typeHint,
float pixel[4])
{
}
ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FormatComponentType typeHint,
TextureDisplayOverlay overlay, uint32_t eventID,
const vector<uint32_t> &passEvents)