~RawResource() { if (m_owned && p_resource) { p_resource->Release(); } }
ID3D12Resource* RenderAPI_D3D12::GetUploadResource(UINT64 size) { if (s_D3D12Upload) { D3D12_RESOURCE_DESC desc = s_D3D12Upload->GetDesc(); if (desc.Width == size) return s_D3D12Upload; else s_D3D12Upload->Release(); } // Texture upload buffer 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 = kNodeMask; heapProps.VisibleNodeMask = kNodeMask; D3D12_RESOURCE_DESC heapDesc = {}; heapDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; heapDesc.Alignment = 0; heapDesc.Width = size; heapDesc.Height = 1; heapDesc.DepthOrArraySize = 1; heapDesc.MipLevels = 1; heapDesc.Format = DXGI_FORMAT_UNKNOWN; heapDesc.SampleDesc.Count = 1; heapDesc.SampleDesc.Quality = 0; heapDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; heapDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Device* device = s_D3D12->GetDevice(); HRESULT hr = device->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &heapDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&s_D3D12Upload)); if (FAILED(hr)) { OutputDebugStringA("Failed to CreateCommittedResource.\n"); } return s_D3D12Upload; }
void FD3D12DynamicRHI::UnlockBuffer(FRHICommandListImmediate* RHICmdList, BufferType* Buffer) { // Find the outstanding lock for this Buffer. FD3D12LockedKey LockedKey(Buffer); FD3D12LockedData* LockedData = FindInOutstandingLocks(LockedKey); check(LockedData); // Determine whether the buffer is dynamic or not. const bool bIsDynamic = (Buffer->GetUsage() & BUF_AnyDynamic) ? true : false; if (bIsDynamic) { // If the Buffer is dynamic, its upload heap memory can always stay mapped. Don't do anything. } else { // If the static Buffer lock involved a staging resource, it was locked for reading. if (LockedData->StagingResource) { // Unmap the staging buffer's memory. ID3D12Resource* StagingBuffer = LockedData->StagingResource.GetReference()->GetResource(); StagingBuffer->Unmap(0, nullptr); } else { // Copy the contents of the temporary memory buffer allocated for writing into the Buffer. FD3D12ResourceLocation* UploadHeapLocation = LockedData->UploadHeapLocation.GetReference(); // If we are on the render thread, queue up the copy on the RHIThread so it happens at the correct time. if (ShouldDeferBufferLockOperation(RHICmdList)) { new (RHICmdList->AllocCommand<FRHICommandUpdateBuffer>()) FRHICommandUpdateBuffer(Buffer->ResourceLocation, UploadHeapLocation, LockedData->Pitch); } else { UpdateBuffer(Buffer->ResourceLocation->GetResource(), Buffer->ResourceLocation->GetOffset(), UploadHeapLocation->GetResource(), UploadHeapLocation->GetOffset(), LockedData->Pitch); } } } // Remove the FD3D12LockedData from the lock map. // If the lock involved a staging resource, this releases it. RemoveFromOutstandingLocks(LockedKey); }
LinearAllocationPage* LinearAllocatorPageManager::CreateNewPage( void ) { D3D12_HEAP_PROPERTIES HeapProps; HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; HeapProps.CreationNodeMask = 1; HeapProps.VisibleNodeMask = 1; D3D12_RESOURCE_DESC ResourceDesc; ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; ResourceDesc.Alignment = 0; ResourceDesc.Height = 1; ResourceDesc.DepthOrArraySize = 1; ResourceDesc.MipLevels = 1; ResourceDesc.Format = DXGI_FORMAT_UNKNOWN; ResourceDesc.SampleDesc.Count = 1; ResourceDesc.SampleDesc.Quality = 0; ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; D3D12_RESOURCE_STATES DefaultUsage; if (m_AllocationType == kGpuExclusive) { HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT; ResourceDesc.Width = kGpuAllocatorPageSize; ResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; DefaultUsage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } else { HeapProps.Type = D3D12_HEAP_TYPE_UPLOAD; ResourceDesc.Width = kCpuAllocatorPageSize; ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; DefaultUsage = D3D12_RESOURCE_STATE_GENERIC_READ; } ID3D12Resource* pBuffer; ASSERT_SUCCEEDED( g_Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &ResourceDesc, DefaultUsage, nullptr, MY_IID_PPV_ARGS(&pBuffer)) ); pBuffer->SetName(L"LinearAllocator Page"); return new LinearAllocationPage(pBuffer, DefaultUsage); }
void* RenderAPI_D3D12::BeginModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int* outRowPitch) { ID3D12Fence* fence = s_D3D12->GetFrameFence(); // Wait on the previous job (example only - simplifies resource management) if (fence->GetCompletedValue() < s_D3D12FenceValue) { fence->SetEventOnCompletion(s_D3D12FenceValue, s_D3D12Event); WaitForSingleObject(s_D3D12Event, INFINITE); } // Begin a command list s_D3D12CmdAlloc->Reset(); s_D3D12CmdList->Reset(s_D3D12CmdAlloc, nullptr); // Fill data const UINT64 kDataSize = textureWidth * textureHeight * 4; ID3D12Resource* upload = GetUploadResource(kDataSize); void* mapped = NULL; upload->Map(0, NULL, &mapped); *outRowPitch = textureWidth * 4; return mapped; }
void RenderAPI_D3D12::EndModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int rowPitch, void* dataPtr) { ID3D12Device* device = s_D3D12->GetDevice(); const UINT64 kDataSize = textureWidth * textureHeight * 4; ID3D12Resource* upload = GetUploadResource(kDataSize); upload->Unmap(0, NULL); ID3D12Resource* resource = (ID3D12Resource*)textureHandle; D3D12_RESOURCE_DESC desc = resource->GetDesc(); assert(desc.Width == textureWidth); assert(desc.Height == textureHeight); D3D12_TEXTURE_COPY_LOCATION srcLoc = {}; srcLoc.pResource = upload; srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; device->GetCopyableFootprints(&desc, 0, 1, 0, &srcLoc.PlacedFootprint, nullptr, nullptr, nullptr); D3D12_TEXTURE_COPY_LOCATION dstLoc = {}; dstLoc.pResource = resource; dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dstLoc.SubresourceIndex = 0; // We inform Unity that we expect this resource to be in D3D12_RESOURCE_STATE_COPY_DEST state, // and because we do not barrier it ourselves, we tell Unity that no changes are done on our command list. UnityGraphicsD3D12ResourceState resourceState = {}; resourceState.resource = resource; resourceState.expected = D3D12_RESOURCE_STATE_COPY_DEST; resourceState.current = D3D12_RESOURCE_STATE_COPY_DEST; // Queue data upload s_D3D12CmdList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); // Execute the command list s_D3D12CmdList->Close(); s_D3D12FenceValue = s_D3D12->ExecuteCommandList(s_D3D12CmdList, 1, &resourceState); }
void D3D12GSRender::load_program() { auto rtt_lookup_func = [this](u32 texaddr, rsx::fragment_texture&, bool is_depth) -> std::tuple<bool, u16> { ID3D12Resource *surface = nullptr; if (!is_depth) surface = m_rtts.get_texture_from_render_target_if_applicable(texaddr); else surface = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr); if (!surface) return std::make_tuple(false, 0); D3D12_RESOURCE_DESC desc = surface->GetDesc(); u16 native_pitch = get_dxgi_texel_size(desc.Format) * (u16)desc.Width; return std::make_tuple(true, native_pitch); }; get_current_vertex_program({}, true); get_current_fragment_program_legacy(rtt_lookup_func); if (!current_fragment_program.valid) return; D3D12PipelineProperties prop = {}; prop.Topology = get_primitive_topology_type(rsx::method_registers.current_draw_clause.primitive); static D3D12_BLEND_DESC CD3D12_BLEND_DESC = { FALSE, FALSE, { FALSE,FALSE, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_LOGIC_OP_NOOP, D3D12_COLOR_WRITE_ENABLE_ALL, } }; prop.Blend = CD3D12_BLEND_DESC; if (rsx::method_registers.blend_enabled()) { //We can use the d3d blend factor as long as !(rgb_factor == alpha && a_factor == color) rsx::blend_factor sfactor_rgb = rsx::method_registers.blend_func_sfactor_rgb(); rsx::blend_factor dfactor_rgb = rsx::method_registers.blend_func_dfactor_rgb(); rsx::blend_factor sfactor_a = rsx::method_registers.blend_func_sfactor_a(); rsx::blend_factor dfactor_a = rsx::method_registers.blend_func_dfactor_a(); D3D12_BLEND d3d_sfactor_rgb = get_blend_factor(sfactor_rgb); D3D12_BLEND d3d_dfactor_rgb = get_blend_factor(dfactor_rgb);; D3D12_BLEND d3d_sfactor_alpha = get_blend_factor_alpha(sfactor_a); D3D12_BLEND d3d_dfactor_alpha = get_blend_factor_alpha(dfactor_a); auto BlendColor = rsx::get_constant_blend_colors(); bool color_blend_possible = true; if (sfactor_rgb == rsx::blend_factor::constant_alpha || dfactor_rgb == rsx::blend_factor::constant_alpha) { if (sfactor_rgb == rsx::blend_factor::constant_color || dfactor_rgb == rsx::blend_factor::constant_color) { //Color information will be destroyed color_blend_possible = false; } else { //All components are alpha. //If an alpha factor refers to constant_color, it only refers to the alpha component, so no need to replace it BlendColor[0] = BlendColor[1] = BlendColor[2] = BlendColor[3]; } } if (!color_blend_possible) { LOG_ERROR(RSX, "The constant_color blend factor combination defined is not supported"); auto flatten_d3d12_factor = [](D3D12_BLEND in) -> D3D12_BLEND { switch (in) { case D3D12_BLEND_BLEND_FACTOR: return D3D12_BLEND_ONE; case D3D12_BLEND_INV_BLEND_FACTOR: return D3D12_BLEND_ZERO; } LOG_ERROR(RSX, "No suitable conversion defined for blend factor 0x%X" HERE, (u32)in); return in; }; d3d_sfactor_rgb = flatten_d3d12_factor(d3d_sfactor_rgb); d3d_dfactor_rgb = flatten_d3d12_factor(d3d_dfactor_rgb);; d3d_sfactor_alpha = flatten_d3d12_factor(d3d_sfactor_alpha); d3d_dfactor_alpha = flatten_d3d12_factor(d3d_dfactor_alpha); } else { get_current_resource_storage().command_list->OMSetBlendFactor(BlendColor.data()); } prop.Blend.RenderTarget[0].BlendEnable = true; if (rsx::method_registers.blend_enabled_surface_1()) prop.Blend.RenderTarget[1].BlendEnable = true; if (rsx::method_registers.blend_enabled_surface_2()) prop.Blend.RenderTarget[2].BlendEnable = true; if (rsx::method_registers.blend_enabled_surface_3()) prop.Blend.RenderTarget[3].BlendEnable = true; prop.Blend.RenderTarget[0].BlendOp = get_blend_op(rsx::method_registers.blend_equation_rgb()); prop.Blend.RenderTarget[0].BlendOpAlpha = get_blend_op(rsx::method_registers.blend_equation_a()); if (rsx::method_registers.blend_enabled_surface_1()) { prop.Blend.RenderTarget[1].BlendOp = get_blend_op(rsx::method_registers.blend_equation_rgb()); prop.Blend.RenderTarget[1].BlendOpAlpha = get_blend_op(rsx::method_registers.blend_equation_a()); } if (rsx::method_registers.blend_enabled_surface_2()) { prop.Blend.RenderTarget[2].BlendOp = get_blend_op(rsx::method_registers.blend_equation_rgb()); prop.Blend.RenderTarget[2].BlendOpAlpha = get_blend_op(rsx::method_registers.blend_equation_a()); } if (rsx::method_registers.blend_enabled_surface_3()) { prop.Blend.RenderTarget[3].BlendOp = get_blend_op(rsx::method_registers.blend_equation_rgb()); prop.Blend.RenderTarget[3].BlendOpAlpha = get_blend_op(rsx::method_registers.blend_equation_a()); } prop.Blend.RenderTarget[0].SrcBlend = d3d_sfactor_rgb; prop.Blend.RenderTarget[0].DestBlend = d3d_dfactor_rgb; prop.Blend.RenderTarget[0].SrcBlendAlpha = d3d_sfactor_alpha; prop.Blend.RenderTarget[0].DestBlendAlpha = d3d_dfactor_alpha; if (rsx::method_registers.blend_enabled_surface_1()) { prop.Blend.RenderTarget[1].SrcBlend = d3d_sfactor_rgb; prop.Blend.RenderTarget[1].DestBlend = d3d_dfactor_rgb; prop.Blend.RenderTarget[1].SrcBlendAlpha = d3d_sfactor_alpha; prop.Blend.RenderTarget[1].DestBlendAlpha = d3d_dfactor_alpha; } if (rsx::method_registers.blend_enabled_surface_2()) { prop.Blend.RenderTarget[2].SrcBlend = d3d_sfactor_rgb; prop.Blend.RenderTarget[2].DestBlend = d3d_dfactor_rgb; prop.Blend.RenderTarget[2].SrcBlendAlpha = d3d_sfactor_alpha; prop.Blend.RenderTarget[2].DestBlendAlpha = d3d_dfactor_alpha; } if (rsx::method_registers.blend_enabled_surface_3()) { prop.Blend.RenderTarget[3].SrcBlend = d3d_sfactor_rgb; prop.Blend.RenderTarget[3].DestBlend = d3d_dfactor_rgb; prop.Blend.RenderTarget[3].SrcBlendAlpha = d3d_sfactor_alpha; prop.Blend.RenderTarget[3].DestBlendAlpha = d3d_dfactor_alpha; } } if (rsx::method_registers.logic_op_enabled()) { prop.Blend.RenderTarget[0].LogicOpEnable = true; prop.Blend.RenderTarget[0].LogicOp = get_logic_op(rsx::method_registers.logic_operation()); } prop.DepthStencilFormat = get_depth_stencil_surface_format(rsx::method_registers.surface_depth_fmt()); prop.RenderTargetsFormat = get_color_surface_format(rsx::method_registers.surface_color()); switch (rsx::method_registers.surface_color_target()) { case rsx::surface_target::surface_a: case rsx::surface_target::surface_b: prop.numMRT = 1; break; case rsx::surface_target::surfaces_a_b: prop.numMRT = 2; break; case rsx::surface_target::surfaces_a_b_c: prop.numMRT = 3; break; case rsx::surface_target::surfaces_a_b_c_d: prop.numMRT = 4; break; default: break; } if (rsx::method_registers.depth_test_enabled()) { prop.DepthStencil.DepthEnable = TRUE; prop.DepthStencil.DepthFunc = get_compare_func(rsx::method_registers.depth_func()); } else prop.DepthStencil.DepthEnable = FALSE; prop.DepthStencil.DepthWriteMask = rsx::method_registers.depth_write_enabled() ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; if (rsx::method_registers.stencil_test_enabled()) { prop.DepthStencil.StencilEnable = TRUE; prop.DepthStencil.StencilReadMask = rsx::method_registers.stencil_func_mask(); prop.DepthStencil.StencilWriteMask = rsx::method_registers.stencil_mask(); prop.DepthStencil.FrontFace.StencilPassOp = get_stencil_op(rsx::method_registers.stencil_op_zpass()); prop.DepthStencil.FrontFace.StencilDepthFailOp = get_stencil_op(rsx::method_registers.stencil_op_zfail()); prop.DepthStencil.FrontFace.StencilFailOp = get_stencil_op(rsx::method_registers.stencil_op_fail()); prop.DepthStencil.FrontFace.StencilFunc = get_compare_func(rsx::method_registers.stencil_func()); if (rsx::method_registers.two_sided_stencil_test_enabled()) { prop.DepthStencil.BackFace.StencilFailOp = get_stencil_op(rsx::method_registers.back_stencil_op_fail()); prop.DepthStencil.BackFace.StencilFunc = get_compare_func(rsx::method_registers.back_stencil_func()); prop.DepthStencil.BackFace.StencilPassOp = get_stencil_op(rsx::method_registers.back_stencil_op_zpass()); prop.DepthStencil.BackFace.StencilDepthFailOp = get_stencil_op(rsx::method_registers.back_stencil_op_zfail()); } else { prop.DepthStencil.BackFace.StencilPassOp = get_stencil_op(rsx::method_registers.stencil_op_zpass()); prop.DepthStencil.BackFace.StencilDepthFailOp = get_stencil_op(rsx::method_registers.stencil_op_zfail()); prop.DepthStencil.BackFace.StencilFailOp = get_stencil_op(rsx::method_registers.stencil_op_fail()); prop.DepthStencil.BackFace.StencilFunc = get_compare_func(rsx::method_registers.stencil_func()); } } // Sensible default value static D3D12_RASTERIZER_DESC CD3D12_RASTERIZER_DESC = { D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, FALSE, D3D12_DEFAULT_DEPTH_BIAS, D3D12_DEFAULT_DEPTH_BIAS_CLAMP, D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS, TRUE, FALSE, FALSE, 0, D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF, }; prop.Rasterization = CD3D12_RASTERIZER_DESC; prop.Rasterization.DepthClipEnable = rsx::method_registers.depth_clip_enabled(); if (rsx::method_registers.cull_face_enabled()) { prop.Rasterization.CullMode = get_cull_face(rsx::method_registers.cull_face_mode()); } prop.Rasterization.FrontCounterClockwise = get_front_face_ccw(rsx::method_registers.front_face_mode()); UINT8 mask = 0; mask |= rsx::method_registers.color_mask_r() ? D3D12_COLOR_WRITE_ENABLE_RED : 0; mask |= rsx::method_registers.color_mask_g() ? D3D12_COLOR_WRITE_ENABLE_GREEN : 0; mask |= rsx::method_registers.color_mask_b() ? D3D12_COLOR_WRITE_ENABLE_BLUE : 0; mask |= rsx::method_registers.color_mask_a() ? D3D12_COLOR_WRITE_ENABLE_ALPHA : 0; for (unsigned i = 0; i < prop.numMRT; i++) prop.Blend.RenderTarget[i].RenderTargetWriteMask = mask; if (rsx::method_registers.restart_index_enabled()) { rsx::index_array_type index_type = rsx::method_registers.current_draw_clause.is_immediate_draw? rsx::index_array_type::u32: rsx::method_registers.index_type(); if (index_type == rsx::index_array_type::u32) { prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF; } if (index_type == rsx::index_array_type::u16) { prop.CutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; } } m_current_pso = m_pso_cache.get_graphics_pipeline(current_vertex_program, current_fragment_program, prop, false, m_device.Get(), m_shared_root_signature.Get()); return; }
void D3D12RenderState::ApplyState(ID3D12GraphicsCommandList *cmd) const { if(pipe != ResourceId()) cmd->SetPipelineState(GetResourceManager()->GetCurrentAs<ID3D12PipelineState>(pipe)); if(!views.empty()) cmd->RSSetViewports((UINT)views.size(), &views[0]); if(!scissors.empty()) cmd->RSSetScissorRects((UINT)scissors.size(), &scissors[0]); if(topo != D3D_PRIMITIVE_TOPOLOGY_UNDEFINED) cmd->IASetPrimitiveTopology(topo); cmd->OMSetStencilRef(stencilRef); cmd->OMSetBlendFactor(blendFactor); if(ibuffer.buf != ResourceId()) { D3D12_INDEX_BUFFER_VIEW ib; ID3D12Resource *res = GetResourceManager()->GetCurrentAs<ID3D12Resource>(ibuffer.buf); if(res) ib.BufferLocation = res->GetGPUVirtualAddress() + ibuffer.offs; else ib.BufferLocation = 0; ib.Format = (ibuffer.bytewidth == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT); ib.SizeInBytes = ibuffer.size; cmd->IASetIndexBuffer(&ib); } for(size_t i = 0; i < vbuffers.size(); i++) { D3D12_VERTEX_BUFFER_VIEW vb; ID3D12Resource *res = GetResourceManager()->GetCurrentAs<ID3D12Resource>(vbuffers[i].buf); if(res) vb.BufferLocation = res->GetGPUVirtualAddress() + vbuffers[i].offs; else vb.BufferLocation = 0; vb.StrideInBytes = vbuffers[i].stride; vb.SizeInBytes = vbuffers[i].size; cmd->IASetVertexBuffers((UINT)i, 1, &vb); } std::vector<ID3D12DescriptorHeap *> descHeaps; descHeaps.resize(heaps.size()); for(size_t i = 0; i < heaps.size(); i++) descHeaps[i] = GetResourceManager()->GetCurrentAs<ID3D12DescriptorHeap>(heaps[i]); if(!descHeaps.empty()) cmd->SetDescriptorHeaps((UINT)descHeaps.size(), &descHeaps[0]); if(!rts.empty() || dsv.heap != ResourceId()) { D3D12_CPU_DESCRIPTOR_HANDLE rtHandles[8]; D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = CPUHandleFromPortableHandle(GetResourceManager(), dsv); UINT rtCount = (UINT)rts.size(); UINT numActualHandles = rtSingle ? RDCMIN(1U, rtCount) : rtCount; for(UINT i = 0; i < numActualHandles; i++) rtHandles[i] = CPUHandleFromPortableHandle(GetResourceManager(), rts[i]); // need to unwrap here, as FromPortableHandle unwraps too. Unwrap(cmd)->OMSetRenderTargets((UINT)rts.size(), rtHandles, rtSingle ? TRUE : FALSE, dsv.heap != ResourceId() ? &dsvHandle : NULL); } if(graphics.rootsig != ResourceId()) { cmd->SetGraphicsRootSignature( GetResourceManager()->GetCurrentAs<ID3D12RootSignature>(graphics.rootsig)); ApplyGraphicsRootElements(cmd); } if(compute.rootsig != ResourceId()) { cmd->SetComputeRootSignature( GetResourceManager()->GetCurrentAs<ID3D12RootSignature>(compute.rootsig)); ApplyComputeRootElements(cmd); } }
bool D3D12ResourceManager::Serialise_InitialState(ResourceId resid, ID3D12DeviceChild *liveRes) { D3D12ResourceRecord *record = NULL; if(m_State >= WRITING) record = GetResourceRecord(resid); SERIALISE_ELEMENT(ResourceId, id, resid); SERIALISE_ELEMENT(D3D12ResourceType, type, record->type); if(m_State >= WRITING) { D3D12ResourceManager::InitialContentData initContents = GetInitialContents(id); if(type == Resource_DescriptorHeap) { D3D12Descriptor *descs = (D3D12Descriptor *)initContents.blob; uint32_t numElems = initContents.num; m_pSerialiser->SerialiseComplexArray("Descriptors", descs, numElems); } else if(type == Resource_Resource) { m_Device->ExecuteLists(); m_Device->FlushLists(); ID3D12Resource *copiedBuffer = (ID3D12Resource *)initContents.resource; if(initContents.num == 1) { copiedBuffer = (ID3D12Resource *)liveRes; } if(initContents.num == 2) { D3D12NOTIMP("Multisampled initial contents"); return true; } byte dummy[4] = {}; byte *ptr = NULL; uint64_t size = 0; HRESULT hr = E_NOINTERFACE; if(copiedBuffer) { hr = copiedBuffer->Map(0, NULL, (void **)&ptr); size = (uint64_t)copiedBuffer->GetDesc().Width; } if(FAILED(hr) || ptr == NULL) { size = 4; ptr = dummy; RDCERR("Failed to map buffer for readback! 0x%08x", hr); } m_pSerialiser->Serialise("NumBytes", size); size_t sz = (size_t)size; m_pSerialiser->SerialiseBuffer("BufferData", ptr, sz); if(SUCCEEDED(hr) && ptr) copiedBuffer->Unmap(0, NULL); return true; } else { RDCERR("Unexpected type needing an initial state serialised out: %d", type); return false; } } else { ID3D12DeviceChild *res = GetLiveResource(id); RDCASSERT(res != NULL); ResourceId liveid = GetLiveID(id); if(type == Resource_DescriptorHeap) { WrappedID3D12DescriptorHeap *heap = (WrappedID3D12DescriptorHeap *)res; uint32_t numElems = 0; D3D12Descriptor *descs = NULL; m_pSerialiser->SerialiseComplexArray("Descriptors", descs, numElems); D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc(); // this heap doesn't have to be shader visible, we just use it to copy from desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ID3D12DescriptorHeap *copyheap = NULL; HRESULT hr = m_Device->GetReal()->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)©heap); if(FAILED(hr)) { RDCERR("Failed to create CPU descriptor heap for initial state: 0x%08x", hr); return false; } copyheap = new WrappedID3D12DescriptorHeap(copyheap, m_Device, desc); D3D12_CPU_DESCRIPTOR_HANDLE handle = copyheap->GetCPUDescriptorHandleForHeapStart(); UINT increment = m_Device->GetDescriptorHandleIncrementSize(desc.Type); for(uint32_t i = 0; i < numElems; i++) { descs[i].Create(desc.Type, m_Device, handle); handle.ptr += increment; } SAFE_DELETE_ARRAY(descs); SetInitialContents(id, D3D12ResourceManager::InitialContentData(copyheap, 0, NULL)); } else if(type == Resource_Resource) { D3D12_RESOURCE_DESC resDesc = ((ID3D12Resource *)res)->GetDesc(); if(resDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && resDesc.SampleDesc.Count > 1) { D3D12NOTIMP("Multisampled initial contents"); return true; } uint64_t size = 0; m_pSerialiser->Serialise("NumBytes", size); 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 desc; desc.Alignment = 0; desc.DepthOrArraySize = 1; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Flags = D3D12_RESOURCE_FLAG_NONE; desc.Format = DXGI_FORMAT_UNKNOWN; desc.Height = 1; desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; desc.MipLevels = 1; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Width = size; ID3D12Resource *copySrc = NULL; HRESULT hr = m_Device->GetReal()->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, __uuidof(ID3D12Resource), (void **)©Src); if(FAILED(hr)) { RDCERR("Couldn't create upload buffer: 0x%08x", hr); return false; } byte *ptr = NULL; hr = copySrc->Map(0, NULL, (void **)&ptr); if(FAILED(hr)) { RDCERR("Couldn't map upload buffer: 0x%08x", hr); ptr = NULL; } size_t sz = (size_t)size; m_pSerialiser->SerialiseBuffer("BufferData", ptr, sz); if(SUCCEEDED(hr)) copySrc->Unmap(0, NULL); else SAFE_DELETE_ARRAY(ptr); SetInitialContents(id, D3D12ResourceManager::InitialContentData(copySrc, 1, NULL)); return true; } else { RDCERR("Unexpected type needing an initial state serialised in: %d", type); return false; } } return true; }
void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, InitialContentData data) { D3D12ResourceType type = IdentifyTypeByPtr(live); if(type == Resource_DescriptorHeap) { ID3D12DescriptorHeap *dstheap = (ID3D12DescriptorHeap *)live; ID3D12DescriptorHeap *srcheap = (ID3D12DescriptorHeap *)data.resource; if(srcheap) { // copy the whole heap m_Device->CopyDescriptorsSimple( srcheap->GetDesc().NumDescriptors, dstheap->GetCPUDescriptorHandleForHeapStart(), srcheap->GetCPUDescriptorHandleForHeapStart(), srcheap->GetDesc().Type); } } else if(type == Resource_Resource) { if(data.num == 1 && data.resource) { ID3D12Resource *copyDst = Unwrap((ID3D12Resource *)live); ID3D12Resource *copySrc = (ID3D12Resource *)data.resource; D3D12_HEAP_PROPERTIES heapProps = {}; copyDst->GetHeapProperties(&heapProps, NULL); // if destination is on the upload heap, it's impossible to copy via the device, // so we have to map both sides and CPU copy. if(heapProps.Type == D3D12_HEAP_TYPE_UPLOAD) { byte *src = NULL, *dst = NULL; HRESULT hr = S_OK; hr = copySrc->Map(0, NULL, (void **)&src); if(FAILED(hr)) { RDCERR("Doing CPU-side copy, couldn't map source: 0x%08x", hr); src = NULL; } if(copyDst->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { hr = copyDst->Map(0, NULL, (void **)&dst); if(FAILED(hr)) { RDCERR("Doing CPU-side copy, couldn't map source: 0x%08x", hr); dst = NULL; } if(src && dst) { memcpy(dst, src, (size_t)copySrc->GetDesc().Width); } if(dst) copyDst->Unmap(0, NULL); } else { D3D12_RESOURCE_DESC desc = copyDst->GetDesc(); 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]; UINT *numrows = new UINT[numSubresources]; UINT64 *rowsizes = new UINT64[numSubresources]; m_Device->GetCopyableFootprints(&desc, 0, numSubresources, 0, layouts, numrows, rowsizes, NULL); for(UINT i = 0; i < numSubresources; i++) { hr = copyDst->Map(i, NULL, (void **)&dst); if(FAILED(hr)) { RDCERR("Doing CPU-side copy, couldn't map source: 0x%08x", hr); dst = NULL; } if(src && dst) { byte *bufPtr = src + layouts[i].Offset; byte *texPtr = dst; for(UINT d = 0; d < layouts[i].Footprint.Depth; d++) { for(UINT r = 0; r < numrows[i]; r++) { memcpy(bufPtr, texPtr, (size_t)rowsizes[i]); bufPtr += layouts[i].Footprint.RowPitch; texPtr += rowsizes[i]; } } } if(dst) copyDst->Unmap(0, NULL); } delete[] layouts; delete[] numrows; delete[] rowsizes; } if(src) copySrc->Unmap(0, NULL); } else { ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList()); vector<D3D12_RESOURCE_BARRIER> barriers; const vector<D3D12_RESOURCE_STATES> &states = m_Device->GetSubresourceStates(GetResID(live)); barriers.reserve(states.size()); for(size_t i = 0; i < states.size(); i++) { if(states[i] & D3D12_RESOURCE_STATE_COPY_DEST) continue; D3D12_RESOURCE_BARRIER barrier; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = copyDst; barrier.Transition.Subresource = (UINT)i; barrier.Transition.StateBefore = states[i]; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; barriers.push_back(barrier); } // transition to copy dest if(!barriers.empty()) list->ResourceBarrier((UINT)barriers.size(), &barriers[0]); if(copyDst->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { list->CopyBufferRegion(copyDst, 0, copySrc, 0, copySrc->GetDesc().Width); } else { D3D12_RESOURCE_DESC desc = copyDst->GetDesc(); 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, NULL); for(UINT i = 0; i < numSubresources; i++) { D3D12_TEXTURE_COPY_LOCATION dst, src; dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dst.pResource = copyDst; dst.SubresourceIndex = i; src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; src.pResource = copySrc; src.PlacedFootprint = layouts[i]; list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL); } delete[] layouts; } // transition back to whatever it was before 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]); #if ENABLED(SINGLE_FLUSH_VALIDATE) m_Device->CloseInitialStateList(); m_Device->ExecuteLists(); m_Device->FlushLists(true); #endif } } else { RDCERR("Unexpected num or NULL resource: %d, %p", data.num, data.resource); } } else { RDCERR("Unexpected type needing an initial state created: %d", type); } }
ResourceManager::~ResourceManager() { if (m_pUpload) { WaitForGPU(); m_pUpload->Release(); m_pUpload = nullptr; } m_pDev = nullptr; CloseHandle(m_hdlFenceEvent); if (m_pFence) { m_pFence->Release(); m_pFence = nullptr; } if (m_pCmdAllocator) { m_pCmdAllocator->Release(); m_pCmdAllocator = nullptr; } if (m_pCmdList) { m_pCmdList->Release(); m_pCmdList = nullptr; } while (!m_listFileData.empty()) { unsigned char* tmp = m_listFileData.back(); if (tmp) delete[] tmp; m_listFileData.pop_back(); } while (!m_listResources.empty()) { ID3D12Resource* tex = m_listResources.back(); if (tex) tex->Release(); m_listResources.pop_back(); } if (m_pheapSampler) { m_pheapSampler->Release(); m_pheapSampler = nullptr; } if (m_pheapCBVSRVUAV) { m_pheapCBVSRVUAV->Release(); m_pheapCBVSRVUAV = nullptr; } if (m_pheapDSV) { m_pheapDSV->Release(); m_pheapDSV = nullptr; } if (m_pheapRTV) { m_pheapRTV->Release(); m_pheapRTV = nullptr; } }
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 D3D12RenderState::ApplyState(ID3D12GraphicsCommandList *cmd) { if(pipe != ResourceId()) cmd->SetPipelineState(GetResourceManager()->GetCurrentAs<ID3D12PipelineState>(pipe)); if(!views.empty()) cmd->RSSetViewports((UINT)views.size(), &views[0]); if(!scissors.empty()) cmd->RSSetScissorRects((UINT)scissors.size(), &scissors[0]); if(topo != D3D_PRIMITIVE_TOPOLOGY_UNDEFINED) cmd->IASetPrimitiveTopology(topo); cmd->OMSetStencilRef(stencilRef); cmd->OMSetBlendFactor(blendFactor); if(ibuffer.buf != ResourceId()) { D3D12_INDEX_BUFFER_VIEW ib; ID3D12Resource *res = GetResourceManager()->GetCurrentAs<ID3D12Resource>(ibuffer.buf); if(res) ib.BufferLocation = res->GetGPUVirtualAddress() + ibuffer.offs; else ib.BufferLocation = 0; ib.Format = (ibuffer.bytewidth == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT); ib.SizeInBytes = ibuffer.size; cmd->IASetIndexBuffer(&ib); } for(size_t i = 0; i < vbuffers.size(); i++) { D3D12_VERTEX_BUFFER_VIEW vb; ID3D12Resource *res = GetResourceManager()->GetCurrentAs<ID3D12Resource>(vbuffers[i].buf); if(res) vb.BufferLocation = res->GetGPUVirtualAddress() + vbuffers[i].offs; else vb.BufferLocation = 0; vb.StrideInBytes = vbuffers[i].stride; vb.SizeInBytes = vbuffers[i].size; cmd->IASetVertexBuffers((UINT)i, 1, &vb); } std::vector<ID3D12DescriptorHeap *> descHeaps; descHeaps.resize(heaps.size()); for(size_t i = 0; i < heaps.size(); i++) descHeaps[i] = GetResourceManager()->GetCurrentAs<ID3D12DescriptorHeap>(heaps[i]); if(!descHeaps.empty()) cmd->SetDescriptorHeaps((UINT)descHeaps.size(), &descHeaps[0]); if(!rts.empty() || dsv.heap != ResourceId()) { D3D12_CPU_DESCRIPTOR_HANDLE rtHandles[8]; D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = CPUHandleFromPortableHandle(GetResourceManager(), dsv); UINT numActualHandles = rtSingle ? 1 : (UINT)rts.size(); for(UINT i = 0; i < numActualHandles; i++) rtHandles[i] = CPUHandleFromPortableHandle(GetResourceManager(), rts[i]); // need to unwrap here, as FromPortableHandle unwraps too. Unwrap(cmd)->OMSetRenderTargets((UINT)rts.size(), rtHandles, rtSingle ? TRUE : FALSE, dsv.heap != ResourceId() ? &dsvHandle : NULL); } if(graphics.rootsig != ResourceId()) { cmd->SetGraphicsRootSignature( GetResourceManager()->GetCurrentAs<ID3D12RootSignature>(graphics.rootsig)); for(size_t i = 0; i < graphics.sigelems.size(); i++) { // just don't set tables that aren't in the descriptor heaps, since it's invalid and can crash // and is probably just from stale bindings that aren't going to be used if(graphics.sigelems[i].type == eRootTable || std::find(heaps.begin(), heaps.end(), graphics.sigelems[i].id) != heaps.end()) { graphics.sigelems[i].SetToGraphics(GetResourceManager(), cmd, (UINT)i); } else { RDCDEBUG("Skipping setting possibly stale graphics root table referring to heap %llu", graphics.sigelems[i].id); } } } if(compute.rootsig != ResourceId()) { cmd->SetComputeRootSignature( GetResourceManager()->GetCurrentAs<ID3D12RootSignature>(compute.rootsig)); for(size_t i = 0; i < compute.sigelems.size(); i++) { // just don't set tables that aren't in the descriptor heaps, since it's invalid and can crash // and is probably just from stale bindings that aren't going to be used if(compute.sigelems[i].type != eRootTable || std::find(heaps.begin(), heaps.end(), compute.sigelems[i].id) != heaps.end()) { compute.sigelems[i].SetToCompute(GetResourceManager(), cmd, (UINT)i); } else { RDCDEBUG("Skipping setting possibly stale compute root table referring to heap %llu", compute.sigelems[i].id); } } } }
void DepthBuffer::CreateDerivedViews( ID3D12Device* Device, DXGI_FORMAT Format ) { ID3D12Resource* Resource = m_pResource.Get(); D3D12_DEPTH_STENCIL_VIEW_DESC DSVDesc; DSVDesc.Format = GetDSVFormat( Format ); if (Resource->GetDesc().SampleDesc.Count ==1) { DSVDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; DSVDesc.Texture2D.MipSlice = 0; } else { DSVDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS; } if (m_DSVHandle[0].ptr == D3D12_GPU_VIRTUAL_ADDRESS_UNKNOWN) { m_DSVHandle[0] = Graphics::g_pDSVDescriptorHeap->Append().GetCPUHandle(); m_DSVHandle[1] = Graphics::g_pDSVDescriptorHeap->Append().GetCPUHandle(); } DSVDesc.Flags = D3D12_DSV_FLAG_NONE; Device->CreateDepthStencilView( Resource, &DSVDesc, m_DSVHandle[0] ); DSVDesc.Flags = D3D12_DSV_FLAG_READ_ONLY_DEPTH; Device->CreateDepthStencilView( Resource, &DSVDesc, m_DSVHandle[1] ); DXGI_FORMAT stencilReadFormat = GetStencilFormat( Format ); if (stencilReadFormat != DXGI_FORMAT_UNKNOWN) { if (m_DSVHandle[2].ptr == D3D12_GPU_VIRTUAL_ADDRESS_UNKNOWN) { m_DSVHandle[2] = Graphics::g_pDSVDescriptorHeap->Append().GetCPUHandle(); m_DSVHandle[3] = Graphics::g_pDSVDescriptorHeap->Append().GetCPUHandle(); } DSVDesc.Flags = D3D12_DSV_FLAG_READ_ONLY_STENCIL; Device->CreateDepthStencilView( Resource, &DSVDesc, m_DSVHandle[2] ); DSVDesc.Flags = D3D12_DSV_FLAG_READ_ONLY_DEPTH | D3D12_DSV_FLAG_READ_ONLY_STENCIL; Device->CreateDepthStencilView( Resource, &DSVDesc, m_DSVHandle[3] ); } else { m_DSVHandle[2] = m_DSVHandle[0]; m_DSVHandle[3] = m_DSVHandle[1]; } if (m_DepthSRVHandle.ptr == D3D12_GPU_VIRTUAL_ADDRESS_UNKNOWN) m_DepthSRVHandle = Graphics::g_pCSUDescriptorHeap->Append().GetCPUHandle(); D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {}; SRVDesc.Format = GetDepthFormat( Format ); if (DSVDesc.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE2D) { SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; SRVDesc.Texture2D.MipLevels = 1; } else { SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS; } SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; Device->CreateShaderResourceView( Resource, &SRVDesc, m_DepthSRVHandle ); if (stencilReadFormat != DXGI_FORMAT_UNKNOWN) { if (m_StencilSRVHandle.ptr == D3D12_GPU_VIRTUAL_ADDRESS_UNKNOWN) { m_StencilSRVHandle = Graphics::g_pCSUDescriptorHeap->Append().GetCPUHandle(); } SRVDesc.Format = stencilReadFormat; Device->CreateShaderResourceView( Resource, &SRVDesc, m_StencilSRVHandle ); } }
~HandledResource() { resource->Release(); }
vector<CounterResult> D3D12Replay::FetchCounters(const vector<uint32_t> &counters) { uint32_t maxEID = m_pDevice->GetQueue()->GetMaxEID(); vector<CounterResult> ret; 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.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; bufDesc.Alignment = 0; bufDesc.Width = sizeof(uint64_t) * maxEID * 2; bufDesc.Height = 1; bufDesc.DepthOrArraySize = 1; bufDesc.MipLevels = 1; bufDesc.Format = DXGI_FORMAT_UNKNOWN; bufDesc.SampleDesc.Count = 1; bufDesc.SampleDesc.Quality = 0; bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; bufDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Resource *readbackBuf; HRESULT hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource), (void **)&readbackBuf); if(FAILED(hr)) { RDCERR("Failed to create query readback buffer %08x", hr); return ret; } D3D12_QUERY_HEAP_DESC queryDesc; queryDesc.Count = maxEID * 2; queryDesc.NodeMask = 1; queryDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP; ID3D12QueryHeap *queryHeap = NULL; hr = m_pDevice->CreateQueryHeap(&queryDesc, __uuidof(queryHeap), (void **)&queryHeap); if(FAILED(hr)) { RDCERR("Failed to create query heap %08x", hr); return ret; } m_pDevice->SetStablePowerState(TRUE); D3D12GPUTimerCallback cb(m_pDevice, this, queryHeap); // replay the events to perform all the queries m_pDevice->ReplayLog(0, maxEID, eReplay_Full); m_pDevice->SetStablePowerState(FALSE); ID3D12GraphicsCommandList *list = m_pDevice->GetNewList(); list->ResolveQueryData(queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, maxEID * 2, readbackBuf, 0); list->Close(); m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); D3D12_RANGE range = {0, (SIZE_T)bufDesc.Width}; void *data; hr = readbackBuf->Map(0, &range, &data); if(FAILED(hr)) { RDCERR("Failed to create query heap %08x", hr); SAFE_RELEASE(queryHeap); SAFE_RELEASE(readbackBuf); return ret; } uint64_t *timestamps = (uint64_t *)data; uint64_t freq; m_pDevice->GetQueue()->GetTimestampFrequency(&freq); for(size_t i = 0; i < cb.m_Results.size(); i++) { CounterResult result; uint64_t delta = timestamps[i * 2 + 1] - timestamps[i * 2 + 0]; result.eventID = cb.m_Results[i]; result.counterID = eCounter_EventGPUDuration; result.value.d = double(delta) / double(freq); ret.push_back(result); } for(size_t i = 0; i < cb.m_AliasEvents.size(); i++) { CounterResult search; search.counterID = eCounter_EventGPUDuration; search.eventID = cb.m_AliasEvents[i].first; // find the result we're aliasing auto it = std::find(ret.begin(), ret.end(), search); RDCASSERT(it != ret.end()); // duplicate the result and append CounterResult aliased = *it; aliased.eventID = cb.m_AliasEvents[i].second; ret.push_back(aliased); } // sort so that the alias results appear in the right places std::sort(ret.begin(), ret.end()); return ret; }
void ParticleEffects::Initialize( uint32_t MaxDisplayWidth, uint32_t MaxDisplayHeight ) { D3D12_SAMPLER_DESC SamplerBilinearBorderDesc = SamplerPointBorderDesc; SamplerBilinearBorderDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT; RootSig.Reset(5, 3); RootSig.InitStaticSampler(0, SamplerBilinearBorderDesc); RootSig.InitStaticSampler(1, SamplerPointBorderDesc); RootSig.InitStaticSampler(2, SamplerPointClampDesc); RootSig[0].InitAsConstants(0, 3); RootSig[1].InitAsConstantBuffer(1); RootSig[2].InitAsConstantBuffer(2); RootSig[3].InitAsDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, 8); RootSig[4].InitAsDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 10); RootSig.Finalize(); #define CreatePSO( ObjName, ShaderByteCode ) \ ObjName.SetRootSignature(RootSig); \ ObjName.SetComputeShader(ShaderByteCode, sizeof(ShaderByteCode) ); \ ObjName.Finalize(); CreatePSO(s_ParticleSpawnCS, g_pParticleSpawnCS); CreatePSO(s_ParticleUpdateCS, g_pParticleUpdateCS); CreatePSO(s_ParticleDispatchIndirectArgsCS, g_pParticleDispatchIndirectArgsCS); CreatePSO(s_ParticleFinalDispatchIndirectArgsCS, g_pParticleFinalDispatchIndirectArgsCS); CreatePSO(s_ParticleLargeBinCullingCS, g_pParticleLargeBinCullingCS); CreatePSO(s_ParticleBinCullingCS, g_pParticleBinCullingCS); CreatePSO(s_ParticleTileCullingCS, g_pParticleTileCullingCS); if (g_bTypedUAVLoadSupport_R11G11B10_FLOAT) { CreatePSO(s_ParticleTileRenderSlowCS[0], g_pParticleTileRender2CS); CreatePSO(s_ParticleTileRenderFastCS[0], g_pParticleTileRenderFast2CS); CreatePSO(s_ParticleTileRenderSlowCS[1], g_pParticleTileRenderSlowLowRes2CS); CreatePSO(s_ParticleTileRenderFastCS[1], g_pParticleTileRenderFastLowRes2CS); CreatePSO(s_ParticleTileRenderSlowCS[2], g_pParticleTileRenderSlowDynamic2CS); CreatePSO(s_ParticleTileRenderFastCS[2], g_pParticleTileRenderFastDynamic2CS); } else { CreatePSO(s_ParticleTileRenderSlowCS[0], g_pParticleTileRenderCS); CreatePSO(s_ParticleTileRenderFastCS[0], g_pParticleTileRenderFastCS); CreatePSO(s_ParticleTileRenderSlowCS[1], g_pParticleTileRenderSlowLowResCS); CreatePSO(s_ParticleTileRenderFastCS[1], g_pParticleTileRenderFastLowResCS); CreatePSO(s_ParticleTileRenderSlowCS[2], g_pParticleTileRenderSlowDynamicCS); CreatePSO(s_ParticleTileRenderFastCS[2], g_pParticleTileRenderFastDynamicCS); } CreatePSO(s_ParticleDepthBoundsCS, g_pParticleDepthBoundsCS); CreatePSO(s_ParticleSortIndirectArgsCS, g_pParticleSortIndirectArgsCS); CreatePSO(s_ParticlePreSortCS, g_pParticlePreSortCS); CreatePSO(s_ParticleInnerSortCS, g_pParticleInnerSortCS); CreatePSO(s_ParticleOuterSortCS, g_pParticleOuterSortCS); #undef CreatePSO //VSPS Render, no tiles. s_NoTileRasterizationPSO.SetRootSignature(RootSig); s_NoTileRasterizationPSO.SetRasterizerState(RasterizerTwoSided); s_NoTileRasterizationPSO.SetDepthStencilState(DepthStateReadOnly); s_NoTileRasterizationPSO.SetBlendState(BlendPreMultiplied); s_NoTileRasterizationPSO.SetInputLayout(0, nullptr); s_NoTileRasterizationPSO.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE); s_NoTileRasterizationPSO.SetRenderTargetFormat(g_SceneColorBuffer.GetFormat(), g_SceneDepthBuffer.GetFormat()); s_NoTileRasterizationPSO.SetVertexShader(g_pParticleVS, sizeof(g_pParticleVS)); s_NoTileRasterizationPSO.SetPixelShader(g_pParticlePS, sizeof(g_pParticlePS)); s_NoTileRasterizationPSO.Finalize(); __declspec(align(16)) UINT InitialDrawIndirectArgs[4] = { 4, 0, 0, 0 }; DrawIndirectArgs.Create(L"ParticleEffects::DrawIndirectArgs", 1, sizeof(D3D12_DRAW_ARGUMENTS), InitialDrawIndirectArgs); __declspec(align(16)) UINT InitialDispatchIndirectArgs[6] = { 0, 1, 1, 0, 1, 1 }; FinalDispatchIndirectArgs.Create(L"ParticleEffects::FinalDispatchIndirectArgs", 1, sizeof(D3D12_DISPATCH_ARGUMENTS), InitialDispatchIndirectArgs); SpriteVertexBuffer.Create(L"ParticleEffects::SpriteVertexBuffer", MAX_TOTAL_PARTICLES, sizeof(ParticleVertex)); VisibleParticleBuffer.Create(L"ParticleEffects::VisibleParticleBuffer", MAX_TOTAL_PARTICLES, sizeof(ParticleScreenData)); SpriteIndexBuffer.Create(L"ParticleEffects::SpriteIndexBuffer", MAX_TOTAL_PARTICLES, sizeof(UINT)); SortIndirectArgs.Create(L"ParticleEffects::SortIndirectArgs", 8, sizeof(D3D12_DISPATCH_ARGUMENTS)); TileDrawDispatchIndirectArgs.Create(L"ParticleEffects::DrawPackets_IArgs", 2, sizeof(D3D12_DISPATCH_ARGUMENTS), InitialDispatchIndirectArgs); const uint32_t LargeBinsPerRow = DivideByMultiple(MaxDisplayWidth, 4 * BIN_SIZE_X); const uint32_t LargeBinsPerCol = DivideByMultiple(MaxDisplayHeight, 4 * BIN_SIZE_Y); const uint32_t BinsPerRow = LargeBinsPerRow * 4; const uint32_t BinsPerCol = LargeBinsPerCol * 4; const uint32_t MaxParticlesPerLargeBin = MAX_PARTICLES_PER_BIN * 16; const uint32_t ParticleBinCapacity = LargeBinsPerRow * LargeBinsPerCol * MaxParticlesPerLargeBin; const uint32_t TilesPerRow = DivideByMultiple(MaxDisplayWidth, TILE_SIZE); const uint32_t TilesPerCol = DivideByMultiple(MaxDisplayHeight, TILE_SIZE); // Padding is necessary to eliminate bounds checking when outputting data to bins or tiles. const uint32_t PaddedTilesPerRow = AlignUp(TilesPerRow, TILES_PER_BIN_X * 4); const uint32_t PaddedTilesPerCol = AlignUp(TilesPerCol, TILES_PER_BIN_Y * 4); BinParticles[0].Create(L"ParticleEffects::BinParticles[0]", ParticleBinCapacity, sizeof(UINT)); BinParticles[1].Create(L"ParticleEffects::BinParticles[1]", ParticleBinCapacity, sizeof(UINT)); BinCounters[0].Create(L"ParticleEffects::LargeBinCounters", LargeBinsPerRow * LargeBinsPerCol, sizeof(UINT)); BinCounters[1].Create(L"ParticleEffects::BinCounters", BinsPerRow * BinsPerCol, sizeof(UINT)); TileCounters.Create(L"ParticleEffects::TileCounters", PaddedTilesPerRow * PaddedTilesPerCol, sizeof(UINT)); TileHitMasks.Create(L"ParticleEffects::TileHitMasks", PaddedTilesPerRow * PaddedTilesPerCol, MAX_PARTICLES_PER_BIN / 8); TileDrawPackets.Create(L"ParticleEffects::DrawPackets", TilesPerRow * TilesPerCol, sizeof(UINT)); TileFastDrawPackets.Create(L"ParticleEffects::FastDrawPackets", TilesPerRow * TilesPerCol, sizeof(UINT)); D3D12_RESOURCE_DESC TexDesc = {}; TexDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; TexDesc.Format = DXGI_FORMAT_BC3_UNORM_SRGB; TexDesc.Width = 64; TexDesc.Height = 64; TexDesc.DepthOrArraySize = 16; TexDesc.MipLevels = 4; TexDesc.SampleDesc.Count = 1; TexDesc.Alignment = 0x10000; 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; ID3D12Resource* tex = nullptr; ASSERT_SUCCEEDED( g_Device->CreateCommittedResource( &HeapProps, D3D12_HEAP_FLAG_NONE, &TexDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, MY_IID_PPV_ARGS(&tex)) ); TextureArray = GpuResource(tex, D3D12_RESOURCE_STATE_COMMON); tex->Release(); D3D12_SHADER_RESOURCE_VIEW_DESC SRVDesc = {}; SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; SRVDesc.Format = DXGI_FORMAT_BC3_UNORM_SRGB; SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; SRVDesc.Texture2DArray.MipLevels = 4; SRVDesc.Texture2DArray.ArraySize = 16; TextureArraySRV = AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); g_Device->CreateShaderResourceView(TextureArray.GetResource(), &SRVDesc, TextureArraySRV); if (s_ReproFrame > 0) s_RNG.SetSeed(1); TotalElapsedFrames = 0; s_InitComplete = true; }
// Upload to the buffer stored at index i. void ResourceManager::UploadToBuffer(unsigned int i, unsigned int numSubResources, D3D12_SUBRESOURCE_DATA* data, D3D12_RESOURCE_STATES initialState) { if (i < 0 || i >= m_listResources.size()) { std::string msg = "ResourceManager::UploadToBuffer failed due to index " + std::to_string(i) + " out of bounds."; throw GFX_Exception(msg.c_str()); } if (FAILED(m_pCmdList->Reset(m_pCmdAllocator, NULL))) { throw GFX_Exception("ResourceManager::UploadToBuffer: CommandList Reset failed."); } m_pCmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_listResources[i], initialState, D3D12_RESOURCE_STATE_COPY_DEST)); auto size = GetRequiredIntermediateSize(m_listResources[i], 0, numSubResources); size = (UINT64)pow(2.0, ceil(log(size) / log(2))); // round size up to the next power of 2 to ensure good alignment in upload buffer. if (size > DEFAULT_UPLOAD_BUFFER_SIZE) { // then we're going to have to create a new temporary buffer. ID3D12Resource* tmpUpload; m_pDev->CreateCommittedResource(tmpUpload, &CD3DX12_RESOURCE_DESC::Buffer(size), &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr); UpdateSubresources(m_pCmdList, m_listResources[i], tmpUpload, 0, 0, numSubResources, data); // set resource barriers to inform GPU that data is ready for use. m_pCmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_listResources[i], initialState, D3D12_RESOURCE_STATE_COPY_DEST)); // close the command list. if (FAILED(m_pCmdList->Close())) { throw GFX_Exception("ResourceManager::UploadToBuffer: CommandList Close failed."); } // load the command list. ID3D12CommandList* lCmds[] = { m_pCmdList }; m_pDev->ExecuteCommandLists(lCmds, __crt_countof(lCmds)); // add fence signal. ++m_valFence; m_pDev->SetFence(m_pFence, m_valFence); WaitForGPU(); tmpUpload->Release(); } else { if (size > DEFAULT_UPLOAD_BUFFER_SIZE - m_iUpload) { // then we need to wait for the GPU to finish with whatever it is currently uploading. // check to see if it is already done. if (m_pFence->GetCompletedValue() < m_valFence) { // then we're not done, so wait. WaitForGPU(); } m_iUpload = 0; } UpdateSubresources(m_pCmdList, m_listResources[i], m_pUpload, m_iUpload, 0, numSubResources, data); m_iUpload += size; // set resource barriers to inform GPU that data is ready for use. m_pCmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_listResources[i], D3D12_RESOURCE_STATE_COPY_DEST, initialState)); // close the command list. if (FAILED(m_pCmdList->Close())) { throw GFX_Exception("ResourceManager::UploadToBuffer: CommandList Close failed."); } // load the command list. ID3D12CommandList* lCmds[] = { m_pCmdList }; m_pDev->ExecuteCommandLists(lCmds, __crt_countof(lCmds)); // add fence signal. ++m_valFence; m_pDev->SetFence(m_pFence, m_valFence); } }