diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 19decce16f..003f41db02 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -89,11 +89,6 @@ D3D12DLLManagement::~D3D12DLLManagement() D3D12GSRender::D3D12GSRender() : GSRender(frame_type::DX12), m_d3d12_lib(), m_current_pso({}) { - m_previous_address_a = 0; - m_previous_address_b = 0; - m_previous_address_c = 0; - m_previous_address_d = 0; - m_previous_address_z = 0; gfxHandler = [this](u32 addr) { bool result = invalidate_address(addr); if (result) @@ -423,15 +418,15 @@ void D3D12GSRender::flip(int buffer) } else { - if (m_rtts.bound_render_targets[0] != nullptr) + if (std::get<1>(m_rtts.m_bound_render_targets[0]) != nullptr) { - get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_render_targets[0], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); - resource_to_flip = m_rtts.bound_render_targets[0]; + get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_render_targets[0]), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); + resource_to_flip = std::get<1>(m_rtts.m_bound_render_targets[0]); } - else if (m_rtts.bound_render_targets[1] != nullptr) + else if (std::get<1>(m_rtts.m_bound_render_targets[1]) != nullptr) { - get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_render_targets[1], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); - resource_to_flip = m_rtts.bound_render_targets[1]; + get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_render_targets[1]), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); + resource_to_flip = std::get<1>(m_rtts.m_bound_render_targets[1]); } else resource_to_flip = nullptr; @@ -533,6 +528,8 @@ void D3D12GSRender::flip(int buffer) storage.fence_value++; storage.in_use = true; + storage.dirty_textures.merge(m_rtts.invalidated_resources); + m_rtts.invalidated_resources.clear(); // Get the put pos - 1. This way after cleaning we can set the get ptr to // this value, allowing heap to proceed even if we cleant before allocating diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index 775f31c7c1..faf49573b6 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -129,11 +129,11 @@ private: ID3D12Resource *m_dummy_texture; // Store previous fbo addresses to detect RTT config changes. - u32 m_previous_address_a; - u32 m_previous_address_b; - u32 m_previous_address_c; - u32 m_previous_address_d; - u32 m_previous_address_z; + std::array m_previous_color_address = {}; + u32 m_previous_address_z = 0; + u32 m_previous_target = 0; + u32 m_previous_clip_horizontal = 0; + u32 m_previous_clip_vertical = 0; public: D3D12GSRender(); virtual ~D3D12GSRender(); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp index 7289595104..ed29409bfc 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -77,29 +77,25 @@ void D3D12GSRender::clear_surface(u32 arg) if (arg & 0x1 || arg & 0x2) { - CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart()) - .Offset((INT)get_current_resource_storage().depth_stencil_descriptor_heap_index * g_descriptor_stride_rtv); - m_rtts.bind_depth_stencil(m_device.Get(), m_surface.depth_format, handle); get_current_resource_storage().depth_stencil_descriptor_heap_index++; if (arg & 0x1) { u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8; u32 max_depth_value = m_surface.depth_format == CELL_GCM_SURFACE_Z16 ? 0x0000ffff : 0x00ffffff; - get_current_resource_storage().command_list->ClearDepthStencilView(handle, D3D12_CLEAR_FLAG_DEPTH, clear_depth / (float)max_depth_value, 0, + get_current_resource_storage().command_list->ClearDepthStencilView(m_rtts.current_ds_handle, D3D12_CLEAR_FLAG_DEPTH, clear_depth / (float)max_depth_value, 0, 1, &get_scissor(rsx::method_registers[NV4097_SET_SCISSOR_HORIZONTAL], rsx::method_registers[NV4097_SET_SCISSOR_VERTICAL])); } if (arg & 0x2) - get_current_resource_storage().command_list->ClearDepthStencilView(handle, D3D12_CLEAR_FLAG_STENCIL, 0.f, get_clear_stencil(rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE]), + get_current_resource_storage().command_list->ClearDepthStencilView(m_rtts.current_ds_handle, D3D12_CLEAR_FLAG_STENCIL, 0.f, get_clear_stencil(rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE]), 1, &get_scissor(rsx::method_registers[NV4097_SET_SCISSOR_HORIZONTAL], rsx::method_registers[NV4097_SET_SCISSOR_VERTICAL])); } if (arg & 0xF0) { - CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().render_targets_descriptors_heap->GetCPUDescriptorHandleForHeapStart()) - .Offset((INT)get_current_resource_storage().render_targets_descriptors_heap_index * g_descriptor_stride_rtv); - size_t rtt_index = m_rtts.bind_render_targets(m_device.Get(), m_surface.color_format, handle); + CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtts.current_rtts_handle); + size_t rtt_index = get_num_rtt(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]); get_current_resource_storage().render_targets_descriptors_heap_index += rtt_index; for (unsigned i = 0; i < rtt_index; i++) get_current_resource_storage().command_list->ClearRenderTargetView(handle.Offset(i, g_descriptor_stride_rtv), get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]).data(), @@ -120,16 +116,8 @@ void D3D12GSRender::clear_surface(u32 arg) void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlist) { + // check if something has changed u32 surface_format = rsx::method_registers[NV4097_SET_SURFACE_FORMAT]; - - u32 clip_horizontal = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL]; - u32 clip_vertical = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL]; - - u32 clip_width = clip_horizontal >> 16; - u32 clip_height = clip_vertical >> 16; - u32 clip_x = clip_horizontal; - u32 clip_y = clip_vertical; - u32 context_dma_color[] = { rsx::method_registers[NV4097_SET_CONTEXT_DMA_COLOR_A], @@ -149,7 +137,7 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis u32 offset_zeta = rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET]; // FBO location has changed, previous data might be copied - u32 address_color[] = + std::array address_color = { rsx::get_address(offset_color[0], context_dma_color[0]), rsx::get_address(offset_color[1], context_dma_color[1]), @@ -158,202 +146,71 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis }; u32 address_z = rsx::get_address(offset_zeta, m_context_dma_z); + u32 clip_h_reg = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL]; + u32 clip_v_reg = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL]; + u32 target_reg = rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]; + // Exit early if there is no rtt changes - if (m_previous_address_a == address_color[0] && - m_previous_address_b == address_color[1] && - m_previous_address_c == address_color[2] && - m_previous_address_d == address_color[3] && + if (m_previous_color_address == address_color && m_previous_address_z == address_z && - m_surface.format == surface_format) + m_surface.format == surface_format && + m_previous_clip_horizontal == clip_h_reg && + m_previous_clip_vertical == clip_v_reg && + m_previous_target == target_reg) return; - m_previous_address_a = address_color[0]; - m_previous_address_b = address_color[1]; - m_previous_address_c = address_color[2]; - m_previous_address_d = address_color[3]; + m_previous_color_address = address_color; m_previous_address_z = address_z; + m_previous_target = target_reg; + m_previous_clip_horizontal = clip_h_reg; + m_previous_clip_vertical = clip_v_reg; if (m_surface.format != surface_format) - { m_surface.unpack(surface_format); - m_surface.width = clip_width; - m_surface.height = clip_height; - } - // Make previous RTTs sampleable - for (unsigned i = 0; i < 4; i++) - { - if (m_rtts.bound_render_targets[i] == nullptr) - continue; - copycmdlist->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_render_targets[i], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); - } - // Reset bound data - memset(m_rtts.bound_render_targets_address, 0, 4 * sizeof(u32)); - memset(m_rtts.bound_render_targets, 0, 4 * sizeof(ID3D12Resource *)); - - - // Create/Reuse requested rtts std::array clear_color = get_clear_color(rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]); - for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])) - { - ComPtr old_render_target_resource; - m_rtts.bound_render_targets[i] = m_rtts.bind_address_as_render_targets(m_device.Get(), copycmdlist, address_color[i], clip_width, clip_height, m_surface.color_format, - clear_color, old_render_target_resource); - if (old_render_target_resource) - get_current_resource_storage().dirty_textures.push_back(old_render_target_resource); - m_rtts.bound_render_targets_address[i] = address_color[i]; - } + m_rtts.prepare_render_target(copycmdlist, surface_format, clip_h_reg, clip_v_reg, target_reg, address_color, address_z, m_device.Get(), clear_color, 1.f, 0); - // Same for depth buffer - if (m_rtts.bound_depth_stencil != nullptr) - copycmdlist->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ)); - m_rtts.bound_depth_stencil = nullptr; - m_rtts.bound_depth_stencil_address = 0; - if (!address_z) - return; - ComPtr old_depth_stencil_resource; - ID3D12Resource *ds = m_rtts.bind_address_as_depth_stencil(m_device.Get(), copycmdlist, address_z, clip_width, clip_height, m_surface.depth_format, 1., 0, old_depth_stencil_resource); - if (old_depth_stencil_resource) - get_current_resource_storage().dirty_textures.push_back(old_depth_stencil_resource); - m_rtts.bound_depth_stencil_address = address_z; - m_rtts.bound_depth_stencil = ds; -} - -size_t render_targets::bind_render_targets(ID3D12Device *device, u32 color_format, D3D12_CPU_DESCRIPTOR_HANDLE handle) -{ - DXGI_FORMAT dxgi_format = get_color_surface_format(color_format); + // write descriptors + DXGI_FORMAT dxgi_format = get_color_surface_format(m_surface.color_format); D3D12_RENDER_TARGET_VIEW_DESC rtt_view_desc = {}; rtt_view_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtt_view_desc.Format = dxgi_format; + m_rtts.current_rtts_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().render_targets_descriptors_heap->GetCPUDescriptorHandleForHeapStart()) + .Offset((INT)get_current_resource_storage().render_targets_descriptors_heap_index * g_descriptor_stride_rtv); size_t rtt_index = 0; for (u8 i : get_rtt_indexes(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])) { - if (bound_render_targets[i] == nullptr) + if (std::get<1>(m_rtts.m_bound_render_targets[i]) == nullptr) continue; - device->CreateRenderTargetView(bound_render_targets[i], &rtt_view_desc, - CD3DX12_CPU_DESCRIPTOR_HANDLE(handle).Offset((INT)rtt_index * g_descriptor_stride_rtv)); + m_device->CreateRenderTargetView(std::get<1>(m_rtts.m_bound_render_targets[i]), &rtt_view_desc, + CD3DX12_CPU_DESCRIPTOR_HANDLE(m_rtts.current_rtts_handle).Offset((INT)rtt_index * g_descriptor_stride_rtv)); rtt_index++; } - return rtt_index; -} + get_current_resource_storage().render_targets_descriptors_heap_index += rtt_index; -size_t render_targets::bind_depth_stencil(ID3D12Device *device, u32 depth_format, D3D12_CPU_DESCRIPTOR_HANDLE handle) -{ - if (!bound_depth_stencil) - return 0; + if (std::get<1>(m_rtts.m_bound_depth_stencil) == nullptr) + return; + m_rtts.current_ds_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart()) + .Offset((INT)get_current_resource_storage().depth_stencil_descriptor_heap_index * g_descriptor_stride_rtv); + get_current_resource_storage().depth_stencil_descriptor_heap_index += 1; D3D12_DEPTH_STENCIL_VIEW_DESC depth_stencil_view_desc = {}; - depth_stencil_view_desc.Format = get_depth_stencil_surface_format(depth_format); + depth_stencil_view_desc.Format = get_depth_stencil_surface_format(m_surface.depth_format); depth_stencil_view_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - device->CreateDepthStencilView(bound_depth_stencil, &depth_stencil_view_desc, handle); - return 1; + m_device->CreateDepthStencilView(std::get<1>(m_rtts.m_bound_depth_stencil), &depth_stencil_view_desc, m_rtts.current_ds_handle); } void D3D12GSRender::set_rtt_and_ds(ID3D12GraphicsCommandList *command_list) { - CD3DX12_CPU_DESCRIPTOR_HANDLE handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().render_targets_descriptors_heap->GetCPUDescriptorHandleForHeapStart()) - .Offset((INT)get_current_resource_storage().render_targets_descriptors_heap_index * g_descriptor_stride_rtv); - size_t num_rtt = m_rtts.bind_render_targets(m_device.Get(), m_surface.color_format, handle); - get_current_resource_storage().render_targets_descriptors_heap_index += num_rtt; - CD3DX12_CPU_DESCRIPTOR_HANDLE depth_stencil_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart()) - .Offset((INT)get_current_resource_storage().depth_stencil_descriptor_heap_index * g_descriptor_stride_rtv); - size_t num_ds = m_rtts.bind_depth_stencil(m_device.Get(), m_surface.depth_format, depth_stencil_handle); - get_current_resource_storage().depth_stencil_descriptor_heap_index += num_ds; - command_list->OMSetRenderTargets((UINT)num_rtt, num_rtt > 0 ? &handle : nullptr, !!num_rtt, - num_ds > 0 ? &depth_stencil_handle : nullptr); + UINT num_rtt = get_num_rtt(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]); + D3D12_CPU_DESCRIPTOR_HANDLE* rtt_handle = (num_rtt > 0) ? &m_rtts.current_rtts_handle : nullptr; + D3D12_CPU_DESCRIPTOR_HANDLE* ds_handle = (std::get<1>(m_rtts.m_bound_depth_stencil) != nullptr) ? &m_rtts.current_ds_handle : nullptr; + command_list->OMSetRenderTargets((UINT)num_rtt, rtt_handle, true, ds_handle); } -ID3D12Resource *render_targets::bind_address_as_render_targets(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, u32 address, - size_t width, size_t height, u8 surfaceColorFormat, const std::array &clear_color, ComPtr &dirtyRTT) +void render_targets::init(ID3D12Device *device) { - DXGI_FORMAT dxgi_format = get_color_surface_format(surfaceColorFormat); - auto It = render_targets_storage.find(address); - // TODO: Check if format and size match - if (It != render_targets_storage.end()) - { - ComPtr rtt; - rtt = It->second.Get(); - if (rtt->GetDesc().Format == dxgi_format && rtt->GetDesc().Width == width && rtt->GetDesc().Height == height) - { - cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt.Get(), D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET)); - return rtt.Get(); - } - render_targets_storage.erase(address); - dirtyRTT = rtt; - } - ComPtr rtt; - LOG_WARNING(RSX, "Creating RTT"); - - D3D12_CLEAR_VALUE clear_color_value = {}; - clear_color_value.Format = dxgi_format; - clear_color_value.Color[0] = clear_color[0]; - clear_color_value.Color[1] = clear_color[1]; - clear_color_value.Color[2] = clear_color[2]; - clear_color_value.Color[3] = clear_color[3]; - - device->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)width, (UINT)height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET), - D3D12_RESOURCE_STATE_RENDER_TARGET, - &clear_color_value, - IID_PPV_ARGS(rtt.GetAddressOf()) - ); - render_targets_storage[address] = rtt; - std::wstring name = L"rtt_@" + std::to_wstring(address); - rtt->SetName(name.c_str()); - - return rtt.Get(); -} - -ID3D12Resource * render_targets::bind_address_as_depth_stencil(ID3D12Device * device, ID3D12GraphicsCommandList * cmdList, u32 address, size_t width, size_t height, u8 surfaceDepthFormat, float depthClear, u8 stencilClear, ComPtr &dirtyDS) -{ - auto It = depth_stencil_storage.find(address); - - // TODO: Check if surface depth format match - - if (It != depth_stencil_storage.end()) - { - ComPtr ds = It->second; - if (ds->GetDesc().Width == width && ds->GetDesc().Height == height) - { - // set the resource as depth write - cmdList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds.Get(), D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE)); - return ds.Get(); - } - // If size doesn't match, remove ds from cache - depth_stencil_storage.erase(address); - dirtyDS = ds; - } - - D3D12_CLEAR_VALUE clear_depth_value = {}; - clear_depth_value.DepthStencil.Depth = depthClear; - - DXGI_FORMAT dxgi_format = get_depth_stencil_typeless_surface_format(surfaceDepthFormat); - clear_depth_value.Format = get_depth_stencil_surface_clear_format(surfaceDepthFormat); - - ComPtr new_depth_stencil; - device->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)width, (UINT)height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL), - D3D12_RESOURCE_STATE_DEPTH_WRITE, - &clear_depth_value, - IID_PPV_ARGS(new_depth_stencil.GetAddressOf()) - ); - depth_stencil_storage[address] = new_depth_stencil; - std::wstring name = L"ds_@" + std::to_wstring(address); - new_depth_stencil->SetName(name.c_str()); - - return new_depth_stencil.Get(); -} - -void render_targets::init(ID3D12Device *device)//, u8 surfaceDepthFormat, size_t width, size_t height, float clearColor[4], float clearDepth) -{ - memset(bound_render_targets_address, 0, 4 * sizeof(u32)); - memset(bound_render_targets, 0, 4 * sizeof(ID3D12Resource*)); - bound_depth_stencil = nullptr; - bound_depth_stencil_address = 0; g_descriptor_stride_rtv = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } @@ -492,7 +349,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() shader_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shader_resource_view_desc.Texture2D.MipLevels = 1; shader_resource_view_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - m_device->CreateShaderResourceView(m_rtts.bound_depth_stencil, &shader_resource_view_desc, + m_device->CreateShaderResourceView(std::get<1>(m_rtts.m_bound_depth_stencil), &shader_resource_view_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(descriptor_heap->GetCPUDescriptorHandleForHeapStart())); D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {}; uav_desc.Format = DXGI_FORMAT_R8_UNORM; @@ -501,7 +358,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() CD3DX12_CPU_DESCRIPTOR_HANDLE(descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(1, g_descriptor_stride_srv_cbv_uav)); // Convert - get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ)); + get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ)); get_current_resource_storage().command_list->SetPipelineState(m_convertPSO); get_current_resource_storage().command_list->SetComputeRootSignature(m_convertRootSignature); @@ -511,7 +368,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() D3D12_RESOURCE_BARRIER barriers[] = { - CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE), + CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE), CD3DX12_RESOURCE_BARRIER::UAV(depth_format_conversion_buffer.Get()), }; get_current_resource_storage().command_list->ResourceBarrier(2, barriers); @@ -531,7 +388,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() { if (!address_color[i]) continue; - color_buffer_offset_in_heap[i] = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, m_rtts.bound_render_targets[i], m_surface.color_format); + color_buffer_offset_in_heap[i] = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, std::get<1>(m_rtts.m_bound_render_targets[i]), m_surface.color_format); invalidate_address(address_color[i]); need_transfer = true; } @@ -605,7 +462,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() void D3D12GSRender::copy_render_targets_to_memory(void *buffer, u8 rtt) { - size_t heap_offset = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, m_rtts.bound_render_targets[rtt], m_surface.color_format); + size_t heap_offset = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, std::get<1>(m_rtts.m_bound_render_targets[rtt]), m_surface.color_format); CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); @@ -645,11 +502,11 @@ void D3D12GSRender::copy_depth_buffer_to_memory(void *buffer) size_t buffer_size = row_pitch * clip_h; size_t heap_offset = m_readback_resources.alloc(buffer_size); - get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE)); + get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE)); get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { heap_offset,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0, - &CD3DX12_TEXTURE_COPY_LOCATION(m_rtts.bound_depth_stencil, 0), nullptr); - get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); + &CD3DX12_TEXTURE_COPY_LOCATION(std::get<1>(m_rtts.m_bound_depth_stencil), 0), nullptr); + get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); @@ -680,11 +537,11 @@ void D3D12GSRender::copy_stencil_buffer_to_memory(void *buffer) size_t buffer_size = row_pitch * clip_h; size_t heap_offset = m_readback_resources.alloc(buffer_size); - get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE)); + get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE)); get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { heap_offset, { DXGI_FORMAT_R8_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)row_pitch } }), 0, 0, 0, - &CD3DX12_TEXTURE_COPY_LOCATION(m_rtts.bound_depth_stencil, 1), nullptr); - get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_rtts.bound_depth_stencil, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); + &CD3DX12_TEXTURE_COPY_LOCATION(std::get<1>(m_rtts.m_bound_depth_stencil), 1), nullptr); + get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h index 1b0fd69747..3d0970f94b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h @@ -1,30 +1,297 @@ #pragma once +#include #include +#include "d3dx12.h" -struct render_targets +#include "D3D12Formats.h" +#include + +namespace rsx +{ + namespace + { + std::vector get_rtt_indexes(u8 color_target) + { + switch (color_target) + { + case CELL_GCM_SURFACE_TARGET_NONE: return{}; + case CELL_GCM_SURFACE_TARGET_0: return{ 0 }; + case CELL_GCM_SURFACE_TARGET_1: return{ 1 }; + case CELL_GCM_SURFACE_TARGET_MRT1: return{ 0, 1 }; + case CELL_GCM_SURFACE_TARGET_MRT2: return{ 0, 1, 2 }; + case CELL_GCM_SURFACE_TARGET_MRT3: return{ 0, 1, 2, 3 }; + } + throw EXCEPTION("Wrong color_target (%d)", color_target); + } + } + + template + struct surface_store + { + private: + using surface_storage_type = typename Traits::surface_storage_type; + using surface_type = typename Traits::surface_type; + using command_list_type = typename Traits::command_list_type; + + std::unordered_map m_render_targets_storage = {}; + std::unordered_map m_depth_stencil_storage = {}; + + public: + std::array, 4> m_bound_render_targets = {}; + std::tuple m_bound_depth_stencil = {}; + + std::list invalidated_resources; + + surface_store() = default; + ~surface_store() = default; + surface_store(const surface_store&) = delete; + private: + /** + * If render target already exists at address, issue state change operation on cmdList. + * Otherwise create one with width, height, clearColor info. + * returns the corresponding render target resource. + */ + template + gsl::not_null bind_address_as_render_targets( + command_list_type command_list, + u32 address, + u8 surface_color_format, size_t width, size_t height, + Args&&... extra_params) + { + auto It = m_render_targets_storage.find(address); + // TODO: Fix corner cases + // This doesn't take overlapping surface(s) into account. + // Invalidated surface(s) should also copy their content to the new resources. + if (It != m_render_targets_storage.end()) + { + surface_storage_type &rtt = It->second; + if (Traits::rtt_has_format_width_height(rtt, surface_color_format, width, height)) + { + Traits::prepare_rtt_for_drawing(command_list, rtt.Get()); + return rtt.Get(); + } + invalidated_resources.push_back(std::move(rtt)); + m_render_targets_storage.erase(address); + } + + m_render_targets_storage[address] = Traits::create_new_render_target(address, surface_color_format, width, height, std::forward(extra_params)...); + return m_render_targets_storage[address].Get(); + } + + template + gsl::not_null bind_address_as_depth_stencil( + command_list_type command_list, + u32 address, + u8 surface_depth_format, size_t width, size_t height, + Args&&... extra_params) + { + auto It = m_depth_stencil_storage.find(address); + if (It != m_depth_stencil_storage.end()) + { + surface_storage_type &ds = It->second; + if (Traits::ds_has_format_width_height(ds, surface_depth_format, width, height)) + { + Traits::prepare_ds_for_drawing(command_list, ds.Get()); + return ds.Get(); + } + invalidated_resources.push_back(std::move(ds)); + m_depth_stencil_storage.erase(address); + } + + m_depth_stencil_storage[address] = Traits::create_new_depth_stencil(address, surface_depth_format, width, height, std::forward(extra_params)...); + return m_depth_stencil_storage[address].Get(); + } + public: + template + void prepare_render_target( + command_list_type command_list, + u32 set_surface_format_reg, + u32 clip_horizontal_reg, u32 clip_vertical_reg, + u32 set_surface_target, + const std::array &surface_addresses, u32 address_z, + Args&&... extra_params) + { + u32 clip_width = clip_horizontal_reg >> 16; + u32 clip_height = clip_vertical_reg >> 16; + u32 clip_x = clip_horizontal_reg; + u32 clip_y = clip_vertical_reg; + + rsx::surface_info surface = {}; + surface.unpack(set_surface_format_reg); + + // Make previous RTTs sampleable + for (std::tuple &rtt : m_bound_render_targets) + { + if (std::get<1>(rtt) != nullptr) + Traits::prepare_rtt_for_sampling(command_list, std::get<1>(rtt)); + rtt = std::make_tuple(0, nullptr); + } + + // Create/Reuse requested rtts + for (u8 surface_index : get_rtt_indexes(set_surface_target)) + { + if (surface_addresses[surface_index] == 0) + continue; + + m_bound_render_targets[surface_index] = std::make_tuple(surface_addresses[surface_index], + bind_address_as_render_targets(command_list, surface_addresses[surface_index], surface.color_format, clip_width, clip_height, std::forward(extra_params)...)); + } + + // Same for depth buffer + if (std::get<1>(m_bound_depth_stencil) != nullptr) + Traits::prepare_ds_for_sampling(command_list, std::get<1>(m_bound_depth_stencil)); + m_bound_depth_stencil = std::make_tuple(0, nullptr); + if (!address_z) + return; + m_bound_depth_stencil = std::make_tuple(address_z, + bind_address_as_depth_stencil(command_list, address_z, surface.depth_format, clip_width, clip_height, std::forward(extra_params)...)); + } + + surface_type get_texture_from_render_target_if_applicable(u32 address) + { + // TODO: Handle texture that overlaps one (or several) surface. + // Handle texture conversion + // FIXME: Disgaea 3 loading screen seems to use a subset of a surface. It's not properly handled here. + // Note: not const because conversions/resolve/... can happen + auto It = m_render_targets_storage.find(address); + if (It != m_render_targets_storage.end()) + return It->second.Get(); + return surface_type(); + } + + surface_type get_texture_from_depth_stencil_if_applicable(u32 address) + { + // TODO: Same as above although there wasn't any game using corner case for DS yet. + auto It = m_depth_stencil_storage.find(address); + if (It != m_depth_stencil_storage.end()) + return It->second.Get(); + return surface_type(); + } + }; +} + +struct render_target_traits +{ + using surface_storage_type = ComPtr; + using surface_type = ID3D12Resource*; + using command_list_type = gsl::not_null; + + static + ComPtr create_new_render_target( + u32 address, + u8 surface_color_format, size_t width, size_t height, + gsl::not_null device, const std::array &clear_color, float, u8) + { + DXGI_FORMAT dxgi_format = get_color_surface_format(surface_color_format); + ComPtr rtt; + LOG_WARNING(RSX, "Creating RTT"); + + D3D12_CLEAR_VALUE clear_color_value = {}; + clear_color_value.Format = dxgi_format; + clear_color_value.Color[0] = clear_color[0]; + clear_color_value.Color[1] = clear_color[1]; + clear_color_value.Color[2] = clear_color[2]; + clear_color_value.Color[3] = clear_color[3]; + + device->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)width, (UINT)height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET), + D3D12_RESOURCE_STATE_RENDER_TARGET, + &clear_color_value, + IID_PPV_ARGS(rtt.GetAddressOf()) + ); + + std::wstring name = L"rtt_@" + std::to_wstring(address); + rtt->SetName(name.c_str()); + + return rtt; + } + + static + void prepare_rtt_for_drawing( + gsl::not_null command_list, + ID3D12Resource* rtt) + { + command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET)); + } + + static + void prepare_rtt_for_sampling( + gsl::not_null command_list, + ID3D12Resource* rtt) + { + command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rtt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); + } + + static + ComPtr create_new_depth_stencil( + u32 address, + u8 surfaceDepthFormat, size_t width, size_t height, + gsl::not_null device, const std::array& , float clear_depth, u8 clear_stencil) + { + D3D12_CLEAR_VALUE clear_depth_value = {}; + clear_depth_value.DepthStencil.Depth = clear_depth; + clear_depth_value.DepthStencil.Stencil = clear_stencil; + + DXGI_FORMAT dxgi_format = get_depth_stencil_typeless_surface_format(surfaceDepthFormat); + clear_depth_value.Format = get_depth_stencil_surface_clear_format(surfaceDepthFormat); + + ComPtr new_depth_stencil; + device->CreateCommittedResource( + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, (UINT)width, (UINT)height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL), + D3D12_RESOURCE_STATE_DEPTH_WRITE, + &clear_depth_value, + IID_PPV_ARGS(new_depth_stencil.GetAddressOf()) + ); + std::wstring name = L"ds_@" + std::to_wstring(address); + new_depth_stencil->SetName(name.c_str()); + + return new_depth_stencil; + } + + static + void prepare_ds_for_drawing( + gsl::not_null command_list, + ID3D12Resource* ds) + { + // set the resource as depth write + command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE)); + } + + static + void prepare_ds_for_sampling( + gsl::not_null command_list, + ID3D12Resource* ds) + { + command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ)); + } + + + static + bool rtt_has_format_width_height(const ComPtr &rtt, u8 surface_color_format, size_t width, size_t height) + { + DXGI_FORMAT dxgi_format = get_color_surface_format(surface_color_format); + return rtt->GetDesc().Format == dxgi_format && rtt->GetDesc().Width == width && rtt->GetDesc().Height == height; + } + + static + bool ds_has_format_width_height(const ComPtr &rtt, u8 surface_depth_stencil_format, size_t width, size_t height) + { + //TODO: Check format + return rtt->GetDesc().Width == width && rtt->GetDesc().Height == height; + } +}; + +struct render_targets : public rsx::surface_store { INT g_descriptor_stride_rtv; - std::unordered_map > render_targets_storage; - ID3D12Resource *bound_render_targets[4]; - u32 bound_render_targets_address[4]; - std::unordered_map > depth_stencil_storage; - ID3D12Resource *bound_depth_stencil; - u32 bound_depth_stencil_address; - size_t bind_render_targets(ID3D12Device *, u32 color_format, D3D12_CPU_DESCRIPTOR_HANDLE); - size_t bind_depth_stencil(ID3D12Device *, u32 depth_format, D3D12_CPU_DESCRIPTOR_HANDLE); - - /** - * If render target already exists at address, issue state change operation on cmdList. - * Otherwise create one with width, height, clearColor info. - * returns the corresponding render target resource. - */ - ID3D12Resource *bind_address_as_render_targets(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, u32 address, - size_t width, size_t height, u8 surfaceColorFormat, const std::array &clearColor, ComPtr &dirtyDS); - - ID3D12Resource *bind_address_as_depth_stencil(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, u32 address, - size_t width, size_t height, u8 surfaceDepthFormat, float depthClear, u8 stencilClear, ComPtr &dirtyDS); + D3D12_CPU_DESCRIPTOR_HANDLE current_rtts_handle; + D3D12_CPU_DESCRIPTOR_HANDLE current_ds_handle; void init(ID3D12Device *device); }; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index da8a4adeee..e34780cd23 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -167,18 +167,15 @@ void D3D12GSRender::upload_and_bind_textures(ID3D12GraphicsCommandList *command_ bool is_swizzled = !(textures[i].format() & CELL_GCM_TEXTURE_LN); ID3D12Resource *vram_texture; - std::unordered_map >::const_iterator ItRTT = m_rtts.render_targets_storage.find(texaddr); - std::unordered_map >::const_iterator ItDS = m_rtts.depth_stencil_storage.find(texaddr); std::pair > *cached_texture = m_texture_cache.find_data_if_available(texaddr); bool is_render_target = false, is_depth_stencil_texture = false; - if (ItRTT != m_rtts.render_targets_storage.end()) + + if (vram_texture = m_rtts.get_texture_from_render_target_if_applicable(texaddr)) { - vram_texture = ItRTT->second.Get(); is_render_target = true; } - else if (ItDS != m_rtts.depth_stencil_storage.end()) + else if (vram_texture = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) { - vram_texture = ItDS->second.Get(); is_depth_stencil_texture = true; } else if (cached_texture != nullptr && (cached_texture->first == texture_entry(format, w, h, textures[i].mipmap())))