From 2e79eac976678a5328e8ce2aff97fc7b55da9a2d Mon Sep 17 00:00:00 2001 From: Triang3l Date: Thu, 23 Aug 2018 19:50:11 +0300 Subject: [PATCH] [D3D12] Window output --- .../gpu/d3d12/d3d12_command_processor.cc | 132 +++++++++++++ src/xenia/gpu/d3d12/d3d12_command_processor.h | 7 + src/xenia/gpu/d3d12/d3d12_graphics_system.cc | 175 +++++++++++++++++- src/xenia/gpu/d3d12/d3d12_graphics_system.h | 15 ++ src/xenia/gpu/d3d12/render_target_cache.cc | 4 +- src/xenia/gpu/d3d12/render_target_cache.h | 4 + .../shaders/edram_tile_sample_32bpp.cs.hlsl | 2 +- .../gpu/d3d12/shaders/fullscreen.vs.hlsl | 7 + src/xenia/gpu/d3d12/shaders/stretch.ps.hlsl | 5 + src/xenia/gpu/d3d12/shared_memory.h | 1 - src/xenia/gpu/d3d12/texture_cache.cc | 33 ++++ src/xenia/gpu/d3d12/texture_cache.h | 2 + src/xenia/ui/d3d12/d3d12_context.h | 4 + 13 files changed, 384 insertions(+), 7 deletions(-) create mode 100644 src/xenia/gpu/d3d12/shaders/fullscreen.vs.hlsl create mode 100644 src/xenia/gpu/d3d12/shaders/stretch.ps.hlsl diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index 223f1ef64..b40862add 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -16,6 +16,7 @@ #include "xenia/base/logging.h" #include "xenia/base/math.h" #include "xenia/base/profiling.h" +#include "xenia/gpu/d3d12/d3d12_graphics_system.h" #include "xenia/gpu/d3d12/d3d12_shader.h" #include "xenia/gpu/xenos.h" @@ -525,6 +526,69 @@ bool D3D12CommandProcessor::SetupContext() { return false; } + D3D12_HEAP_PROPERTIES swap_texture_heap_properties = {}; + swap_texture_heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT; + D3D12_RESOURCE_DESC swap_texture_desc; + swap_texture_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + swap_texture_desc.Alignment = 0; + swap_texture_desc.Width = kSwapTextureWidth; + swap_texture_desc.Height = kSwapTextureHeight; + swap_texture_desc.DepthOrArraySize = 1; + swap_texture_desc.MipLevels = 1; + swap_texture_desc.Format = ui::d3d12::D3D12Context::kSwapChainFormat; + swap_texture_desc.SampleDesc.Count = 1; + swap_texture_desc.SampleDesc.Quality = 0; + swap_texture_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + swap_texture_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + // Can be sampled at any time, switch to render target when needed, then back. + if (FAILED(device->CreateCommittedResource( + &swap_texture_heap_properties, D3D12_HEAP_FLAG_NONE, + &swap_texture_desc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + nullptr, IID_PPV_ARGS(&swap_texture_)))) { + XELOGE("Failed to create the command processor front buffer"); + return false; + } + D3D12_DESCRIPTOR_HEAP_DESC swap_descriptor_heap_desc; + swap_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + swap_descriptor_heap_desc.NumDescriptors = 1; + swap_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + swap_descriptor_heap_desc.NodeMask = 0; + if (FAILED(device->CreateDescriptorHeap( + &swap_descriptor_heap_desc, + IID_PPV_ARGS(&swap_texture_rtv_descriptor_heap_)))) { + XELOGE("Failed to create the command processor front buffer RTV heap"); + return false; + } + swap_texture_rtv_ = + swap_texture_rtv_descriptor_heap_->GetCPUDescriptorHandleForHeapStart(); + D3D12_RENDER_TARGET_VIEW_DESC swap_rtv_desc; + swap_rtv_desc.Format = ui::d3d12::D3D12Context::kSwapChainFormat; + swap_rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + swap_rtv_desc.Texture2D.MipSlice = 0; + swap_rtv_desc.Texture2D.PlaneSlice = 0; + device->CreateRenderTargetView(swap_texture_, &swap_rtv_desc, + swap_texture_rtv_); + swap_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + swap_descriptor_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + if (FAILED(device->CreateDescriptorHeap( + &swap_descriptor_heap_desc, + IID_PPV_ARGS(&swap_texture_srv_descriptor_heap_)))) { + XELOGE("Failed to create the command processor front buffer SRV heap"); + return false; + } + D3D12_SHADER_RESOURCE_VIEW_DESC swap_srv_desc; + swap_srv_desc.Format = ui::d3d12::D3D12Context::kSwapChainFormat; + swap_srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + swap_srv_desc.Shader4ComponentMapping = + D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + swap_srv_desc.Texture2D.MostDetailedMip = 0; + swap_srv_desc.Texture2D.MipLevels = 1; + swap_srv_desc.Texture2D.PlaneSlice = 0; + swap_srv_desc.Texture2D.ResourceMinLODClamp = 0.0f; + device->CreateShaderResourceView( + swap_texture_, &swap_srv_desc, + swap_texture_srv_descriptor_heap_->GetCPUDescriptorHandleForHeapStart()); + return true; } @@ -543,6 +607,26 @@ void D3D12CommandProcessor::ShutdownContext() { } buffers_for_deletion_.clear(); + if (swap_texture_srv_descriptor_heap_ != nullptr) { + { + std::lock_guard lock(swap_state_.mutex); + swap_state_.pending = false; + swap_state_.front_buffer_texture = 0; + } + auto graphics_system = static_cast(graphics_system_); + graphics_system->AwaitFrontBufferUnused(); + swap_texture_srv_descriptor_heap_->Release(); + swap_texture_srv_descriptor_heap_ = nullptr; + } + if (swap_texture_rtv_descriptor_heap_ != nullptr) { + swap_texture_rtv_descriptor_heap_->Release(); + swap_texture_rtv_descriptor_heap_ = nullptr; + } + if (swap_texture_ != nullptr) { + swap_texture_->Release(); + swap_texture_ = nullptr; + } + sampler_heap_pool_.reset(); view_heap_pool_.reset(); constant_buffer_pool_.reset(); @@ -593,6 +677,54 @@ void D3D12CommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_height) { SCOPE_profile_cpu_f("gpu"); + // In case the swap command is the only one in the frame. + BeginFrame(); + + D3D12_CPU_DESCRIPTOR_HANDLE frontbuffer_cpu_handle; + D3D12_GPU_DESCRIPTOR_HANDLE frontbuffer_gpu_handle; + if (RequestViewDescriptors(0, 1, 1, frontbuffer_cpu_handle, + frontbuffer_gpu_handle) != 0) { + if (texture_cache_->RequestSwapTexture(frontbuffer_cpu_handle)) { + auto command_list = GetCurrentCommandList(); + render_target_cache_->UnbindRenderTargets(); + // The swap texture is kept as an SRV because the graphics system may draw + // with it at any time. It's switched to RTV and back when needed. + PushTransitionBarrier(swap_texture_, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_RENDER_TARGET); + SubmitBarriers(); + command_list->OMSetRenderTargets(1, &swap_texture_rtv_, TRUE, nullptr); + D3D12_VIEWPORT viewport; + viewport.TopLeftX = 0.0f; + viewport.TopLeftY = 0.0f; + viewport.Width = float(kSwapTextureWidth); + viewport.Height = float(kSwapTextureHeight); + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 0.0f; + command_list->RSSetViewports(1, &viewport); + D3D12_RECT scissor; + scissor.left = 0; + scissor.top = 0; + scissor.right = kSwapTextureWidth; + scissor.bottom = kSwapTextureHeight; + command_list->RSSetScissorRects(1, &scissor); + D3D12GraphicsSystem* graphics_system = + static_cast(graphics_system_); + graphics_system->StretchTextureToFrontBuffer(frontbuffer_gpu_handle, + command_list); + PushTransitionBarrier(swap_texture_, D3D12_RESOURCE_STATE_RENDER_TARGET, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + // Don't care about graphics state because the frame is ending anyway. + { + std::lock_guard lock(swap_state_.mutex); + swap_state_.width = kSwapTextureWidth; + swap_state_.height = kSwapTextureHeight; + swap_state_.front_buffer_texture = + reinterpret_cast(swap_texture_srv_descriptor_heap_); + } + } + } + EndFrame(); if (cache_clear_requested_) { diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index 038ef1c3b..2cfc3eef9 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -185,6 +185,13 @@ class D3D12CommandProcessor : public CommandProcessor { std::unique_ptr view_heap_pool_ = nullptr; std::unique_ptr sampler_heap_pool_ = nullptr; + static constexpr uint32_t kSwapTextureWidth = 1280; + static constexpr uint32_t kSwapTextureHeight = 720; + ID3D12Resource* swap_texture_ = nullptr; + ID3D12DescriptorHeap* swap_texture_rtv_descriptor_heap_ = nullptr; + D3D12_CPU_DESCRIPTOR_HANDLE swap_texture_rtv_; + ID3D12DescriptorHeap* swap_texture_srv_descriptor_heap_ = nullptr; + // Unsubmitted barrier batch. std::vector barriers_; diff --git a/src/xenia/gpu/d3d12/d3d12_graphics_system.cc b/src/xenia/gpu/d3d12/d3d12_graphics_system.cc index 258f5867e..ae6272b45 100644 --- a/src/xenia/gpu/d3d12/d3d12_graphics_system.cc +++ b/src/xenia/gpu/d3d12/d3d12_graphics_system.cc @@ -9,6 +9,7 @@ #include "xenia/gpu/d3d12/d3d12_graphics_system.h" +#include "xenia/base/logging.h" #include "xenia/gpu/d3d12/d3d12_command_processor.h" #include "xenia/ui/d3d12/d3d12_provider.h" #include "xenia/xbox.h" @@ -17,6 +18,10 @@ namespace xe { namespace gpu { namespace d3d12 { +// Generated with `xb buildhlsl`. +#include "xenia/gpu/d3d12/shaders/bin/fullscreen_vs.h" +#include "xenia/gpu/d3d12/shaders/bin/stretch_ps.h" + D3D12GraphicsSystem::D3D12GraphicsSystem() {} D3D12GraphicsSystem::~D3D12GraphicsSystem() {} @@ -25,11 +30,138 @@ X_STATUS D3D12GraphicsSystem::Setup(cpu::Processor* processor, kernel::KernelState* kernel_state, ui::Window* target_window) { provider_ = xe::ui::d3d12::D3D12Provider::Create(target_window); + auto device = + static_cast(provider())->GetDevice(); - return GraphicsSystem::Setup(processor, kernel_state, target_window); + auto result = GraphicsSystem::Setup(processor, kernel_state, target_window); + if (result != X_STATUS_SUCCESS) { + return result; + } + + if (target_window) { + display_context_ = reinterpret_cast( + target_window->context()); + } + + // Create the stretch pipeline root signature. + D3D12_ROOT_PARAMETER stretch_root_parameter; + stretch_root_parameter.ParameterType = + D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + stretch_root_parameter.DescriptorTable.NumDescriptorRanges = 1; + D3D12_DESCRIPTOR_RANGE stretch_root_texture_range; + stretch_root_texture_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + stretch_root_texture_range.NumDescriptors = 1; + stretch_root_texture_range.BaseShaderRegister = 0; + stretch_root_texture_range.RegisterSpace = 0; + stretch_root_texture_range.OffsetInDescriptorsFromTableStart = 0; + stretch_root_parameter.DescriptorTable.pDescriptorRanges = + &stretch_root_texture_range; + stretch_root_parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + D3D12_STATIC_SAMPLER_DESC stretch_sampler_desc; + stretch_sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; + stretch_sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + stretch_sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + stretch_sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + stretch_sampler_desc.MipLODBias = 0.0f; + stretch_sampler_desc.MaxAnisotropy = 1; + stretch_sampler_desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + stretch_sampler_desc.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK; + stretch_sampler_desc.MinLOD = 0.0f; + stretch_sampler_desc.MaxLOD = 0.0f; + stretch_sampler_desc.ShaderRegister = 0; + stretch_sampler_desc.RegisterSpace = 0; + stretch_sampler_desc.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + D3D12_ROOT_SIGNATURE_DESC stretch_root_desc; + stretch_root_desc.NumParameters = 1; + stretch_root_desc.pParameters = &stretch_root_parameter; + stretch_root_desc.NumStaticSamplers = 1; + stretch_root_desc.pStaticSamplers = &stretch_sampler_desc; + stretch_root_desc.Flags = + D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS; + ID3DBlob* stretch_root_blob; + ID3DBlob* stretch_root_error_blob = nullptr; + if (FAILED(D3D12SerializeRootSignature( + &stretch_root_desc, D3D_ROOT_SIGNATURE_VERSION_1, &stretch_root_blob, + &stretch_root_error_blob))) { + XELOGE("Failed to serialize the front buffer stretch root signature"); + if (stretch_root_error_blob != nullptr) { + XELOGE("%s", reinterpret_cast( + stretch_root_error_blob->GetBufferPointer())); + stretch_root_error_blob->Release(); + } + return X_STATUS_UNSUCCESSFUL; + } + if (stretch_root_error_blob != nullptr) { + stretch_root_error_blob->Release(); + } + if (FAILED(device->CreateRootSignature( + 0, stretch_root_blob->GetBufferPointer(), + stretch_root_blob->GetBufferSize(), + IID_PPV_ARGS(&stretch_root_signature_)))) { + XELOGE("Failed to create the front buffer stretch root signature"); + stretch_root_blob->Release(); + return X_STATUS_UNSUCCESSFUL; + } + stretch_root_blob->Release(); + + // Create the stretch pipeline. + D3D12_GRAPHICS_PIPELINE_STATE_DESC stretch_pipeline_desc = {}; + stretch_pipeline_desc.pRootSignature = stretch_root_signature_; + stretch_pipeline_desc.VS.pShaderBytecode = fullscreen_vs; + stretch_pipeline_desc.VS.BytecodeLength = sizeof(fullscreen_vs); + stretch_pipeline_desc.PS.pShaderBytecode = stretch_ps; + stretch_pipeline_desc.PS.BytecodeLength = sizeof(stretch_ps); + stretch_pipeline_desc.BlendState.RenderTarget[0].RenderTargetWriteMask = + D3D12_COLOR_WRITE_ENABLE_ALL; + stretch_pipeline_desc.SampleMask = UINT_MAX; + stretch_pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + stretch_pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + stretch_pipeline_desc.RasterizerState.DepthClipEnable = TRUE; + stretch_pipeline_desc.PrimitiveTopologyType = + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + stretch_pipeline_desc.NumRenderTargets = 1; + stretch_pipeline_desc.RTVFormats[0] = + ui::d3d12::D3D12Context::kSwapChainFormat; + stretch_pipeline_desc.SampleDesc.Count = 1; + if (FAILED(device->CreateGraphicsPipelineState( + &stretch_pipeline_desc, IID_PPV_ARGS(&stretch_pipeline_)))) { + XELOGE("Failed to create the front buffer stretch pipeline state"); + stretch_root_signature_->Release(); + stretch_root_signature_ = nullptr; + return X_STATUS_UNSUCCESSFUL; + } + + return X_STATUS_SUCCESS; } -void D3D12GraphicsSystem::Shutdown() { GraphicsSystem::Shutdown(); } +void D3D12GraphicsSystem::Shutdown() { + if (stretch_pipeline_ != nullptr) { + stretch_pipeline_->Release(); + stretch_pipeline_ = nullptr; + } + if (stretch_root_signature_ != nullptr) { + stretch_root_signature_->Release(); + stretch_root_signature_ = nullptr; + } + + GraphicsSystem::Shutdown(); +} + +void D3D12GraphicsSystem::AwaitFrontBufferUnused() { + if (display_context_ != nullptr) { + display_context_->AwaitAllFramesCompletion(); + } +} + +void D3D12GraphicsSystem::StretchTextureToFrontBuffer( + D3D12_GPU_DESCRIPTOR_HANDLE handle, + ID3D12GraphicsCommandList* command_list) { + command_list->SetPipelineState(stretch_pipeline_); + command_list->SetGraphicsRootSignature(stretch_root_signature_); + command_list->SetGraphicsRootDescriptorTable(0, handle); + command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + command_list->DrawInstanced(3, 1, 0, 0); +} std::unique_ptr D3D12GraphicsSystem::CreateCommandProcessor() { @@ -38,13 +170,48 @@ D3D12GraphicsSystem::CreateCommandProcessor() { } void D3D12GraphicsSystem::Swap(xe::ui::UIEvent* e) { + if (display_context_->WasLost()) { + // We're crashing. Cheese it. + return; + } + if (!command_processor_) { return; } auto& swap_state = command_processor_->swap_state(); - std::lock_guard lock(swap_state.mutex); - swap_state.pending = false; + ID3D12DescriptorHeap* swap_srv_heap; + { + std::lock_guard lock(swap_state.mutex); + swap_state.pending = false; + swap_srv_heap = reinterpret_cast( + swap_state.front_buffer_texture); + } + if (swap_srv_heap == nullptr) { + // Not ready yet. + return; + } + + auto command_list = display_context_->GetSwapCommandList(); + uint32_t swap_width, swap_height; + display_context_->GetSwapChainSize(swap_width, swap_height); + D3D12_VIEWPORT viewport; + viewport.TopLeftX = 0.0f; + viewport.TopLeftY = 0.0f; + viewport.Width = float(swap_width); + viewport.Height = float(swap_height); + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 0.0f; + command_list->RSSetViewports(1, &viewport); + D3D12_RECT scissor; + scissor.left = 0; + scissor.top = 0; + scissor.right = swap_width; + scissor.bottom = swap_height; + command_list->RSSetScissorRects(1, &scissor); + command_list->SetDescriptorHeaps(1, &swap_srv_heap); + StretchTextureToFrontBuffer( + swap_srv_heap->GetGPUDescriptorHandleForHeapStart(), command_list); } } // namespace d3d12 diff --git a/src/xenia/gpu/d3d12/d3d12_graphics_system.h b/src/xenia/gpu/d3d12/d3d12_graphics_system.h index a8e6c711a..ec87082e5 100644 --- a/src/xenia/gpu/d3d12/d3d12_graphics_system.h +++ b/src/xenia/gpu/d3d12/d3d12_graphics_system.h @@ -14,6 +14,7 @@ #include "xenia/gpu/command_processor.h" #include "xenia/gpu/graphics_system.h" +#include "xenia/ui/d3d12/d3d12_context.h" namespace xe { namespace gpu { @@ -30,10 +31,24 @@ class D3D12GraphicsSystem : public GraphicsSystem { ui::Window* target_window) override; void Shutdown() override; + void AwaitFrontBufferUnused(); + + // Draws a texture covering the entire viewport to the render target currently + // bound on the specified command list (in D3D12Context::kSwapChainFormat). + // This changes the current pipeline, graphics root signature and primitive + // topology. + void StretchTextureToFrontBuffer(D3D12_GPU_DESCRIPTOR_HANDLE handle, + ID3D12GraphicsCommandList* command_list); + private: std::unique_ptr CreateCommandProcessor() override; void Swap(xe::ui::UIEvent* e) override; + + ui::d3d12::D3D12Context* display_context_ = nullptr; + + ID3D12RootSignature* stretch_root_signature_ = nullptr; + ID3D12PipelineState* stretch_pipeline_ = nullptr; }; } // namespace d3d12 diff --git a/src/xenia/gpu/d3d12/render_target_cache.cc b/src/xenia/gpu/d3d12/render_target_cache.cc index 28adddf6f..9f52cb217 100644 --- a/src/xenia/gpu/d3d12/render_target_cache.cc +++ b/src/xenia/gpu/d3d12/render_target_cache.cc @@ -1061,11 +1061,13 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory, return true; } -void RenderTargetCache::EndFrame() { +void RenderTargetCache::UnbindRenderTargets() { StoreRenderTargetsToEDRAM(); ClearBindings(); } +void RenderTargetCache::EndFrame() { UnbindRenderTargets(); } + DXGI_FORMAT RenderTargetCache::GetColorDXGIFormat( ColorRenderTargetFormat format) { switch (format) { diff --git a/src/xenia/gpu/d3d12/render_target_cache.h b/src/xenia/gpu/d3d12/render_target_cache.h index 253624854..74c85cf9f 100644 --- a/src/xenia/gpu/d3d12/render_target_cache.h +++ b/src/xenia/gpu/d3d12/render_target_cache.h @@ -220,6 +220,10 @@ class RenderTargetCache { // register values, and also clears the EDRAM buffer if needed. Must be in a // frame for calling. bool Resolve(SharedMemory* shared_memory, Memory* memory); + // Flushes the render targets to EDRAM and unbinds them, for instance, when + // the command processor takes over framebuffer bindings to draw something + // special. + void UnbindRenderTargets(); void EndFrame(); static inline bool IsColorFormat64bpp(ColorRenderTargetFormat format) { diff --git a/src/xenia/gpu/d3d12/shaders/edram_tile_sample_32bpp.cs.hlsl b/src/xenia/gpu/d3d12/shaders/edram_tile_sample_32bpp.cs.hlsl index 0df7dbdbb..e4c86f62a 100644 --- a/src/xenia/gpu/d3d12/shaders/edram_tile_sample_32bpp.cs.hlsl +++ b/src/xenia/gpu/d3d12/shaders/edram_tile_sample_32bpp.cs.hlsl @@ -22,7 +22,7 @@ void main(uint3 xe_group_id : SV_GroupID, uint4 sample_info = (xe_edram_tile_sample_dest_info.xxxx >> uint4(15u, 14u, 17u, 16u)) & 1u; uint2 edram_tile_quarter = - uint2(uint2(10u, 8u) <= xe_group_thread_id) * sample_info.xy; + uint2(uint2(10u, 8u) <= xe_group_thread_id.xy) * sample_info.xy; uint edram_offset = XeEDRAMOffset( (xe_group_id.xy << sample_info.xy) + edram_tile_quarter, (xe_group_thread_id.xy - edram_tile_quarter * uint2(10u, 8u)) << diff --git a/src/xenia/gpu/d3d12/shaders/fullscreen.vs.hlsl b/src/xenia/gpu/d3d12/shaders/fullscreen.vs.hlsl new file mode 100644 index 000000000..e862f0b7c --- /dev/null +++ b/src/xenia/gpu/d3d12/shaders/fullscreen.vs.hlsl @@ -0,0 +1,7 @@ +// A triangle covering the whole viewport. +void main(uint xe_vertex_id : SV_VertexID, out float2 xe_texcoord : TEXCOORD, + out float4 xe_position : SV_Position) { + xe_texcoord = float2(uint2(xe_vertex_id, xe_vertex_id << 1u) & 2u); + xe_position = + float4(xe_texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); +} diff --git a/src/xenia/gpu/d3d12/shaders/stretch.ps.hlsl b/src/xenia/gpu/d3d12/shaders/stretch.ps.hlsl new file mode 100644 index 000000000..e8a0647fe --- /dev/null +++ b/src/xenia/gpu/d3d12/shaders/stretch.ps.hlsl @@ -0,0 +1,5 @@ +Texture2D xe_texture : register(t0); +SamplerState xe_sampler : register(s0); +float4 main(float2 xe_texcoord : TEXCOORD) : SV_Target { + return xe_texture.SampleLevel(xe_sampler, xe_texcoord, 0.0f); +} diff --git a/src/xenia/gpu/d3d12/shared_memory.h b/src/xenia/gpu/d3d12/shared_memory.h index 39b21eb8a..828c74b30 100644 --- a/src/xenia/gpu/d3d12/shared_memory.h +++ b/src/xenia/gpu/d3d12/shared_memory.h @@ -16,7 +16,6 @@ #include "xenia/memory.h" #include "xenia/ui/d3d12/d3d12_api.h" -#include "xenia/ui/d3d12/d3d12_context.h" #include "xenia/ui/d3d12/pools.h" namespace xe { diff --git a/src/xenia/gpu/d3d12/texture_cache.cc b/src/xenia/gpu/d3d12/texture_cache.cc index 55ffa672a..920766d0f 100644 --- a/src/xenia/gpu/d3d12/texture_cache.cc +++ b/src/xenia/gpu/d3d12/texture_cache.cc @@ -450,6 +450,39 @@ void TextureCache::WriteSampler(uint32_t fetch_constant, device->CreateSampler(&desc, handle); } +bool TextureCache::RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle) { + auto group = reinterpret_cast( + ®ister_file_->values[XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0]); + auto& fetch = group->texture_fetch; + TextureKey key; + uint32_t swizzle; + TextureKeyFromFetchConstant(group->texture_fetch, key, swizzle); + if (key.base_page == 0 || key.dimension != Dimension::k2D) { + return false; + } + Texture* texture = FindOrCreateTexture(key); + if (texture == nullptr || !LoadTextureData(texture)) { + return false; + } + command_processor_->PushTransitionBarrier( + texture->resource, texture->state, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc; + srv_desc.Format = host_formats_[uint32_t(key.format)].dxgi_format; + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srv_desc.Shader4ComponentMapping = + swizzle | + D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES; + srv_desc.Texture2D.MostDetailedMip = 0; + srv_desc.Texture2D.MipLevels = 1; + srv_desc.Texture2D.PlaneSlice = 0; + srv_desc.Texture2D.ResourceMinLODClamp = 0.0f; + auto device = + command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice(); + device->CreateShaderResourceView(texture->resource, &srv_desc, handle); + return true; +} + void TextureCache::TextureKeyFromFetchConstant( const xenos::xe_gpu_texture_fetch_t& fetch, TextureKey& key_out, uint32_t& swizzle_out) { diff --git a/src/xenia/gpu/d3d12/texture_cache.h b/src/xenia/gpu/d3d12/texture_cache.h index e717126af..cc4d73d00 100644 --- a/src/xenia/gpu/d3d12/texture_cache.h +++ b/src/xenia/gpu/d3d12/texture_cache.h @@ -78,6 +78,8 @@ class TextureCache { void WriteSampler(uint32_t fetch_constant, D3D12_CPU_DESCRIPTOR_HANDLE handle); + bool RequestSwapTexture(D3D12_CPU_DESCRIPTOR_HANDLE handle); + private: struct CopyModeInfo { const void* load_shader; diff --git a/src/xenia/ui/d3d12/d3d12_context.h b/src/xenia/ui/d3d12/d3d12_context.h index e64cff97e..8217e4861 100644 --- a/src/xenia/ui/d3d12/d3d12_context.h +++ b/src/xenia/ui/d3d12/d3d12_context.h @@ -69,6 +69,10 @@ class D3D12Context : public GraphicsContext { D3D12_CPU_DESCRIPTOR_HANDLE GetSwapChainBackBufferRTV() const { return GetSwapChainBufferRTV(GetSwapChainBackBufferIndex()); } + void GetSwapChainSize(uint32_t& width, uint32_t& height) const { + width = swap_chain_width_; + height = swap_chain_height_; + } ID3D12GraphicsCommandList* GetSwapCommandList() const { return swap_command_lists_[current_queue_frame_]->GetCommandList(); }