void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D12_RESOURCE_STATES current_resource_state) { const unsigned int upload_size = AlignValue(src_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * height; if (!s_texture_upload_stream_buffer) { s_texture_upload_stream_buffer = new D3DStreamBuffer(4 * 1024 * 1024, 64 * 1024 * 1024, nullptr); } bool current_command_list_executed = s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); if (current_command_list_executed) { g_renderer->SetViewport(); D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12()); } ResourceBarrier(current_command_list, texture12, current_resource_state, D3D12_RESOURCE_STATE_COPY_DEST, level); D3D12_PLACED_SUBRESOURCE_FOOTPRINT upload_footprint = {}; u32 upload_rows = 0; u64 upload_row_size_in_bytes = 0; u64 upload_total_bytes = 0; D3D::device12->GetCopyableFootprints(&texture12->GetDesc(), level, 1, s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation(), &upload_footprint, &upload_rows, &upload_row_size_in_bytes, &upload_total_bytes); u8* dest_data = reinterpret_cast<u8*>(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation()); const u8* src_data = reinterpret_cast<const u8*>(buffer); for (u32 y = 0; y < upload_rows; ++y) { memcpy( dest_data + upload_footprint.Footprint.RowPitch * y, src_data + src_pitch * y, upload_row_size_in_bytes ); } D3D::current_command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(texture12, level), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(s_texture_upload_stream_buffer->GetBuffer(), upload_footprint), nullptr); ResourceBarrier(D3D::current_command_list, texture12, D3D12_RESOURCE_STATE_COPY_DEST, current_resource_state, level); }
void TextureCache::TCacheEntry::CopyRectangleFromTexture( const TCacheEntryBase* source, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect) { const TCacheEntry* srcentry = reinterpret_cast<const TCacheEntry*>(source); if (src_rect.GetWidth() == dst_rect.GetWidth() && src_rect.GetHeight() == dst_rect.GetHeight()) { D3D12_BOX srcbox; srcbox.left = src_rect.left; srcbox.top = src_rect.top; srcbox.right = src_rect.right; srcbox.bottom = src_rect.bottom; srcbox.front = 0; srcbox.back = srcentry->config.layers; if (static_cast<u32>(src_rect.GetHeight()) > config.height || static_cast<u32>(src_rect.GetWidth()) > config.width) { // To mimic D3D11 behavior, we're just going to drop the clear since it is invalid. // This invalid copy needs to be fixed above the Backend level. // On D3D12, instead of silently dropping this invalid clear, the runtime throws an exception // so we need to filter it out ourselves. return; } D3D12_TEXTURE_COPY_LOCATION dst_location = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), 0); D3D12_TEXTURE_COPY_LOCATION src_location = CD3DX12_TEXTURE_COPY_LOCATION(srcentry->m_texture->GetTex12(), 0); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST); srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); D3D::current_command_list->CopyTextureRegion(&dst_location, dst_rect.left, dst_rect.top, 0, &src_location, &srcbox); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); return; } else if (!config.rendertarget) { return; } D3D::SetViewportAndScissor(dst_rect.left, dst_rect.top, dst_rect.GetWidth(), dst_rect.GetHeight()); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); D3D::current_command_list->OMSetRenderTargets(1, &m_texture->GetRTV12(), FALSE, nullptr); D3D::SetLinearCopySampler(); D3D12_RECT src_rc; src_rc.left = src_rect.left; src_rc.right = src_rect.right; src_rc.top = src_rect.top; src_rc.bottom = src_rect.bottom; D3D::DrawShadedTexQuad(srcentry->m_texture, &src_rc, srcentry->config.width, srcentry->config.height, StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, m_texture->GetMultisampled()); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12()); g_renderer->RestoreAPIState(); }
void D3D12GSRender::flip(int buffer) { ID3D12Resource *resource_to_flip; float viewport_w, viewport_h; if (!is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))) { resource_storage &storage = get_current_resource_storage(); assert(storage.ram_framebuffer == nullptr); size_t w = 0, h = 0, row_pitch = 0; size_t offset = 0; if (false) { CellGcmDisplayInfo* buffers = nullptr;// = vm::ps3::_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr); u32 addr = rsx::get_address(gcm_buffers[gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL); w = gcm_buffers[gcm_current_buffer].width; h = gcm_buffers[gcm_current_buffer].height; u8 *src_buffer = vm::ps3::_ptr<u8>(addr); row_pitch = align(w * 4, 256); size_t texture_size = row_pitch * h; // * 4 for mipmap levels size_t heap_offset = m_buffer_data.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(texture_size); void *mapped_buffer = m_buffer_data.map<void>(heap_offset); for (unsigned row = 0; row < h; row++) memcpy((char*)mapped_buffer + row * row_pitch, (char*)src_buffer + row * w * 4, w * 4); m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + texture_size)); offset = heap_offset; } CHECK_HRESULT( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, (UINT)w, (UINT)h, 1, 1), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(storage.ram_framebuffer.GetAddressOf()) ) ); get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(storage.ram_framebuffer.Get(), 0), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(m_buffer_data.get_heap(), { offset, { DXGI_FORMAT_R8G8B8A8_UNORM, (UINT)w, (UINT)h, 1, (UINT)row_pitch } }), nullptr); get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(storage.ram_framebuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ)); resource_to_flip = storage.ram_framebuffer.Get(); viewport_w = (float)w, viewport_h = (float)h; } else { if (std::get<1>(m_rtts.m_bound_render_targets[0]) != nullptr) { 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 (std::get<1>(m_rtts.m_bound_render_targets[1]) != nullptr) { 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; } get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); D3D12_VIEWPORT viewport = { 0.f, 0.f, (float)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Width, (float)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Height, 0.f, 1.f }; get_current_resource_storage().command_list->RSSetViewports(1, &viewport); D3D12_RECT box = { 0, 0, (LONG)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Width, (LONG)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Height, }; get_current_resource_storage().command_list->RSSetScissorRects(1, &box); get_current_resource_storage().command_list->SetGraphicsRootSignature(m_output_scaling_pass.root_signature); get_current_resource_storage().command_list->SetPipelineState(m_output_scaling_pass.pso); D3D12_SHADER_RESOURCE_VIEW_DESC shader_resource_view_desc = {}; // FIXME: Not always true shader_resource_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; shader_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shader_resource_view_desc.Texture2D.MipLevels = 1; if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))) shader_resource_view_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; else shader_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0 ); m_device->CreateShaderResourceView(resource_to_flip, &shader_resource_view_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.texture_descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_srv_cbv_uav)); D3D12_SAMPLER_DESC sampler_desc = {}; sampler_desc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; m_device->CreateSampler(&sampler_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.sampler_descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_samplers)); ID3D12DescriptorHeap *descriptors_heaps[] = { m_output_scaling_pass.texture_descriptor_heap, m_output_scaling_pass.sampler_descriptor_heap }; get_current_resource_storage().command_list->SetDescriptorHeaps(2, descriptors_heaps); get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0, CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.texture_descriptor_heap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_srv_cbv_uav)); get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(1, CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.sampler_descriptor_heap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_samplers)); get_current_resource_storage().command_list->OMSetRenderTargets(1, &CD3DX12_CPU_DESCRIPTOR_HANDLE(m_backbuffer_descriptor_heap[m_swap_chain->GetCurrentBackBufferIndex()]->GetCPUDescriptorHandleForHeapStart()), true, nullptr); D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {}; vertex_buffer_view.BufferLocation = m_output_scaling_pass.vertex_buffer->GetGPUVirtualAddress(); vertex_buffer_view.StrideInBytes = 4 * sizeof(float); vertex_buffer_view.SizeInBytes = 16 * sizeof(float); get_current_resource_storage().command_list->IASetVertexBuffers(0, 1, &vertex_buffer_view); get_current_resource_storage().command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); if (resource_to_flip) get_current_resource_storage().command_list->DrawInstanced(4, 1, 0, 0); if (!rpcs3::config.rsx.d3d12.overlay.value()) get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])) && resource_to_flip != nullptr) get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(resource_to_flip, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET)); CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); if(rpcs3::config.rsx.d3d12.overlay.value()) render_overlay(); reset_timer(); std::chrono::time_point<std::chrono::system_clock> flip_start = std::chrono::system_clock::now(); CHECK_HRESULT(m_swap_chain->Present(rpcs3::state.config.rsx.vsync.value() ? 1 : 0, 0)); // Add an event signaling queue completion resource_storage &storage = get_non_current_resource_storage(); m_command_queue->Signal(storage.frame_finished_fence.Get(), storage.fence_value); storage.frame_finished_fence->SetEventOnCompletion(storage.fence_value, storage.frame_finished_handle); 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 // a new value (that's the reason of the -1) storage.buffer_heap_get_pos = m_buffer_data.get_current_put_pos_minus_one(); storage.readback_heap_get_pos = m_readback_resources.get_current_put_pos_minus_one(); // Now get ready for next frame resource_storage &new_storage = get_current_resource_storage(); new_storage.wait_and_clean(); if (new_storage.in_use) { m_buffer_data.m_get_pos = new_storage.buffer_heap_get_pos; m_readback_resources.m_get_pos = new_storage.readback_heap_get_pos; } m_frame->flip(nullptr); std::chrono::time_point<std::chrono::system_clock> flip_end = std::chrono::system_clock::now(); m_timers.flip_duration += std::chrono::duration_cast<std::chrono::microseconds>(flip_end - flip_start).count(); }
void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect) { const TCacheEntry* srcentry = reinterpret_cast<const TCacheEntry*>(source); if (src_rect.GetWidth() == dst_rect.GetWidth() && src_rect.GetHeight() == dst_rect.GetHeight()) { // These assertions should hold true unless the base code is passing us sizes too large, in // which case it should be fixed instead. _assert_msg_(VIDEO, static_cast<u32>(src_rect.GetWidth()) <= source->config.width && static_cast<u32>(src_rect.GetHeight()) <= source->config.height, "Source rect is too large for CopyRectangleFromTexture"); _assert_msg_(VIDEO, static_cast<u32>(dst_rect.GetWidth()) <= config.width && static_cast<u32>(dst_rect.GetHeight()) <= config.height, "Dest rect is too large for CopyRectangleFromTexture"); CD3DX12_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, srcentry->config.layers); D3D12_TEXTURE_COPY_LOCATION dst_location = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), 0); D3D12_TEXTURE_COPY_LOCATION src_location = CD3DX12_TEXTURE_COPY_LOCATION(srcentry->m_texture->GetTex12(), 0); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST); srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); D3D::current_command_list->CopyTextureRegion(&dst_location, dst_rect.left, dst_rect.top, 0, &src_location, &src_box); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); return; } else if (!config.rendertarget) { return; } D3D::SetViewportAndScissor(dst_rect.left, dst_rect.top, dst_rect.GetWidth(), dst_rect.GetHeight()); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); D3D::current_command_list->OMSetRenderTargets(1, &m_texture->GetRTV12(), FALSE, nullptr); D3D::SetLinearCopySampler(); D3D12_RECT src_rc; src_rc.left = src_rect.left; src_rc.right = src_rect.right; src_rc.top = src_rect.top; src_rc.bottom = src_rect.bottom; D3D::DrawShadedTexQuad( srcentry->m_texture, &src_rc, srcentry->config.width, srcentry->config.height, StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, m_texture->GetMultisampled()); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); FramebufferManager::GetEFBColorTexture()->TransitionToResourceState( D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState( D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); g_renderer->RestoreAPIState(); }
void TextureCache::TCacheEntry::CopyRectangleFromTexture( const TCacheEntryBase* source, const MathUtil::Rectangle<int>& src_rect, const MathUtil::Rectangle<int>& dst_rect) { TCacheEntry* srcentry = (TCacheEntry*)source; if (src_rect.GetWidth() == dst_rect.GetWidth() && src_rect.GetHeight() == dst_rect.GetHeight()) { const D3D12_BOX *psrcbox = nullptr; D3D12_BOX srcbox; if (src_rect.left != 0 || src_rect.top != 0 || src_rect.GetWidth() != srcentry->config.width || src_rect.GetHeight() != srcentry->config.height) { srcbox.left = src_rect.left; srcbox.top = src_rect.top; srcbox.right = src_rect.right; srcbox.bottom = src_rect.bottom; srcbox.front = 0; srcbox.back = 1; psrcbox = &srcbox; } D3D12_TEXTURE_COPY_LOCATION dst = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), 0); D3D12_TEXTURE_COPY_LOCATION src = CD3DX12_TEXTURE_COPY_LOCATION(srcentry->m_texture->GetTex12(), 0); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST); srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); D3D::current_command_list->CopyTextureRegion(&dst, dst_rect.left, dst_rect.top, 0, &src, psrcbox); return; } else if (!config.rendertarget) { return; } const D3D12_VIEWPORT vp12 = { float(dst_rect.left), float(dst_rect.top), float(dst_rect.GetWidth()), float(dst_rect.GetHeight()), D3D12_MIN_DEPTH, D3D12_MAX_DEPTH }; D3D::current_command_list->RSSetViewports(1, &vp12); m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); D3D::current_command_list->OMSetRenderTargets(1, &m_texture->GetRTV12(), FALSE, nullptr); D3D::SetLinearCopySampler(); D3D12_RECT srcRC; srcRC.left = src_rect.left; srcRC.right = src_rect.right; srcRC.top = src_rect.top; srcRC.bottom = src_rect.bottom; D3D::DrawShadedTexQuad(srcentry->m_texture, &srcRC, srcentry->config.width, srcentry->config.height, StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, m_texture->GetMultisampled()); FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE); D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12()); g_renderer->RestoreAPIState(); }
bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level) { // EXISTINGD3D11TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs) static bool warn_once = true; if (level && warn_once) { WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!"); warn_once = false; return false; } D3D12_RESOURCE_DESC textureDesc = m_texture->GetTex12()->GetDesc(); UINT requiredReadbackBufferSize = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT + ((textureDesc.Width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)) * textureDesc.Height; if (s_texture_cache_entry_readback_buffer_size < requiredReadbackBufferSize) { s_texture_cache_entry_readback_buffer_size = requiredReadbackBufferSize; // We know the readback buffer won't be in use right now, since we wait on this thread // for the GPU to finish execution right after copying to it. SAFE_RELEASE(s_texture_cache_entry_readback_buffer); } if (!s_texture_cache_entry_readback_buffer_size) { CheckHR( D3D::device12->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(s_texture_cache_entry_readback_buffer_size), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&s_texture_cache_entry_readback_buffer) ) ); CheckHR(s_texture_cache_entry_readback_buffer->Map(0, nullptr, &s_texture_cache_entry_readback_buffer_data)); } bool saved_png = false; m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); D3D12_TEXTURE_COPY_LOCATION dst_location = {}; dst_location.pResource = s_texture_cache_entry_readback_buffer; dst_location.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dst_location.PlacedFootprint.Offset = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; dst_location.PlacedFootprint.Footprint.Depth = 1; dst_location.PlacedFootprint.Footprint.Format = textureDesc.Format; dst_location.PlacedFootprint.Footprint.Width = static_cast<UINT>(textureDesc.Width); dst_location.PlacedFootprint.Footprint.Height = textureDesc.Height; dst_location.PlacedFootprint.Footprint.RowPitch = ((textureDesc.Width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)); D3D12_TEXTURE_COPY_LOCATION src_location = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), 0); D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr); D3D::command_list_mgr->ExecuteQueuedWork(true); saved_png = TextureToPng( static_cast<u8*>(s_texture_cache_entry_readback_buffer_data) + D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT, dst_location.PlacedFootprint.Footprint.RowPitch, filename, dst_location.PlacedFootprint.Footprint.Width, dst_location.PlacedFootprint.Footprint.Height ); return saved_png; }
void D3DPostProcessor::CopyTexture(const TargetRectangle& dst_rect, uintptr_t dst_tex, const TargetRectangle& src_rect, uintptr_t src_tex, const TargetSize& src_size, int src_layer, bool is_depth_texture, bool force_shader_copy) { D3DTexture2D* dst_texture = reinterpret_cast<D3DTexture2D*>(dst_tex); D3DTexture2D* src_texture = reinterpret_cast<D3DTexture2D*>(src_tex); // If the dimensions are the same, we can copy instead of using a shader. bool scaling = (dst_rect.GetWidth() != src_rect.GetWidth() || dst_rect.GetHeight() != src_rect.GetHeight()); if (!scaling && !force_shader_copy) { D3D12_BOX srcbox = { static_cast<UINT>(src_rect.left), static_cast<UINT>(src_rect.top), 0, static_cast<UINT>(src_rect.right), static_cast<UINT>(src_rect.bottom), 1 }; D3D12_TEXTURE_COPY_LOCATION dst = CD3DX12_TEXTURE_COPY_LOCATION(dst_texture->GetTex(), 0); D3D12_TEXTURE_COPY_LOCATION src = CD3DX12_TEXTURE_COPY_LOCATION(src_texture->GetTex(), 0); dst_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST); src_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE); if (src_layer < 0) { // Copy all layers for (unsigned int layer = 0; layer < FramebufferManager::GetEFBLayers(); layer++) { src.SubresourceIndex = D3D12CalcSubresource(0, layer, 0, 1, FramebufferManager::GetEFBLayers()); dst.SubresourceIndex = src.SubresourceIndex; D3D::current_command_list->CopyTextureRegion(&dst, dst_rect.left, dst_rect.top, 0, &src, &srcbox); } } else { // Copy single layer to layer 0 D3D::current_command_list->CopyTextureRegion(&dst, dst_rect.left, dst_rect.top, 0, &src, &srcbox); } } else { D3D::SetViewportAndScissor(dst_rect.left, dst_rect.top, dst_rect.GetWidth(), dst_rect.GetHeight()); dst_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET); D3D::current_command_list->OMSetRenderTargets(1, &dst_texture->GetRTV(), FALSE, nullptr); if (scaling) D3D::SetLinearCopySampler(); else D3D::SetPointCopySampler(); D3D12_SHADER_BYTECODE bytecode = {}; D3D::DrawShadedTexQuad(src_texture, src_rect.AsRECT(), src_size.width, src_size.height, StaticShaderCache::GetColorCopyPixelShader(false), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), (src_layer < 0) ? StaticShaderCache::GetCopyGeometryShader() : bytecode, 0, dst_texture->GetFormat(), false, dst_texture->GetMultisampled()); } }
void D3D12GSRender::copy_render_target_to_dma_location() { // Add all buffer write // Cell can't make any assumption about readyness of color/depth buffer // Except when a semaphore is written by RSX int clip_w = rsx::method_registers.surface_clip_width(); int clip_h = rsx::method_registers.surface_clip_height(); size_t depth_row_pitch = align(clip_w * 4, 256); size_t depth_buffer_offset_in_heap = 0; u32 address_color[] = { rsx::get_address(rsx::method_registers.surface_a_offset(), rsx::method_registers.surface_a_dma()), rsx::get_address(rsx::method_registers.surface_b_offset(), rsx::method_registers.surface_b_dma()), rsx::get_address(rsx::method_registers.surface_c_offset(), rsx::method_registers.surface_c_dma()), rsx::get_address(rsx::method_registers.surface_d_offset(), rsx::method_registers.surface_d_dma()), }; u32 address_z = rsx::get_address(rsx::method_registers.surface_z_offset(), rsx::method_registers.surface_z_dma()); bool need_transfer = false; if (rsx::method_registers.surface_z_dma() && g_cfg_rsx_write_depth_buffer) { 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(), { depth_buffer_offset_in_heap,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)depth_row_pitch } }), 0, 0, 0, &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)); invalidate_address(address_z); need_transfer = true; } size_t color_buffer_offset_in_heap[4]; if (g_cfg_rsx_write_color_buffers) { for (u8 i : get_rtt_indexes(rsx::method_registers.surface_color_target())) { 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, std::get<1>(m_rtts.m_bound_render_targets[i]), rsx::method_registers.surface_color()); invalidate_address(address_color[i]); need_transfer = true; } } if (need_transfer) { CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); get_current_resource_storage().set_new_command_list(); } //Wait for result wait_for_command_queue(m_device.Get(), m_command_queue.Get()); if (address_z && g_cfg_rsx_write_depth_buffer) { auto ptr = vm::base(address_z); char *depth_buffer = (char*)ptr; u8 *mapped_buffer = m_readback_resources.map<u8>(depth_buffer_offset_in_heap); for (unsigned row = 0; row < (unsigned)clip_h; row++) { for (unsigned i = 0; i < (unsigned)clip_w; i++) { unsigned char c = mapped_buffer[row * depth_row_pitch + i]; depth_buffer[4 * (row * clip_w + i)] = c; depth_buffer[4 * (row * clip_w + i) + 1] = c; depth_buffer[4 * (row * clip_w + i) + 2] = c; depth_buffer[4 * (row * clip_w + i) + 3] = c; } } m_readback_resources.unmap(); } if (g_cfg_rsx_write_color_buffers) { size_t srcPitch = get_aligned_pitch(rsx::method_registers.surface_color(), clip_w); size_t dstPitch = get_packed_pitch(rsx::method_registers.surface_color(), clip_w); void *dest_buffer[] = { vm::base(address_color[0]), vm::base(address_color[1]), vm::base(address_color[2]), vm::base(address_color[3]), }; for (u8 i : get_rtt_indexes(rsx::method_registers.surface_color_target())) { if (!address_color[i]) continue; copy_readback_buffer_to_dest(dest_buffer[i], m_readback_resources, color_buffer_offset_in_heap[i], srcPitch, dstPitch, clip_h); } } }