[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) {

View File

@ -198,6 +198,9 @@ class D3D12CommandProcessor : public CommandProcessor {
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_pixel_float_constants_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_fetch_constants_;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle_shared_memory_;
// Current primitive topology.
D3D_PRIMITIVE_TOPOLOGY primitive_topology_;
};
} // namespace d3d12

View File

@ -168,13 +168,14 @@ std::vector<uint8_t> HlslShaderTranslator::CompleteTranslation() {
source.Append(
"cbuffer xe_system_constants : register(b0) {\n"
" float3 xe_mul_rcp_w;\n"
" uint xe_vertex_index_endian;\n"
" uint xe_vertex_base_index;\n"
" float3 xe_ndc_scale;\n"
" uint xe_textures_are_3d;\n"
" uint xe_vertex_index_endian;\n"
" float3 xe_ndc_offset;\n"
" float xe_pixel_half_pixel_offset;\n"
" float2 xe_ssaa_inv_scale;\n"
" uint xe_pixel_pos_reg;\n"
" uint xe_textures_are_3d;\n"
"};\n"
"\n"
"cbuffer xe_loop_bool_constants : register(b1) {\n"
@ -229,7 +230,8 @@ std::vector<uint8_t> HlslShaderTranslator::CompleteTranslation() {
"XeVertexShaderOutput main(uint xe_vertex_index_be : SV_VertexID) {\n"
" float4 xe_r[%u];\n"
" uint xe_vertex_index =\n"
" XeByteSwap(xe_vertex_index_be, xe_vertex_index_endian);\n"
" XeByteSwap(xe_vertex_index_be, xe_vertex_index_endian) +\n"
" xe_vertex_base_index;\n"
" uint4 xe_vertex_element;\n"
" xe_r[0].r = float(xe_vertex_index);\n"
" XeVertexShaderOutput xe_output;\n"

View File

@ -27,16 +27,17 @@ class HlslShaderTranslator : public ShaderTranslator {
struct SystemConstants {
// vec4 0
float mul_rcp_w[3];
uint32_t vertex_index_endian;
uint32_t vertex_base_index;
// vec4 1
float ndc_scale[3];
uint32_t textures_are_3d;
uint32_t vertex_index_endian;
// vec4 2
float ndc_offset[3];
float pixel_half_pixel_offset;
// vec4 3
float ssaa_inv_scale[2];
uint32_t pixel_pos_reg;
uint32_t textures_are_3d;
};
enum class SRVType : uint32_t {

View File

@ -88,7 +88,7 @@ uint8_t* UploadBufferPool::RequestFull(
if (current_gpu_address_ == 0) {
current_gpu_address_ = unsent_->buffer->GetGPUVirtualAddress();
}
*gpu_address_out = current_gpu_address_ = current_size_;
*gpu_address_out = current_gpu_address_ + current_size_;
}
uint8_t* mapping = current_mapping_ + current_size_;
current_size_ += size;
@ -118,7 +118,7 @@ uint8_t* UploadBufferPool::RequestPartial(
if (current_gpu_address_ == 0) {
current_gpu_address_ = unsent_->buffer->GetGPUVirtualAddress();
}
*gpu_address_out = current_gpu_address_ = current_size_;
*gpu_address_out = current_gpu_address_ + current_size_;
}
uint8_t* mapping = current_mapping_ + current_size_;
current_size_ += size;