bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res) { ResourceId id = GetResID(res); D3D12ResourceType type = IdentifyTypeByPtr(res); if(type == Resource_DescriptorHeap) { WrappedID3D12DescriptorHeap *heap = (WrappedID3D12DescriptorHeap *)res; UINT numElems = heap->GetDesc().NumDescriptors; D3D12Descriptor *descs = (D3D12Descriptor *)Serialiser::AllocAlignedBuffer(sizeof(D3D12Descriptor) * numElems); memcpy(descs, heap->GetDescriptors(), sizeof(D3D12Descriptor) * numElems); SetInitialContents(heap->GetResourceID(), D3D12ResourceManager::InitialContentData(NULL, numElems, (byte *)descs)); return true; } else if(type == Resource_Resource) { WrappedID3D12Resource *r = (WrappedID3D12Resource *)res; ID3D12Pageable *pageable = r; bool nonresident = false; if(!r->Resident()) nonresident = true; D3D12_RESOURCE_DESC desc = r->GetDesc(); if(desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && desc.SampleDesc.Count > 1) { D3D12NOTIMP("Multisampled initial contents"); SetInitialContents(GetResID(r), D3D12ResourceManager::InitialContentData(NULL, 2, NULL)); return true; } else if(desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { D3D12_HEAP_PROPERTIES heapProps; r->GetHeapProperties(&heapProps, NULL); if(heapProps.Type == D3D12_HEAP_TYPE_READBACK) { // already on readback heap, just mark that we can map it directly and continue SetInitialContents(GetResID(r), D3D12ResourceManager::InitialContentData(NULL, 1, NULL)); return true; } 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; desc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Resource *copyDst = NULL; HRESULT hr = m_Device->GetReal()->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource), (void **)©Dst); if(nonresident) m_Device->MakeResident(1, &pageable); if(SUCCEEDED(hr)) { ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); list->CopyResource(copyDst, r->GetReal()); } else { RDCERR("Couldn't create readback buffer: 0x%08x", hr); } if(nonresident) { m_Device->CloseInitialStateList(); m_Device->ExecuteLists(); m_Device->FlushLists(); m_Device->Evict(1, &pageable); } SetInitialContents(GetResID(r), D3D12ResourceManager::InitialContentData(copyDst, 0, NULL)); return true; } else { 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; D3D12_RESOURCE_DESC bufDesc; bufDesc.Alignment = 0; bufDesc.DepthOrArraySize = 1; bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; bufDesc.Flags = D3D12_RESOURCE_FLAG_NONE; bufDesc.Format = DXGI_FORMAT_UNKNOWN; bufDesc.Height = 1; bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; bufDesc.MipLevels = 1; bufDesc.SampleDesc.Count = 1; bufDesc.SampleDesc.Quality = 0; bufDesc.Width = 1; UINT numSubresources = desc.MipLevels; if(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D) numSubresources *= desc.DepthOrArraySize; D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts = new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources]; m_Device->GetCopyableFootprints(&desc, 0, numSubresources, 0, layouts, NULL, NULL, &bufDesc.Width); ID3D12Resource *copyDst = NULL; HRESULT hr = m_Device->GetReal()->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &bufDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource), (void **)©Dst); if(nonresident) m_Device->MakeResident(1, &pageable); if(SUCCEEDED(hr)) { ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); vector<D3D12_RESOURCE_BARRIER> barriers; const vector<D3D12_RESOURCE_STATES> &states = m_Device->GetSubresourceStates(GetResID(r)); barriers.reserve(states.size()); for(size_t i = 0; i < states.size(); i++) { if(states[i] & D3D12_RESOURCE_STATE_COPY_SOURCE) continue; D3D12_RESOURCE_BARRIER barrier; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = r->GetReal(); barrier.Transition.Subresource = (UINT)i; barrier.Transition.StateBefore = states[i]; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; barriers.push_back(barrier); } // transition to copy dest if(!barriers.empty()) list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); for(UINT i = 0; i < numSubresources; i++) { D3D12_TEXTURE_COPY_LOCATION dst, src; src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; src.pResource = r->GetReal(); src.SubresourceIndex = i; dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dst.pResource = copyDst; dst.PlacedFootprint = layouts[i]; list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); } // transition back for(size_t i = 0; i < barriers.size(); i++) std::swap(barriers[i].Transition.StateBefore, barriers[i].Transition.StateAfter); if(!barriers.empty()) list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); } else { RDCERR("Couldn't create readback buffer: 0x%08x", hr); } if(nonresident) { m_Device->CloseInitialStateList(); m_Device->ExecuteLists(); m_Device->FlushLists(); m_Device->Evict(1, &pageable); } SAFE_DELETE_ARRAY(layouts); SetInitialContents(GetResID(r), D3D12ResourceManager::InitialContentData(copyDst, 0, NULL)); return true; } } else { RDCERR("Unexpected type needing an initial state prepared: %d", type); } return false; }
ResourceId D3D12Replay::RenderOverlay(ResourceId texid, CompType typeHint, DebugOverlay overlay, uint32_t eventId, const vector<uint32_t> &passEvents) { ID3D12Resource *resource = WrappedID3D12Resource::GetList()[texid]; if(resource == NULL) return ResourceId(); D3D12_RESOURCE_DESC resourceDesc = resource->GetDesc(); std::vector<D3D12_RESOURCE_BARRIER> barriers; int resType = 0; GetDebugManager()->PrepareTextureSampling(resource, typeHint, resType, barriers); D3D12_RESOURCE_DESC overlayTexDesc; overlayTexDesc.Alignment = 0; overlayTexDesc.DepthOrArraySize = 1; overlayTexDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; overlayTexDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; overlayTexDesc.Format = DXGI_FORMAT_R16G16B16A16_UNORM; overlayTexDesc.Height = resourceDesc.Height; overlayTexDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; overlayTexDesc.MipLevels = 1; overlayTexDesc.SampleDesc = resourceDesc.SampleDesc; overlayTexDesc.Width = resourceDesc.Width; 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; D3D12_RESOURCE_DESC currentOverlayDesc; RDCEraseEl(currentOverlayDesc); if(m_Overlay.Texture) currentOverlayDesc = m_Overlay.Texture->GetDesc(); WrappedID3D12Resource *wrappedCustomRenderTex = (WrappedID3D12Resource *)m_Overlay.Texture; // need to recreate backing custom render tex if(overlayTexDesc.Width != currentOverlayDesc.Width || overlayTexDesc.Height != currentOverlayDesc.Height || overlayTexDesc.Format != currentOverlayDesc.Format || overlayTexDesc.SampleDesc.Count != currentOverlayDesc.SampleDesc.Count || overlayTexDesc.SampleDesc.Quality != currentOverlayDesc.SampleDesc.Quality) { SAFE_RELEASE(m_Overlay.Texture); m_Overlay.resourceId = ResourceId(); ID3D12Resource *customRenderTex = NULL; HRESULT hr = m_pDevice->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &overlayTexDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, NULL, __uuidof(ID3D12Resource), (void **)&customRenderTex); if(FAILED(hr)) { RDCERR("Failed to create custom render tex HRESULT: %s", ToStr(hr).c_str()); return ResourceId(); } wrappedCustomRenderTex = (WrappedID3D12Resource *)customRenderTex; customRenderTex->SetName(L"customRenderTex"); m_Overlay.Texture = wrappedCustomRenderTex; m_Overlay.resourceId = wrappedCustomRenderTex->GetResourceID(); } D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; ID3D12Resource *renderDepth = NULL; D3D12Descriptor *dsView = GetWrapped(rs.dsv); D3D12_RESOURCE_DESC depthTexDesc = {}; D3D12_DEPTH_STENCIL_VIEW_DESC dsViewDesc = {}; if(dsView) { ID3D12Resource *realDepth = dsView->nonsamp.resource; dsViewDesc = dsView->nonsamp.dsv; depthTexDesc = realDepth->GetDesc(); depthTexDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; depthTexDesc.Alignment = 0; HRESULT hr = S_OK; hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &depthTexDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource), (void **)&renderDepth); if(FAILED(hr)) { RDCERR("Failed to create renderDepth HRESULT: %s", ToStr(hr).c_str()); return m_Overlay.resourceId; } renderDepth->SetName(L"Overlay renderDepth"); ID3D12GraphicsCommandList *list = m_pDevice->GetNewList(); const vector<D3D12_RESOURCE_STATES> &states = m_pDevice->GetSubresourceStates(GetResID(realDepth)); vector<D3D12_RESOURCE_BARRIER> depthBarriers; depthBarriers.reserve(states.size()); for(size_t i = 0; i < states.size(); i++) { D3D12_RESOURCE_BARRIER b; // skip unneeded barriers if(states[i] & D3D12_RESOURCE_STATE_COPY_SOURCE) continue; b.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; b.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; b.Transition.pResource = realDepth; b.Transition.Subresource = (UINT)i; b.Transition.StateBefore = states[i]; b.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; depthBarriers.push_back(b); } if(!depthBarriers.empty()) list->ResourceBarrier((UINT)depthBarriers.size(), &depthBarriers[0]); list->CopyResource(renderDepth, realDepth); for(size_t i = 0; i < depthBarriers.size(); i++) std::swap(depthBarriers[i].Transition.StateBefore, depthBarriers[i].Transition.StateAfter); if(!depthBarriers.empty()) list->ResourceBarrier((UINT)depthBarriers.size(), &depthBarriers[0]); D3D12_RESOURCE_BARRIER b = {}; b.Transition.pResource = renderDepth; b.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; b.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; b.Transition.StateAfter = D3D12_RESOURCE_STATE_DEPTH_WRITE; // prepare tex resource for copying list->ResourceBarrier(1, &b); list->Close(); } D3D12_RENDER_TARGET_VIEW_DESC rtDesc = {}; rtDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtDesc.Format = DXGI_FORMAT_R16G16B16A16_UNORM; rtDesc.Texture2D.MipSlice = 0; rtDesc.Texture2D.PlaneSlice = 0; if(overlayTexDesc.SampleDesc.Count > 1 || overlayTexDesc.SampleDesc.Quality > 0) rtDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; D3D12_CPU_DESCRIPTOR_HANDLE rtv = GetDebugManager()->GetCPUHandle(OVERLAY_RTV); m_pDevice->CreateRenderTargetView(wrappedCustomRenderTex, &rtDesc, rtv); ID3D12GraphicsCommandList *list = m_pDevice->GetNewList(); FLOAT black[] = {0.0f, 0.0f, 0.0f, 0.0f}; list->ClearRenderTargetView(rtv, black, 0, NULL); D3D12_CPU_DESCRIPTOR_HANDLE dsv = {}; if(renderDepth) { dsv = GetDebugManager()->GetCPUHandle(OVERLAY_DSV); m_pDevice->CreateDepthStencilView( renderDepth, dsViewDesc.Format == DXGI_FORMAT_UNKNOWN ? NULL : &dsViewDesc, dsv); } D3D12_DEPTH_STENCIL_DESC dsDesc; dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP; dsDesc.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS; dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP; dsDesc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS; dsDesc.DepthEnable = TRUE; dsDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; dsDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; dsDesc.StencilEnable = FALSE; dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff; WrappedID3D12PipelineState *pipe = NULL; if(rs.pipe != ResourceId()) pipe = m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12PipelineState>(rs.pipe); if(overlay == DebugOverlay::NaN || overlay == DebugOverlay::Clipping) { // just need the basic texture } else if(overlay == DebugOverlay::Drawcall) { if(pipe && pipe->IsGraphics()) { D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = pipe->GetGraphicsDesc(); float overlayConsts[4] = {0.8f, 0.1f, 0.8f, 1.0f}; ID3DBlob *ps = m_pDevice->GetShaderCache()->MakeFixedColShader(overlayConsts); psoDesc.PS.pShaderBytecode = ps->GetBufferPointer(); psoDesc.PS.BytecodeLength = ps->GetBufferSize(); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.BlendState.AlphaToCoverageEnable = FALSE; psoDesc.BlendState.IndependentBlendEnable = FALSE; psoDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0xf; psoDesc.BlendState.RenderTarget[0].LogicOpEnable = FALSE; RDCEraseEl(psoDesc.RTVFormats); psoDesc.RTVFormats[0] = DXGI_FORMAT_R16G16B16A16_UNORM; psoDesc.NumRenderTargets = 1; psoDesc.SampleMask = ~0U; psoDesc.SampleDesc.Count = RDCMAX(1U, psoDesc.SampleDesc.Count); psoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; psoDesc.RasterizerState.FrontCounterClockwise = FALSE; psoDesc.RasterizerState.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; psoDesc.RasterizerState.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; psoDesc.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; psoDesc.RasterizerState.DepthClipEnable = FALSE; psoDesc.RasterizerState.MultisampleEnable = FALSE; psoDesc.RasterizerState.AntialiasedLineEnable = FALSE; float clearColour[] = {0.0f, 0.0f, 0.0f, 0.5f}; list->ClearRenderTargetView(rtv, clearColour, 0, NULL); list->Close(); list = NULL; ID3D12PipelineState *pso = NULL; HRESULT hr = m_pDevice->CreateGraphicsPipelineState(&psoDesc, __uuidof(ID3D12PipelineState), (void **)&pso); if(FAILED(hr)) { RDCERR("Failed to create overlay pso HRESULT: %s", ToStr(hr).c_str()); SAFE_RELEASE(ps); return m_Overlay.resourceId; } D3D12RenderState prev = rs; rs.pipe = GetResID(pso); rs.rtSingle = true; rs.rts.resize(1); rs.rts[0] = rtv; rs.dsv = D3D12_CPU_DESCRIPTOR_HANDLE(); m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); rs = prev; m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); SAFE_RELEASE(pso); SAFE_RELEASE(ps); } } else if(overlay == DebugOverlay::BackfaceCull) { if(pipe && pipe->IsGraphics()) { D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = pipe->GetGraphicsDesc(); D3D12_CULL_MODE origCull = psoDesc.RasterizerState.CullMode; float redCol[4] = {1.0f, 0.0f, 0.0f, 1.0f}; ID3DBlob *red = m_pDevice->GetShaderCache()->MakeFixedColShader(redCol); float greenCol[4] = {0.0f, 1.0f, 0.0f, 1.0f}; ID3DBlob *green = m_pDevice->GetShaderCache()->MakeFixedColShader(greenCol); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.BlendState.AlphaToCoverageEnable = FALSE; psoDesc.BlendState.IndependentBlendEnable = FALSE; psoDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0xf; psoDesc.BlendState.RenderTarget[0].LogicOpEnable = FALSE; RDCEraseEl(psoDesc.RTVFormats); psoDesc.RTVFormats[0] = DXGI_FORMAT_R16G16B16A16_UNORM; psoDesc.NumRenderTargets = 1; psoDesc.SampleMask = ~0U; psoDesc.SampleDesc.Count = RDCMAX(1U, psoDesc.SampleDesc.Count); psoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; psoDesc.RasterizerState.FrontCounterClockwise = FALSE; psoDesc.RasterizerState.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; psoDesc.RasterizerState.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; psoDesc.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; psoDesc.RasterizerState.DepthClipEnable = FALSE; psoDesc.RasterizerState.MultisampleEnable = FALSE; psoDesc.RasterizerState.AntialiasedLineEnable = FALSE; psoDesc.PS.pShaderBytecode = red->GetBufferPointer(); psoDesc.PS.BytecodeLength = red->GetBufferSize(); list->Close(); list = NULL; ID3D12PipelineState *redPSO = NULL; HRESULT hr = m_pDevice->CreateGraphicsPipelineState(&psoDesc, __uuidof(ID3D12PipelineState), (void **)&redPSO); if(FAILED(hr)) { RDCERR("Failed to create overlay pso HRESULT: %s", ToStr(hr).c_str()); SAFE_RELEASE(red); SAFE_RELEASE(green); return m_Overlay.resourceId; } psoDesc.RasterizerState.CullMode = origCull; psoDesc.PS.pShaderBytecode = green->GetBufferPointer(); psoDesc.PS.BytecodeLength = green->GetBufferSize(); ID3D12PipelineState *greenPSO = NULL; hr = m_pDevice->CreateGraphicsPipelineState(&psoDesc, __uuidof(ID3D12PipelineState), (void **)&greenPSO); if(FAILED(hr)) { RDCERR("Failed to create overlay pso HRESULT: %s", ToStr(hr).c_str()); SAFE_RELEASE(red); SAFE_RELEASE(redPSO); SAFE_RELEASE(green); return m_Overlay.resourceId; } D3D12RenderState prev = rs; rs.pipe = GetResID(redPSO); rs.rtSingle = true; rs.rts.resize(1); rs.rts[0] = rtv; rs.dsv = D3D12_CPU_DESCRIPTOR_HANDLE(); m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); rs.pipe = GetResID(greenPSO); m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); rs = prev; m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); SAFE_RELEASE(red); SAFE_RELEASE(green); SAFE_RELEASE(redPSO); SAFE_RELEASE(greenPSO); } } else if(overlay == DebugOverlay::Wireframe) { if(pipe && pipe->IsGraphics()) { D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = pipe->GetGraphicsDesc(); float overlayConsts[] = {200.0f / 255.0f, 255.0f / 255.0f, 0.0f / 255.0f, 1.0f}; ID3DBlob *ps = m_pDevice->GetShaderCache()->MakeFixedColShader(overlayConsts); psoDesc.PS.pShaderBytecode = ps->GetBufferPointer(); psoDesc.PS.BytecodeLength = ps->GetBufferSize(); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.BlendState.AlphaToCoverageEnable = FALSE; psoDesc.BlendState.IndependentBlendEnable = FALSE; psoDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0xf; psoDesc.BlendState.RenderTarget[0].LogicOpEnable = FALSE; RDCEraseEl(psoDesc.RTVFormats); psoDesc.RTVFormats[0] = DXGI_FORMAT_R16G16B16A16_UNORM; psoDesc.NumRenderTargets = 1; psoDesc.SampleMask = ~0U; psoDesc.SampleDesc.Count = RDCMAX(1U, psoDesc.SampleDesc.Count); psoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME; psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; psoDesc.RasterizerState.FrontCounterClockwise = FALSE; psoDesc.RasterizerState.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; psoDesc.RasterizerState.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; psoDesc.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; psoDesc.RasterizerState.DepthClipEnable = FALSE; psoDesc.RasterizerState.MultisampleEnable = FALSE; psoDesc.RasterizerState.AntialiasedLineEnable = FALSE; overlayConsts[3] = 0.0f; list->ClearRenderTargetView(rtv, overlayConsts, 0, NULL); list->Close(); list = NULL; ID3D12PipelineState *pso = NULL; HRESULT hr = m_pDevice->CreateGraphicsPipelineState(&psoDesc, __uuidof(ID3D12PipelineState), (void **)&pso); if(FAILED(hr)) { RDCERR("Failed to create overlay pso HRESULT: %s", ToStr(hr).c_str()); SAFE_RELEASE(ps); return m_Overlay.resourceId; } D3D12RenderState prev = rs; rs.pipe = GetResID(pso); rs.rtSingle = true; rs.rts.resize(1); rs.rts[0] = rtv; rs.dsv = dsv; m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); rs = prev; m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); SAFE_RELEASE(pso); SAFE_RELEASE(ps); } } else if(overlay == DebugOverlay::ClearBeforePass || overlay == DebugOverlay::ClearBeforeDraw) { vector<uint32_t> events = passEvents; if(overlay == DebugOverlay::ClearBeforeDraw) events.clear(); events.push_back(eventId); if(!events.empty()) { list->Close(); list = NULL; bool rtSingle = rs.rtSingle; std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> rts = rs.rts; if(overlay == DebugOverlay::ClearBeforePass) m_pDevice->ReplayLog(0, events[0], eReplay_WithoutDraw); list = m_pDevice->GetNewList(); for(size_t i = 0; i < rts.size(); i++) { D3D12Descriptor *desc = rtSingle ? GetWrapped(rts[0]) : GetWrapped(rts[i]); if(desc) { if(rtSingle) desc += i; Unwrap(list)->ClearRenderTargetView(UnwrapCPU(desc), black, 0, NULL); } } list->Close(); list = NULL; for(size_t i = 0; i < events.size(); i++) { m_pDevice->ReplayLog(events[i], events[i], eReplay_OnlyDraw); if(overlay == DebugOverlay::ClearBeforePass && i + 1 < events.size()) m_pDevice->ReplayLog(events[i] + 1, events[i + 1], eReplay_WithoutDraw); } } } else if(overlay == DebugOverlay::ViewportScissor) { if(pipe && pipe->IsGraphics() && !rs.views.empty()) { list->OMSetRenderTargets(1, &rtv, TRUE, NULL); D3D12_VIEWPORT viewport = rs.views[0]; list->RSSetViewports(1, &viewport); D3D12_RECT scissor = {0, 0, 16384, 16384}; list->RSSetScissorRects(1, &scissor); list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); list->SetPipelineState(m_General.FixedColPipe); list->SetGraphicsRootSignature(m_General.ConstOnlyRootSig); DebugPixelCBufferData pixelData = {0}; // border colour (dark, 2px, opaque) pixelData.WireframeColour = Vec3f(0.1f, 0.1f, 0.1f); // inner colour (light, transparent) pixelData.Channels = Vec4f(0.2f, 0.2f, 0.9f, 0.7f); pixelData.OutputDisplayFormat = 0; pixelData.RangeMinimum = viewport.TopLeftX; pixelData.InverseRangeSize = viewport.TopLeftY; pixelData.TextureResolutionPS = Vec3f(viewport.Width, viewport.Height, 0.0f); D3D12_GPU_VIRTUAL_ADDRESS viewCB = GetDebugManager()->UploadConstants(&pixelData, sizeof(pixelData)); list->SetGraphicsRootConstantBufferView(0, viewCB); list->SetGraphicsRootConstantBufferView(1, viewCB); list->SetGraphicsRootConstantBufferView(2, viewCB); Vec4f dummy; list->SetGraphicsRoot32BitConstants(3, 4, &dummy.x, 0); float factor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; list->OMSetBlendFactor(factor); list->DrawInstanced(3, 1, 0, 0); viewport.TopLeftX = (float)rs.scissors[0].left; viewport.TopLeftY = (float)rs.scissors[0].top; viewport.Width = (float)(rs.scissors[0].right - rs.scissors[0].left); viewport.Height = (float)(rs.scissors[0].bottom - rs.scissors[0].top); list->RSSetViewports(1, &viewport); pixelData.OutputDisplayFormat = 1; pixelData.RangeMinimum = viewport.TopLeftX; pixelData.InverseRangeSize = viewport.TopLeftY; pixelData.TextureResolutionPS = Vec3f(viewport.Width, viewport.Height, 0.0f); D3D12_GPU_VIRTUAL_ADDRESS scissorCB = GetDebugManager()->UploadConstants(&pixelData, sizeof(pixelData)); list->SetGraphicsRootConstantBufferView(1, scissorCB); list->DrawInstanced(3, 1, 0, 0); } } else if(overlay == DebugOverlay::TriangleSizeDraw || overlay == DebugOverlay::TriangleSizePass) { if(pipe && pipe->IsGraphics()) { SCOPED_TIMER("Triangle size"); vector<uint32_t> events = passEvents; if(overlay == DebugOverlay::TriangleSizeDraw) events.clear(); while(!events.empty()) { const DrawcallDescription *draw = m_pDevice->GetDrawcall(events[0]); // remove any non-drawcalls, like the pass boundary. if(!(draw->flags & DrawFlags::Drawcall)) events.erase(events.begin()); else break; } events.push_back(eventId); D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc = pipe->GetGraphicsDesc(); pipeDesc.pRootSignature = m_General.ConstOnlyRootSig; pipeDesc.SampleMask = 0xFFFFFFFF; pipeDesc.SampleDesc.Count = 1; pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; pipeDesc.NumRenderTargets = 1; RDCEraseEl(pipeDesc.RTVFormats); pipeDesc.RTVFormats[0] = DXGI_FORMAT_R16G16B16A16_UNORM; pipeDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; pipeDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; pipeDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; pipeDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; pipeDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; pipeDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; pipeDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; D3D12_INPUT_ELEMENT_DESC ia[2] = {}; ia[0].SemanticName = "pos"; ia[0].Format = DXGI_FORMAT_R32G32B32A32_FLOAT; ia[1].SemanticName = "sec"; ia[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT; ia[1].InputSlot = 1; ia[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; pipeDesc.InputLayout.NumElements = 2; pipeDesc.InputLayout.pInputElementDescs = ia; pipeDesc.VS.BytecodeLength = m_Overlay.MeshVS->GetBufferSize(); pipeDesc.VS.pShaderBytecode = m_Overlay.MeshVS->GetBufferPointer(); RDCEraseEl(pipeDesc.HS); RDCEraseEl(pipeDesc.DS); pipeDesc.GS.BytecodeLength = m_Overlay.TriangleSizeGS->GetBufferSize(); pipeDesc.GS.pShaderBytecode = m_Overlay.TriangleSizeGS->GetBufferPointer(); pipeDesc.PS.BytecodeLength = m_Overlay.TriangleSizePS->GetBufferSize(); pipeDesc.PS.pShaderBytecode = m_Overlay.TriangleSizePS->GetBufferPointer(); pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; if(pipeDesc.DepthStencilState.DepthFunc == D3D12_COMPARISON_FUNC_GREATER) pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL; if(pipeDesc.DepthStencilState.DepthFunc == D3D12_COMPARISON_FUNC_LESS) pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; // enough for all primitive topology types ID3D12PipelineState *pipes[D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH + 1] = {}; DebugVertexCBuffer vertexData = {}; vertexData.LineStrip = 0; vertexData.ModelViewProj = Matrix4f::Identity(); vertexData.SpriteSize = Vec2f(); Vec4f viewport(rs.views[0].Width, rs.views[0].Height); if(rs.dsv.ptr) { D3D12_CPU_DESCRIPTOR_HANDLE realDSV = Unwrap(rs.dsv); list->OMSetRenderTargets(1, &rtv, TRUE, &realDSV); } list->RSSetViewports(1, &rs.views[0]); D3D12_RECT scissor = {0, 0, 16384, 16384}; list->RSSetScissorRects(1, &scissor); list->SetGraphicsRootSignature(m_General.ConstOnlyRootSig); list->SetGraphicsRootConstantBufferView( 0, GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData))); list->SetGraphicsRootConstantBufferView( 1, GetDebugManager()->UploadConstants(&overdrawRamp[0].x, sizeof(overdrawRamp))); list->SetGraphicsRootConstantBufferView( 2, GetDebugManager()->UploadConstants(&viewport, sizeof(viewport))); list->SetGraphicsRoot32BitConstants(3, 4, &viewport.x, 0); for(size_t i = 0; i < events.size(); i++) { const DrawcallDescription *draw = m_pDevice->GetDrawcall(events[i]); for(uint32_t inst = 0; draw && inst < RDCMAX(1U, draw->numInstances); inst++) { MeshFormat fmt = GetPostVSBuffers(events[i], inst, MeshDataStage::GSOut); if(fmt.vertexResourceId == ResourceId()) fmt = GetPostVSBuffers(events[i], inst, MeshDataStage::VSOut); if(fmt.vertexResourceId != ResourceId()) { D3D_PRIMITIVE_TOPOLOGY topo = MakeD3DPrimitiveTopology(fmt.topology); if(topo == D3D_PRIMITIVE_TOPOLOGY_POINTLIST || topo >= D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST) pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; else if(topo == D3D_PRIMITIVE_TOPOLOGY_LINESTRIP || topo == D3D_PRIMITIVE_TOPOLOGY_LINELIST || topo == D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ || topo == D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ) pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; else pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; list->IASetPrimitiveTopology(topo); if(pipes[pipeDesc.PrimitiveTopologyType] == NULL) { HRESULT hr = m_pDevice->CreateGraphicsPipelineState( &pipeDesc, __uuidof(ID3D12PipelineState), (void **)&pipes[pipeDesc.PrimitiveTopologyType]); RDCASSERTEQUAL(hr, S_OK); } ID3D12Resource *vb = m_pDevice->GetResourceManager()->GetCurrentAs<ID3D12Resource>(fmt.vertexResourceId); D3D12_VERTEX_BUFFER_VIEW vbView = {}; vbView.BufferLocation = vb->GetGPUVirtualAddress() + fmt.vertexByteOffset; vbView.StrideInBytes = fmt.vertexByteStride; vbView.SizeInBytes = UINT(vb->GetDesc().Width - fmt.vertexByteOffset); // second bind is just a dummy, so we don't have to make a shader // that doesn't accept the secondary stream list->IASetVertexBuffers(0, 1, &vbView); list->IASetVertexBuffers(1, 1, &vbView); list->SetPipelineState(pipes[pipeDesc.PrimitiveTopologyType]); if(fmt.indexByteStride && fmt.indexResourceId != ResourceId()) { ID3D12Resource *ib = m_pDevice->GetResourceManager()->GetCurrentAs<ID3D12Resource>(fmt.indexResourceId); D3D12_INDEX_BUFFER_VIEW view; view.BufferLocation = ib->GetGPUVirtualAddress() + fmt.indexByteOffset; view.SizeInBytes = UINT(ib->GetDesc().Width - fmt.indexByteOffset); view.Format = fmt.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; list->IASetIndexBuffer(&view); list->DrawIndexedInstanced(fmt.numIndices, 1, 0, fmt.baseVertex, 0); } else { list->DrawInstanced(fmt.numIndices, 1, 0, 0); } } } } list->Close(); list = NULL; m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); for(size_t i = 0; i < ARRAY_COUNT(pipes); i++) SAFE_RELEASE(pipes[i]); } // restore back to normal m_pDevice->ReplayLog(0, eventId, eReplay_WithoutDraw); } else if(overlay == DebugOverlay::QuadOverdrawPass || overlay == DebugOverlay::QuadOverdrawDraw) { SCOPED_TIMER("Quad Overdraw"); vector<uint32_t> events = passEvents; if(overlay == DebugOverlay::QuadOverdrawDraw) events.clear(); events.push_back(eventId); if(!events.empty()) { if(overlay == DebugOverlay::QuadOverdrawPass) { list->Close(); m_pDevice->ReplayLog(0, events[0], eReplay_WithoutDraw); list = m_pDevice->GetNewList(); } uint32_t width = uint32_t(resourceDesc.Width >> 1); uint32_t height = resourceDesc.Height >> 1; width = RDCMAX(1U, width); height = RDCMAX(1U, height); D3D12_RESOURCE_DESC uavTexDesc = {}; uavTexDesc.Alignment = 0; uavTexDesc.DepthOrArraySize = 4; uavTexDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; uavTexDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; uavTexDesc.Format = DXGI_FORMAT_R32_UINT; uavTexDesc.Height = height; uavTexDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; uavTexDesc.MipLevels = 1; uavTexDesc.SampleDesc.Count = 1; uavTexDesc.SampleDesc.Quality = 0; uavTexDesc.Width = width; ID3D12Resource *overdrawTex = NULL; HRESULT hr = m_pDevice->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &uavTexDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, __uuidof(ID3D12Resource), (void **)&overdrawTex); if(FAILED(hr)) { RDCERR("Failed to create overdrawTex HRESULT: %s", ToStr(hr).c_str()); list->Close(); list = NULL; return m_Overlay.resourceId; } m_pDevice->CreateShaderResourceView(overdrawTex, NULL, GetDebugManager()->GetCPUHandle(OVERDRAW_SRV)); m_pDevice->CreateUnorderedAccessView(overdrawTex, NULL, NULL, GetDebugManager()->GetCPUHandle(OVERDRAW_UAV)); m_pDevice->CreateUnorderedAccessView(overdrawTex, NULL, NULL, GetDebugManager()->GetUAVClearHandle(OVERDRAW_UAV)); UINT zeroes[4] = {0, 0, 0, 0}; list->ClearUnorderedAccessViewUint(GetDebugManager()->GetGPUHandle(OVERDRAW_UAV), GetDebugManager()->GetUAVClearHandle(OVERDRAW_UAV), overdrawTex, zeroes, 0, NULL); list->Close(); list = NULL; #if ENABLED(SINGLE_FLUSH_VALIDATE) m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); #endif m_pDevice->ReplayLog(0, events[0], eReplay_WithoutDraw); D3D12_SHADER_BYTECODE quadWrite; quadWrite.BytecodeLength = m_Overlay.QuadOverdrawWritePS->GetBufferSize(); quadWrite.pShaderBytecode = m_Overlay.QuadOverdrawWritePS->GetBufferPointer(); // declare callback struct here D3D12QuadOverdrawCallback cb(m_pDevice, quadWrite, events, ToPortableHandle(GetDebugManager()->GetCPUHandle(OVERDRAW_UAV))); m_pDevice->ReplayLog(events.front(), events.back(), eReplay_Full); // resolve pass { list = m_pDevice->GetNewList(); D3D12_RESOURCE_BARRIER overdrawBarriers[2] = {}; // make sure UAV work is done then prepare for reading in PS overdrawBarriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; overdrawBarriers[0].UAV.pResource = overdrawTex; overdrawBarriers[1].Transition.pResource = overdrawTex; overdrawBarriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; overdrawBarriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; overdrawBarriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; // prepare tex resource for copying list->ResourceBarrier(2, overdrawBarriers); list->OMSetRenderTargets(1, &rtv, TRUE, NULL); list->RSSetViewports(1, &rs.views[0]); D3D12_RECT scissor = {0, 0, 16384, 16384}; list->RSSetScissorRects(1, &scissor); list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); list->SetPipelineState(m_Overlay.QuadResolvePipe); list->SetGraphicsRootSignature(m_Overlay.QuadResolveRootSig); GetDebugManager()->SetDescriptorHeaps(list, true, false); list->SetGraphicsRootConstantBufferView( 0, GetDebugManager()->UploadConstants(&overdrawRamp[0].x, sizeof(overdrawRamp))); list->SetGraphicsRootDescriptorTable(1, GetDebugManager()->GetGPUHandle(OVERDRAW_SRV)); list->DrawInstanced(3, 1, 0, 0); list->Close(); list = NULL; } m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); for(auto it = cb.m_PipelineCache.begin(); it != cb.m_PipelineCache.end(); ++it) { SAFE_RELEASE(it->second.pipe); SAFE_RELEASE(it->second.sig); } SAFE_RELEASE(overdrawTex); } if(overlay == DebugOverlay::QuadOverdrawPass) m_pDevice->ReplayLog(0, eventId, eReplay_WithoutDraw); }
void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists( UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists) { ID3D12CommandList **unwrapped = m_pDevice->GetTempArray<ID3D12CommandList *>(NumCommandLists); for(UINT i = 0; i < NumCommandLists; i++) unwrapped[i] = Unwrap(ppCommandLists[i]); m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped); if(m_State >= WRITING) { SCOPED_LOCK(m_Lock); SCOPED_LOCK(m_pDevice->GetCapTransitionLock()); bool capframe = (m_State == WRITING_CAPFRAME); set<ResourceId> refdIDs; for(UINT i = 0; i < NumCommandLists; i++) { D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]); if(record->ContainsExecuteIndirect) m_QueueRecord->ContainsExecuteIndirect = true; m_pDevice->ApplyBarriers(record->bakedCommands->cmdInfo->barriers); // need to lock the whole section of code, not just the check on // m_State, as we also need to make sure we don't check the state, // start marking dirty resources then while we're doing so the // state becomes capframe. // the next sections where we mark resources referenced and add // the submit chunk to the frame record don't have to be protected. // Only the decision of whether we're inframe or not, and marking // dirty. if(capframe) { for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) GetResourceManager()->MarkPendingDirty(*it); } else { for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) GetResourceManager()->MarkDirtyResource(*it); } if(capframe) { // any descriptor copies or writes could reference new resources not in the // bound descs list yet. So we take all of those referenced descriptors and // include them to see if we need to flush std::vector<D3D12Descriptor> dynDescRefs; m_pDevice->GetDynamicDescriptorReferences(dynDescRefs); for(size_t d = 0; d < dynDescRefs.size(); d++) { ResourceId id, id2; FrameRefType ref = eFrameRef_Read; dynDescRefs[d].GetRefIDs(id, id2, ref); if(id != ResourceId()) { refdIDs.insert(id); GetResourceManager()->MarkResourceFrameReferenced(id, ref); } if(id2 != ResourceId()) { refdIDs.insert(id2); GetResourceManager()->MarkResourceFrameReferenced(id2, ref); } } // for each bound descriptor table, mark it referenced as well as all resources currently // bound to it for(auto it = record->bakedCommands->cmdInfo->boundDescs.begin(); it != record->bakedCommands->cmdInfo->boundDescs.end(); ++it) { D3D12Descriptor *desc = *it; ResourceId id, id2; FrameRefType ref = eFrameRef_Read; desc->GetRefIDs(id, id2, ref); if(id != ResourceId()) { refdIDs.insert(id); GetResourceManager()->MarkResourceFrameReferenced(id, ref); } if(id2 != ResourceId()) { refdIDs.insert(id2); GetResourceManager()->MarkResourceFrameReferenced(id2, ref); } } // pull in frame refs from this baked command list record->bakedCommands->AddResourceReferences(GetResourceManager()); record->bakedCommands->AddReferencedIDs(refdIDs); // reference all executed bundles as well for(size_t b = 0; b < record->bakedCommands->cmdInfo->bundles.size(); b++) { record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddResourceReferences( GetResourceManager()); record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddReferencedIDs(refdIDs); GetResourceManager()->MarkResourceFrameReferenced( record->bakedCommands->cmdInfo->bundles[b]->GetResourceID(), eFrameRef_Read); record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddRef(); } { m_CmdListRecords.push_back(record->bakedCommands); for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->bundles.size(); sub++) m_CmdListRecords.push_back(record->bakedCommands->cmdInfo->bundles[sub]->bakedCommands); } record->bakedCommands->AddRef(); } record->cmdInfo->dirtied.clear(); } if(capframe) { vector<MapState> maps = m_pDevice->GetMaps(); for(auto it = maps.begin(); it != maps.end(); ++it) { WrappedID3D12Resource *res = it->res; UINT subres = it->subres; size_t size = (size_t)it->totalSize; // only need to flush memory that could affect this submitted batch of work if(refdIDs.find(res->GetResourceID()) == refdIDs.end()) { RDCDEBUG("Map of memory %llu not referenced in this queue - not flushing", res->GetResourceID()); continue; } size_t diffStart = 0, diffEnd = 0; bool found = true; byte *ref = res->GetShadow(subres); byte *data = res->GetMap(subres); if(ref) found = FindDiffRange(data, ref, size, diffStart, diffEnd); else diffEnd = size; if(found) { RDCLOG("Persistent map flush forced for %llu (%llu -> %llu)", res->GetResourceID(), (uint64_t)diffStart, (uint64_t)diffEnd); D3D12_RANGE range = {diffStart, diffEnd}; m_pDevice->MapDataWrite(res, subres, data, range); if(ref == NULL) { res->AllocShadow(subres, size); ref = res->GetShadow(subres); } // update comparison shadow for next time memcpy(ref, res->GetMap(subres), size); GetResourceManager()->MarkPendingDirty(res->GetResourceID()); } else { RDCDEBUG("Persistent map flush not needed for %llu", res->GetResourceID()); } } for(UINT i = 0; i < NumCommandLists; i++) { SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LISTS); Serialise_ExecuteCommandLists(1, ppCommandLists + i); m_QueueRecord->AddChunk(scope.Get()); } } } }
HRESULT WrappedID3D12Device::CreatePlacedResource(ID3D12Heap *pHeap, UINT64 HeapOffset, const D3D12_RESOURCE_DESC *pDesc, D3D12_RESOURCE_STATES InitialState, const D3D12_CLEAR_VALUE *pOptimizedClearValue, REFIID riid, void **ppvResource) { if(ppvResource == NULL) return m_pDevice->CreatePlacedResource(Unwrap(pHeap), HeapOffset, pDesc, InitialState, pOptimizedClearValue, riid, NULL); if(riid != __uuidof(ID3D12Resource)) return E_NOINTERFACE; ID3D12Resource *real = NULL; HRESULT ret = m_pDevice->CreatePlacedResource(Unwrap(pHeap), HeapOffset, pDesc, InitialState, pOptimizedClearValue, riid, (void **)&real); if(SUCCEEDED(ret)) { SCOPED_LOCK(m_D3DLock); WrappedID3D12Resource *wrapped = new WrappedID3D12Resource(real, this); if(m_State >= WRITING) { SCOPED_SERIALISE_CONTEXT(CREATE_PLACED_RESOURCE); Serialise_CreatePlacedResource(pHeap, HeapOffset, pDesc, InitialState, pOptimizedClearValue, riid, (void **)&wrapped); D3D12ResourceRecord *record = GetResourceManager()->AddResourceRecord(wrapped->GetResourceID()); record->type = Resource_Resource; record->Length = 0; wrapped->SetResourceRecord(record); RDCASSERT(pHeap); record->AddParent(GetRecord(pHeap)); record->AddChunk(scope.Get()); { SCOPED_LOCK(m_CapTransitionLock); if(m_State != WRITING_CAPFRAME) GetResourceManager()->MarkDirtyResource(wrapped->GetResourceID()); else GetResourceManager()->MarkPendingDirty(wrapped->GetResourceID()); } } else { GetResourceManager()->AddLiveResource(wrapped->GetResourceID(), wrapped); } { SCOPED_LOCK(m_ResourceStatesLock); SubresourceStateVector &states = m_ResourceStates[wrapped->GetResourceID()]; states.resize(GetNumSubresources(pDesc), InitialState); } *ppvResource = (ID3D12Resource *)wrapped; } return ret; }