[GPU] Set VGT_DRAW_INITIATOR and use major mode from it

This commit is contained in:
Triang3l 2020-02-24 23:27:25 +03:00
parent 8204fa163a
commit 90b772a330
13 changed files with 118 additions and 60 deletions

View File

@ -1153,44 +1153,51 @@ bool CommandProcessor::ExecutePacketType3_DRAW_INDX(RingBuffer* reader,
// ID = dword0 & 0x3F;
// use = dword0 & 0x40;
uint32_t dword0 = reader->ReadAndSwap<uint32_t>(); // viz query info
uint32_t dword1 = reader->ReadAndSwap<uint32_t>();
uint32_t index_count = dword1 >> 16;
auto prim_type = static_cast<PrimitiveType>(dword1 & 0x3F);
reg::VGT_DRAW_INITIATOR vgt_draw_initiator;
vgt_draw_initiator.value = reader->ReadAndSwap<uint32_t>();
WriteRegister(XE_GPU_REG_VGT_DRAW_INITIATOR, vgt_draw_initiator.value);
bool is_indexed = false;
IndexBufferInfo index_buffer_info;
uint32_t src_sel = (dword1 >> 6) & 0x3;
if (src_sel == 0x0) {
// DI_SRC_SEL_DMA
switch (vgt_draw_initiator.source_select) {
case xenos::SourceSelect::kDMA: {
// Indexed draw.
is_indexed = true;
index_buffer_info.guest_base = reader->ReadAndSwap<uint32_t>();
uint32_t index_size = reader->ReadAndSwap<uint32_t>();
index_buffer_info.endianness = static_cast<Endian>(index_size >> 30);
index_size &= 0x00FFFFFF;
bool index_32bit = (dword1 >> 11) & 0x1;
index_buffer_info.format =
index_32bit ? IndexFormat::kInt32 : IndexFormat::kInt16;
index_size *= index_32bit ? 4 : 2;
index_buffer_info.format = vgt_draw_initiator.index_size;
index_size *=
(vgt_draw_initiator.index_size == IndexFormat::kInt32) ? 4 : 2;
index_buffer_info.length = index_size;
index_buffer_info.count = index_count;
} else if (src_sel == 0x1) {
// DI_SRC_SEL_IMMEDIATE
index_buffer_info.count = vgt_draw_initiator.num_indices;
} break;
case xenos::SourceSelect::kImmediate: {
// TODO(Triang3l): VGT_IMMED_DATA.
assert_always();
} else if (src_sel == 0x2) {
// DI_SRC_SEL_AUTO_INDEX
} break;
case xenos::SourceSelect::kAutoIndex: {
// Auto draw.
index_buffer_info.guest_base = 0;
index_buffer_info.length = 0;
} else {
} break;
default: {
// Invalid source select.
assert_always();
} break;
}
bool success = IssueDraw(prim_type, index_count,
is_indexed ? &index_buffer_info : nullptr);
bool success =
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) {
XELOGE("PM4_DRAW_INDX(%d, %d, %d): Failed in backend", index_count,
prim_type, src_sel);
XELOGE("PM4_DRAW_INDX(%d, %d, %d): Failed in backend",
vgt_draw_initiator.num_indices,
uint32_t(vgt_draw_initiator.prim_type),
uint32_t(vgt_draw_initiator.source_select));
}
return true;
@ -1200,21 +1207,27 @@ bool CommandProcessor::ExecutePacketType3_DRAW_INDX_2(RingBuffer* reader,
uint32_t packet,
uint32_t count) {
// draw using supplied indices in packet
uint32_t dword0 = reader->ReadAndSwap<uint32_t>();
uint32_t index_count = dword0 >> 16;
auto prim_type = static_cast<PrimitiveType>(dword0 & 0x3F);
uint32_t src_sel = (dword0 >> 6) & 0x3;
assert_true(src_sel == 0x2); // 'SrcSel=AutoIndex'
reg::VGT_DRAW_INITIATOR vgt_draw_initiator;
vgt_draw_initiator.value = reader->ReadAndSwap<uint32_t>();
WriteRegister(XE_GPU_REG_VGT_DRAW_INITIATOR, vgt_draw_initiator.value);
assert_true(vgt_draw_initiator.source_select ==
xenos::SourceSelect::kAutoIndex);
// Index buffer unused as automatic.
// bool index_32bit = (dword0 >> 11) & 0x1;
// uint32_t indices_size = index_count * (index_32bit ? 4 : 2);
// uint32_t indices_size =
// vgt_draw_initiator.num_indices *
// (vgt_draw_initiator.index_size == IndexFormat::kInt32 ? 4 : 2);
// uint32_t index_ptr = reader->ptr();
// TODO(Triang3l): VGT_IMMED_DATA.
reader->AdvanceRead((count - 1) * sizeof(uint32_t));
bool success = IssueDraw(prim_type, index_count, nullptr);
bool success = IssueDraw(
vgt_draw_initiator.prim_type, vgt_draw_initiator.num_indices, nullptr,
xenos::IsMajorModeExplicit(vgt_draw_initiator.major_mode,
vgt_draw_initiator.prim_type));
if (!success) {
XELOGE("PM4_DRAW_INDX_IMM(%d, %d): Failed in backend", index_count,
prim_type);
XELOGE("PM4_DRAW_INDX_IMM(%d, %d): Failed in backend",
vgt_draw_initiator.num_indices,
uint32_t(vgt_draw_initiator.prim_type));
}
return true;

View File

@ -239,7 +239,8 @@ class CommandProcessor {
uint32_t dword_count) = 0;
virtual bool IssueDraw(PrimitiveType prim_type, uint32_t index_count,
IndexBufferInfo* index_buffer_info) = 0;
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) = 0;
virtual bool IssueCopy() = 0;
virtual void InitializeTrace() = 0;

View File

@ -1245,7 +1245,8 @@ Shader* D3D12CommandProcessor::LoadShader(ShaderType shader_type,
bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
uint32_t index_count,
IndexBufferInfo* index_buffer_info) {
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) {
auto device = GetD3D12Context()->GetD3D12Provider()->GetDevice();
auto& regs = *register_file_;
@ -1272,8 +1273,7 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
// Check if using tessellation to get the correct primitive type.
bool tessellated;
if (uint32_t(primitive_type) >=
uint32_t(PrimitiveType::kExplicitMajorModeForceStart)) {
if (major_mode_explicit) {
tessellated = regs.Get<reg::VGT_OUTPUT_PATH_CNTL>().path_select ==
xenos::VGTOutputPath::kTessellationEnable;
} else {

View File

@ -171,7 +171,8 @@ class D3D12CommandProcessor : public CommandProcessor {
uint32_t dword_count) override;
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
IndexBufferInfo* index_buffer_info) override;
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) override;
bool IssueCopy() override;
void InitializeTrace() override;

View File

@ -44,7 +44,8 @@ Shader* NullCommandProcessor::LoadShader(ShaderType shader_type,
bool NullCommandProcessor::IssueDraw(PrimitiveType prim_type,
uint32_t index_count,
IndexBufferInfo* index_buffer_info) {
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) {
return true;
}

View File

@ -41,7 +41,8 @@ class NullCommandProcessor : public CommandProcessor {
uint32_t dword_count) override;
bool IssueDraw(PrimitiveType prim_type, uint32_t index_count,
IndexBufferInfo* index_buffer_info) override;
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) override;
bool IssueCopy() override;
void InitializeTrace() override;

View File

@ -131,7 +131,10 @@ XE_GPU_REGISTER(0x2182, kDword, SQ_INTERPOLATOR_CNTL)
XE_GPU_REGISTER(0x2183, kDword, SQ_WRAPPING_0)
XE_GPU_REGISTER(0x2184, kDword, SQ_WRAPPING_1)
// These three registers are set by the command processor.
XE_GPU_REGISTER(0x21F9, kDword, VGT_EVENT_INITIATOR)
XE_GPU_REGISTER(0x21FC, kDword, VGT_DRAW_INITIATOR)
XE_GPU_REGISTER(0x21FD, kDword, VGT_IMMED_DATA)
XE_GPU_REGISTER(0x2200, kDword, RB_DEPTHCONTROL)
XE_GPU_REGISTER(0x2201, kDword, RB_BLENDCONTROL0)

View File

@ -145,6 +145,22 @@ union SQ_CONTEXT_MISC {
*******************************************************************************/
union VGT_DRAW_INITIATOR {
// Different than on A2xx and R6xx/R7xx.
struct {
PrimitiveType prim_type : 6; // +0
xenos::SourceSelect source_select : 2; // +6
xenos::MajorMode major_mode : 2; // +8
uint32_t : 1; // +10
IndexFormat index_size : 1; // +11
uint32_t not_eop : 1; // +12
uint32_t : 3; // +13
uint32_t num_indices : 16; // +16
};
uint32_t value;
static constexpr Register register_index = XE_GPU_REG_VGT_DRAW_INITIATOR;
};
union VGT_OUTPUT_PATH_CNTL {
struct {
xenos::VGTOutputPath path_select : 2; // +0

View File

@ -40,7 +40,8 @@ Shader* VulkanCommandProcessor::LoadShader(ShaderType shader_type,
bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
uint32_t index_count,
IndexBufferInfo* index_buffer_info) {
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) {
return true;
}

View File

@ -40,7 +40,8 @@ class VulkanCommandProcessor : public CommandProcessor {
uint32_t dword_count) override;
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
IndexBufferInfo* index_buffer_info) override;
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) override;
bool IssueCopy() override;
void InitializeTrace() override;

View File

@ -598,7 +598,8 @@ Shader* VulkanCommandProcessor::LoadShader(ShaderType shader_type,
bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
uint32_t index_count,
IndexBufferInfo* index_buffer_info) {
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) {
auto& regs = *register_file_;
#if FINE_GRAINED_DRAW_SCOPES

View File

@ -81,7 +81,8 @@ class VulkanCommandProcessor : public CommandProcessor {
uint32_t dword_count) override;
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
IndexBufferInfo* index_buffer_info) override;
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) override;
bool PopulateConstants(VkCommandBuffer command_buffer,
VulkanShader* vertex_shader,
VulkanShader* pixel_shader);

View File

@ -37,12 +37,11 @@ enum class PrimitiveType : uint32_t {
kQuadStrip = 0x0E,
kPolygon = 0x0F,
// Starting with this primitive mode, registers like VGT_OUTPUT_PATH_CNTL have
// effect (deduced from R6xx/R7xx registers, and Halo 3 also doesn't reset
// VGT_OUTPUT_PATH_CNTL after the first draw with tessellation).
// TODO(Triang3l): Find out if VGT_DRAW_INITIATOR (0x21FC on Adreno 2xx, but
// not seen being used in games) specifies the major mode (or if it's set
// somewhere else).
// Starting with this primitive type, explicit major mode is assumed (in the
// R6xx/R7xx registers, k2DCopyRectListV0 is 22, and implicit major mode is
// only used for primitive types 0 through 21) - and tessellation patches use
// the range that starts from k2DCopyRectListV0.
// TODO(Triang3l): Verify if this is also true for the Xenos.
kExplicitMajorModeForceStart = 0x10,
k2DCopyRectListV0 = 0x10,
@ -460,6 +459,25 @@ typedef enum {
XE_GPU_INVALIDATE_MASK_ALL = 0x7FFF,
} XE_GPU_INVALIDATE_MASK;
// VGT_DRAW_INITIATOR::DI_SRC_SEL_*
enum class SourceSelect : uint32_t {
kDMA,
kImmediate,
kAutoIndex,
};
// VGT_DRAW_INITIATOR::DI_MAJOR_MODE_*
enum class MajorMode : uint32_t {
kImplicit,
kExplicit,
};
inline bool IsMajorModeExplicit(MajorMode major_mode,
PrimitiveType primitive_type) {
return major_mode != MajorMode::kImplicit ||
primitive_type >= PrimitiveType::kExplicitMajorModeForceStart;
}
// instr_arbitrary_filter_t
enum class ArbitraryFilter : uint32_t {
k2x4Sym = 0,