From cedc94679b76439214bc155f362a5834d60918a2 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Tue, 28 Jun 2022 21:40:06 +0300 Subject: [PATCH 1/3] [GPU] Don't drop the rest of the command list if IssueDraw fails --- src/xenia/gpu/command_processor.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/xenia/gpu/command_processor.cc b/src/xenia/gpu/command_processor.cc index f935f22ec..bb452c13d 100644 --- a/src/xenia/gpu/command_processor.cc +++ b/src/xenia/gpu/command_processor.cc @@ -1281,7 +1281,7 @@ bool CommandProcessor::ExecutePacketType3Draw(RingBuffer* reader, --count_remaining; WriteRegister(XE_GPU_REG_VGT_DRAW_INITIATOR, vgt_draw_initiator.value); - bool success = true; + bool draw_succeeded = true; // TODO(Triang3l): Remove IndexBufferInfo and replace handling of all this // with PrimitiveProcessor when the old Vulkan renderer is removed. bool is_indexed = false; @@ -1330,7 +1330,7 @@ bool CommandProcessor::ExecutePacketType3Draw(RingBuffer* reader, "{}: Using immediate vertex indices, which are not supported yet. " "Report the game to Xenia developers!", opcode_name, uint32_t(vgt_draw_initiator.source_select)); - success = false; + draw_succeeded = false; assert_always(); } break; case xenos::SourceSelect::kAutoIndex: { @@ -1340,7 +1340,7 @@ bool CommandProcessor::ExecutePacketType3Draw(RingBuffer* reader, } break; default: { // Invalid source selection. - success = false; + draw_succeeded = false; assert_unhandled_case(vgt_draw_initiator.source_select); } break; } @@ -1349,19 +1349,19 @@ bool CommandProcessor::ExecutePacketType3Draw(RingBuffer* reader, // we don't support yet. reader->AdvanceRead(count_remaining * sizeof(uint32_t)); - if (success) { + if (draw_succeeded) { auto viz_query = register_file_->Get(); if (!(viz_query.viz_query_ena && viz_query.kill_pix_post_hi_z)) { // TODO(Triang3l): Don't drop the draw call completely if the vertex // shader has memexport. // TODO(Triang3l || JoelLinn): Handle this properly in the render // backends. - success = IssueDraw( + draw_succeeded = IssueDraw( vgt_draw_initiator.prim_type, vgt_draw_initiator.num_indices, is_indexed ? &index_buffer_info : nullptr, xenos::IsMajorModeExplicit(vgt_draw_initiator.major_mode, vgt_draw_initiator.prim_type)); - if (!success) { + if (!draw_succeeded) { XELOGE("{}({}, {}, {}): Failed in backend", opcode_name, vgt_draw_initiator.num_indices, uint32_t(vgt_draw_initiator.prim_type), @@ -1370,7 +1370,11 @@ bool CommandProcessor::ExecutePacketType3Draw(RingBuffer* reader, } } - return success; + // If read the packed correctly, but merely couldn't execute it (because of, + // for instance, features not supported by the host), don't terminate command + // buffer processing as that would leave rendering in a way more inconsistent + // state than just a single dropped draw command. + return true; } bool CommandProcessor::ExecutePacketType3_DRAW_INDX(RingBuffer* reader, From 382710bab78eed75344f574c3491f503882ff858 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Tue, 28 Jun 2022 21:58:58 +0300 Subject: [PATCH 2/3] [GPU] Normalize sampler clamp modes --- src/xenia/gpu/d3d12/d3d12_texture_cache.cc | 34 +++++++++++++++++++--- src/xenia/gpu/d3d12/d3d12_texture_cache.h | 2 ++ src/xenia/gpu/texture_util.cc | 23 +++++++++++++++ src/xenia/gpu/texture_util.h | 7 +++++ src/xenia/gpu/xenos.h | 5 ++++ 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/xenia/gpu/d3d12/d3d12_texture_cache.cc b/src/xenia/gpu/d3d12/d3d12_texture_cache.cc index b06e46fc7..c34343670 100644 --- a/src/xenia/gpu/d3d12/d3d12_texture_cache.cc +++ b/src/xenia/gpu/d3d12/d3d12_texture_cache.cc @@ -965,10 +965,19 @@ D3D12TextureCache::SamplerParameters D3D12TextureCache::GetSamplerParameters( SamplerParameters parameters; - parameters.clamp_x = fetch.clamp_x; - parameters.clamp_y = fetch.clamp_y; - parameters.clamp_z = fetch.clamp_z; - parameters.border_color = fetch.border_color; + xenos::ClampMode fetch_clamp_x, fetch_clamp_y, fetch_clamp_z; + texture_util::GetClampModesForDimension(fetch, fetch_clamp_x, fetch_clamp_y, + fetch_clamp_z); + parameters.clamp_x = NormalizeClampMode(fetch_clamp_x); + parameters.clamp_y = NormalizeClampMode(fetch_clamp_y); + parameters.clamp_z = NormalizeClampMode(fetch_clamp_z); + if (xenos::ClampModeUsesBorder(parameters.clamp_x) || + xenos::ClampModeUsesBorder(parameters.clamp_y) || + xenos::ClampModeUsesBorder(parameters.clamp_z)) { + parameters.border_color = fetch.border_color; + } else { + parameters.border_color = xenos::BorderColor::k_ABGR_Black; + } uint32_t mip_min_level; texture_util::GetSubresourcesFromFetchConstant(fetch, nullptr, nullptr, @@ -976,6 +985,7 @@ D3D12TextureCache::SamplerParameters D3D12TextureCache::GetSamplerParameters( &mip_min_level, nullptr); parameters.mip_min_level = mip_min_level; + // TODO(Triang3l): Disable filtering for texture formats not supporting it. xenos::AnisoFilter aniso_filter = binding.aniso_filter == xenos::AnisoFilter::kUseFetchConst ? fetch.aniso_filter @@ -2204,6 +2214,22 @@ D3D12_CPU_DESCRIPTOR_HANDLE D3D12TextureCache::GetTextureDescriptorCPUHandle( return provider.OffsetViewDescriptor(heap_start, heap_offset); } +xenos::ClampMode D3D12TextureCache::NormalizeClampMode( + xenos::ClampMode clamp_mode) const { + if (clamp_mode == xenos::ClampMode::kClampToHalfway) { + // No GL_CLAMP (clamp to half edge, half border) equivalent in Direct3D 12, + // but there's no Direct3D 9 equivalent anyway, and too weird to be suitable + // for intentional real usage. + return xenos::ClampMode::kClampToEdge; + } + if (clamp_mode == xenos::ClampMode::kMirrorClampToHalfway || + clamp_mode == xenos::ClampMode::kMirrorClampToBorder) { + // No Direct3D 12 equivalents. + return xenos::ClampMode::kMirrorClampToEdge; + } + return clamp_mode; +} + } // namespace d3d12 } // namespace gpu } // namespace xe diff --git a/src/xenia/gpu/d3d12/d3d12_texture_cache.h b/src/xenia/gpu/d3d12/d3d12_texture_cache.h index 50c51fa14..9b22b1e9b 100644 --- a/src/xenia/gpu/d3d12/d3d12_texture_cache.h +++ b/src/xenia/gpu/d3d12/d3d12_texture_cache.h @@ -463,6 +463,8 @@ class D3D12TextureCache final : public TextureCache { return *scaled_resolve_buffer; } + xenos::ClampMode NormalizeClampMode(xenos::ClampMode clamp_mode) const; + static const HostFormat host_formats_[64]; D3D12CommandProcessor& command_processor_; diff --git a/src/xenia/gpu/texture_util.cc b/src/xenia/gpu/texture_util.cc index f07a3df50..ada6cf140 100644 --- a/src/xenia/gpu/texture_util.cc +++ b/src/xenia/gpu/texture_util.cc @@ -612,6 +612,29 @@ uint8_t SwizzleSigns(const xenos::xe_gpu_texture_fetch_t& fetch) { return signs; } +void GetClampModesForDimension(const xenos::xe_gpu_texture_fetch_t& fetch, + xenos::ClampMode& clamp_x_out, + xenos::ClampMode& clamp_y_out, + xenos::ClampMode& clamp_z_out) { + clamp_x_out = xenos::ClampMode::kClampToEdge; + clamp_y_out = xenos::ClampMode::kClampToEdge; + clamp_z_out = xenos::ClampMode::kClampToEdge; + switch (fetch.dimension) { + case xenos::DataDimension::k3D: + clamp_z_out = fetch.clamp_z; + [[fallthrough]]; + case xenos::DataDimension::k2DOrStacked: + clamp_y_out = fetch.clamp_y; + [[fallthrough]]; + case xenos::DataDimension::k1D: + clamp_x_out = fetch.clamp_x; + break; + default: + // Not applicable to cube textures. + break; + } +} + } // namespace texture_util } // namespace gpu } // namespace xe diff --git a/src/xenia/gpu/texture_util.h b/src/xenia/gpu/texture_util.h index 3eab10c31..bcc080de3 100644 --- a/src/xenia/gpu/texture_util.h +++ b/src/xenia/gpu/texture_util.h @@ -334,6 +334,13 @@ constexpr bool IsAnySignSigned(uint8_t packed_signs) { return ((xor_signed | (xor_signed >> 1)) & 0b01010101) != 0b01010101; } +// Returns normalized clamp modes specified in the fetch constant based on the +// texture data dimension in it. +void GetClampModesForDimension(const xenos::xe_gpu_texture_fetch_t& fetch, + xenos::ClampMode& clamp_x_out, + xenos::ClampMode& clamp_y_out, + xenos::ClampMode& clamp_z_out); + } // namespace texture_util } // namespace gpu } // namespace xe diff --git a/src/xenia/gpu/xenos.h b/src/xenia/gpu/xenos.h index 4ce4794f5..d0cb4666e 100644 --- a/src/xenia/gpu/xenos.h +++ b/src/xenia/gpu/xenos.h @@ -99,6 +99,11 @@ enum class ClampMode : uint32_t { kMirrorClampToBorder = 7, }; +constexpr bool ClampModeUsesBorder(ClampMode clamp_mode) { + return clamp_mode == ClampMode::kClampToBorder || + clamp_mode == ClampMode::kMirrorClampToBorder; +} + // TEX_FORMAT_COMP, known as GPUSIGN on the Xbox 360. enum class TextureSign : uint32_t { kUnsigned = 0, From 243683d2e9d119d83fa9ccba8f9d810055e6c530 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Tue, 28 Jun 2022 22:04:26 +0300 Subject: [PATCH 3/3] [GPU] Cleanup Texture::MarkAsUsed conditionals --- src/xenia/gpu/texture_cache.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/xenia/gpu/texture_cache.cc b/src/xenia/gpu/texture_cache.cc index b09f6ad46..030ae2be7 100644 --- a/src/xenia/gpu/texture_cache.cc +++ b/src/xenia/gpu/texture_cache.cc @@ -526,8 +526,10 @@ void TextureCache::Texture::MakeUpToDateAndWatch( } void TextureCache::Texture::MarkAsUsed() { + assert_true(last_usage_submission_index_ <= + texture_cache_.current_submission_index_); // This is called very frequently, don't relink unless needed for caching. - if (last_usage_submission_index_ == + if (last_usage_submission_index_ >= texture_cache_.current_submission_index_) { return; } @@ -545,9 +547,7 @@ void TextureCache::Texture::MarkAsUsed() { used_next_->used_previous_ = used_previous_; used_previous_ = texture_cache_.texture_used_last_; used_next_ = nullptr; - if (texture_cache_.texture_used_last_ != nullptr) { - texture_cache_.texture_used_last_->used_next_ = this; - } + texture_cache_.texture_used_last_->used_next_ = this; texture_cache_.texture_used_last_ = this; }