[GPU] --gpu_allow_invalid_fetch_constants to bypass invalid fetch constant type errors

This commit is contained in:
Triang3l 2020-02-16 19:35:26 +03:00
parent d18e63e6e2
commit 710d225d0a
10 changed files with 108 additions and 23 deletions

View File

@ -20,6 +20,7 @@
#include "xenia/gpu/d3d12/d3d12_command_processor.h" #include "xenia/gpu/d3d12/d3d12_command_processor.h"
#include "xenia/gpu/d3d12/d3d12_graphics_system.h" #include "xenia/gpu/d3d12/d3d12_graphics_system.h"
#include "xenia/gpu/d3d12/d3d12_shader.h" #include "xenia/gpu/d3d12/d3d12_shader.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/xenos.h" #include "xenia/gpu/xenos.h"
#include "xenia/ui/d3d12/d3d12_util.h" #include "xenia/ui/d3d12/d3d12_util.h"
@ -1476,8 +1477,21 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
} }
const auto& vfetch_constant = regs.Get<xenos::xe_gpu_vertex_fetch_t>( const auto& vfetch_constant = regs.Get<xenos::xe_gpu_vertex_fetch_t>(
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + vfetch_index * 2); XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + vfetch_index * 2);
if (vfetch_constant.type != 3) { switch (vfetch_constant.type) {
XELOGW("Vertex fetch type is not 3 (fetch constant %u is %.8X %.8X)!", case xenos::FetchConstantType::kVertex:
break;
case xenos::FetchConstantType::kInvalidVertex:
if (cvars::gpu_allow_invalid_fetch_constants) {
break;
}
XELOGW(
"Vertex fetch constant %u (%.8X %.8X) has \"invalid\" type! This "
"is incorrect behavior, but you can try bypassing this by "
"launching Xenia with --gpu_allow_invalid_fetch_constants=true.",
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1);
return false;
default:
XELOGW("Vertex fetch constant %u (%.8X %.8X) is completely invalid!",
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1); vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1);
return false; return false;
} }

View File

