[GPU] Primitive processor with Vulkan 1.0 base cases, 24-bit indices and clamping
This commit is contained in:
@@ -1177,40 +1177,77 @@ bool CommandProcessor::ExecutePacketType3_EVENT_WRITE_ZPD(RingBuffer* reader,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandProcessor::ExecutePacketType3_DRAW_INDX(RingBuffer* reader,
|
||||
uint32_t packet,
|
||||
uint32_t count) {
|
||||
// initiate fetch of index buffer and draw
|
||||
// if dword0 != 0, this is a conditional draw based on viz query.
|
||||
bool CommandProcessor::ExecutePacketType3Draw(RingBuffer* reader,
|
||||
uint32_t packet,
|
||||
const char* opcode_name,
|
||||
uint32_t viz_query_condition,
|
||||
uint32_t count_remaining) {
|
||||
// if viz_query_condition != 0, this is a conditional draw based on viz query.
|
||||
// This ID matches the one issued in PM4_VIZ_QUERY
|
||||
uint32_t dword0 = reader->ReadAndSwap<uint32_t>(); // viz query info
|
||||
// uint32_t viz_id = dword0 & 0x3F;
|
||||
// uint32_t viz_id = viz_query_condition & 0x3F;
|
||||
// when true, render conditionally based on query result
|
||||
// uint32_t viz_use = dword0 & 0x100;
|
||||
// uint32_t viz_use = viz_query_condition & 0x100;
|
||||
|
||||
assert_not_zero(count_remaining);
|
||||
if (!count_remaining) {
|
||||
XELOGE("{}: Packet too small, can't read VGT_DRAW_INITIATOR", opcode_name);
|
||||
return false;
|
||||
}
|
||||
reg::VGT_DRAW_INITIATOR vgt_draw_initiator;
|
||||
vgt_draw_initiator.value = reader->ReadAndSwap<uint32_t>();
|
||||
--count_remaining;
|
||||
WriteRegister(XE_GPU_REG_VGT_DRAW_INITIATOR, vgt_draw_initiator.value);
|
||||
|
||||
bool success = true;
|
||||
// TODO(Triang3l): Remove IndexBufferInfo and replace handling of all this
|
||||
// with PrimitiveProcessor when the old Vulkan renderer is removed.
|
||||
bool is_indexed = false;
|
||||
IndexBufferInfo index_buffer_info;
|
||||
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<xenos::Endian>(index_size >> 30);
|
||||
index_size &= 0x00FFFFFF;
|
||||
|
||||
// Two separate bounds checks so if there's only one missing register
|
||||
// value out of two, one uint32_t will be skipped in the command buffer,
|
||||
// not two.
|
||||
assert_not_zero(count_remaining);
|
||||
if (!count_remaining) {
|
||||
XELOGE("{}: Packet too small, can't read VGT_DMA_BASE", opcode_name);
|
||||
return false;
|
||||
}
|
||||
uint32_t vgt_dma_base = reader->ReadAndSwap<uint32_t>();
|
||||
--count_remaining;
|
||||
WriteRegister(XE_GPU_REG_VGT_DMA_BASE, vgt_dma_base);
|
||||
reg::VGT_DMA_SIZE vgt_dma_size;
|
||||
assert_not_zero(count_remaining);
|
||||
if (!count_remaining) {
|
||||
XELOGE("{}: Packet too small, can't read VGT_DMA_SIZE", opcode_name);
|
||||
return false;
|
||||
}
|
||||
vgt_dma_size.value = reader->ReadAndSwap<uint32_t>();
|
||||
--count_remaining;
|
||||
WriteRegister(XE_GPU_REG_VGT_DMA_SIZE, vgt_dma_size.value);
|
||||
|
||||
uint32_t index_size_bytes =
|
||||
vgt_draw_initiator.index_size == xenos::IndexFormat::kInt16
|
||||
? sizeof(uint16_t)
|
||||
: sizeof(uint32_t);
|
||||
// The base address must already be word-aligned according to the R6xx
|
||||
// documentation, but for safety.
|
||||
index_buffer_info.guest_base = vgt_dma_base & ~(index_size_bytes - 1);
|
||||
index_buffer_info.endianness = vgt_dma_size.swap_mode;
|
||||
index_buffer_info.format = vgt_draw_initiator.index_size;
|
||||
index_size *=
|
||||
(vgt_draw_initiator.index_size == xenos::IndexFormat::kInt32) ? 4 : 2;
|
||||
index_buffer_info.length = index_size;
|
||||
index_buffer_info.length = vgt_dma_size.num_words * index_size_bytes;
|
||||
index_buffer_info.count = vgt_draw_initiator.num_indices;
|
||||
} break;
|
||||
case xenos::SourceSelect::kImmediate: {
|
||||
// TODO(Triang3l): VGT_IMMED_DATA.
|
||||
XELOGE(
|
||||
"{}: 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;
|
||||
assert_always();
|
||||
} break;
|
||||
case xenos::SourceSelect::kAutoIndex: {
|
||||
@@ -1219,71 +1256,65 @@ bool CommandProcessor::ExecutePacketType3_DRAW_INDX(RingBuffer* reader,
|
||||
index_buffer_info.length = 0;
|
||||
} break;
|
||||
default: {
|
||||
// Invalid source select.
|
||||
assert_always();
|
||||
// Invalid source selection.
|
||||
success = false;
|
||||
assert_unhandled_case(vgt_draw_initiator.source_select);
|
||||
} break;
|
||||
}
|
||||
|
||||
auto viz_query = register_file_->Get<reg::PA_SC_VIZ_QUERY>();
|
||||
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.
|
||||
return true;
|
||||
// Skip to the next command, for example, if there are immediate indexes that
|
||||
// we don't support yet.
|
||||
reader->AdvanceRead(count_remaining * sizeof(uint32_t));
|
||||
|
||||
if (success) {
|
||||
auto viz_query = register_file_->Get<reg::PA_SC_VIZ_QUERY>();
|
||||
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(
|
||||
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("{}({}, {}, {}): Failed in backend", opcode_name,
|
||||
vgt_draw_initiator.num_indices,
|
||||
uint32_t(vgt_draw_initiator.prim_type),
|
||||
uint32_t(vgt_draw_initiator.source_select));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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({}, {}, {}): Failed in backend",
|
||||
vgt_draw_initiator.num_indices,
|
||||
uint32_t(vgt_draw_initiator.prim_type),
|
||||
uint32_t(vgt_draw_initiator.source_select));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool CommandProcessor::ExecutePacketType3_DRAW_INDX(RingBuffer* reader,
|
||||
uint32_t packet,
|
||||
uint32_t count) {
|
||||
// "initiate fetch of index buffer and draw"
|
||||
// Generally used by Xbox 360 Direct3D 9 for kDMA and kAutoIndex sources.
|
||||
// With a viz query token as the first one.
|
||||
uint32_t count_remaining = count;
|
||||
assert_not_zero(count_remaining);
|
||||
if (!count_remaining) {
|
||||
XELOGE("PM4_DRAW_INDX: Packet too small, can't read the viz query token");
|
||||
return false;
|
||||
}
|
||||
uint32_t viz_query_condition = reader->ReadAndSwap<uint32_t>();
|
||||
--count_remaining;
|
||||
return ExecutePacketType3Draw(reader, packet, "PM4_DRAW_INDX",
|
||||
viz_query_condition, count_remaining);
|
||||
}
|
||||
|
||||
bool CommandProcessor::ExecutePacketType3_DRAW_INDX_2(RingBuffer* reader,
|
||||
uint32_t packet,
|
||||
uint32_t count) {
|
||||
// draw using supplied indices in packet
|
||||
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.
|
||||
// uint32_t indices_size =
|
||||
// vgt_draw_initiator.num_indices *
|
||||
// (vgt_draw_initiator.index_size == xenos::IndexFormat::kInt32 ? 4
|
||||
// : 2);
|
||||
// uint32_t index_ptr = reader->ptr();
|
||||
// TODO(Triang3l): VGT_IMMED_DATA.
|
||||
reader->AdvanceRead((count - 1) * sizeof(uint32_t));
|
||||
|
||||
auto viz_query = register_file_->Get<reg::PA_SC_VIZ_QUERY>();
|
||||
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.
|
||||
return true;
|
||||
}
|
||||
|
||||
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({}, {}): Failed in backend",
|
||||
vgt_draw_initiator.num_indices,
|
||||
uint32_t(vgt_draw_initiator.prim_type));
|
||||
}
|
||||
|
||||
return true;
|
||||
// "draw using supplied indices in packet"
|
||||
// Generally used by Xbox 360 Direct3D 9 for kAutoIndex source.
|
||||
// No viz query token.
|
||||
return ExecutePacketType3Draw(reader, packet, "PM4_DRAW_INDX_2", 0, count);
|
||||
}
|
||||
|
||||
bool CommandProcessor::ExecutePacketType3_SET_CONSTANT(RingBuffer* reader,
|
||||
|
||||
Reference in New Issue
Block a user