diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 417be2686b..ee438f32fb 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -36,7 +36,6 @@ void D3D12GSRender::ResourceStorage::Reset() void D3D12GSRender::ResourceStorage::Init(ID3D12Device *device) { - m_queueCompletion = 0; // Create a global command allocator device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator)); device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_textureUploadCommandAllocator)); @@ -345,6 +344,57 @@ void D3D12GSRender::Close() void D3D12GSRender::InitDrawBuffers() { + // FBO location has changed, previous data might be copied + if (m_fbo != nullptr) + { + // TODO : move to texture heap + u32 address_a = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000); + if (m_fbo->m_address_color_a != address_a) + { + LOG_WARNING(RSX, "Copy draw buffer A"); + Microsoft::WRL::ComPtr Texture; + D3D12_HEAP_PROPERTIES hp = {}; + hp.Type = D3D12_HEAP_TYPE_DEFAULT; + check( + m_device->CreateCommittedResource( + &hp, + D3D12_HEAP_FLAG_NONE, + &getTexture2DResourceDesc(RSXThread::m_width, RSXThread::m_height, DXGI_FORMAT_R8G8B8A8_UNORM), + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&Texture) + ) + ); + + ID3D12GraphicsCommandList *copycmdlist; + check(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_perFrameStorage.m_commandAllocator, nullptr, IID_PPV_ARGS(©cmdlist))); + + copycmdlist->ResourceBarrier(1, &getResourceBarrierTransition(m_fbo->getRenderTargetTexture(0), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE)); + + D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst.pResource = Texture.Get(); + src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src.pResource = m_fbo->getRenderTargetTexture(0); + + copycmdlist->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + + D3D12_RESOURCE_BARRIER barriers[2] = + { + getResourceBarrierTransition(m_fbo->getRenderTargetTexture(0), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET), + getResourceBarrierTransition(Texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ), + }; + copycmdlist->ResourceBarrier(2, barriers); + check(copycmdlist->Close()); + + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)©cmdlist); + + m_texturesRTTs[address_a] = Texture; + m_fbo->m_address_color_a = address_a; + } + + } + if (m_fbo == nullptr || RSXThread::m_width != m_lastWidth || RSXThread::m_height != m_lastHeight || m_lastDepth != m_surface_depth_format) { @@ -361,6 +411,11 @@ void D3D12GSRender::InitDrawBuffers() }; m_fbo = new D3D12RenderTargetSets(m_device, (u8)m_lastDepth, m_lastWidth, m_lastHeight, clearColor, 1.f); + m_fbo->m_address_color_a = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000); + m_fbo->m_address_color_b = GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000); + m_fbo->m_address_color_c = GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000); + m_fbo->m_address_color_d = GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000); + m_fbo->m_address_z = GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000); } } @@ -602,6 +657,8 @@ bool D3D12GSRender::LoadProgram() void D3D12GSRender::ExecCMD() { + InitDrawBuffers(); + ID3D12GraphicsCommandList *commandList; m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_perFrameStorage.m_commandAllocator, nullptr, IID_PPV_ARGS(&commandList)); m_perFrameStorage.m_inflightCommandList.push_back(commandList); @@ -681,8 +738,6 @@ void D3D12GSRender::ExecCMD() m_perFrameStorage.m_currentTextureIndex += usedTexture; - InitDrawBuffers(); - D3D12_CPU_DESCRIPTOR_HANDLE *DepthStencilHandle = &m_fbo->getDSVCPUHandle(); switch (m_surface_color_target) { @@ -1123,6 +1178,7 @@ void D3D12GSRender::Flip() WaitForSingleObject(handle, INFINITE); CloseHandle(handle); m_perFrameStorage.Reset(); + m_texturesRTTs.clear(); m_frame->Flip(nullptr); } diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index 8000c812e4..7f7492565b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -47,7 +47,8 @@ void SetGetD3DGSFrameCallback(GetGSFrameCb2 value); class D3D12GSRender : public GSRender { private: - + // Copy of RTT to be used as texture + std::unordered_map > m_texturesRTTs; // std::vector m_post_draw_objs; PipelineStateObjectCache m_cachePSO; @@ -85,9 +86,6 @@ private: ID3D12DescriptorHeap *m_samplerDescriptorHeap; size_t m_currentTextureIndex; - // Fence - HANDLE m_queueCompletion; - void Reset(); void Init(ID3D12Device *device); void Release(); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h index 9d9e81a75c..0dbd553be2 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h @@ -25,5 +25,7 @@ public: D3D12_CPU_DESCRIPTOR_HANDLE getDSVCPUHandle() const; ID3D12Resource *getRenderTargetTexture(u8 Id) const; ID3D12Resource *getDepthStencilTexture() const; + + u32 m_address_color_a, m_address_color_b, m_address_color_c, m_address_color_d, m_address_z; }; #endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index f4de5a5bc7..60e2c3cd4b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -90,13 +90,13 @@ size_t D3D12GSRender::UploadTextures() if (!m_textures[i].IsEnabled()) continue; size_t w = m_textures[i].GetWidth(), h = m_textures[i].GetHeight(); - // Upload at each iteration to take advantage of overlapping transfer - ID3D12GraphicsCommandList *commandList; - check(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_perFrameStorage.m_textureUploadCommandAllocator, nullptr, IID_PPV_ARGS(&commandList))); + const u32 texaddr = GetAddress(m_textures[i].GetOffset(), m_textures[i].GetLocation()); + u32 address = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000); DXGI_FORMAT dxgiFormat; size_t blockSizeInByte, blockWidthInPixel, blockHeightInPixel; int format = m_textures[i].GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + bool is_swizzled = !(m_textures[i].GetFormat() & CELL_GCM_TEXTURE_LN); switch (format) { @@ -146,90 +146,104 @@ size_t D3D12GSRender::UploadTextures() break; } - size_t heightInBlocks = (m_textures[i].GetHeight() + blockHeightInPixel - 1) / blockHeightInPixel; - size_t widthInBlocks = (m_textures[i].GetWidth() + blockWidthInPixel - 1) / blockWidthInPixel; - // Multiple of 256 - size_t rowPitch = blockSizeInByte * widthInBlocks; - rowPitch = (rowPitch + 255) & ~255; - - - ID3D12Resource *Texture, *vramTexture; - size_t textureSize = rowPitch * heightInBlocks; - - check(m_device->CreatePlacedResource( - m_perFrameStorage.m_uploadTextureHeap, - m_perFrameStorage.m_currentStorageOffset, - &getBufferResourceDesc(textureSize), - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(&Texture) - )); - - const u32 texaddr = GetAddress(m_textures[i].GetOffset(), m_textures[i].GetLocation()); - auto pixels = vm::get_ptr(texaddr); - void *textureData; - check(Texture->Map(0, nullptr, (void**)&textureData)); - - // Upload with correct rowpitch - for (unsigned row = 0; row < heightInBlocks; row++) + ID3D12Resource *vramTexture; + std::unordered_map >::const_iterator It = m_texturesRTTs.find(address); + if (It != m_texturesRTTs.end()) { - size_t m_texture_pitch = m_textures[i].m_pitch; - if (!m_texture_pitch) m_texture_pitch = rowPitch; - if (format == CELL_GCM_TEXTURE_A8R8G8B8 && is_swizzled) - { - u32 *src, *dst; - u32 log2width, log2height; - - src = (u32*)pixels; - dst = (u32*)textureData; - - log2width = (u32)(logf(m_textures[i].GetWidth()) / logf(2.f)); - log2height = (u32)(logf(m_textures[i].GetHeight()) / logf(2.f)); - - for (int j = 0; j < m_textures[i].GetWidth(); j++) - { - dst[(row * rowPitch / 4) + j] = src[LinearToSwizzleAddress(j, i, 0, log2width, log2height, 0)]; - } - } - else - streamToBuffer((char*)textureData + row * rowPitch, (char*)pixels + row * m_texture_pitch, m_texture_pitch); + vramTexture = It->second.Get(); } - Texture->Unmap(0, nullptr); + else + { + // Upload at each iteration to take advantage of overlapping transfer + ID3D12GraphicsCommandList *commandList; + check(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_perFrameStorage.m_textureUploadCommandAllocator, nullptr, IID_PPV_ARGS(&commandList))); - check(m_device->CreatePlacedResource( - m_perFrameStorage.m_textureStorage, - m_perFrameStorage.m_currentStorageOffset, - &getTexture2DResourceDesc(m_textures[i].GetWidth(), m_textures[i].GetHeight(), dxgiFormat), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&vramTexture) - )); + size_t heightInBlocks = (m_textures[i].GetHeight() + blockHeightInPixel - 1) / blockHeightInPixel; + size_t widthInBlocks = (m_textures[i].GetWidth() + blockWidthInPixel - 1) / blockWidthInPixel; + // Multiple of 256 + size_t rowPitch = blockSizeInByte * widthInBlocks; + rowPitch = (rowPitch + 255) & ~255; - m_perFrameStorage.m_currentStorageOffset += textureSize; - m_perFrameStorage.m_currentStorageOffset = (m_perFrameStorage.m_currentStorageOffset + 65536 - 1) & ~65535; - m_perFrameStorage.m_inflightResources.push_back(Texture); - m_perFrameStorage.m_inflightResources.push_back(vramTexture); + ID3D12Resource *Texture; + size_t textureSize = rowPitch * heightInBlocks; + check(m_device->CreatePlacedResource( + m_perFrameStorage.m_uploadTextureHeap, + m_perFrameStorage.m_currentStorageOffset, + &getBufferResourceDesc(textureSize), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&Texture) + )); - D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; - dst.pResource = vramTexture; - dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - src.pResource = Texture; - src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.PlacedFootprint.Footprint.Depth = 1; - src.PlacedFootprint.Footprint.Width = m_textures[i].GetWidth(); - src.PlacedFootprint.Footprint.Height = m_textures[i].GetHeight(); - src.PlacedFootprint.Footprint.RowPitch = (UINT)rowPitch; - src.PlacedFootprint.Footprint.Format = dxgiFormat; + auto pixels = vm::get_ptr(texaddr); + void *textureData; + check(Texture->Map(0, nullptr, (void**)&textureData)); - commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + // Upload with correct rowpitch + for (unsigned row = 0; row < heightInBlocks; row++) + { + size_t m_texture_pitch = m_textures[i].m_pitch; + if (!m_texture_pitch) m_texture_pitch = rowPitch; + if (format == CELL_GCM_TEXTURE_A8R8G8B8 && is_swizzled) + { + u32 *src, *dst; + u32 log2width, log2height; - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = vramTexture; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; - commandList->ResourceBarrier(1, &barrier); + src = (u32*)pixels; + dst = (u32*)textureData; + + log2width = (u32)(logf(m_textures[i].GetWidth()) / logf(2.f)); + log2height = (u32)(logf(m_textures[i].GetHeight()) / logf(2.f)); + + for (int j = 0; j < m_textures[i].GetWidth(); j++) + { + dst[(row * rowPitch / 4) + j] = src[LinearToSwizzleAddress(j, i, 0, log2width, log2height, 0)]; + } + } + else + streamToBuffer((char*)textureData + row * rowPitch, (char*)pixels + row * m_texture_pitch, m_texture_pitch); + } + Texture->Unmap(0, nullptr); + + check(m_device->CreatePlacedResource( + m_perFrameStorage.m_textureStorage, + m_perFrameStorage.m_currentStorageOffset, + &getTexture2DResourceDesc(m_textures[i].GetWidth(), m_textures[i].GetHeight(), dxgiFormat), + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&vramTexture) + )); + + m_perFrameStorage.m_currentStorageOffset += textureSize; + m_perFrameStorage.m_currentStorageOffset = (m_perFrameStorage.m_currentStorageOffset + 65536 - 1) & ~65535; + m_perFrameStorage.m_inflightResources.push_back(Texture); + m_perFrameStorage.m_inflightResources.push_back(vramTexture); + + D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; + dst.pResource = vramTexture; + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src.pResource = Texture; + src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src.PlacedFootprint.Footprint.Depth = 1; + src.PlacedFootprint.Footprint.Width = m_textures[i].GetWidth(); + src.PlacedFootprint.Footprint.Height = m_textures[i].GetHeight(); + src.PlacedFootprint.Footprint.RowPitch = (UINT)rowPitch; + src.PlacedFootprint.Footprint.Format = dxgiFormat; + + commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = vramTexture; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; + commandList->ResourceBarrier(1, &barrier); + + commandList->Close(); + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&commandList); + m_perFrameStorage.m_inflightCommandList.push_back(commandList); + } D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; @@ -274,10 +288,6 @@ size_t D3D12GSRender::UploadTextures() Handle.ptr += (m_perFrameStorage.m_currentTextureIndex + usedTexture) * m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); m_device->CreateSampler(&samplerDesc, Handle); - commandList->Close(); - m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&commandList); - m_perFrameStorage.m_inflightCommandList.push_back(commandList); - usedTexture++; }