@ -1087,7 +1087,7 @@ bool RenderTargetCache::Resolve(SharedMemory* shared_memory,
// HACK: Vertices to use are always in vf0. // HACK: Vertices to use are always in vf0.
const auto& fetch = regs.Get<xenos::xe_gpu_vertex_fetch_t>( const auto& fetch = regs.Get<xenos::xe_gpu_vertex_fetch_t>(
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0); XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0);
assert_true(fetch.type == 3); assert_true(fetch.type == xenos::FetchConstantType::kVertex);
assert_true(fetch.endian == Endian::k8in32); assert_true(fetch.endian == Endian::k8in32);
assert_true(fetch.size == 6); assert_true(fetch.size == 6);
trace_writer_->WriteMemoryRead(fetch.address << 2, fetch.size << 2); trace_writer_->WriteMemoryRead(fetch.address << 2, fetch.size << 2);

View File

@ -21,6 +21,7 @@
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/base/profiling.h" #include "xenia/base/profiling.h"
#include "xenia/gpu/d3d12/d3d12_command_processor.h" #include "xenia/gpu/d3d12/d3d12_command_processor.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/texture_info.h" #include "xenia/gpu/texture_info.h"
#include "xenia/gpu/texture_util.h" #include "xenia/gpu/texture_util.h"
#include "xenia/ui/d3d12/d3d12_util.h" #include "xenia/ui/d3d12/d3d12_util.h"
@ -2094,10 +2095,25 @@ void TextureCache::BindingInfoFromFetchConstant(
*has_signed_out = false; *has_signed_out = false;
} }
if (fetch.type != 2) { switch (fetch.type) {
case xenos::FetchConstantType::kTexture:
break;
case xenos::FetchConstantType::kInvalidTexture:
if (cvars::gpu_allow_invalid_fetch_constants) {
break;
}
XELOGW( XELOGW(
"Texture fetch type is not 2 - ignoring (fetch constant is %.8X %.8X " "Texture fetch constant (%.8X %.8X %.8X %.8X %.8X %.8X) has "
"%.8X %.8X %.8X %.8X)!", "\"invalid\" type! This is incorrect behavior, but you can try "
"bypassing this by launching Xenia with "
"--gpu_allow_invalid_fetch_constants=true.",
fetch.dword_0, fetch.dword_1, fetch.dword_2, fetch.dword_3,
fetch.dword_4, fetch.dword_5);
return;
default:
XELOGW(
"Texture fetch constant (%.8X %.8X %.8X %.8X %.8X %.8X) is "
"completely invalid!",
fetch.dword_0, fetch.dword_1, fetch.dword_2, fetch.dword_3, fetch.dword_0, fetch.dword_1, fetch.dword_2, fetch.dword_3,
fetch.dword_4, fetch.dword_5); fetch.dword_4, fetch.dword_5);
return; return;

View File

@ -17,3 +17,11 @@ DEFINE_string(dump_shaders, "",
"Path to write GPU shaders to as they are compiled.", "GPU"); "Path to write GPU shaders to as they are compiled.", "GPU");
DEFINE_bool(vsync, true, "Enable VSYNC.", "GPU"); DEFINE_bool(vsync, true, "Enable VSYNC.", "GPU");
DEFINE_bool(
gpu_allow_invalid_fetch_constants, false,
"Allow texture and vertex fetch constants with invalid type - generally "
"unsafe because the constant may contain completely invalid values, but "
"may be used to bypass fetch constant type errors in certain games until "
"the real reason why they're invalid is found.",
"GPU");

View File

@ -18,4 +18,6 @@ DECLARE_string(dump_shaders);
DECLARE_bool(vsync); DECLARE_bool(vsync);
DECLARE_bool(gpu_allow_invalid_fetch_constants);
#endif // XENIA_GPU_GPU_FLAGS_H_ #endif // XENIA_GPU_GPU_FLAGS_H_

View File

@ -19,6 +19,7 @@
#include "xenia/base/string.h" #include "xenia/base/string.h"
#include "xenia/base/threading.h" #include "xenia/base/threading.h"
#include "xenia/gpu/command_processor.h" #include "xenia/gpu/command_processor.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/graphics_system.h" #include "xenia/gpu/graphics_system.h"
#include "xenia/gpu/packet_disassembler.h" #include "xenia/gpu/packet_disassembler.h"
#include "xenia/gpu/register_file.h" #include "xenia/gpu/register_file.h"
@ -664,7 +665,9 @@ void TraceViewer::DrawTextureInfo(
texture_binding.fetch_constant * 6; texture_binding.fetch_constant * 6;
auto group = reinterpret_cast<const xe_gpu_fetch_group_t*>(&regs.values[r]); auto group = reinterpret_cast<const xe_gpu_fetch_group_t*>(&regs.values[r]);
auto& fetch = group->texture_fetch; auto& fetch = group->texture_fetch;
if (fetch.type != 0x2) { if (fetch.type != xenos::FetchConstantType::kTexture &&
(!cvars::gpu_allow_invalid_fetch_constants ||
fetch.type != xenos::FetchConstantType::kInvalidTexture)) {
DrawFailedTextureInfo(texture_binding, "Invalid fetch type"); DrawFailedTextureInfo(texture_binding, "Invalid fetch type");
return; return;
} }

View File

@ -639,8 +639,23 @@ VkDescriptorSet BufferCache::PrepareVertexSet(
break; break;
} }
if (fetch->type != 0x3) { // TODO(DrChat): Some games use type kInvalidTexture (with no data).
// TODO(DrChat): Some games use type 0x0 (with no data). switch (fetch->type) {
case xenos::FetchConstantType::kVertex:
break;
case xenos::FetchConstantType::kInvalidVertex:
if (cvars::gpu_allow_invalid_fetch_constants) {
break;
}
XELOGW(
"Vertex fetch constant %u (%.8X %.8X) has \"invalid\" type! This "
"is incorrect behavior, but you can try bypassing this by "
"launching Xenia with --gpu_allow_invalid_fetch_constants=true.",
vertex_binding.fetch_constant, fetch->dword_0, fetch->dword_1);
return nullptr;
default:
XELOGW("Vertex fetch constant %u (%.8X %.8X) is completely invalid!",
vertex_binding.fetch_constant, fetch->dword_0, fetch->dword_1);
return nullptr; return nullptr;
} }

