#include "ac6_native_graphics.h" #include #include #include #include #include #include #include #include #include #include #include "d3d_hooks.h" #if REX_HAS_D3D12 #include #include #include #include #include #endif REXCVAR_DEFINE_BOOL(ac6_native_graphics_bootstrap, true, "AC6/Render", "Use the experimental native graphics bootstrap backend"); REXCVAR_DEFINE_BOOL( ac6_native_graphics_placeholder_present, false, "AC6/Render", "Allow the native graphics bootstrap backend to replace the legacy swap path with a " "preview frame generated by the experimental native replay compositor"); REXCVAR_DEFINE_BOOL( ac6_allow_gpu_trace_stream, false, "AC6/Render", "Allow legacy GPU trace streaming during AC6 native graphics experiments"); namespace ac6::graphics { namespace { using rex::X_STATUS; #if REX_HAS_D3D12 namespace shaders { #include "thirdparty/rexglue-sdk/src/ui/shaders/bytecode/d3d12_5_1/immediate_ps.h" #include "thirdparty/rexglue-sdk/src/ui/shaders/bytecode/d3d12_5_1/immediate_vs.h" } // namespace shaders #endif std::mutex g_native_graphics_status_mutex; NativeGraphicsStatusSnapshot g_native_graphics_status{}; struct CapturedFrameEvent { enum class Type { kDraw, kClear, kResolve, }; uint32_t sequence = 0; Type type = Type::kDraw; const ac6::d3d::ShadowState* shadow_state = nullptr; }; struct ReplayPassCandidate { ac6::d3d::ShadowState binding{}; uint32_t start_sequence = 0; uint32_t end_sequence = 0; uint32_t draw_count = 0; uint32_t clear_count = 0; uint32_t resolve_count = 0; }; struct ReplayCandidateKey { uint32_t rt0 = 0; uint32_t depth_stencil = 0; uint32_t viewport_x = 0; uint32_t viewport_y = 0; uint32_t viewport_width = 0; uint32_t viewport_height = 0; }; constexpr uint32_t kSelectedPassPreviewColorSampleCount = 4; constexpr uint32_t kSelectedPassPreviewStepCount = 4; using FloatColor = std::array; struct SelectedPassClearStep { uint32_t color = 0; uint32_t rect_count = 0; std::array rects{}; }; struct SelectedPassPreviewData { SelectedPassPreviewSummary summary{}; std::array clear_steps{}; uint32_t clear_step_count = 0; }; bool SamePassBinding(const ac6::d3d::ShadowState& left, const ac6::d3d::ShadowState& right) { return left.render_targets[0] == right.render_targets[0] && left.depth_stencil == right.depth_stencil && left.viewport.width == right.viewport.width && left.viewport.height == right.viewport.height; } bool SameReplayCandidate(const ReplayCandidateKey& left, const ReplayCandidateKey& right) { return left.rt0 == right.rt0 && left.depth_stencil == right.depth_stencil && left.viewport_x == right.viewport_x && left.viewport_y == right.viewport_y && left.viewport_width == right.viewport_width && left.viewport_height == right.viewport_height; } ReplayCandidateKey MakeReplayCandidateKey(const NativeReplayPlanSummary& replay_plan) { return ReplayCandidateKey{replay_plan.present_candidate_rt0, replay_plan.present_candidate_depth_stencil, replay_plan.present_candidate_viewport_x, replay_plan.present_candidate_viewport_y, replay_plan.present_candidate_viewport_width, replay_plan.present_candidate_viewport_height}; } bool SequenceInSelectedPass(uint32_t sequence, const NativeReplayPlanSummary& replay_plan) { return replay_plan.valid && sequence >= replay_plan.selected_pass_start_sequence && sequence <= replay_plan.selected_pass_end_sequence; } FloatColor DecodeArgbColor(uint32_t packed_color) { return {float((packed_color >> 16) & 0xFFu) / 255.0f, float((packed_color >> 8) & 0xFFu) / 255.0f, float(packed_color & 0xFFu) / 255.0f, 1.0f}; } FloatColor MixColors(const FloatColor& left, const FloatColor& right, float t) { const float clamped_t = std::clamp(t, 0.0f, 1.0f); const float inverse_t = 1.0f - clamped_t; return {left[0] * inverse_t + right[0] * clamped_t, left[1] * inverse_t + right[1] * clamped_t, left[2] * inverse_t + right[2] * clamped_t, 1.0f}; } uint32_t PackImmediateColor(const FloatColor& color) { const auto pack_channel = [](float value) -> uint32_t { return uint32_t(std::clamp(value, 0.0f, 1.0f) * 255.0f + 0.5f); }; const uint32_t r = pack_channel(color[0]); const uint32_t g = pack_channel(color[1]); const uint32_t b = pack_channel(color[2]); const uint32_t a = pack_channel(color[3]); return r | (g << 8) | (b << 16) | (a << 24); } uint32_t ScoreReplayPass(const ReplayPassCandidate& pass, const rex::system::GraphicsSwapSubmission& submission, bool is_last_pass) { uint32_t score = 0; if (pass.binding.viewport.width == submission.frontbuffer_width && pass.binding.viewport.height == submission.frontbuffer_height) { score += 100; } if (pass.draw_count) { score += 40 + std::min(pass.draw_count, 64); } if (pass.resolve_count) { score += 20; } if (pass.binding.render_targets[0]) { score += 10; } if (is_last_pass) { score += 25; } return score; } NativeReplayPlanSummary AnalyzeReplayPlan( const ac6::d3d::FrameCaptureSnapshot& frame_capture, const rex::system::GraphicsSwapSubmission& submission) { NativeReplayPlanSummary summary; summary.frame_index = frame_capture.frame_index; std::vector events; events.reserve(frame_capture.draws.size() + frame_capture.clears.size() + frame_capture.resolves.size()); for (const auto& draw : frame_capture.draws) { events.push_back( {draw.sequence, CapturedFrameEvent::Type::kDraw, &draw.shadow_state}); } for (const auto& clear : frame_capture.clears) { events.push_back( {clear.sequence, CapturedFrameEvent::Type::kClear, &clear.shadow_state}); } for (const auto& resolve : frame_capture.resolves) { events.push_back( {resolve.sequence, CapturedFrameEvent::Type::kResolve, &resolve.shadow_state}); } if (events.empty()) { return summary; } std::sort(events.begin(), events.end(), [](const CapturedFrameEvent& left, const CapturedFrameEvent& right) { return left.sequence < right.sequence; }); std::vector passes; ReplayPassCandidate current_pass; bool current_pass_valid = false; auto flush_pass = [&]() { if (!current_pass_valid) { return; } passes.push_back(current_pass); current_pass = {}; current_pass_valid = false; }; for (const CapturedFrameEvent& event : events) { if (!event.shadow_state) { continue; } if (!current_pass_valid || !SamePassBinding(current_pass.binding, *event.shadow_state)) { flush_pass(); current_pass.binding = *event.shadow_state; current_pass.start_sequence = event.sequence; current_pass_valid = true; } current_pass.end_sequence = event.sequence; switch (event.type) { case CapturedFrameEvent::Type::kDraw: ++summary.draw_event_count; ++current_pass.draw_count; break; case CapturedFrameEvent::Type::kClear: ++summary.clear_event_count; ++current_pass.clear_count; break; case CapturedFrameEvent::Type::kResolve: ++summary.resolve_event_count; ++current_pass.resolve_count; break; } } flush_pass(); summary.pass_count = static_cast(passes.size()); if (!passes.empty()) { summary.first_pass_draw_count = passes.front().draw_count; summary.last_pass_draw_count = passes.back().draw_count; } uint32_t best_score = 0; uint32_t best_index = 0; bool best_index_valid = false; for (uint32_t i = 0; i < passes.size(); ++i) { const ReplayPassCandidate& pass = passes[i]; summary.largest_pass_draw_count = std::max(summary.largest_pass_draw_count, pass.draw_count); bool matches_swap_size = pass.binding.viewport.width == submission.frontbuffer_width && pass.binding.viewport.height == submission.frontbuffer_height; if (matches_swap_size) { ++summary.swap_size_match_pass_count; } bool is_last_pass = (i + 1) == passes.size(); uint32_t score = ScoreReplayPass(pass, submission, is_last_pass); if (!best_index_valid || score > best_score || (score == best_score && i > best_index)) { best_index_valid = true; best_index = i; best_score = score; } } if (best_index_valid) { const ReplayPassCandidate& selected_pass = passes[best_index]; summary.selected_pass_index = best_index; summary.selected_pass_score = best_score; summary.selected_pass_start_sequence = selected_pass.start_sequence; summary.selected_pass_end_sequence = selected_pass.end_sequence; summary.selected_pass_draw_count = selected_pass.draw_count; summary.selected_pass_clear_count = selected_pass.clear_count; summary.selected_pass_resolve_count = selected_pass.resolve_count; summary.selected_pass_is_last = (best_index + 1) == passes.size(); summary.selected_pass_has_resolve = selected_pass.resolve_count != 0; summary.present_candidate_rt0 = selected_pass.binding.render_targets[0]; summary.present_candidate_depth_stencil = selected_pass.binding.depth_stencil; summary.present_candidate_viewport_x = selected_pass.binding.viewport.x; summary.present_candidate_viewport_y = selected_pass.binding.viewport.y; summary.present_candidate_viewport_width = selected_pass.binding.viewport.width; summary.present_candidate_viewport_height = selected_pass.binding.viewport.height; summary.present_candidate_matches_swap_size = summary.present_candidate_viewport_width == submission.frontbuffer_width && summary.present_candidate_viewport_height == submission.frontbuffer_height; summary.valid = true; } return summary; } SelectedPassPreviewData BuildSelectedPassPreview( const ac6::d3d::FrameCaptureSnapshot& frame_capture, const NativeReplayPlanSummary& replay_plan) { SelectedPassPreviewData preview; if (!replay_plan.valid) { return preview; } preview.summary.valid = true; preview.summary.draw_count = replay_plan.selected_pass_draw_count; preview.summary.clear_count = replay_plan.selected_pass_clear_count; preview.summary.resolve_count = replay_plan.selected_pass_resolve_count; bool has_first_clear = false; for (const auto& clear : frame_capture.clears) { if (!SequenceInSelectedPass(clear.sequence, replay_plan)) { continue; } if (!has_first_clear) { preview.summary.first_clear_color = clear.color; has_first_clear = true; } preview.summary.last_clear_color = clear.color; preview.summary.using_clear_fill = true; preview.summary.sampled_clear_rect_count += clear.captured_rect_count; if (preview.clear_step_count < preview.clear_steps.size()) { SelectedPassClearStep& step = preview.clear_steps[preview.clear_step_count++]; step.color = clear.color; step.rect_count = clear.captured_rect_count; step.rects = clear.rects; } else { SelectedPassClearStep& step = preview.clear_steps.back(); step.color = clear.color; step.rect_count = clear.captured_rect_count; step.rects = clear.rects; } } preview.summary.sampled_clear_color_count = preview.clear_step_count; return preview; } #if REX_HAS_D3D12 class Ac6NativeGraphicsSystem final : public rex::graphics::d3d12::D3D12GraphicsSystem { public: X_STATUS Setup(rex::runtime::FunctionDispatcher* function_dispatcher, rex::system::KernelState* kernel_state, rex::ui::WindowedAppContext* app_context, bool with_presentation) override { X_STATUS status = rex::graphics::d3d12::D3D12GraphicsSystem::Setup( function_dispatcher, kernel_state, app_context, with_presentation); if (XFAILED(status)) { return status; } d3d12_provider_ = static_cast(provider()); d3d12_presenter_ = with_presentation ? static_cast(presenter()) : nullptr; if (!d3d12_provider_) { REXLOG_ERROR("AC6 native graphics bootstrap failed to acquire the D3D12 provider"); rex::graphics::d3d12::D3D12GraphicsSystem::Shutdown(); return X_STATUS_UNSUCCESSFUL; } { std::lock_guard lock(g_native_graphics_status_mutex); g_native_graphics_status.backend_active = true; g_native_graphics_status.provider_ready = d3d12_provider_ != nullptr; g_native_graphics_status.presenter_ready = d3d12_presenter_ != nullptr; } if (REXCVAR_GET(ac6_native_graphics_placeholder_present)) { REXLOG_WARN( "AC6 native graphics bootstrap backend is active. The legacy D3D12 " "graphics core remains enabled for compatibility, while direct swap " "presentation is intercepted by the native replay preview path."); } else { REXLOG_WARN( "AC6 native graphics bootstrap backend is active. The legacy D3D12 " "graphics core remains enabled for compatibility, and direct swap " "submissions are observed natively while legacy PM4 presentation " "remains authoritative."); } return X_STATUS_SUCCESS; } void Shutdown() override { ShutdownPlaceholderRefreshResources(); { std::lock_guard lock(g_native_graphics_status_mutex); g_native_graphics_status.backend_active = false; g_native_graphics_status.provider_ready = false; g_native_graphics_status.presenter_ready = false; g_native_graphics_status.placeholder_resources_initialized = false; g_native_graphics_status.last_swap_intercepted = false; g_native_graphics_status.last_swap_fell_back = false; } d3d12_presenter_ = nullptr; d3d12_provider_ = nullptr; last_swap_submission_ = {}; swap_count_ = 0; last_replay_plan_ = {}; last_selected_pass_preview_ = {}; last_selected_candidate_ = {}; last_selected_candidate_valid_ = false; selected_candidate_streak_ = 0; logged_first_swap_ = false; logged_first_present_ = false; logged_passthrough_swap_ = false; logged_refresh_failure_ = false; last_present_used_raster_replay_ = false; rex::graphics::d3d12::D3D12GraphicsSystem::Shutdown(); } bool HandleVideoSwap(const rex::system::GraphicsSwapSubmission& submission) override { last_swap_submission_ = submission; ++swap_count_; last_present_used_raster_replay_ = false; ac6::d3d::FrameCaptureSnapshot frame_capture = ac6::d3d::GetFrameCapture(); NativeReplayPlanSummary replay_plan = AnalyzeReplayPlan(frame_capture, submission); if (replay_plan.valid) { ReplayCandidateKey candidate_key = MakeReplayCandidateKey(replay_plan); if (last_selected_candidate_valid_ && SameReplayCandidate(last_selected_candidate_, candidate_key)) { ++selected_candidate_streak_; } else { last_selected_candidate_ = candidate_key; last_selected_candidate_valid_ = true; selected_candidate_streak_ = 1; } replay_plan.selected_pass_streak = selected_candidate_streak_; replay_plan.selected_pass_is_stable = selected_candidate_streak_ >= 3; } else { last_selected_candidate_valid_ = false; selected_candidate_streak_ = 0; } last_replay_plan_ = replay_plan; last_selected_pass_preview_ = BuildSelectedPassPreview(frame_capture, replay_plan); { std::lock_guard lock(g_native_graphics_status_mutex); g_native_graphics_status.total_swap_count = swap_count_; g_native_graphics_status.last_frontbuffer_virtual_address = submission.frontbuffer_virtual_address; g_native_graphics_status.last_frontbuffer_physical_address = submission.frontbuffer_physical_address; g_native_graphics_status.last_frontbuffer_width = submission.frontbuffer_width; g_native_graphics_status.last_frontbuffer_height = submission.frontbuffer_height; g_native_graphics_status.last_texture_format = submission.texture_format; g_native_graphics_status.last_color_space = submission.color_space; g_native_graphics_status.capture_summary = ac6::d3d::GetFrameCaptureSummary(); g_native_graphics_status.replay_plan = replay_plan; g_native_graphics_status.selected_pass_preview = last_selected_pass_preview_.summary; g_native_graphics_status.last_swap_intercepted = false; g_native_graphics_status.last_swap_fell_back = false; } if (!logged_first_swap_) { logged_first_swap_ = true; REXLOG_WARN( "AC6 native graphics bootstrap received the first direct swap " "(fb_va={:08X}, fb_pa={:08X}, {}x{}, fmt={:08X})", submission.frontbuffer_virtual_address, submission.frontbuffer_physical_address, submission.frontbuffer_width, submission.frontbuffer_height, submission.texture_format); } if (!REXCVAR_GET(ac6_native_graphics_placeholder_present)) { if (!logged_passthrough_swap_) { logged_passthrough_swap_ = true; REXLOG_WARN( "AC6 native graphics bootstrap is leaving direct swap presentation " "on the legacy PM4 path because ac6_native_graphics_placeholder_present=false"); } { std::lock_guard lock(g_native_graphics_status_mutex); ++g_native_graphics_status.fallback_swap_count; g_native_graphics_status.last_swap_fell_back = true; } return false; } if (!EnsurePlaceholderRefreshResources()) { if (!logged_refresh_failure_) { logged_refresh_failure_ = true; REXLOG_WARN( "AC6 native graphics bootstrap could not initialize diagnostic " "direct-swap replay resources; falling back to the legacy PM4 swap path"); } { std::lock_guard lock(g_native_graphics_status_mutex); ++g_native_graphics_status.fallback_swap_count; g_native_graphics_status.last_swap_fell_back = true; } return false; } if (!RefreshPlaceholderFrame(submission)) { if (!logged_refresh_failure_) { logged_refresh_failure_ = true; REXLOG_WARN( "AC6 native graphics bootstrap could not refresh the diagnostic " "direct-swap replay frame; falling back to the legacy PM4 swap path"); } { std::lock_guard lock(g_native_graphics_status_mutex); ++g_native_graphics_status.fallback_swap_count; g_native_graphics_status.last_swap_fell_back = true; } return false; } if (!logged_first_present_) { logged_first_present_ = true; REXLOG_WARN( "AC6 native graphics bootstrap is now presenting a raster replay " "preview frame through the direct swap path"); } { std::lock_guard lock(g_native_graphics_status_mutex); ++g_native_graphics_status.intercepted_swap_count; g_native_graphics_status.selected_pass_preview.using_raster_replay = last_present_used_raster_replay_; g_native_graphics_status.last_swap_intercepted = true; } DispatchInterruptCallback(0, 2); return true; } private: static constexpr uint32_t kPlaceholderRefreshSlotCount = 3; static constexpr uint32_t kPlaceholderHeartbeatPeriod = 120; static constexpr uint32_t kRasterPreviewMaxRectCount = 64; static constexpr uint32_t kRasterPreviewMaxVertexCount = kRasterPreviewMaxRectCount * 6; struct PlaceholderRefreshSlot { Microsoft::WRL::ComPtr command_allocator; Microsoft::WRL::ComPtr shader_visible_uav_heap; Microsoft::WRL::ComPtr cpu_uav_heap; Microsoft::WRL::ComPtr rtv_heap; Microsoft::WRL::ComPtr raster_render_target; Microsoft::WRL::ComPtr vertex_upload_buffer; uint8_t* vertex_upload_mapping = nullptr; uint32_t raster_target_width = 0; uint32_t raster_target_height = 0; uint64_t last_submission = 0; }; bool EnsurePlaceholderRefreshResources() { if (placeholder_resources_initialized_) { return true; } if (!InitializePlaceholderRefreshResources()) { return false; } placeholder_resources_initialized_ = true; { std::lock_guard lock(g_native_graphics_status_mutex); g_native_graphics_status.placeholder_resources_initialized = true; } return true; } bool InitializeRasterPreviewResources(ID3D12Device* device) { D3D12_ROOT_PARAMETER root_parameters[3] = {}; D3D12_DESCRIPTOR_RANGE descriptor_range_texture = {}; D3D12_DESCRIPTOR_RANGE descriptor_range_sampler = {}; root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; root_parameters[0].DescriptorTable.NumDescriptorRanges = 1; root_parameters[0].DescriptorTable.pDescriptorRanges = &descriptor_range_texture; root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; descriptor_range_texture.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; descriptor_range_texture.NumDescriptors = 1; descriptor_range_texture.BaseShaderRegister = 0; descriptor_range_texture.RegisterSpace = 0; descriptor_range_texture.OffsetInDescriptorsFromTableStart = 0; root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; root_parameters[1].DescriptorTable.NumDescriptorRanges = 1; root_parameters[1].DescriptorTable.pDescriptorRanges = &descriptor_range_sampler; root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; descriptor_range_sampler.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; descriptor_range_sampler.NumDescriptors = 1; descriptor_range_sampler.BaseShaderRegister = 0; descriptor_range_sampler.RegisterSpace = 0; descriptor_range_sampler.OffsetInDescriptorsFromTableStart = 0; root_parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; root_parameters[2].Constants.ShaderRegister = 0; root_parameters[2].Constants.RegisterSpace = 0; root_parameters[2].Constants.Num32BitValues = 2; root_parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {}; root_signature_desc.NumParameters = uint32_t(std::size(root_parameters)); root_signature_desc.pParameters = root_parameters; root_signature_desc.NumStaticSamplers = 0; root_signature_desc.pStaticSamplers = nullptr; root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; raster_preview_root_signature_.Attach( rex::ui::d3d12::util::CreateRootSignature(*d3d12_provider_, root_signature_desc)); if (!raster_preview_root_signature_) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to create the raster replay " "root signature"); return false; } D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc = {}; pipeline_desc.pRootSignature = raster_preview_root_signature_.Get(); pipeline_desc.VS.pShaderBytecode = shaders::immediate_vs; pipeline_desc.VS.BytecodeLength = sizeof(shaders::immediate_vs); pipeline_desc.PS.pShaderBytecode = shaders::immediate_ps; pipeline_desc.PS.BytecodeLength = sizeof(shaders::immediate_ps); D3D12_RENDER_TARGET_BLEND_DESC& blend_desc = pipeline_desc.BlendState.RenderTarget[0]; blend_desc.BlendEnable = TRUE; blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA; blend_desc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA; blend_desc.BlendOp = D3D12_BLEND_OP_ADD; blend_desc.SrcBlendAlpha = D3D12_BLEND_ONE; blend_desc.DestBlendAlpha = D3D12_BLEND_ONE; blend_desc.BlendOpAlpha = D3D12_BLEND_OP_ADD; blend_desc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; pipeline_desc.SampleMask = UINT_MAX; pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; pipeline_desc.RasterizerState.FrontCounterClockwise = FALSE; pipeline_desc.RasterizerState.DepthClipEnable = TRUE; D3D12_INPUT_ELEMENT_DESC input_elements[3] = {}; input_elements[0].SemanticName = "POSITION"; input_elements[0].Format = DXGI_FORMAT_R32G32_FLOAT; input_elements[0].AlignedByteOffset = offsetof(rex::ui::ImmediateVertex, x); input_elements[1].SemanticName = "TEXCOORD"; input_elements[1].Format = DXGI_FORMAT_R32G32_FLOAT; input_elements[1].AlignedByteOffset = offsetof(rex::ui::ImmediateVertex, u); input_elements[2].SemanticName = "COLOR"; input_elements[2].Format = DXGI_FORMAT_R8G8B8A8_UNORM; input_elements[2].AlignedByteOffset = offsetof(rex::ui::ImmediateVertex, color); pipeline_desc.InputLayout.pInputElementDescs = input_elements; pipeline_desc.InputLayout.NumElements = uint32_t(std::size(input_elements)); pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; pipeline_desc.NumRenderTargets = 1; pipeline_desc.RTVFormats[0] = rex::ui::d3d12::D3D12Presenter::kGuestOutputFormat; pipeline_desc.SampleDesc.Count = 1; if (FAILED(device->CreateGraphicsPipelineState(&pipeline_desc, IID_PPV_ARGS(&raster_preview_pipeline_)))) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to create the raster replay " "pipeline"); return false; } D3D12_DESCRIPTOR_HEAP_DESC view_heap_desc = {}; view_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; view_heap_desc.NumDescriptors = 1; view_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; if (FAILED(device->CreateDescriptorHeap(&view_heap_desc, IID_PPV_ARGS(&raster_preview_view_heap_)))) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to create the raster replay " "view heap"); return false; } D3D12_SHADER_RESOURCE_VIEW_DESC texture_view_desc = {}; texture_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; texture_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; texture_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1); texture_view_desc.Texture2D.MostDetailedMip = 0; texture_view_desc.Texture2D.MipLevels = 1; texture_view_desc.Texture2D.PlaneSlice = 0; texture_view_desc.Texture2D.ResourceMinLODClamp = 0.0f; device->CreateShaderResourceView( nullptr, &texture_view_desc, raster_preview_view_heap_->GetCPUDescriptorHandleForHeapStart()); D3D12_DESCRIPTOR_HEAP_DESC sampler_heap_desc = {}; sampler_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; sampler_heap_desc.NumDescriptors = 1; sampler_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; if (FAILED(device->CreateDescriptorHeap(&sampler_heap_desc, IID_PPV_ARGS(&raster_preview_sampler_heap_)))) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to create the raster replay " "sampler heap"); return false; } D3D12_SAMPLER_DESC sampler_desc = {}; sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; sampler_desc.MaxAnisotropy = 1; device->CreateSampler(&sampler_desc, raster_preview_sampler_heap_->GetCPUDescriptorHandleForHeapStart()); D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc = {}; rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtv_heap_desc.NumDescriptors = 1; rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; rtv_heap_desc.NodeMask = 0; D3D12_RESOURCE_DESC upload_buffer_desc = {}; rex::ui::d3d12::util::FillBufferResourceDesc( upload_buffer_desc, sizeof(rex::ui::ImmediateVertex) * kRasterPreviewMaxVertexCount, D3D12_RESOURCE_FLAG_NONE); for (PlaceholderRefreshSlot& slot : placeholder_refresh_slots_) { if (FAILED(device->CreateDescriptorHeap(&rtv_heap_desc, IID_PPV_ARGS(&slot.rtv_heap)))) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to create a raster replay " "RTV heap"); return false; } if (FAILED(device->CreateCommittedResource( &rex::ui::d3d12::util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE, &upload_buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&slot.vertex_upload_buffer)))) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to create a raster replay " "vertex upload buffer"); return false; } D3D12_RANGE read_range = {0, 0}; if (FAILED(slot.vertex_upload_buffer->Map(0, &read_range, reinterpret_cast(&slot.vertex_upload_mapping)))) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to map a raster replay " "vertex upload buffer"); return false; } } return true; } bool EnsureRasterPreviewRenderTarget(PlaceholderRefreshSlot& slot, uint32_t width, uint32_t height) { if (slot.raster_render_target && slot.raster_target_width == width && slot.raster_target_height == height) { return true; } slot.raster_render_target.Reset(); slot.raster_target_width = 0; slot.raster_target_height = 0; D3D12_CLEAR_VALUE clear_value = {}; clear_value.Format = rex::ui::d3d12::D3D12Presenter::kGuestOutputFormat; clear_value.Color[0] = 0.0f; clear_value.Color[1] = 0.0f; clear_value.Color[2] = 0.0f; clear_value.Color[3] = 1.0f; D3D12_RESOURCE_DESC render_target_desc = {}; render_target_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; render_target_desc.Alignment = 0; render_target_desc.Width = width; render_target_desc.Height = height; render_target_desc.DepthOrArraySize = 1; render_target_desc.MipLevels = 1; render_target_desc.Format = rex::ui::d3d12::D3D12Presenter::kGuestOutputFormat; render_target_desc.SampleDesc.Count = 1; render_target_desc.SampleDesc.Quality = 0; render_target_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; render_target_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; if (FAILED(d3d12_provider_->GetDevice()->CreateCommittedResource( &rex::ui::d3d12::util::kHeapPropertiesDefault, d3d12_provider_->GetHeapFlagCreateNotZeroed(), &render_target_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clear_value, IID_PPV_ARGS(&slot.raster_render_target)))) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to create a {}x{} raster replay " "render target", width, height); return false; } d3d12_provider_->GetDevice()->CreateRenderTargetView( slot.raster_render_target.Get(), nullptr, slot.rtv_heap->GetCPUDescriptorHandleForHeapStart()); slot.raster_target_width = width; slot.raster_target_height = height; return true; } bool InitializePlaceholderRefreshResources() { auto fail = [this](const char* message) { REXLOG_ERROR("{}", message); ShutdownPlaceholderRefreshResources(); return false; }; ID3D12Device* device = d3d12_provider_->GetDevice(); ID3D12CommandQueue* direct_queue = d3d12_provider_->GetDirectQueue(); if (!device || !direct_queue) { return fail("AC6 native graphics bootstrap D3D12 provider is missing device or queue"); } if (!placeholder_submission_tracker_.Initialize(device, direct_queue)) { return fail("AC6 native graphics bootstrap failed to create the placeholder submission tracker"); } D3D12_DESCRIPTOR_HEAP_DESC uav_heap_desc = {}; uav_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; uav_heap_desc.NumDescriptors = 1; uav_heap_desc.NodeMask = 0; for (uint32_t i = 0; i < kPlaceholderRefreshSlotCount; ++i) { PlaceholderRefreshSlot& slot = placeholder_refresh_slots_[i]; if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&slot.command_allocator)))) { return fail("AC6 native graphics bootstrap failed to create a placeholder command allocator"); } uav_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; if (FAILED(device->CreateDescriptorHeap(&uav_heap_desc, IID_PPV_ARGS(&slot.shader_visible_uav_heap)))) { return fail( "AC6 native graphics bootstrap failed to create a shader-visible UAV heap"); } uav_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; if (FAILED(device->CreateDescriptorHeap(&uav_heap_desc, IID_PPV_ARGS(&slot.cpu_uav_heap)))) { return fail("AC6 native graphics bootstrap failed to create a CPU UAV heap"); } } if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, placeholder_refresh_slots_[0].command_allocator.Get(), nullptr, IID_PPV_ARGS(&placeholder_command_list_)))) { return fail("AC6 native graphics bootstrap failed to create the placeholder command list"); } if (FAILED(placeholder_command_list_->Close())) { return fail("AC6 native graphics bootstrap failed to close the placeholder command list"); } if (!InitializeRasterPreviewResources(device)) { return fail("AC6 native graphics bootstrap failed to initialize raster replay resources"); } placeholder_refresh_slot_index_ = 0; return true; } void ShutdownPlaceholderRefreshResources() { placeholder_submission_tracker_.Shutdown(); placeholder_command_list_.Reset(); raster_preview_pipeline_.Reset(); raster_preview_root_signature_.Reset(); raster_preview_view_heap_.Reset(); raster_preview_sampler_heap_.Reset(); placeholder_refresh_slot_index_ = 0; placeholder_resources_initialized_ = false; { std::lock_guard lock(g_native_graphics_status_mutex); g_native_graphics_status.placeholder_resources_initialized = false; } for (PlaceholderRefreshSlot& slot : placeholder_refresh_slots_) { slot.last_submission = 0; if (slot.vertex_upload_buffer && slot.vertex_upload_mapping) { slot.vertex_upload_buffer->Unmap(0, nullptr); } slot.vertex_upload_mapping = nullptr; slot.vertex_upload_buffer.Reset(); slot.raster_render_target.Reset(); slot.rtv_heap.Reset(); slot.raster_target_width = 0; slot.raster_target_height = 0; slot.cpu_uav_heap.Reset(); slot.shader_visible_uav_heap.Reset(); slot.command_allocator.Reset(); } } bool RefreshPlaceholderFrame(const rex::system::GraphicsSwapSubmission& submission) { if (!d3d12_presenter_ || !submission.frontbuffer_width || !submission.frontbuffer_height) { return false; } return d3d12_presenter_->RefreshGuestOutput( submission.frontbuffer_width, submission.frontbuffer_height, submission.frontbuffer_width, submission.frontbuffer_height, [this, submission](rex::ui::Presenter::GuestOutputRefreshContext& context) { return RecordPlaceholderFrame( static_cast( context), submission); }); } bool SubmitPlaceholderCommandList(PlaceholderRefreshSlot& slot) { if (FAILED(placeholder_command_list_->Close())) { REXLOG_ERROR("AC6 native graphics bootstrap failed to close the placeholder command list"); return false; } ID3D12CommandList* execute_command_list = placeholder_command_list_.Get(); d3d12_provider_->GetDirectQueue()->ExecuteCommandLists(1, &execute_command_list); slot.last_submission = placeholder_submission_tracker_.GetCurrentSubmission(); if (!placeholder_submission_tracker_.NextSubmission()) { REXLOG_WARN( "AC6 native graphics bootstrap could not signal the placeholder " "refresh fence immediately"); } placeholder_refresh_slot_index_ = (placeholder_refresh_slot_index_ + 1) % kPlaceholderRefreshSlotCount; return true; } bool TryRecordRasterPlaceholderFrame( PlaceholderRefreshSlot& slot, ID3D12Resource* guest_output_resource, const rex::system::GraphicsSwapSubmission& submission) { if (!raster_preview_pipeline_ || !raster_preview_root_signature_ || !raster_preview_view_heap_ || !raster_preview_sampler_heap_ || !slot.rtv_heap || !slot.vertex_upload_mapping || !guest_output_resource) { return false; } if (!EnsureRasterPreviewRenderTarget(slot, submission.frontbuffer_width, submission.frontbuffer_height)) { return false; } const UINT width = submission.frontbuffer_width; const UINT height = submission.frontbuffer_height; const UINT title_band_height = std::max(1, height / 8); const UINT status_band_height = std::max(1, height / 20); const UINT heartbeat_width = std::max(1, UINT((uint64_t(width) * (((swap_count_ - 1) % kPlaceholderHeartbeatPeriod) + 1)) / kPlaceholderHeartbeatPeriod)); const NativeReplayPlanSummary& replay_plan = last_replay_plan_; const SelectedPassPreviewData& selected_pass_preview = last_selected_pass_preview_; const uint32_t candidate_seed = replay_plan.present_candidate_rt0 ^ (replay_plan.present_candidate_depth_stencil * 33u) ^ (replay_plan.selected_pass_score * 2654435761u); auto channel = [candidate_seed](uint32_t shift, float low, float high) { const float t = float((candidate_seed >> shift) & 0xFFu) / 255.0f; return low + (high - low) * t; }; const FloatColor background_color = {replay_plan.valid ? 0.03f : 0.08f, replay_plan.valid ? 0.04f : 0.06f, replay_plan.valid ? 0.07f : 0.10f, 1.0f}; const FloatColor title_band_color = { replay_plan.selected_pass_is_stable ? 0.18f : (replay_plan.present_candidate_matches_swap_size ? 0.18f : 0.55f), replay_plan.selected_pass_is_stable ? 0.62f : (replay_plan.present_candidate_matches_swap_size ? 0.56f : 0.22f), replay_plan.selected_pass_is_stable ? 0.46f : (replay_plan.present_candidate_matches_swap_size ? 0.24f : 0.18f), 1.0f}; const FloatColor fallback_candidate_color = {channel(0, 0.20f, 0.92f), channel(8, 0.18f, 0.75f), channel(16, 0.16f, 0.88f), 1.0f}; const FloatColor resolve_color = {0.98f, 0.95f, 0.28f, 0.92f}; const FloatColor heartbeat_color = {0.96f, 0.92f, 0.22f, 1.0f}; const FloatColor candidate_base_color = selected_pass_preview.summary.using_clear_fill ? DecodeArgbColor(selected_pass_preview.summary.last_clear_color) : fallback_candidate_color; const FloatColor stripe_color = MixColors(candidate_base_color, title_band_color, 0.40f); const FloatColor candidate_outline_color = MixColors(candidate_base_color, heartbeat_color, 0.55f); const FloatColor score_color = MixColors(candidate_outline_color, heartbeat_color, 0.35f); UINT candidate_left = 0; UINT candidate_top = title_band_height; UINT candidate_width = width; UINT candidate_height = std::max(1, height - title_band_height - status_band_height); if (replay_plan.valid && replay_plan.present_candidate_viewport_width && replay_plan.present_candidate_viewport_height) { candidate_left = std::min(width - 1, replay_plan.present_candidate_viewport_x); candidate_top = std::min(height - 1, replay_plan.present_candidate_viewport_y); candidate_width = std::max(1, std::min(replay_plan.present_candidate_viewport_width, width - candidate_left)); candidate_height = std::max(1, std::min(replay_plan.present_candidate_viewport_height, height - candidate_top)); } const UINT candidate_right = std::min(width, candidate_left + candidate_width); const UINT candidate_bottom = std::min(height, candidate_top + candidate_height); std::array vertices = {}; uint32_t vertex_count = 0; auto push_rect = [&](float left, float top, float right, float bottom, FloatColor color) { left = std::clamp(left, 0.0f, float(width)); top = std::clamp(top, 0.0f, float(height)); right = std::clamp(right, 0.0f, float(width)); bottom = std::clamp(bottom, 0.0f, float(height)); if (left >= right || top >= bottom || vertex_count + 6 > vertices.size()) { return; } const uint32_t packed_color = PackImmediateColor(color); auto emit_vertex = [&](float x, float y) { rex::ui::ImmediateVertex& vertex = vertices[vertex_count++]; vertex.x = x; vertex.y = y; vertex.u = 0.0f; vertex.v = 0.0f; vertex.color = packed_color; }; emit_vertex(left, top); emit_vertex(right, top); emit_vertex(right, bottom); emit_vertex(left, top); emit_vertex(right, bottom); emit_vertex(left, bottom); }; push_rect(float(candidate_left), float(candidate_top), float(candidate_right), float(candidate_bottom), candidate_base_color); const FloatColor clear_overlay_tint = {1.0f, 1.0f, 1.0f, 0.92f}; for (uint32_t i = 0; i < selected_pass_preview.clear_step_count; ++i) { const SelectedPassClearStep& step = selected_pass_preview.clear_steps[i]; FloatColor step_color = DecodeArgbColor(step.color); step_color[3] = clear_overlay_tint[3]; if (step.rect_count) { for (uint32_t rect_index = 0; rect_index < step.rect_count; ++rect_index) { const ac6::d3d::ClearRect& rect = step.rects[rect_index]; push_rect(float(rect.left), float(rect.top), float(rect.right), float(rect.bottom), step_color); } } else { push_rect(float(candidate_left), float(candidate_top), float(candidate_right), float(candidate_bottom), step_color); } } UINT resolve_band_height = 0; if (replay_plan.valid && replay_plan.selected_pass_has_resolve) { resolve_band_height = std::max(1, candidate_height / 10); push_rect(float(candidate_left), float(candidate_bottom - resolve_band_height), float(candidate_right), float(candidate_bottom), resolve_color); } if (selected_pass_preview.summary.draw_count && candidate_width > 8 && candidate_height > 8) { const UINT stripe_count = std::min(12, std::max(1, 1 + (selected_pass_preview.summary.draw_count / 6))); const UINT stripe_width = std::max(1, candidate_width / std::max(24, stripe_count * 5)); const UINT stripe_top = candidate_top; const UINT stripe_bottom = candidate_bottom > resolve_band_height ? (candidate_bottom - resolve_band_height) : candidate_bottom; const UINT stripe_area_height = stripe_bottom > stripe_top ? (stripe_bottom - stripe_top) : 0; for (UINT i = 0; i < stripe_count && stripe_area_height; ++i) { const UINT stripe_center_x = candidate_left + ((i + 1) * candidate_width) / (stripe_count + 1); const UINT stripe_left = stripe_center_x > stripe_width / 2 ? stripe_center_x - stripe_width / 2 : candidate_left; const UINT stripe_right = std::min(candidate_right, stripe_left + stripe_width); const UINT stripe_height = std::max(1, stripe_area_height * (45 + ((i * 13) % 40)) / 100); const UINT stripe_start = stripe_bottom > stripe_height ? (stripe_bottom - stripe_height) : stripe_top; FloatColor lane_color = (i & 1u) ? MixColors(stripe_color, heartbeat_color, 0.22f) : MixColors(stripe_color, background_color, 0.10f); lane_color[3] = 0.42f; push_rect(float(stripe_left), float(stripe_start), float(stripe_right), float(stripe_bottom), lane_color); } } if (candidate_width > 2 && candidate_height > 2) { const UINT outline_thickness = std::max(1, std::min(4, std::min(candidate_width, candidate_height) / 96 + 1)); const UINT bottom_outline_top = candidate_bottom > outline_thickness ? (candidate_bottom - outline_thickness) : candidate_top; push_rect(float(candidate_left), float(candidate_top), float(candidate_right), float(std::min(candidate_bottom, candidate_top + outline_thickness)), candidate_outline_color); push_rect(float(candidate_left), float(bottom_outline_top), float(candidate_right), float(candidate_bottom), candidate_outline_color); push_rect(float(candidate_left), float(candidate_top), float(std::min(candidate_right, candidate_left + outline_thickness)), float(candidate_bottom), candidate_outline_color); push_rect(float(candidate_right > outline_thickness ? (candidate_right - outline_thickness) : candidate_left), float(candidate_top), float(candidate_right), float(candidate_bottom), candidate_outline_color); } if (replay_plan.valid && replay_plan.pass_count) { const UINT score_width = std::max( 1, UINT((uint64_t(width) * std::min(replay_plan.selected_pass_score, 220u)) / 220u)); push_rect(0.0f, float(title_band_height), float(score_width), float(std::min(height, title_band_height + status_band_height)), score_color); } push_rect(0.0f, 0.0f, float(width), float(title_band_height), title_band_color); push_rect(0.0f, float(height - status_band_height), float(heartbeat_width), float(height), heartbeat_color); D3D12_VIEWPORT viewport = {}; viewport.TopLeftX = 0.0f; viewport.TopLeftY = 0.0f; viewport.Width = float(width); viewport.Height = float(height); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; D3D12_RECT scissor = {0, 0, LONG(width), LONG(height)}; placeholder_command_list_->RSSetViewports(1, &viewport); placeholder_command_list_->RSSetScissorRects(1, &scissor); const D3D12_CPU_DESCRIPTOR_HANDLE rtv = slot.rtv_heap->GetCPUDescriptorHandleForHeapStart(); placeholder_command_list_->OMSetRenderTargets(1, &rtv, TRUE, nullptr); placeholder_command_list_->ClearRenderTargetView(rtv, background_color.data(), 0, nullptr); if (vertex_count) { std::memcpy(slot.vertex_upload_mapping, vertices.data(), sizeof(rex::ui::ImmediateVertex) * vertex_count); D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {}; vertex_buffer_view.BufferLocation = slot.vertex_upload_buffer->GetGPUVirtualAddress(); vertex_buffer_view.SizeInBytes = UINT(sizeof(rex::ui::ImmediateVertex) * vertex_count); vertex_buffer_view.StrideInBytes = UINT(sizeof(rex::ui::ImmediateVertex)); ID3D12DescriptorHeap* descriptor_heaps[] = {raster_preview_view_heap_.Get(), raster_preview_sampler_heap_.Get()}; placeholder_command_list_->SetDescriptorHeaps(uint32_t(std::size(descriptor_heaps)), descriptor_heaps); placeholder_command_list_->SetGraphicsRootSignature(raster_preview_root_signature_.Get()); const float coordinate_space_size_inv[2] = {1.0f / float(width), 1.0f / float(height)}; placeholder_command_list_->SetGraphicsRoot32BitConstants(2, 2, coordinate_space_size_inv, 0); placeholder_command_list_->SetGraphicsRootDescriptorTable( 0, raster_preview_view_heap_->GetGPUDescriptorHandleForHeapStart()); placeholder_command_list_->SetGraphicsRootDescriptorTable( 1, raster_preview_sampler_heap_->GetGPUDescriptorHandleForHeapStart()); placeholder_command_list_->SetPipelineState(raster_preview_pipeline_.Get()); placeholder_command_list_->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); placeholder_command_list_->IASetVertexBuffers(0, 1, &vertex_buffer_view); placeholder_command_list_->DrawInstanced(vertex_count, 1, 0, 0); } D3D12_RESOURCE_BARRIER barriers[3] = {}; barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barriers[0].Transition.pResource = slot.raster_render_target.Get(); barriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barriers[1].Transition.pResource = guest_output_resource; barriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barriers[1].Transition.StateBefore = rex::ui::d3d12::D3D12Presenter::kGuestOutputInternalState; barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; placeholder_command_list_->ResourceBarrier(2, barriers); D3D12_TEXTURE_COPY_LOCATION copy_dest = {}; copy_dest.pResource = guest_output_resource; copy_dest.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; copy_dest.SubresourceIndex = 0; D3D12_TEXTURE_COPY_LOCATION copy_source = {}; copy_source.pResource = slot.raster_render_target.Get(); copy_source.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; copy_source.SubresourceIndex = 0; placeholder_command_list_->CopyTextureRegion(©_dest, 0, 0, 0, ©_source, nullptr); barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; barriers[0].Transition.StateAfter = rex::ui::d3d12::D3D12Presenter::kGuestOutputInternalState; barriers[0].Transition.pResource = guest_output_resource; barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barriers[1].Transition.pResource = slot.raster_render_target.Get(); placeholder_command_list_->ResourceBarrier(2, barriers); return true; } bool RecordPlaceholderFrame( rex::ui::d3d12::D3D12Presenter::D3D12GuestOutputRefreshContext& context, const rex::system::GraphicsSwapSubmission& submission) { std::lock_guard lock(placeholder_refresh_mutex_); if (!d3d12_provider_ || !placeholder_command_list_) { return false; } PlaceholderRefreshSlot& slot = placeholder_refresh_slots_[placeholder_refresh_slot_index_]; if (slot.last_submission && !placeholder_submission_tracker_.AwaitSubmissionCompletion(slot.last_submission)) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to await placeholder refresh " "slot {}", placeholder_refresh_slot_index_); return false; } ID3D12Resource* guest_output_resource = context.resource_uav_capable(); if (!guest_output_resource) { return false; } if (FAILED(slot.command_allocator->Reset())) { REXLOG_ERROR("AC6 native graphics bootstrap failed to reset a placeholder command allocator"); return false; } if (FAILED(placeholder_command_list_->Reset(slot.command_allocator.Get(), nullptr))) { REXLOG_ERROR("AC6 native graphics bootstrap failed to reset the placeholder command list"); return false; } last_present_used_raster_replay_ = false; if (TryRecordRasterPlaceholderFrame(slot, guest_output_resource, submission)) { context.SetIs8bpc(true); last_present_used_raster_replay_ = true; return SubmitPlaceholderCommandList(slot); } if (FAILED(placeholder_command_list_->Reset(slot.command_allocator.Get(), nullptr))) { REXLOG_ERROR( "AC6 native graphics bootstrap failed to reset the placeholder command list " "for the legacy fallback path"); return false; } ID3D12Device* device = d3d12_provider_->GetDevice(); D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {}; uav_desc.Format = rex::ui::d3d12::D3D12Presenter::kGuestOutputFormat; uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; uav_desc.Texture2D.MipSlice = 0; uav_desc.Texture2D.PlaneSlice = 0; D3D12_CPU_DESCRIPTOR_HANDLE uav_cpu_visible = slot.shader_visible_uav_heap->GetCPUDescriptorHandleForHeapStart(); D3D12_GPU_DESCRIPTOR_HANDLE uav_gpu_visible = slot.shader_visible_uav_heap->GetGPUDescriptorHandleForHeapStart(); D3D12_CPU_DESCRIPTOR_HANDLE uav_cpu = slot.cpu_uav_heap->GetCPUDescriptorHandleForHeapStart(); device->CreateUnorderedAccessView(guest_output_resource, nullptr, &uav_desc, uav_cpu_visible); device->CreateUnorderedAccessView(guest_output_resource, nullptr, &uav_desc, uav_cpu); ID3D12DescriptorHeap* descriptor_heaps[] = {slot.shader_visible_uav_heap.Get()}; placeholder_command_list_->SetDescriptorHeaps(1, descriptor_heaps); D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = guest_output_resource; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.StateBefore = rex::ui::d3d12::D3D12Presenter::kGuestOutputInternalState; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; placeholder_command_list_->ResourceBarrier(1, &barrier); context.SetIs8bpc(true); const UINT width = submission.frontbuffer_width; const UINT height = submission.frontbuffer_height; const UINT title_band_height = std::max(1, height / 8); const UINT status_band_height = std::max(1, height / 20); const UINT heartbeat_width = std::max(1, UINT((uint64_t(width) * (((swap_count_ - 1) % kPlaceholderHeartbeatPeriod) + 1)) / kPlaceholderHeartbeatPeriod)); const NativeReplayPlanSummary& replay_plan = last_replay_plan_; const SelectedPassPreviewData& selected_pass_preview = last_selected_pass_preview_; const uint32_t candidate_seed = replay_plan.present_candidate_rt0 ^ (replay_plan.present_candidate_depth_stencil * 33u) ^ (replay_plan.selected_pass_score * 2654435761u); auto channel = [candidate_seed](uint32_t shift, float low, float high) { float t = float((candidate_seed >> shift) & 0xFFu) / 255.0f; return low + (high - low) * t; }; const FloatColor background_color = {replay_plan.valid ? 0.04f : 0.08f, replay_plan.valid ? 0.05f : 0.06f, replay_plan.valid ? 0.08f : 0.10f, 1.0f}; const FloatColor title_band_color = { replay_plan.selected_pass_is_stable ? 0.18f : (replay_plan.present_candidate_matches_swap_size ? 0.18f : 0.55f), replay_plan.selected_pass_is_stable ? 0.62f : (replay_plan.present_candidate_matches_swap_size ? 0.56f : 0.22f), replay_plan.selected_pass_is_stable ? 0.46f : (replay_plan.present_candidate_matches_swap_size ? 0.24f : 0.18f), 1.0f}; const FloatColor fallback_candidate_color = {channel(0, 0.20f, 0.92f), channel(8, 0.18f, 0.75f), channel(16, 0.16f, 0.88f), 1.0f}; const FloatColor resolve_color = {0.96f, 0.94f, 0.30f, 1.0f}; const FloatColor heartbeat_color = {0.95f, 0.92f, 0.24f, 1.0f}; const FloatColor candidate_base_color = selected_pass_preview.summary.using_clear_fill ? DecodeArgbColor(selected_pass_preview.summary.last_clear_color) : fallback_candidate_color; const FloatColor candidate_outline_color = MixColors(candidate_base_color, heartbeat_color, 0.5f); const FloatColor stripe_color = MixColors(candidate_base_color, title_band_color, 0.4f); auto clear_rect = [&](const FloatColor& color, UINT left, UINT top, UINT right, UINT bottom) { if (left >= right || top >= bottom) { return; } D3D12_RECT rect = {LONG(left), LONG(top), LONG(right), LONG(bottom)}; placeholder_command_list_->ClearUnorderedAccessViewFloat( uav_gpu_visible, uav_cpu, guest_output_resource, color.data(), 1, &rect); }; placeholder_command_list_->ClearUnorderedAccessViewFloat( uav_gpu_visible, uav_cpu, guest_output_resource, background_color.data(), 0, nullptr); UINT candidate_left = 0; UINT candidate_top = title_band_height; UINT candidate_width = width; UINT candidate_height = std::max(1, height - title_band_height - status_band_height); if (replay_plan.valid && replay_plan.present_candidate_viewport_width && replay_plan.present_candidate_viewport_height) { candidate_left = std::min(width - 1, replay_plan.present_candidate_viewport_x); candidate_top = std::min(height - 1, replay_plan.present_candidate_viewport_y); candidate_width = std::max(1, std::min(replay_plan.present_candidate_viewport_width, width - candidate_left)); candidate_height = std::max(1, std::min(replay_plan.present_candidate_viewport_height, height - candidate_top)); } D3D12_RECT center_block_rect = {LONG(candidate_left), LONG(candidate_top), LONG(std::min(width, candidate_left + candidate_width)), LONG(std::min(height, candidate_top + candidate_height))}; placeholder_command_list_->ClearUnorderedAccessViewFloat( uav_gpu_visible, uav_cpu, guest_output_resource, candidate_base_color.data(), 1, ¢er_block_rect); const UINT candidate_right = std::min(width, candidate_left + candidate_width); const UINT candidate_bottom = std::min(height, candidate_top + candidate_height); UINT sampled_clear_band_height = 0; if (selected_pass_preview.clear_step_count && candidate_height > 2) { sampled_clear_band_height = std::max(1, std::min(candidate_height / 12, height / 32 + 1)); for (uint32_t i = 0; i < selected_pass_preview.clear_step_count; ++i) { const UINT band_top = std::min(candidate_bottom, candidate_top + sampled_clear_band_height * i); const UINT band_bottom = std::min(candidate_bottom, band_top + sampled_clear_band_height); clear_rect(DecodeArgbColor(selected_pass_preview.clear_steps[i].color), candidate_left, band_top, candidate_right, band_bottom); } } UINT resolve_band_height = 0; if (replay_plan.valid && replay_plan.selected_pass_has_resolve) { resolve_band_height = std::max(1, candidate_height / 10); clear_rect(resolve_color, candidate_left, std::min(candidate_bottom, candidate_bottom - resolve_band_height), candidate_right, candidate_bottom); } if (selected_pass_preview.summary.draw_count && candidate_width > 8 && candidate_height > 8) { const UINT stripe_count = std::min(12, std::max(1, 1 + (selected_pass_preview.summary.draw_count / 6))); const UINT stripe_width = std::max(1, candidate_width / std::max(24, stripe_count * 5)); const UINT stripe_top = std::min(candidate_bottom, candidate_top + sampled_clear_band_height); const UINT stripe_bottom = candidate_bottom > resolve_band_height ? (candidate_bottom - resolve_band_height) : candidate_bottom; const UINT stripe_area_height = stripe_bottom > stripe_top ? (stripe_bottom - stripe_top) : 0; for (UINT i = 0; i < stripe_count && stripe_area_height; ++i) { const UINT stripe_center_x = candidate_left + ((i + 1) * candidate_width) / (stripe_count + 1); const UINT stripe_left = stripe_center_x > stripe_width / 2 ? stripe_center_x - stripe_width / 2 : candidate_left; const UINT stripe_right = std::min(candidate_right, stripe_left + stripe_width); const UINT stripe_height = std::max(1, stripe_area_height * (45 + ((i * 13) % 40)) / 100); const UINT stripe_start = stripe_bottom > stripe_height ? (stripe_bottom - stripe_height) : stripe_top; const FloatColor lane_color = (i & 1u) ? MixColors(stripe_color, heartbeat_color, 0.22f) : MixColors(stripe_color, background_color, 0.10f); clear_rect(lane_color, stripe_left, stripe_start, stripe_right, stripe_bottom); } } if (candidate_width > 2 && candidate_height > 2) { const UINT outline_thickness = std::max(1, std::min(4, std::min(candidate_width, candidate_height) / 96 + 1)); const UINT bottom_outline_top = candidate_bottom > outline_thickness ? (candidate_bottom - outline_thickness) : candidate_top; clear_rect(candidate_outline_color, candidate_left, candidate_top, candidate_right, std::min(candidate_bottom, candidate_top + outline_thickness)); clear_rect(candidate_outline_color, candidate_left, bottom_outline_top, candidate_right, candidate_bottom); clear_rect(candidate_outline_color, candidate_left, candidate_top, std::min(candidate_right, candidate_left + outline_thickness), candidate_bottom); clear_rect(candidate_outline_color, candidate_right > outline_thickness ? (candidate_right - outline_thickness) : candidate_left, candidate_top, candidate_right, candidate_bottom); } if (replay_plan.valid && replay_plan.pass_count) { const UINT score_width = std::max( 1, UINT((uint64_t(width) * std::min(replay_plan.selected_pass_score, 220u)) / 220u)); clear_rect(candidate_outline_color, 0, title_band_height, score_width, std::min(height, title_band_height + status_band_height)); } clear_rect(title_band_color, 0, 0, width, title_band_height); clear_rect(heartbeat_color, 0, height - status_band_height, heartbeat_width, height); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; barrier.Transition.StateAfter = rex::ui::d3d12::D3D12Presenter::kGuestOutputInternalState; placeholder_command_list_->ResourceBarrier(1, &barrier); return SubmitPlaceholderCommandList(slot); } rex::ui::d3d12::D3D12Provider* d3d12_provider_ = nullptr; rex::ui::d3d12::D3D12Presenter* d3d12_presenter_ = nullptr; std::mutex placeholder_refresh_mutex_; rex::ui::d3d12::D3D12SubmissionTracker placeholder_submission_tracker_; std::array placeholder_refresh_slots_; Microsoft::WRL::ComPtr placeholder_command_list_; Microsoft::WRL::ComPtr raster_preview_root_signature_; Microsoft::WRL::ComPtr raster_preview_pipeline_; Microsoft::WRL::ComPtr raster_preview_view_heap_; Microsoft::WRL::ComPtr raster_preview_sampler_heap_; uint32_t placeholder_refresh_slot_index_ = 0; rex::system::GraphicsSwapSubmission last_swap_submission_; NativeReplayPlanSummary last_replay_plan_{}; SelectedPassPreviewData last_selected_pass_preview_{}; ReplayCandidateKey last_selected_candidate_{}; bool last_selected_candidate_valid_ = false; uint32_t selected_candidate_streak_ = 0; uint64_t swap_count_ = 0; bool logged_first_swap_ = false; bool logged_first_present_ = false; bool logged_passthrough_swap_ = false; bool logged_refresh_failure_ = false; bool last_present_used_raster_replay_ = false; bool placeholder_resources_initialized_ = false; }; #endif } // namespace void ConfigureGraphicsBackend(rex::RuntimeConfig& config) { { std::lock_guard lock(g_native_graphics_status_mutex); g_native_graphics_status = {}; g_native_graphics_status.bootstrap_enabled = REXCVAR_GET(ac6_native_graphics_bootstrap); g_native_graphics_status.placeholder_present_enabled = REXCVAR_GET(ac6_native_graphics_placeholder_present); } #if REX_HAS_D3D12 if (!REXCVAR_GET(ac6_native_graphics_bootstrap)) { return; } config.graphics = std::make_unique(); #else (void)config; #endif } NativeGraphicsStatusSnapshot GetNativeGraphicsStatus() { std::lock_guard lock(g_native_graphics_status_mutex); NativeGraphicsStatusSnapshot snapshot = g_native_graphics_status; snapshot.bootstrap_enabled = REXCVAR_GET(ac6_native_graphics_bootstrap); snapshot.placeholder_present_enabled = REXCVAR_GET(ac6_native_graphics_placeholder_present); return snapshot; } } // namespace ac6::graphics