/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_GPU_D3D12_D3D12_RENDER_TARGET_CACHE_H_ #define XENIA_GPU_D3D12_D3D12_RENDER_TARGET_CACHE_H_ #include #include #include #include #include #include #include #include #include #include #include "xenia/base/assert.h" #include "xenia/gpu/d3d12/d3d12_shared_memory.h" #include "xenia/gpu/d3d12/d3d12_texture_cache.h" #include "xenia/gpu/draw_util.h" #include "xenia/gpu/render_target_cache.h" #include "xenia/gpu/trace_writer.h" #include "xenia/gpu/xenos.h" #include "xenia/memory.h" #include "xenia/ui/d3d12/d3d12_cpu_descriptor_pool.h" #include "xenia/ui/d3d12/d3d12_provider.h" #include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h" #include "xenia/ui/d3d12/d3d12_util.h" namespace xe { namespace gpu { namespace d3d12 { class D3D12CommandProcessor; class D3D12RenderTargetCache final : public RenderTargetCache { public: D3D12RenderTargetCache(const RegisterFile& register_file, const Memory& memory, TraceWriter& trace_writer, uint32_t draw_resolution_scale_x, uint32_t draw_resolution_scale_y, D3D12CommandProcessor& command_processor, bool bindless_resources_used) : RenderTargetCache(register_file, memory, &trace_writer, draw_resolution_scale_x, draw_resolution_scale_y), command_processor_(command_processor), trace_writer_(trace_writer), bindless_resources_used_(bindless_resources_used) {} ~D3D12RenderTargetCache() override; bool Initialize(); void Shutdown(bool from_destructor = false); void CompletedSubmissionUpdated(); void BeginSubmission(); Path GetPath() const override { return path_; } bool Update(bool is_rasterization_done, reg::RB_DEPTHCONTROL normalized_depth_control, uint32_t normalized_color_mask, const Shader& vertex_shader) override; void InvalidateCommandListRenderTargets() { are_current_command_list_render_targets_valid_ = false; } bool msaa_2x_supported() const { return msaa_2x_supported_; } void WriteEdramRawSRVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle); void WriteEdramRawUAVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle); void WriteEdramUintPow2SRVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t element_size_bytes_pow2); void WriteEdramUintPow2UAVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle, uint32_t element_size_bytes_pow2); // Performs the resolve to a shared memory area according to the current // register values, and also clears the render targets if needed. Must be in a // frame for calling. bool Resolve(const Memory& memory, D3D12SharedMemory& shared_memory, D3D12TextureCache& texture_cache, uint32_t& written_address_out, uint32_t& written_length_out); // Returns true if any downloads were submitted to the command processor. bool InitializeTraceSubmitDownloads(); void InitializeTraceCompleteDownloads(); void RestoreEdramSnapshot(const void* snapshot); // For host render targets. bool gamma_render_target_as_srgb() const { return gamma_render_target_as_srgb_; } // Using R16G16[B16A16]_SNORM, which are -1...1, not the needed -32...32. // Persistent data doesn't depend on this, so can be overriden by per-game // configuration. bool IsFixed16TruncatedToMinus1To1() const { return GetPath() == Path::kHostRenderTargets && !cvars::snorm16_render_target_full_range; } bool depth_float24_round() const { return depth_float24_round_; } bool depth_float24_convert_in_pixel_shader() const { return depth_float24_convert_in_pixel_shader_; } DXGI_FORMAT GetColorResourceDXGIFormat( xenos::ColorRenderTargetFormat format) const; DXGI_FORMAT GetColorDrawDXGIFormat( xenos::ColorRenderTargetFormat format) const; DXGI_FORMAT GetColorOwnershipTransferDXGIFormat( xenos::ColorRenderTargetFormat format, bool* is_integer_out = nullptr) const; static DXGI_FORMAT GetDepthResourceDXGIFormat( xenos::DepthRenderTargetFormat format); static DXGI_FORMAT GetDepthDSVDXGIFormat( xenos::DepthRenderTargetFormat format); static DXGI_FORMAT GetDepthSRVDepthDXGIFormat( xenos::DepthRenderTargetFormat format); static DXGI_FORMAT GetDepthSRVStencilDXGIFormat( xenos::DepthRenderTargetFormat format); protected: uint32_t GetMaxRenderTargetWidth() const override { return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; } uint32_t GetMaxRenderTargetHeight() const override { return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; } RenderTarget* CreateRenderTarget(RenderTargetKey key) override; bool IsHostDepthEncodingDifferent( xenos::DepthRenderTargetFormat format) const override; void RequestPixelShaderInterlockBarrier() override; private: enum class EdramBufferModificationStatus { // The values are ordered by how strong the barrier conditions are. // No uncommitted ROV/UAV writes. kUnmodified, // Need to commit before the next ROV usage with overlap. kAsROV, // Need to commit before any next ROV usage. kAsUAV, }; void TransitionEdramBuffer(D3D12_RESOURCE_STATES new_state); void MarkEdramBufferModified( EdramBufferModificationStatus modification_status = EdramBufferModificationStatus::kAsUAV); void CommitEdramBufferUAVWrites(EdramBufferModificationStatus commit_status = EdramBufferModificationStatus::kAsROV); D3D12CommandProcessor& command_processor_; TraceWriter& trace_writer_; bool bindless_resources_used_; Path path_ = Path::kHostRenderTargets; // For host render targets, an EDRAM-sized scratch buffer for: // - Guest render target data copied from host render targets during copying // in resolves and in frame trace creation. // - Host float32 depth in ownership transfers when the host depth texture and // the destination are the same. // For rasterizer-ordered view, the buffer containing the EDRAM data. // (Note that if a hybrid RTV / DSV + ROV approach to color render targets is // added, which is, however, unlikely as it would have very complicated // interaction with depth / stencil testing, host depth will need to be // copied to a different buffer - the same range may have ROV-owned color and // host float32 depth at the same time). ID3D12Resource* edram_buffer_ = nullptr; D3D12_RESOURCE_STATES edram_buffer_state_; EdramBufferModificationStatus edram_buffer_modification_status_ = EdramBufferModificationStatus::kUnmodified; // Non-shader-visible descriptor heap containing pre-created SRV and UAV // descriptors of the EDRAM buffer, for faster binding (by copying rather // than creation). enum class EdramBufferDescriptorIndex : uint32_t { kRawSRV, kR32UintSRV, kR32G32UintSRV, kR32G32B32A32UintSRV, kRawUAV, kR32UintUAV, kR32G32UintUAV, kR32G32B32A32UintUAV, kCount, }; ID3D12DescriptorHeap* edram_buffer_descriptor_heap_ = nullptr; D3D12_CPU_DESCRIPTOR_HANDLE edram_buffer_descriptor_heap_start_; // Resolve copying root signature and pipelines. // Parameter 0 - draw_util::ResolveCopyShaderConstants or its ::DestRelative. // Parameter 1 - destination (shared memory or a part of it). // Parameter 2 - source (EDRAM). ID3D12RootSignature* resolve_copy_root_signature_ = nullptr; struct ResolveCopyShaderCode { const void* unscaled; size_t unscaled_size; const void* scaled; size_t scaled_size; }; static const ResolveCopyShaderCode kResolveCopyShaders[size_t(draw_util::ResolveCopyShaderIndex::kCount)]; ID3D12PipelineState* resolve_copy_pipelines_[size_t( draw_util::ResolveCopyShaderIndex::kCount)] = {}; // For traces. ID3D12Resource* edram_snapshot_download_buffer_ = nullptr; std::unique_ptr edram_snapshot_restore_pool_; // For host render targets. class D3D12RenderTarget final : public RenderTarget { public: // descriptor_draw_srgb is only used for k_8_8_8_8 render targets when host // sRGB (gamma_render_target_as_srgb) is used. descriptor_load is present // when the DXGI formats are different for drawing and bit-exact loading // (for NaN pattern preservation across EDRAM tile ownership transfers in // floating-point formats, and to distinguish between two -1 representations // in snorm formats). D3D12RenderTarget( RenderTargetKey key, ID3D12Resource* resource, ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_draw, ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_draw_srgb, ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_load_separate, ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_srv, ui::d3d12::D3D12CpuDescriptorPool::Descriptor&& descriptor_srv_stencil, D3D12_RESOURCE_STATES resource_state) : RenderTarget(key), resource_(resource), descriptor_draw_(std::move(descriptor_draw)), descriptor_draw_srgb_(std::move(descriptor_draw_srgb)), descriptor_load_separate_(std::move(descriptor_load_separate)), descriptor_srv_(std::move(descriptor_srv)), descriptor_srv_stencil_(std::move(descriptor_srv_stencil)), resource_state_(resource_state) {} ID3D12Resource* resource() const { return resource_.Get(); } const ui::d3d12::D3D12CpuDescriptorPool::Descriptor& descriptor_draw() const { return descriptor_draw_; } const ui::d3d12::D3D12CpuDescriptorPool::Descriptor& descriptor_draw_srgb() const { return descriptor_draw_srgb_; } const ui::d3d12::D3D12CpuDescriptorPool::Descriptor& descriptor_srv() const { return descriptor_srv_; } const ui::d3d12::D3D12CpuDescriptorPool::Descriptor& descriptor_srv_stencil() const { return descriptor_srv_stencil_; } const ui::d3d12::D3D12CpuDescriptorPool::Descriptor& descriptor_load_separate() const { return descriptor_load_separate_; } D3D12_RESOURCE_STATES SetResourceState(D3D12_RESOURCE_STATES new_state) { D3D12_RESOURCE_STATES old_state = resource_state_; resource_state_ = new_state; return old_state; } uint32_t temporary_srv_descriptor_index() const { return temporary_srv_descriptor_index_; } void SetTemporarySRVDescriptorIndex(uint32_t index) { temporary_srv_descriptor_index_ = index; } uint32_t temporary_srv_descriptor_index_stencil() const { return temporary_srv_descriptor_index_stencil_; } void SetTemporarySRVDescriptorIndexStencil(uint32_t index) { temporary_srv_descriptor_index_stencil_ = index; } uint32_t temporary_sort_index() const { return temporary_sort_index_; } void SetTemporarySortIndex(uint32_t index) { temporary_sort_index_ = index; } private: Microsoft::WRL::ComPtr resource_; ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_draw_; ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_draw_srgb_; ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_load_separate_; // Texture SRV non-shader-visible descriptors, to prepare shader-visible // descriptors faster, by copying rather than by creating every time. // TODO(Triang3l): With bindless resources, persistently store them in the // heap. ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_srv_; ui::d3d12::D3D12CpuDescriptorPool::Descriptor descriptor_srv_stencil_; D3D12_RESOURCE_STATES resource_state_; // Temporary storage for indices in operations like transfers and dumps. uint32_t temporary_srv_descriptor_index_ = UINT32_MAX; uint32_t temporary_srv_descriptor_index_stencil_ = UINT32_MAX; uint32_t temporary_sort_index_ = 0; }; enum TransferCBVRegister : uint32_t { kTransferCBVRegisterStencilMask, kTransferCBVRegisterAddress, kTransferCBVRegisterHostDepthAddress, }; enum TransferSRVRegister : uint32_t { kTransferSRVRegisterColor, kTransferSRVRegisterDepth, kTransferSRVRegisterStencil, kTransferSRVRegisterHostDepth, kTransferSRVRegisterCount, }; enum TransferUsedRootParameter : uint32_t { // Changed 8 times per transfer. kTransferUsedRootParameterStencilMaskConstant, kTransferUsedRootParameterColorSRV, // Mutually exclusive with ColorSRV. kTransferUsedRootParameterDepthSRV, // Mutually exclusive with ColorSRV. kTransferUsedRootParameterStencilSRV, // May happen to be the same for different sources. kTransferUsedRootParameterAddressConstant, kTransferUsedRootParameterHostDepthSRV, kTransferUsedRootParameterHostDepthAddressConstant, kTransferUsedRootParameterCount, kTransferUsedRootParameterStencilMaskConstantBit = uint32_t(1) << kTransferUsedRootParameterStencilMaskConstant, kTransferUsedRootParameterColorSRVBit = uint32_t(1) << kTransferUsedRootParameterColorSRV, kTransferUsedRootParameterDepthSRVBit = uint32_t(1) << kTransferUsedRootParameterDepthSRV, kTransferUsedRootParameterStencilSRVBit = uint32_t(1) << kTransferUsedRootParameterStencilSRV, kTransferUsedRootParameterAddressConstantBit = uint32_t(1) << kTransferUsedRootParameterAddressConstant, kTransferUsedRootParameterHostDepthSRVBit = uint32_t(1) << kTransferUsedRootParameterHostDepthSRV, kTransferUsedRootParameterHostDepthAddressConstantBit = uint32_t(1) << kTransferUsedRootParameterHostDepthAddressConstant, kTransferUsedRootParametersDescriptorMask = kTransferUsedRootParameterColorSRVBit | kTransferUsedRootParameterDepthSRVBit | kTransferUsedRootParameterStencilSRVBit | kTransferUsedRootParameterHostDepthSRVBit, }; enum class TransferRootSignatureIndex { kColor, kDepth, kDepthStencil, kColorToStencilBit, kStencilToStencilBit, kColorAndHostDepth, kDepthAndHostDepth, kDepthStencilAndHostDepth, kCount, }; static const uint32_t kTransferUsedRootParameters[size_t(TransferRootSignatureIndex::kCount)]; enum class TransferMode : uint32_t { // 1 SRV (color texture), source constant. kColorToDepth, // 1 SRV (color texture), source constant. kColorToColor, // 1 or 2 SRVs (depth texture, stencil texture if SV_StencilRef is // supported), source constant. kDepthToDepth, // 2 SRVs (depth texture, stencil texture), source constant. kDepthToColor, // 1 SRV (color texture), mask constant (most frequently changed, 8 times // per transfer), source constant. kColorToStencilBit, // 1 SRV (stencil texture), mask constant, source constant. kDepthToStencilBit, // Two-source modes, using the host depth if it, when converted to the guest // format, matches what's in the owner source (not modified, keep host // precision), or the guest data otherwise (significantly modified, possibly // cleared). Stencil for SV_StencilRef is always taken from the guest // source. // 2 SRVs (color texture, host depth texture or buffer), source constant, // host depth source constant. kColorAndHostDepthToDepth, // When using different source and destination depth formats. 2 or 3 SRVs // (depth texture, stencil texture if SV_StencilRef is supported, host depth // texture or buffer), source constant, host depth source constant. kDepthAndHostDepthToDepth, kCount, }; enum class TransferOutput { kColor, kDepth, // With this output, kTransferCBVRegisterStencilMask is used. kStencilBit, }; struct TransferModeInfo { TransferOutput output; TransferRootSignatureIndex root_signature_no_stencil_ref; TransferRootSignatureIndex root_signature_with_stencil_ref; }; static const TransferModeInfo kTransferModes[size_t(TransferMode::kCount)]; union TransferShaderKey { uint32_t key; struct { xenos::MsaaSamples dest_msaa_samples : xenos::kMsaaSamplesBits; uint32_t dest_resource_format : xenos::kRenderTargetFormatBits; xenos::MsaaSamples source_msaa_samples : xenos::kMsaaSamplesBits; // Always 1x when host_depth_source_is_copy is true not to create the same // pipeline for different MSAA sample counts as it doesn't matter in this // case. xenos::MsaaSamples host_depth_source_msaa_samples : xenos::kMsaaSamplesBits; uint32_t source_resource_format : xenos::kRenderTargetFormatBits; // If host depth is also fetched, whether it's pre-copied to the EDRAM // buffer (but since it's just a scratch buffer, with tiles laid out // linearly with the same pitch as in the original render target; also no // swapping of 40-sample columns as opposed to the host render target - // this is done only for the color source). uint32_t host_depth_source_is_copy : 1; // Last bits because this affects the root signature - after sorting, only // change it as fewer times as possible. Depth buffers have an additional // stencil SRV. static_assert(size_t(TransferMode::kCount) <= (size_t(1) << 3)); TransferMode mode : 3; }; TransferShaderKey() : key(0) { static_assert_size(*this, sizeof(key)); } struct Hasher { size_t operator()(const TransferShaderKey& key) const { return std::hash{}(key.key); } }; bool operator==(const TransferShaderKey& other_key) const { return key == other_key.key; } bool operator!=(const TransferShaderKey& other_key) const { return !(*this == other_key); } bool operator<(const TransferShaderKey& other_key) const { return key < other_key.key; } }; union TransferAddressConstant { uint32_t constant; struct { // All in tiles. uint32_t dest_pitch : xenos::kEdramPitchTilesBits; uint32_t source_pitch : xenos::kEdramPitchTilesBits; // Safe to use 12 bits for signed difference - no ownership transfer can // ever occur between render targets with EDRAM base >= 2048 as this would // result in 0-length spans. 10 + 10 + 12 is exactly 32, any more bits, // and more root 32-bit constants will be used. // Destination base in tiles minus source base in tiles (not vice versa // because this is a transform of the coordinate system, not addresses // themselves). // 0 for host_depth_source_is_copy (ignored in this case anyway as // destination == source anyway). int32_t source_to_dest : xenos::kEdramBaseTilesBits; }; TransferAddressConstant() : constant(0) { static_assert_size(*this, sizeof(constant)); } bool operator==(const TransferAddressConstant& other_constant) const { return constant == other_constant.constant; } bool operator!=(const TransferAddressConstant& other_constant) const { return !(*this == other_constant); } }; struct TransferInvocation { Transfer transfer; TransferShaderKey shader_key; TransferInvocation(const Transfer& transfer, const TransferShaderKey& shader_key) : transfer(transfer), shader_key(shader_key) {} bool operator<(const TransferInvocation& other_invocation) { // TODO(Triang3l): See if it may be better to sort by the source in the // first place, especially when reading the same data multiple times (like // to write the stencil bits after depth) for better read locality. // Sort by the shader key primarily to reduce pipeline state (context) // switches. if (shader_key != other_invocation.shader_key) { return shader_key < other_invocation.shader_key; } // Host depth render targets are changed rarely if they exist, won't save // many binding changes, ignore them for simplicity (their existence is // caught by the shader key change). assert_not_null(transfer.source); assert_not_null(other_invocation.transfer.source); uint32_t source_index = static_cast(transfer.source) ->temporary_sort_index(); uint32_t other_source_index = static_cast( other_invocation.transfer.source) ->temporary_sort_index(); if (source_index != other_source_index) { return source_index < other_source_index; } return transfer.start_tiles < other_invocation.transfer.start_tiles; } bool CanBeMergedIntoOneDraw( const TransferInvocation& other_invocation) const { return shader_key == other_invocation.shader_key && transfer.AreSourcesSame(other_invocation.transfer); } }; enum { kHostDepthStoreRootParameterConstants, kHostDepthStoreRootParameterSource, kHostDepthStoreRootParameterDest, kHostDepthStoreRootParameterCount, }; union DumpPipelineKey { uint32_t key; struct { xenos::MsaaSamples msaa_samples : 2; uint32_t resource_format : 4; // Last bit because this affects the root signature - after sorting, only // change it at most once. Depth buffers have an additional stencil SRV. uint32_t is_depth : 1; }; DumpPipelineKey() : key(0) { static_assert_size(*this, sizeof(key)); } struct Hasher { size_t operator()(const DumpPipelineKey& key) const { return std::hash{}(key.key); } }; bool operator==(const DumpPipelineKey& other_key) const { return key == other_key.key; } bool operator!=(const DumpPipelineKey& other_key) const { return !(*this == other_key); } bool operator<(const DumpPipelineKey& other_key) const { return key < other_key.key; } xenos::ColorRenderTargetFormat GetColorFormat() const { assert_false(is_depth); return xenos::ColorRenderTargetFormat(resource_format); } xenos::DepthRenderTargetFormat GetDepthFormat() const { assert_true(is_depth); return xenos::DepthRenderTargetFormat(resource_format); } }; union DumpOffsets { uint32_t offsets; struct { uint32_t dispatch_first_tile : xenos::kEdramBaseTilesBits; uint32_t source_base_tiles : xenos::kEdramBaseTilesBits; }; DumpOffsets() : offsets(0) { static_assert_size(*this, sizeof(offsets)); } bool operator==(const DumpOffsets& other_offsets) const { return offsets == other_offsets.offsets; } bool operator!=(const DumpOffsets& other_offsets) const { return !(*this == other_offsets); } }; union DumpPitches { uint32_t pitches; struct { // Both in tiles. uint32_t dest_pitch : xenos::kEdramPitchTilesBits; uint32_t source_pitch : xenos::kEdramPitchTilesBits; }; DumpPitches() : pitches(0) { static_assert_size(*this, sizeof(pitches)); } bool operator==(const DumpPitches& other_pitches) const { return pitches == other_pitches.pitches; } bool operator!=(const DumpPitches& other_pitches) const { return !(*this == other_pitches); } }; enum DumpCbuffer : uint32_t { kDumpCbufferOffsets, kDumpCbufferPitches, kDumpCbufferCount, }; enum DumpRootParameter : uint32_t { // May be changed multiple times for the same source. kDumpRootParameterOffsets, // One resolve may need multiple sources. kDumpRootParameterSource, // May be different for different sources. kDumpRootParameterColorPitches = kDumpRootParameterSource + 1, // Only changed between 32bpp and 64bpp. kDumpRootParameterColorEdram, kDumpRootParameterColorCount, // Same change frequency than the source (though currently the command // processor can't contiguously allocate multiple descriptors with bindless, // when such functionality is added, switch to one root signature). kDumpRootParameterDepthStencil = kDumpRootParameterSource + 1, kDumpRootParameterDepthPitches, kDumpRootParameterDepthEdram, kDumpRootParameterDepthCount, }; struct DumpInvocation { ResolveCopyDumpRectangle rectangle; DumpPipelineKey pipeline_key; DumpInvocation(const ResolveCopyDumpRectangle& rectangle, const DumpPipelineKey& pipeline_key) : rectangle(rectangle), pipeline_key(pipeline_key) {} bool operator<(const DumpInvocation& other_invocation) { // Sort by the pipeline key primarily to reduce pipeline state (context) // switches. if (pipeline_key != other_invocation.pipeline_key) { return pipeline_key < other_invocation.pipeline_key; } assert_not_null(rectangle.render_target); uint32_t render_target_index = static_cast(rectangle.render_target) ->temporary_sort_index(); const ResolveCopyDumpRectangle& other_rectangle = other_invocation.rectangle; uint32_t other_render_target_index = static_cast(other_rectangle.render_target) ->temporary_sort_index(); if (render_target_index != other_render_target_index) { return render_target_index < other_render_target_index; } if (rectangle.row_first != other_rectangle.row_first) { return rectangle.row_first < other_rectangle.row_first; } return rectangle.row_first_start < other_rectangle.row_first_start; } }; // Returns: // - A pointer to 1 pipeline for writing color or depth (or stencil via // SV_StencilRef). // - A pointer to 8 pipelines for writing stencil by discarding samples // depending on whether they have one bit set, from 1 << 0 to 1 << 7. // - Null if failed to create. ID3D12PipelineState* const* GetOrCreateTransferPipelines( TransferShaderKey key); static TransferMode GetTransferMode(bool dest_is_stencil_bit, bool dest_is_depth, bool source_is_depth, bool source_has_host_depth) { assert_true(dest_is_depth || (!dest_is_stencil_bit && !source_has_host_depth)); if (dest_is_stencil_bit) { return source_is_depth ? TransferMode::kDepthToStencilBit : TransferMode::kColorToStencilBit; } if (dest_is_depth) { if (source_is_depth) { return source_has_host_depth ? TransferMode::kDepthAndHostDepthToDepth : TransferMode::kDepthToDepth; } return source_has_host_depth ? TransferMode::kColorAndHostDepthToDepth : TransferMode::kColorToDepth; } return source_is_depth ? TransferMode::kDepthToColor : TransferMode::kColorToColor; } // Do ownership transfers for render targets - each render target / vector may // be null / empty in case there's nothing to do for them. // resolve_clear_rectangle is expected to be provided by // PrepareHostRenderTargetsResolveClear which should do all the needed size // bound checks. void PerformTransfersAndResolveClears( uint32_t render_target_count, RenderTarget* const* render_targets, const std::vector* render_target_transfers, const uint64_t* render_target_resolve_clear_values = nullptr, const Transfer::Rectangle* resolve_clear_rectangle = nullptr); // Accepts an array of (1 + xenos::kMaxColorRenderTargets) render targets, // first depth, then color. void SetCommandListRenderTargets( RenderTarget* const* depth_and_color_render_targets); ID3D12PipelineState* GetOrCreateDumpPipeline(DumpPipelineKey key); // Writes contents of host render targets within rectangles from // ResolveInfo::GetCopyEdramTileSpan to edram_buffer_. void DumpRenderTargets(uint32_t dump_base, uint32_t dump_row_length_used, uint32_t dump_rows, uint32_t dump_pitch); bool use_stencil_reference_output_ = false; bool gamma_render_target_as_srgb_ = false; bool depth_float24_round_ = false; bool depth_float24_convert_in_pixel_shader_ = false; bool msaa_2x_supported_ = false; std::shared_ptr descriptor_pool_color_; std::shared_ptr descriptor_pool_depth_; std::shared_ptr descriptor_pool_srv_; ui::d3d12::D3D12CpuDescriptorPool::Descriptor null_rtv_descriptor_ss_; ui::d3d12::D3D12CpuDescriptorPool::Descriptor null_rtv_descriptor_ms_; // Possible tile ownership transfer paths: // - To color: // - From color: 1 SRV (color). // - From depth: 2 SRVs (depth, stencil). // - To depth / stencil (with SV_StencilRef): // - From color: 1 SRV (color). // - From depth: 2 SRVs (depth, stencil). // - From color and float32 depth: 2 SRVs (color with stencil, depth). // - Different depth buffer: depth SRV is a texture. // - Same depth buffer: depth SRV is a buffer (pre-copied). // - To depth (no SV_StencilRef): // - From color: 1 SRV (color). // - From depth: 1 SRV (depth). // - From color and float32 depth: 2 SRVs (color, depth). // - Different depth buffer: depth SRV is a texture. // - Same depth buffer: depth SRV is a buffer (pre-copied). // - To stencil (no SV_StencilRef): // - From color: 1 SRV (color). // - From depth: 1 SRV (stencil). const RenderTarget* const* current_command_list_render_targets_[1 + xenos::kMaxColorRenderTargets]; uint32_t are_current_command_list_render_targets_srgb_ = 0; bool are_current_command_list_render_targets_valid_ = false; // Temporary storage for descriptors used in PerformTransfersAndResolveClears // and DumpRenderTargets. std::vector current_temporary_descriptors_cpu_; std::vector current_temporary_descriptors_gpu_; ID3D12RootSignature* host_depth_store_root_signature_ = nullptr; ID3D12PipelineState* host_depth_store_pipelines_[size_t(xenos::MsaaSamples::k4X) + 1] = {}; std::unique_ptr transfer_vertex_buffer_pool_; ID3D12RootSignature* transfer_root_signatures_[size_t( TransferRootSignatureIndex::kCount)] = {}; std::unordered_map transfer_pipelines_; std::unordered_map, TransferShaderKey::Hasher> transfer_stencil_bit_pipelines_; // Temporary storage for PerformTransfersAndResolveClears. std::vector current_transfer_invocations_; // Temporary storage for DumpRenderTargets. std::vector dump_rectangles_; std::vector dump_invocations_; ID3D12RootSignature* dump_root_signature_color_ = nullptr; ID3D12RootSignature* dump_root_signature_depth_ = nullptr; // Compute pipelines for copying host render target contents to the EDRAM // buffer. May be null if failed to create. std::unordered_map dump_pipelines_; // Parameter 0 - 2 root constants (red, green). ID3D12RootSignature* uint32_rtv_clear_root_signature_ = nullptr; // [32 or 32_32][MSAA samples]. ID3D12PipelineState* uint32_rtv_clear_pipelines_[2][size_t(xenos::MsaaSamples::k4X) + 1] = {}; std::vector clear_transfers_[2]; // Temporary storage for DXBC building. std::vector built_shader_; // For rasterizer-ordered view (pixel shader interlock). ID3D12RootSignature* resolve_rov_clear_root_signature_ = nullptr; // Clearing 32bpp color or depth. ID3D12PipelineState* resolve_rov_clear_32bpp_pipeline_ = nullptr; // Clearing 64bpp color. ID3D12PipelineState* resolve_rov_clear_64bpp_pipeline_ = nullptr; }; } // namespace d3d12 } // namespace gpu } // namespace xe #endif // XENIA_GPU_D3D12_D3D12_RENDER_TARGET_CACHE_H_