View File

@ -1501,8 +1501,27 @@ bool TextureCache::SetupTextureBinding(VkCommandBuffer command_buffer,
// Disabled? // Disabled?
// TODO(benvanik): reset sampler. // TODO(benvanik): reset sampler.
if (fetch.type != 0x2) { switch (fetch.type) {
XELOGGPU("Fetch type is not 2!"); case xenos::FetchConstantType::kTexture:
break;
case xenos::FetchConstantType::kInvalidTexture:
if (cvars::gpu_allow_invalid_fetch_constants) {
break;
}
XELOGW(
"Texture fetch constant %u (%.8X %.8X %.8X %.8X %.8X %.8X) has "
"\"invalid\" type! This is incorrect behavior, but you can try "
"bypassing this by launching Xenia with "
"--gpu_allow_invalid_fetch_constants=true.",
binding.fetch_constant, fetch.dword_0, fetch.dword_1, fetch.dword_2,
fetch.dword_3, fetch.dword_4, fetch.dword_5);
return false;
default:
XELOGW(
"Texture fetch constant %u (%.8X %.8X %.8X %.8X %.8X %.8X) is "
"completely invalid!",
binding.fetch_constant, fetch.dword_0, fetch.dword_1, fetch.dword_2,
fetch.dword_3, fetch.dword_4, fetch.dword_5);
return false; return false;
} }

View File

@ -966,7 +966,7 @@ bool VulkanCommandProcessor::IssueCopy() {
fetch = &group->vertex_fetch_2; fetch = &group->vertex_fetch_2;
break; break;
} }
assert_true(fetch->type == 3); assert_true(fetch->type == xenos::FetchConstantType::kVertex);
assert_true(fetch->endian == Endian::k8in32); assert_true(fetch->endian == Endian::k8in32);
assert_true(fetch->size == 6); assert_true(fetch->size == 6);
const uint8_t* vertex_addr = memory_->TranslatePhysical(fetch->address << 2); const uint8_t* vertex_addr = memory_->TranslatePhysical(fetch->address << 2);

View File

@ -605,10 +605,18 @@ inline uint32_t GpuToCpu(uint32_t p) { return p; }
inline uint32_t CpuToGpu(uint32_t p) { return p & 0x1FFFFFFF; } inline uint32_t CpuToGpu(uint32_t p) { return p & 0x1FFFFFFF; }
// SQ_TEX_VTX_INVALID/VALID_TEXTURE/BUFFER
enum class FetchConstantType : uint32_t {
kInvalidTexture,
kInvalidVertex,
kTexture,
kVertex,
};
// XE_GPU_REG_SHADER_CONSTANT_FETCH_* // XE_GPU_REG_SHADER_CONSTANT_FETCH_*
XEPACKEDUNION(xe_gpu_vertex_fetch_t, { XEPACKEDUNION(xe_gpu_vertex_fetch_t, {
XEPACKEDSTRUCTANONYMOUS({ XEPACKEDSTRUCTANONYMOUS({
uint32_t type : 2; // +0 FetchConstantType type : 2; // +0
uint32_t address : 30; // +2 address in dwords uint32_t address : 30; // +2 address in dwords
Endian endian : 2; // +0 Endian endian : 2; // +0
@ -624,7 +632,7 @@ XEPACKEDUNION(xe_gpu_vertex_fetch_t, {
// XE_GPU_REG_SHADER_CONSTANT_FETCH_* // XE_GPU_REG_SHADER_CONSTANT_FETCH_*
XEPACKEDUNION(xe_gpu_texture_fetch_t, { XEPACKEDUNION(xe_gpu_texture_fetch_t, {
XEPACKEDSTRUCTANONYMOUS({ XEPACKEDSTRUCTANONYMOUS({
uint32_t type : 2; // +0 dword_0 FetchConstantType type : 2; // +0 dword_0
TextureSign sign_x : 2; // +2 TextureSign sign_x : 2; // +2
TextureSign sign_y : 2; // +4 TextureSign sign_y : 2; // +4
TextureSign sign_z : 2; // +6 TextureSign sign_z : 2; // +6