diff --git a/include/rex/graphics/d3d12/command_processor.h b/include/rex/graphics/d3d12/command_processor.h index 209a5c2..12dd68c 100644 --- a/include/rex/graphics/d3d12/command_processor.h +++ b/include/rex/graphics/d3d12/command_processor.h @@ -103,6 +103,8 @@ class D3D12CommandProcessor : public CommandProcessor { ui::d3d12::D3D12UploadBufferPool& GetConstantBufferPool() const { return *constant_buffer_pool_; } + D3D12SharedMemory& GetSharedMemory() const { return *shared_memory_; } + D3D12_CPU_DESCRIPTOR_HANDLE GetViewBindlessHeapCPUStart() const { assert_true(bindless_resources_used_); return view_bindless_heap_cpu_start_; diff --git a/include/rex/graphics/d3d12/deferred_command_list.h b/include/rex/graphics/d3d12/deferred_command_list.h index d58878d..3bf1684 100644 --- a/include/rex/graphics/d3d12/deferred_command_list.h +++ b/include/rex/graphics/d3d12/deferred_command_list.h @@ -91,6 +91,23 @@ class DeferredCommandList { } } + void D3DClearUnorderedAccessViewFloat( + D3D12_GPU_DESCRIPTOR_HANDLE view_gpu_handle_in_current_heap, + D3D12_CPU_DESCRIPTOR_HANDLE view_cpu_handle, ID3D12Resource* resource, + const FLOAT values[4], UINT num_rects, const D3D12_RECT* rects) { + auto args = reinterpret_cast( + WriteCommand(Command::kD3DClearUnorderedAccessViewFloat, + sizeof(ClearUnorderedAccessViewHeader) + num_rects * sizeof(D3D12_RECT))); + args->view_gpu_handle_in_current_heap = view_gpu_handle_in_current_heap; + args->view_cpu_handle = view_cpu_handle; + args->resource = resource; + std::memcpy(args->values_float, values, 4 * sizeof(FLOAT)); + args->num_rects = num_rects; + if (num_rects != 0) { + std::memcpy(args + 1, rects, num_rects * sizeof(D3D12_RECT)); + } + } + void D3DCopyBufferRegion(ID3D12Resource* dst_buffer, UINT64 dst_offset, ID3D12Resource* src_buffer, UINT64 src_offset, UINT64 num_bytes) { auto& args = *reinterpret_cast( @@ -456,6 +473,7 @@ class DeferredCommandList { kD3DClearDepthStencilView, kD3DClearRenderTargetView, kD3DClearUnorderedAccessViewUint, + kD3DClearUnorderedAccessViewFloat, kD3DCopyBufferRegion, kD3DCopyResource, kCopyTexture, diff --git a/include/rex/graphics/native_guest_renderer.h b/include/rex/graphics/native_guest_renderer.h new file mode 100644 index 0000000..3c93833 --- /dev/null +++ b/include/rex/graphics/native_guest_renderer.h @@ -0,0 +1,89 @@ +#pragma once + +#include + +#if REX_HAS_D3D12 +#include +#endif + +namespace rex::graphics::d3d12 { +class D3D12CommandProcessor; +} + +namespace rex::graphics { + +enum class NativeGuestOutputBackend : uint32_t { + kUnknown = 0, + kD3D12, + kVulkan, +}; + +struct NativeGuestOutputRenderContext { + NativeGuestOutputBackend backend = NativeGuestOutputBackend::kUnknown; + uint32_t guest_output_width = 0; + uint32_t guest_output_height = 0; + uint32_t display_width = 0; + uint32_t display_height = 0; + +#if REX_HAS_D3D12 + struct D3D12Context { + d3d12::D3D12CommandProcessor* command_processor = nullptr; + void* command_processor_user_data = nullptr; + ID3D12Device* device = nullptr; + ID3D12Resource* guest_output_resource = nullptr; + DXGI_FORMAT guest_output_format = DXGI_FORMAT_UNKNOWN; + D3D12_RESOURCE_STATES guest_output_initial_state = D3D12_RESOURCE_STATE_COMMON; + bool (*request_one_use_view_descriptor)(void* user_data, + D3D12_CPU_DESCRIPTOR_HANDLE* cpu_out, + D3D12_GPU_DESCRIPTOR_HANDLE* gpu_out) = nullptr; + bool (*create_root_signature)(void* user_data, const D3D12_ROOT_SIGNATURE_DESC* desc, + ID3D12RootSignature** root_signature_out) = nullptr; + bool (*push_transition_barrier)(void* user_data, ID3D12Resource* resource, + D3D12_RESOURCE_STATES old_state, + D3D12_RESOURCE_STATES new_state) = nullptr; + void (*submit_barriers)(void* user_data) = nullptr; + void (*copy_texture_region)(void* user_data, const D3D12_TEXTURE_COPY_LOCATION* dst, + UINT dst_x, UINT dst_y, UINT dst_z, + const D3D12_TEXTURE_COPY_LOCATION* src, + const D3D12_BOX* src_box) = nullptr; + void (*clear_render_target_view)(void* user_data, D3D12_CPU_DESCRIPTOR_HANDLE rtv, + const FLOAT color[4]) = nullptr; + void (*clear_unordered_access_view_float)(void* user_data, + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, + D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, + ID3D12Resource* resource, + const FLOAT values[4]) = nullptr; + void (*set_graphics_root_signature)(void* user_data, + ID3D12RootSignature* root_signature) = nullptr; + void (*set_graphics_root_32bit_constants)(void* user_data, UINT root_parameter_index, + UINT num_32bit_values_to_set, + const void* src_data, + UINT dest_offset_in_32bit_values) = nullptr; + void (*set_graphics_root_descriptor_table)(void* user_data, UINT root_parameter_index, + D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) = + nullptr; + void (*set_pipeline_state)(void* user_data, ID3D12PipelineState* pipeline_state) = nullptr; + void (*ia_set_primitive_topology)(void* user_data, + D3D12_PRIMITIVE_TOPOLOGY primitive_topology) = nullptr; + void (*ia_set_vertex_buffers)(void* user_data, UINT start_slot, UINT num_views, + const D3D12_VERTEX_BUFFER_VIEW* views) = nullptr; + void (*om_set_render_targets)(void* user_data, UINT num_render_target_descriptors, + const D3D12_CPU_DESCRIPTOR_HANDLE* render_target_descriptors, + BOOL rts_single_handle_to_descriptor_range, + const D3D12_CPU_DESCRIPTOR_HANDLE* depth_stencil_descriptor) = + nullptr; + void (*rs_set_viewport)(void* user_data, const D3D12_VIEWPORT* viewport) = nullptr; + void (*rs_set_scissor_rect)(void* user_data, const D3D12_RECT* rect) = nullptr; + void (*draw_instanced)(void* user_data, UINT vertex_count_per_instance, UINT instance_count, + UINT start_vertex_location, UINT start_instance_location) = nullptr; + } d3d12; +#endif +}; + +using NativeGuestOutputRenderer = bool (*)(const NativeGuestOutputRenderContext& context, + void* user_data); + +void SetNativeGuestOutputRenderer(NativeGuestOutputRenderer renderer, void* user_data); +bool TryRenderNativeGuestOutput(const NativeGuestOutputRenderContext& context); + +} // namespace rex::graphics diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index 8e898b6..43e8e78 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -24,6 +24,7 @@ set(REXGRAPHICS_SYSTEM_SOURCES util/draw_extent_estimator.cpp util/draw.cpp packet_disassembler.cpp + native_guest_renderer.cpp primitive_processor.cpp pipeline/render_target/cache.cpp shared_memory.cpp @@ -148,4 +149,3 @@ if(REXGLUE_USE_D3D12) ) target_compile_definitions(rexgraphics PUBLIC REX_HAS_D3D12=1) endif() - diff --git a/src/graphics/d3d12/command_processor.cpp b/src/graphics/d3d12/command_processor.cpp index a93d9cb..0917a3e 100644 --- a/src/graphics/d3d12/command_processor.cpp +++ b/src/graphics/d3d12/command_processor.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2320,7 +2321,8 @@ void D3D12CommandProcessor::IssueSwap(uint32_t frontbuffer_ptr, uint32_t frontbu presenter->RefreshGuestOutput( guest_output_width, guest_output_height, display_width, display_height, [this, &swap_texture_srv_desc, frontbuffer_format, swap_texture_resource, guest_output_width, - guest_output_height](ui::Presenter::GuestOutputRefreshContext& context) -> bool { + guest_output_height, display_width, + display_height](ui::Presenter::GuestOutputRefreshContext& context) -> bool { const ui::d3d12::D3D12Provider& provider = GetD3D12Provider(); ID3D12Device* device = provider.GetDevice(); @@ -2378,6 +2380,148 @@ void D3D12CommandProcessor::IssueSwap(uint32_t frontbuffer_ptr, uint32_t frontbu context.SetIs8bpc(!use_pwl_gamma_ramp && !use_fxaa); + ID3D12Resource* guest_output_resource = + static_cast(context) + .resource_uav_capable(); + + NativeGuestOutputRenderContext native_context; + native_context.backend = NativeGuestOutputBackend::kD3D12; + native_context.guest_output_width = guest_output_width; + native_context.guest_output_height = guest_output_height; + native_context.display_width = display_width; + native_context.display_height = display_height; + native_context.d3d12.command_processor = this; + native_context.d3d12.command_processor_user_data = this; + native_context.d3d12.device = device; + native_context.d3d12.guest_output_resource = guest_output_resource; + native_context.d3d12.guest_output_format = ui::d3d12::D3D12Presenter::kGuestOutputFormat; + native_context.d3d12.guest_output_initial_state = + ui::d3d12::D3D12Presenter::kGuestOutputInternalState; + native_context.d3d12.request_one_use_view_descriptor = + [](void* user_data, D3D12_CPU_DESCRIPTOR_HANDLE* cpu_out, + D3D12_GPU_DESCRIPTOR_HANDLE* gpu_out) -> bool { + auto* command_processor = static_cast(user_data); + ui::d3d12::util::DescriptorCpuGpuHandlePair descriptor; + if (!command_processor->RequestOneUseSingleViewDescriptors(1, &descriptor)) { + return false; + } + *cpu_out = descriptor.first; + *gpu_out = descriptor.second; + return true; + }; + native_context.d3d12.create_root_signature = + [](void* user_data, const D3D12_ROOT_SIGNATURE_DESC* desc, + ID3D12RootSignature** root_signature_out) -> bool { + auto* command_processor = static_cast(user_data); + *root_signature_out = + ui::d3d12::util::CreateRootSignature(command_processor->GetD3D12Provider(), *desc); + return *root_signature_out != nullptr; + }; + native_context.d3d12.push_transition_barrier = + [](void* user_data, ID3D12Resource* resource, D3D12_RESOURCE_STATES old_state, + D3D12_RESOURCE_STATES new_state) -> bool { + return static_cast(user_data)->PushTransitionBarrier( + resource, old_state, new_state); + }; + native_context.d3d12.submit_barriers = [](void* user_data) { + static_cast(user_data)->SubmitBarriers(); + }; + native_context.d3d12.copy_texture_region = + [](void* user_data, const D3D12_TEXTURE_COPY_LOCATION* dst, UINT dst_x, UINT dst_y, + UINT dst_z, const D3D12_TEXTURE_COPY_LOCATION* src, const D3D12_BOX* src_box) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DCopyTextureRegion(dst, dst_x, dst_y, dst_z, src, src_box); + }; + native_context.d3d12.clear_render_target_view = + [](void* user_data, D3D12_CPU_DESCRIPTOR_HANDLE rtv, const FLOAT color[4]) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DClearRenderTargetView(rtv, color, 0, nullptr); + }; + native_context.d3d12.clear_unordered_access_view_float = + [](void* user_data, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, + D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource* resource, + const FLOAT values[4]) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DClearUnorderedAccessViewFloat(gpu_handle, cpu_handle, resource, values, 0, + nullptr); + }; + native_context.d3d12.set_graphics_root_signature = + [](void* user_data, ID3D12RootSignature* root_signature) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DSetGraphicsRootSignature(root_signature); + }; + native_context.d3d12.set_graphics_root_32bit_constants = + [](void* user_data, UINT root_parameter_index, UINT num_32bit_values_to_set, + const void* src_data, UINT dest_offset_in_32bit_values) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DSetGraphicsRoot32BitConstants(root_parameter_index, num_32bit_values_to_set, + src_data, dest_offset_in_32bit_values); + }; + native_context.d3d12.set_graphics_root_descriptor_table = + [](void* user_data, UINT root_parameter_index, + D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DSetGraphicsRootDescriptorTable(root_parameter_index, base_descriptor); + }; + native_context.d3d12.set_pipeline_state = + [](void* user_data, ID3D12PipelineState* pipeline_state) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DSetPipelineState(pipeline_state); + }; + native_context.d3d12.ia_set_primitive_topology = + [](void* user_data, D3D12_PRIMITIVE_TOPOLOGY primitive_topology) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DIASetPrimitiveTopology(primitive_topology); + }; + native_context.d3d12.ia_set_vertex_buffers = + [](void* user_data, UINT start_slot, UINT num_views, + const D3D12_VERTEX_BUFFER_VIEW* views) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DIASetVertexBuffers(start_slot, num_views, views); + }; + native_context.d3d12.om_set_render_targets = + [](void* user_data, UINT num_render_target_descriptors, + const D3D12_CPU_DESCRIPTOR_HANDLE* render_target_descriptors, + BOOL rts_single_handle_to_descriptor_range, + const D3D12_CPU_DESCRIPTOR_HANDLE* depth_stencil_descriptor) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DOMSetRenderTargets(num_render_target_descriptors, render_target_descriptors, + rts_single_handle_to_descriptor_range, + depth_stencil_descriptor); + }; + native_context.d3d12.rs_set_viewport = [](void* user_data, + const D3D12_VIEWPORT* viewport) { + static_cast(user_data) + ->GetDeferredCommandList() + .RSSetViewport(*viewport); + }; + native_context.d3d12.rs_set_scissor_rect = [](void* user_data, const D3D12_RECT* rect) { + static_cast(user_data)->GetDeferredCommandList().RSSetScissorRect( + *rect); + }; + native_context.d3d12.draw_instanced = + [](void* user_data, UINT vertex_count_per_instance, UINT instance_count, + UINT start_vertex_location, UINT start_instance_location) { + static_cast(user_data) + ->GetDeferredCommandList() + .D3DDrawInstanced(vertex_count_per_instance, instance_count, start_vertex_location, + start_instance_location); + }; + if (TryRenderNativeGuestOutput(native_context)) { + EndSubmission(true); + return true; + } + // Upload the new gamma ramp, using the upload buffer for the current // frame (will close the frame after this anyway, so can't write // multiple times per frame). @@ -2438,10 +2582,6 @@ void D3D12CommandProcessor::IssueSwap(uint32_t frontbuffer_ptr, uint32_t frontbu WriteGammaRampSRV(use_pwl_gamma_ramp, apply_gamma_descriptor_gamma_ramp.first); } - ID3D12Resource* guest_output_resource = - static_cast(context) - .resource_uav_capable(); - if (use_fxaa) { fxaa_source_texture_submission_ = submission_current_; } diff --git a/src/graphics/d3d12/deferred_command_list.cpp b/src/graphics/d3d12/deferred_command_list.cpp index 179a3ea..f9d66f5 100644 --- a/src/graphics/d3d12/deferred_command_list.cpp +++ b/src/graphics/d3d12/deferred_command_list.cpp @@ -36,6 +36,7 @@ DeferredCommandPerfCategory GetPerfCategory(DeferredCommandList::Command command case Command::kD3DClearDepthStencilView: case Command::kD3DClearRenderTargetView: case Command::kD3DClearUnorderedAccessViewUint: + case Command::kD3DClearUnorderedAccessViewFloat: return {CounterId::kDeferredClearCount, CounterId::kDeferredClearUs, CounterId::kGpuClearUs}; case Command::kD3DResourceBarrier: @@ -146,6 +147,13 @@ void DeferredCommandList::Execute(ID3D12GraphicsCommandList* command_list, args.values_uint, args.num_rects, args.num_rects ? reinterpret_cast(&args + 1) : nullptr); } break; + case Command::kD3DClearUnorderedAccessViewFloat: { + auto& args = *reinterpret_cast(stream); + command_list->ClearUnorderedAccessViewFloat( + args.view_gpu_handle_in_current_heap, args.view_cpu_handle, args.resource, + args.values_float, args.num_rects, + args.num_rects ? reinterpret_cast(&args + 1) : nullptr); + } break; case Command::kD3DCopyBufferRegion: { auto& args = *reinterpret_cast(stream); PERF_counter_add(kDeferredCopyBufferBytes, static_cast(args.num_bytes)); diff --git a/src/graphics/native_guest_renderer.cpp b/src/graphics/native_guest_renderer.cpp new file mode 100644 index 0000000..04d0a98 --- /dev/null +++ b/src/graphics/native_guest_renderer.cpp @@ -0,0 +1,27 @@ +#include + +#include + +namespace rex::graphics { +namespace { + +std::atomic g_renderer{nullptr}; +std::atomic g_renderer_user_data{nullptr}; + +} // namespace + +void SetNativeGuestOutputRenderer(NativeGuestOutputRenderer renderer, void* user_data) { + g_renderer_user_data.store(user_data, std::memory_order_release); + g_renderer.store(renderer, std::memory_order_release); +} + +bool TryRenderNativeGuestOutput(const NativeGuestOutputRenderContext& context) { + NativeGuestOutputRenderer renderer = g_renderer.load(std::memory_order_acquire); + if (renderer == nullptr) { + return false; + } + void* user_data = g_renderer_user_data.load(std::memory_order_acquire); + return renderer(context, user_data); +} + +} // namespace rex::graphics diff --git a/src/ui/d3d12/d3d12_presenter.cpp b/src/ui/d3d12/d3d12_presenter.cpp index db67382..146c021 100644 --- a/src/ui/d3d12/d3d12_presenter.cpp +++ b/src/ui/d3d12/d3d12_presenter.cpp @@ -626,7 +626,8 @@ bool D3D12Presenter::RefreshGuestOutputImpl( guest_output_resource_new_desc.SampleDesc.Count = 1; guest_output_resource_new_desc.SampleDesc.Quality = 0; guest_output_resource_new_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - guest_output_resource_new_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + guest_output_resource_new_desc.Flags = + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS | D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; if (FAILED(device->CreateCommittedResource( &util::kHeapPropertiesDefault, provider_.GetHeapFlagCreateNotZeroed(), &guest_output_resource_new_desc, kGuestOutputInternalState, nullptr,