[D3D12] Draw calls

This commit is contained in:
Triang3l
2018-07-31 19:23:43 +03:00
parent bb045cae70
commit 5d0ad2e465
5 changed files with 94 additions and 8 deletions

View File

@@ -481,6 +481,28 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
}
bool indexed = index_buffer_info != nullptr && index_buffer_info->guest_base;
if (indexed && regs[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32 & (1 << 21)) {
uint32_t reset_index = regs[XE_GPU_REG_VGT_MULTI_PRIM_IB_RESET_INDX].u32;
uint32_t reset_index_expected;
if (index_buffer_info->format == IndexFormat::kInt32) {
reset_index_expected = 0xFFFFFFFFu;
} else {
reset_index_expected = 0xFFFFu;
}
if (reset_index != reset_index_expected) {
// Only 0xFFFF and 0xFFFFFFFF primitive restart indices are supported by
// Direct3D 12 (endianness doesn't matter for them). However, Direct3D 9
// uses 0xFFFF as the reset index. With shared memory, it's impossible to
// replace the cut index in the buffer without affecting the game memory.
XELOGE(
"The game uses the primitive restart index 0x%X that isn't 0xFFFF or "
"0xFFFFFFFF. Report the game to Xenia developers so geometry shaders "
"will be added to handle this!",
reset_index);
assert_always();
return false;
}
}
// Shaders will have already been defined by previous loads.
// We need them to do just about anything so validate here.
@@ -502,6 +524,29 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
ID3D12GraphicsCommandList* command_list =
command_lists_[current_queue_frame_]->GetCommandList();
// Set the primitive topology.
D3D_PRIMITIVE_TOPOLOGY primitive_topology;
switch (primitive_type) {
case PrimitiveType::kLineList:
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
break;
case PrimitiveType::kLineStrip:
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
break;
case PrimitiveType::kTriangleList:
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
break;
case PrimitiveType::kTriangleStrip:
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
break;
default:
return false;
}
if (primitive_topology_ != primitive_topology) {
primitive_topology_ = primitive_topology;
command_list->IASetPrimitiveTopology(primitive_topology);
}
// Get the pipeline and translate the shaders so used textures are known.
ID3D12PipelineState* pipeline;
ID3D12RootSignature* root_signature;
@@ -532,13 +577,33 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
return false;
}
// Shared memory test.
// Ensure vertex and index buffers are resident and draw.
// TODO(Triang3l): Cache residency for ranges in a way similar to how texture
// validity will be tracked.
shared_memory_->UseForReading(command_list);
uint64_t vertex_buffers_resident[2] = {};
for (const auto& vertex_binding : vertex_shader->vertex_bindings()) {
uint32_t vfetch_index = vertex_binding.fetch_constant;
if (vertex_buffers_resident[vfetch_index >> 6] &
(1ull << (vfetch_index & 63))) {
continue;
}
uint32_t vfetch_constant_index =
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + vfetch_index * 2;
uint32_t vfetch_address = regs[vfetch_constant_index].u32 << 2;
shared_memory_->UseRange(regs[vfetch_constant_index].u32 << 2,
regs[vfetch_constant_index + 1].u32 & 0x3FFFFFC);
vertex_buffers_resident[vfetch_index >> 6] |= 1ull << (vfetch_index & 63);
}
if (indexed) {
uint32_t index_size = index_buffer_info->format == IndexFormat::kInt32
? sizeof(uint32_t)
: sizeof(uint16_t);
shared_memory_->UseRange(index_buffer_info->guest_base,
index_buffer_info->count * index_size);
command_list->DrawIndexedInstanced(index_count, 1, 0, 0, 0);
} else {
command_list->DrawInstanced(index_count, 1, 0, 0);
}
return true;
@@ -575,10 +640,15 @@ bool D3D12CommandProcessor::BeginFrame() {
cbuffer_bindings_fetch_.up_to_date = false;
draw_view_full_update_ = 0;
draw_sampler_full_update_ = 0;
primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
command_lists_setup_[current_queue_frame_]->BeginRecording();
command_lists_[current_queue_frame_]->BeginRecording();
constant_buffer_pool_->BeginFrame();
view_heap_pool_->BeginFrame();
sampler_heap_pool_->BeginFrame();
shared_memory_->BeginFrame();
return true;
@@ -602,6 +672,10 @@ bool D3D12CommandProcessor::EndFrame() {
}
command_list->Execute();
sampler_heap_pool_->EndFrame();
view_heap_pool_->EndFrame();
constant_buffer_pool_->EndFrame();
auto context = GetD3D12Context();
context->EndSwap();
current_queue_frame_ = UINT32_MAX;
@@ -756,6 +830,7 @@ void D3D12CommandProcessor::UpdateFixedFunctionState(
void D3D12CommandProcessor::UpdateSystemConstantValues(Endian index_endian) {
auto& regs = *register_file_;
uint32_t vgt_indx_offset = regs[XE_GPU_REG_VGT_INDX_OFFSET].u32;
uint32_t pa_cl_vte_cntl = regs[XE_GPU_REG_PA_CL_VTE_CNTL].u32;
uint32_t pa_cl_clip_cntl = regs[XE_GPU_REG_PA_CL_CLIP_CNTL].u32;
uint32_t pa_su_vtx_cntl = regs[XE_GPU_REG_PA_SU_VTX_CNTL].u32;
@@ -765,6 +840,10 @@ void D3D12CommandProcessor::UpdateSystemConstantValues(Endian index_endian) {
bool dirty = false;
// Vertex index offset.
dirty |= system_constants_.vertex_base_index != vgt_indx_offset;
system_constants_.vertex_base_index = vgt_indx_offset;
// Index buffer endianness.
dirty |= system_constants_.vertex_index_endian != uint32_t(index_endian);
system_constants_.vertex_index_endian = uint32_t(index_endian);
@@ -966,6 +1045,7 @@ bool D3D12CommandProcessor::UpdateBindings(
draw_view_full_update_, view_count_partial_update, view_count_full_update,
view_cpu_handle, view_gpu_handle);
if (view_full_update_index == 0) {
XELOGE("View full update index is 0!");
return false;
}
if (draw_view_full_update_ != view_full_update_index) {