diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index 31f1196e4..e8be80d21 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -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) { diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index 987937f70..aa7d0f813 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -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 diff --git a/src/xenia/gpu/hlsl_shader_translator.cc b/src/xenia/gpu/hlsl_shader_translator.cc index 6cb1777b6..ab9653624 100644 --- a/src/xenia/gpu/hlsl_shader_translator.cc +++ b/src/xenia/gpu/hlsl_shader_translator.cc @@ -168,13 +168,14 @@ std::vector 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 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" diff --git a/src/xenia/gpu/hlsl_shader_translator.h b/src/xenia/gpu/hlsl_shader_translator.h index 14c004e5f..3488800ae 100644 --- a/src/xenia/gpu/hlsl_shader_translator.h +++ b/src/xenia/gpu/hlsl_shader_translator.h @@ -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 { diff --git a/src/xenia/ui/d3d12/pools.cc b/src/xenia/ui/d3d12/pools.cc index 394019083..a79b7542c 100644 --- a/src/xenia/ui/d3d12/pools.cc +++ b/src/xenia/ui/d3d12/pools.cc @@ -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;