From 538aa9101567a9d09fa21394e0b925856e957b2b Mon Sep 17 00:00:00 2001 From: Triang3l Date: Fri, 4 Jun 2021 23:56:25 +0300 Subject: [PATCH] [GPU] Primitive processor with Vulkan 1.0 base cases, 24-bit indices and clamping --- src/xenia/gpu/command_processor.cc | 171 +- src/xenia/gpu/command_processor.h | 4 + .../gpu/d3d12/d3d12_command_processor.cc | 397 ++--- src/xenia/gpu/d3d12/d3d12_command_processor.h | 6 +- .../gpu/d3d12/d3d12_primitive_processor.cc | 173 ++ .../gpu/d3d12/d3d12_primitive_processor.h | 90 + .../gpu/d3d12/d3d12_render_target_cache.h | 2 + src/xenia/gpu/d3d12/pipeline_cache.cc | 205 +-- src/xenia/gpu/d3d12/pipeline_cache.h | 20 +- src/xenia/gpu/d3d12/primitive_converter.cc | 762 --------- src/xenia/gpu/d3d12/primitive_converter.h | 189 --- .../d3d12/shaders/dxbc/continuous_quad_hs.cso | Bin 3520 -> 3608 bytes .../d3d12/shaders/dxbc/continuous_quad_hs.h | 453 ++--- .../d3d12/shaders/dxbc/continuous_quad_hs.txt | 42 +- .../shaders/dxbc/continuous_triangle_hs.cso | Bin 3376 -> 3464 bytes .../shaders/dxbc/continuous_triangle_hs.h | 431 ++--- .../shaders/dxbc/continuous_triangle_hs.txt | 42 +- .../d3d12/shaders/dxbc/discrete_quad_hs.cso | Bin 3520 -> 3608 bytes .../gpu/d3d12/shaders/dxbc/discrete_quad_hs.h | 453 ++--- .../d3d12/shaders/dxbc/discrete_quad_hs.txt | 42 +- .../shaders/dxbc/discrete_triangle_hs.cso | Bin 3376 -> 3464 bytes .../d3d12/shaders/dxbc/discrete_triangle_hs.h | 431 ++--- .../shaders/dxbc/discrete_triangle_hs.txt | 42 +- .../shaders/dxbc/primitive_point_list_gs.cso | Bin 7640 -> 7776 bytes .../shaders/dxbc/primitive_point_list_gs.h | 955 ++++++----- .../shaders/dxbc/primitive_point_list_gs.txt | 55 +- .../shaders/dxbc/primitive_quad_list_gs.cso | Bin 4944 -> 4308 bytes .../shaders/dxbc/primitive_quad_list_gs.h | 125 +- .../shaders/dxbc/primitive_quad_list_gs.txt | 28 +- .../shaders/dxbc/tessellation_adaptive_vs.cso | Bin 3476 -> 3564 bytes .../shaders/dxbc/tessellation_adaptive_vs.h | 449 ++--- .../shaders/dxbc/tessellation_adaptive_vs.txt | 42 +- .../shaders/dxbc/tessellation_indexed_vs.cso | Bin 3428 -> 3616 bytes .../shaders/dxbc/tessellation_indexed_vs.h | 458 ++--- .../shaders/dxbc/tessellation_indexed_vs.txt | 49 +- .../shaders/primitive_point_list.gs.hlsl | 2 +- .../d3d12/shaders/primitive_quad_list.gs.hlsl | 16 +- .../shaders/tessellation_adaptive.vs.hlsl | 4 +- .../shaders/tessellation_indexed.vs.hlsl | 9 +- src/xenia/gpu/d3d12/shaders/xenos_draw.hlsli | 24 +- src/xenia/gpu/draw_util.h | 44 + src/xenia/gpu/dxbc_shader_translator.cc | 85 +- src/xenia/gpu/dxbc_shader_translator.h | 161 +- src/xenia/gpu/dxbc_shader_translator_fetch.cc | 12 +- src/xenia/gpu/dxbc_shader_translator_om.cc | 84 +- src/xenia/gpu/primitive_processor.cc | 1512 +++++++++++++++++ src/xenia/gpu/primitive_processor.h | 869 ++++++++++ src/xenia/gpu/register_table.inc | 2 + src/xenia/gpu/registers.h | 73 + src/xenia/gpu/render_target_cache.h | 1 + src/xenia/gpu/shared_memory.h | 4 +- src/xenia/gpu/xenos.h | 38 +- 52 files changed, 5418 insertions(+), 3638 deletions(-) create mode 100644 src/xenia/gpu/d3d12/d3d12_primitive_processor.cc create mode 100644 src/xenia/gpu/d3d12/d3d12_primitive_processor.h delete mode 100644 src/xenia/gpu/d3d12/primitive_converter.cc delete mode 100644 src/xenia/gpu/d3d12/primitive_converter.h create mode 100644 src/xenia/gpu/primitive_processor.cc create mode 100644 src/xenia/gpu/primitive_processor.h diff --git a/src/xenia/gpu/command_processor.cc b/src/xenia/gpu/command_processor.cc index 77c25e0be..28e5a9c1f 100644 --- a/src/xenia/gpu/command_processor.cc +++ b/src/xenia/gpu/command_processor.cc @@ -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(); // 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(); + --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 index_size = reader->ReadAndSwap(); - index_buffer_info.endianness = - static_cast(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(); + --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(); + --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(); - 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(); + 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(); + --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(); - 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(); - 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, diff --git a/src/xenia/gpu/command_processor.h b/src/xenia/gpu/command_processor.h index 918b274cf..8199febcf 100644 --- a/src/xenia/gpu/command_processor.h +++ b/src/xenia/gpu/command_processor.h @@ -218,6 +218,10 @@ class CommandProcessor { uint32_t count); bool ExecutePacketType3_EVENT_WRITE_ZPD(RingBuffer* reader, uint32_t packet, uint32_t count); + bool ExecutePacketType3Draw(RingBuffer* reader, uint32_t packet, + const char* opcode_name, + uint32_t viz_query_condition, + uint32_t count_remaining); bool ExecutePacketType3_DRAW_INDX(RingBuffer* reader, uint32_t packet, uint32_t count); bool ExecutePacketType3_DRAW_INDX_2(RingBuffer* reader, uint32_t packet, diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index 56bf3322c..4c7038146 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -81,7 +81,7 @@ void D3D12CommandProcessor::RequestFrameTrace( void D3D12CommandProcessor::TracePlaybackWroteMemory(uint32_t base_ptr, uint32_t length) { shared_memory_->MemoryInvalidationCallback(base_ptr, length, true); - primitive_converter_->MemoryInvalidationCallback(base_ptr, length, true); + primitive_processor_->MemoryInvalidationCallback(base_ptr, length, true); } void D3D12CommandProcessor::RestoreEdramSnapshot(const void* snapshot) { @@ -1194,6 +1194,13 @@ bool D3D12CommandProcessor::SetupContext() { return false; } + primitive_processor_ = std::make_unique( + *register_file_, *memory_, trace_writer_, *shared_memory_, *this); + if (!primitive_processor_->Initialize()) { + XELOGE("Failed to initialize the geometric primitive processor"); + return false; + } + texture_cache_ = std::make_unique( *this, *register_file_, *shared_memory_, bindless_resources_used_, render_target_cache_->GetResolutionScale()); @@ -1210,13 +1217,6 @@ bool D3D12CommandProcessor::SetupContext() { return false; } - primitive_converter_ = std::make_unique( - *this, *register_file_, *memory_, trace_writer_); - if (!primitive_converter_->Initialize()) { - XELOGE("Failed to initialize the geometric primitive converter"); - return false; - } - D3D12_HEAP_FLAGS heap_flag_create_not_zeroed = provider.GetHeapFlagCreateNotZeroed(); @@ -1529,12 +1529,12 @@ void D3D12CommandProcessor::ShutdownContext() { ui::d3d12::util::ReleaseAndNull(gamma_ramp_upload_); ui::d3d12::util::ReleaseAndNull(gamma_ramp_texture_); - primitive_converter_.reset(); - pipeline_cache_.reset(); texture_cache_.reset(); + primitive_processor_.reset(); + shared_memory_.reset(); // Shut down binding - bindless descriptors may be owned by subsystems like @@ -1842,7 +1842,7 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, return true; } - // Vertex shader. + // Vertex shader analysis. auto vertex_shader = static_cast(active_vertex_shader()); if (!vertex_shader) { // Always need a vertex shader. @@ -1850,16 +1850,9 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, } pipeline_cache_->AnalyzeShaderUcode(*vertex_shader); bool memexport_used_vertex = vertex_shader->is_valid_memexport_used(); - DxbcShaderTranslator::Modification vertex_shader_modification; - pipeline_cache_->GetCurrentShaderModification(*vertex_shader, - vertex_shader_modification); - bool tessellated = - vertex_shader_modification.vertex.host_vertex_shader_type != - Shader::HostVertexShaderType::kVertex; - bool primitive_polygonal = - xenos::IsPrimitivePolygonal(tessellated, primitive_type); - // Pixel shader. + // Pixel shader analysis. + bool primitive_polygonal = draw_util::IsPrimitivePolygonal(regs); bool is_rasterization_done = draw_util::IsRasterizationPotentiallyDone(regs, primitive_polygonal); D3D12Shader* pixel_shader = nullptr; @@ -1884,23 +1877,31 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, return true; } } - bool memexport_used_pixel; - DxbcShaderTranslator::Modification pixel_shader_modification; - if (pixel_shader) { - memexport_used_pixel = pixel_shader->is_valid_memexport_used(); - if (!pipeline_cache_->GetCurrentShaderModification( - *pixel_shader, pixel_shader_modification)) { - return false; - } - } else { - memexport_used_pixel = false; - pixel_shader_modification = DxbcShaderTranslator::Modification(0); - } - + bool memexport_used_pixel = + pixel_shader && pixel_shader->is_valid_memexport_used(); bool memexport_used = memexport_used_vertex || memexport_used_pixel; BeginSubmission(true); + // Process primitives. + PrimitiveProcessor::ProcessingResult primitive_processing_result; + if (!primitive_processor_->Process(primitive_processing_result)) { + return false; + } + if (!primitive_processing_result.host_draw_vertex_count) { + // Nothing to draw. + return true; + } + + // Shader modifications. + DxbcShaderTranslator::Modification vertex_shader_modification = + pipeline_cache_->GetCurrentVertexShaderModification( + *vertex_shader, primitive_processing_result.host_vertex_shader_type); + DxbcShaderTranslator::Modification pixel_shader_modification = + pixel_shader + ? pipeline_cache_->GetCurrentPixelShaderModification(*pixel_shader) + : DxbcShaderTranslator::Modification(0); + // Set up the render targets - this may perform dispatches and draws. uint32_t pixel_shader_writes_color_targets = pixel_shader ? pixel_shader->writes_color_targets() : 0; @@ -1909,66 +1910,6 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, return false; } - // Set up primitive topology. - bool indexed = index_buffer_info != nullptr && index_buffer_info->guest_base; - xenos::PrimitiveType primitive_type_converted; - D3D_PRIMITIVE_TOPOLOGY primitive_topology; - if (tessellated) { - primitive_type_converted = primitive_type; - switch (primitive_type_converted) { - // TODO(Triang3l): Support all kinds of patches if found in games. - case xenos::PrimitiveType::kTriangleList: - case xenos::PrimitiveType::kTrianglePatch: - primitive_topology = D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; - break; - case xenos::PrimitiveType::kQuadList: - case xenos::PrimitiveType::kQuadPatch: - primitive_topology = D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; - break; - default: - return false; - } - } else { - primitive_type_converted = - PrimitiveConverter::GetReplacementPrimitiveType(primitive_type); - switch (primitive_type_converted) { - case xenos::PrimitiveType::kPointList: - primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; - break; - case xenos::PrimitiveType::kLineList: - primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; - break; - case xenos::PrimitiveType::kLineStrip: - primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; - break; - case xenos::PrimitiveType::kTriangleList: - case xenos::PrimitiveType::kRectangleList: - primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - break; - case xenos::PrimitiveType::kTriangleStrip: - primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; - break; - case xenos::PrimitiveType::kQuadList: - primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; - break; - default: - return false; - } - } - SetPrimitiveTopology(primitive_topology); - uint32_t line_loop_closing_index; - if (primitive_type == xenos::PrimitiveType::kLineLoop && !indexed && - index_count >= 3) { - // Add a vertex to close the loop, and make the vertex shader replace its - // index (before adding the offset) with 0 to fetch the first vertex again. - // For indexed line loops, the primitive converter will add the vertex. - line_loop_closing_index = index_count; - ++index_count; - } else { - // Replace index 0 with 0 (do nothing) otherwise. - line_loop_closing_index = 0; - } - // Translate the shaders and create the pipeline if needed. D3D12Shader::D3D12Translation* vertex_shader_translation = static_cast( @@ -1995,9 +1936,7 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, ID3D12RootSignature* root_signature; if (!pipeline_cache_->ConfigurePipeline( vertex_shader_translation, pixel_shader_translation, - primitive_type_converted, - indexed ? index_buffer_info->format : xenos::IndexFormat::kInt16, - bound_depth_and_color_render_target_bits, + primitive_processing_result, bound_depth_and_color_render_target_bits, bound_depth_and_color_render_target_formats, &pipeline_handle, &root_signature)) { return false; @@ -2048,9 +1987,10 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, // Update system constants before uploading them. // TODO(Triang3l): With ROV, pass the disabled render target mask for safety. UpdateSystemConstantValues( - memexport_used, primitive_polygonal, line_loop_closing_index, - indexed ? index_buffer_info->endianness : xenos::Endian::kNone, - viewport_info, used_texture_mask, + memexport_used, primitive_polygonal, + primitive_processing_result.line_loop_closing_index, + primitive_processing_result.host_index_endian, viewport_info, + used_texture_mask, pixel_shader ? GetCurrentColorMask(pixel_shader->writes_color_targets()) : 0); @@ -2206,112 +2146,139 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, } } - // Actually draw. - if (indexed) { - uint32_t index_size = - index_buffer_info->format == xenos::IndexFormat::kInt32 - ? sizeof(uint32_t) - : sizeof(uint16_t); - assert_false(index_buffer_info->guest_base & (index_size - 1)); - uint32_t index_base = - index_buffer_info->guest_base & 0x1FFFFFFF & ~(index_size - 1); - D3D12_INDEX_BUFFER_VIEW index_buffer_view; - index_buffer_view.Format = - index_buffer_info->format == xenos::IndexFormat::kInt32 - ? DXGI_FORMAT_R32_UINT - : DXGI_FORMAT_R16_UINT; - PrimitiveConverter::ConversionResult conversion_result; - uint32_t converted_index_count; - if (tessellated) { - conversion_result = - PrimitiveConverter::ConversionResult::kConversionNotNeeded; - } else { - conversion_result = primitive_converter_->ConvertPrimitives( - primitive_type, index_buffer_info->guest_base, index_count, - index_buffer_info->format, index_buffer_info->endianness, - index_buffer_view.BufferLocation, converted_index_count); - if (conversion_result == PrimitiveConverter::ConversionResult::kFailed) { - return false; - } - if (conversion_result == - PrimitiveConverter::ConversionResult::kPrimitiveEmpty) { - return true; - } - } - ID3D12Resource* scratch_index_buffer = nullptr; - if (conversion_result == PrimitiveConverter::ConversionResult::kConverted) { - index_buffer_view.SizeInBytes = converted_index_count * index_size; - index_count = converted_index_count; - } else { - uint32_t index_buffer_size = index_buffer_info->count * index_size; - if (!shared_memory_->RequestRange(index_base, index_buffer_size)) { + // Primitive topology. + D3D_PRIMITIVE_TOPOLOGY primitive_topology; + if (primitive_processing_result.IsTessellated()) { + switch (primitive_processing_result.host_primitive_type) { + // TODO(Triang3l): Support all primitive types. + case xenos::PrimitiveType::kTriangleList: + case xenos::PrimitiveType::kTrianglePatch: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; + break; + case xenos::PrimitiveType::kQuadList: + case xenos::PrimitiveType::kQuadPatch: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; + break; + default: XELOGE( - "Failed to request index buffer at 0x{:08X} (size {}) in the " - "shared memory", - index_base, index_buffer_size); + "Host tessellated primitive type {} returned by the primitive " + "processor is not supported by the Direct3D 12 command processor", + uint32_t(primitive_processing_result.host_primitive_type)); + assert_unhandled_case(primitive_processing_result.host_primitive_type); return false; - } - if (memexport_used) { - // If the shared memory is a UAV, it can't be used as an index buffer - // (UAV is a read/write state, index buffer is a read-only state). Need - // to copy the indices to a buffer in the index buffer state. - scratch_index_buffer = RequestScratchGPUBuffer( - index_buffer_size, D3D12_RESOURCE_STATE_COPY_DEST); - if (scratch_index_buffer == nullptr) { - return false; - } - shared_memory_->UseAsCopySource(); - SubmitBarriers(); - deferred_command_list_.D3DCopyBufferRegion( - scratch_index_buffer, 0, shared_memory_->GetBuffer(), index_base, - index_buffer_size); - PushTransitionBarrier(scratch_index_buffer, - D3D12_RESOURCE_STATE_COPY_DEST, - D3D12_RESOURCE_STATE_INDEX_BUFFER); - index_buffer_view.BufferLocation = - scratch_index_buffer->GetGPUVirtualAddress(); - } else { - index_buffer_view.BufferLocation = - shared_memory_->GetGPUAddress() + index_base; - } - index_buffer_view.SizeInBytes = index_buffer_size; } + } else { + switch (primitive_processing_result.host_primitive_type) { + case xenos::PrimitiveType::kPointList: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; + break; + case xenos::PrimitiveType::kLineList: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; + break; + case xenos::PrimitiveType::kLineStrip: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; + break; + case xenos::PrimitiveType::kTriangleList: + case xenos::PrimitiveType::kRectangleList: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + break; + case xenos::PrimitiveType::kTriangleStrip: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + break; + case xenos::PrimitiveType::kQuadList: + primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; + break; + default: + XELOGE( + "Host primitive type {} returned by the primitive processor is not " + "supported by the Direct3D 12 command processor", + uint32_t(primitive_processing_result.host_primitive_type)); + assert_unhandled_case(primitive_processing_result.host_primitive_type); + return false; + } + } + SetPrimitiveTopology(primitive_topology); + // Must not call anything that may change the primitive topology from now on! + + // Draw. + if (primitive_processing_result.index_buffer_type == + PrimitiveProcessor::ProcessedIndexBufferType::kNone) { if (memexport_used) { shared_memory_->UseForWriting(); } else { shared_memory_->UseForReading(); } SubmitBarriers(); + deferred_command_list_.D3DDrawInstanced( + primitive_processing_result.host_draw_vertex_count, 1, 0, 0); + } else { + D3D12_INDEX_BUFFER_VIEW index_buffer_view; + index_buffer_view.SizeInBytes = + primitive_processing_result.host_draw_vertex_count; + if (primitive_processing_result.host_index_format == + xenos::IndexFormat::kInt16) { + index_buffer_view.SizeInBytes *= sizeof(uint16_t); + index_buffer_view.Format = DXGI_FORMAT_R16_UINT; + } else { + index_buffer_view.SizeInBytes *= sizeof(uint32_t); + index_buffer_view.Format = DXGI_FORMAT_R32_UINT; + } + ID3D12Resource* scratch_index_buffer = nullptr; + switch (primitive_processing_result.index_buffer_type) { + case PrimitiveProcessor::ProcessedIndexBufferType::kGuest: { + if (memexport_used) { + // If the shared memory is a UAV, it can't be used as an index buffer + // (UAV is a read/write state, index buffer is a read-only state). + // Need to copy the indices to a buffer in the index buffer state. + scratch_index_buffer = RequestScratchGPUBuffer( + index_buffer_view.SizeInBytes, D3D12_RESOURCE_STATE_COPY_DEST); + if (scratch_index_buffer == nullptr) { + return false; + } + shared_memory_->UseAsCopySource(); + SubmitBarriers(); + deferred_command_list_.D3DCopyBufferRegion( + scratch_index_buffer, 0, shared_memory_->GetBuffer(), + primitive_processing_result.guest_index_base, + index_buffer_view.SizeInBytes); + PushTransitionBarrier(scratch_index_buffer, + D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_INDEX_BUFFER); + index_buffer_view.BufferLocation = + scratch_index_buffer->GetGPUVirtualAddress(); + } else { + index_buffer_view.BufferLocation = + shared_memory_->GetGPUAddress() + + primitive_processing_result.guest_index_base; + } + } break; + case PrimitiveProcessor::ProcessedIndexBufferType::kHostConverted: + index_buffer_view.BufferLocation = + primitive_processor_->GetConvertedIndexBufferGpuAddress( + primitive_processing_result.host_index_buffer_handle); + break; + case PrimitiveProcessor::ProcessedIndexBufferType::kHostBuiltin: + index_buffer_view.BufferLocation = + primitive_processor_->GetBuiltinIndexBufferGpuAddress( + primitive_processing_result.host_index_buffer_handle); + break; + default: + assert_unhandled_case(primitive_processing_result.index_buffer_type); + return false; + } deferred_command_list_.D3DIASetIndexBuffer(&index_buffer_view); - deferred_command_list_.D3DDrawIndexedInstanced(index_count, 1, 0, 0, 0); + if (memexport_used) { + shared_memory_->UseForWriting(); + } else { + shared_memory_->UseForReading(); + } + SubmitBarriers(); + deferred_command_list_.D3DDrawIndexedInstanced( + primitive_processing_result.host_draw_vertex_count, 1, 0, 0, 0); if (scratch_index_buffer != nullptr) { ReleaseScratchGPUBuffer(scratch_index_buffer, D3D12_RESOURCE_STATE_INDEX_BUFFER); } - } else { - // Check if need to draw using a conversion index buffer. - uint32_t converted_index_count = 0; - D3D12_GPU_VIRTUAL_ADDRESS conversion_gpu_address = - tessellated ? 0 - : primitive_converter_->GetStaticIndexBuffer( - primitive_type, index_count, converted_index_count); - if (memexport_used) { - shared_memory_->UseForWriting(); - } else { - shared_memory_->UseForReading(); - } - SubmitBarriers(); - if (conversion_gpu_address) { - D3D12_INDEX_BUFFER_VIEW index_buffer_view; - index_buffer_view.BufferLocation = conversion_gpu_address; - index_buffer_view.SizeInBytes = converted_index_count * sizeof(uint16_t); - index_buffer_view.Format = DXGI_FORMAT_R16_UINT; - deferred_command_list_.D3DIASetIndexBuffer(&index_buffer_view); - deferred_command_list_.D3DDrawIndexedInstanced(converted_index_count, 1, - 0, 0, 0); - } else { - deferred_command_list_.D3DDrawInstanced(index_count, 1, 0, 0); - } } if (memexport_used) { @@ -2526,9 +2493,9 @@ void D3D12CommandProcessor::CheckSubmissionFence(uint64_t await_submission) { shared_memory_->CompletedSubmissionUpdated(); - render_target_cache_->CompletedSubmissionUpdated(); + primitive_processor_->CompletedSubmissionUpdated(); - primitive_converter_->CompletedSubmissionUpdated(); + render_target_cache_->CompletedSubmissionUpdated(); } void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) { @@ -2593,11 +2560,11 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) { } primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + primitive_processor_->BeginSubmission(); + render_target_cache_->BeginSubmission(); texture_cache_->BeginSubmission(); - - primitive_converter_->BeginSubmission(); } if (is_opening_frame) { @@ -2645,9 +2612,9 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) { } } - texture_cache_->BeginFrame(); + primitive_processor_->BeginFrame(); - primitive_converter_->BeginFrame(); + texture_cache_->BeginFrame(); } } @@ -2676,6 +2643,8 @@ bool D3D12CommandProcessor::EndSubmission(bool is_swap) { if (is_closing_frame) { texture_cache_->EndFrame(); + + primitive_processor_->EndFrame(); } if (submission_open_) { @@ -2762,8 +2731,6 @@ bool D3D12CommandProcessor::EndSubmission(bool is_swap) { } constant_buffer_pool_->ClearCache(); - primitive_converter_->ClearCache(); - pipeline_cache_->ClearCache(); render_target_cache_->ClearCache(); @@ -2775,6 +2742,8 @@ bool D3D12CommandProcessor::EndSubmission(bool is_swap) { } root_signatures_bindful_.clear(); + primitive_processor_->ClearCache(); + shared_memory_->ClearCache(); } } @@ -2897,7 +2866,9 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( auto rb_surface_info = regs.Get(); auto sq_context_misc = regs.Get(); auto sq_program_cntl = regs.Get(); - int32_t vgt_indx_offset = int32_t(regs[XE_GPU_REG_VGT_INDX_OFFSET].u32); + uint32_t vgt_indx_offset = regs.Get().indx_offset; + uint32_t vgt_max_vtx_indx = regs.Get().max_indx; + uint32_t vgt_min_vtx_indx = regs.Get().min_indx; bool edram_rov_used = render_target_cache_->GetPath() == RenderTargetCache::Path::kPixelShaderInterlock; @@ -3050,8 +3021,14 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( system_constants_.vertex_index_endian = index_endian; // Vertex index offset. - dirty |= system_constants_.vertex_base_index != vgt_indx_offset; - system_constants_.vertex_base_index = vgt_indx_offset; + dirty |= system_constants_.vertex_index_offset != vgt_indx_offset; + system_constants_.vertex_index_offset = vgt_indx_offset; + + // Vertex index range. + dirty |= system_constants_.vertex_index_min != vgt_min_vtx_indx; + dirty |= system_constants_.vertex_index_max != vgt_max_vtx_indx; + system_constants_.vertex_index_min = vgt_min_vtx_indx; + system_constants_.vertex_index_max = vgt_max_vtx_indx; // User clip planes (UCP_ENA_#), when not CLIP_DISABLE. if (!pa_cl_clip_cntl.clip_disable) { @@ -3082,14 +3059,14 @@ void D3D12CommandProcessor::UpdateSystemConstantValues( float point_size_y = float(pa_su_point_size.height) * 0.125f; float point_size_min = float(pa_su_point_minmax.min_size) * 0.125f; float point_size_max = float(pa_su_point_minmax.max_size) * 0.125f; - dirty |= system_constants_.point_size[0] != point_size_x; - dirty |= system_constants_.point_size[1] != point_size_y; - dirty |= system_constants_.point_size_min_max[0] != point_size_min; - dirty |= system_constants_.point_size_min_max[1] != point_size_max; - system_constants_.point_size[0] = point_size_x; - system_constants_.point_size[1] = point_size_y; - system_constants_.point_size_min_max[0] = point_size_min; - system_constants_.point_size_min_max[1] = point_size_max; + dirty |= system_constants_.point_size_x != point_size_x; + dirty |= system_constants_.point_size_y != point_size_y; + dirty |= system_constants_.point_size_min != point_size_min; + dirty |= system_constants_.point_size_max != point_size_max; + system_constants_.point_size_x = point_size_x; + system_constants_.point_size_y = point_size_y; + system_constants_.point_size_min = point_size_min; + system_constants_.point_size_max = point_size_max; float point_screen_to_ndc_x = (/* 0.5f * 2.0f * */ float(resolution_scale)) / std::max(viewport_info.xy_extent[0], uint32_t(1)); diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index 0d90080d0..018c568d0 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -20,11 +20,11 @@ #include "xenia/base/assert.h" #include "xenia/gpu/command_processor.h" #include "xenia/gpu/d3d12/d3d12_graphics_system.h" +#include "xenia/gpu/d3d12/d3d12_primitive_processor.h" #include "xenia/gpu/d3d12/d3d12_render_target_cache.h" #include "xenia/gpu/d3d12/d3d12_shared_memory.h" #include "xenia/gpu/d3d12/deferred_command_list.h" #include "xenia/gpu/d3d12/pipeline_cache.h" -#include "xenia/gpu/d3d12/primitive_converter.h" #include "xenia/gpu/d3d12/texture_cache.h" #include "xenia/gpu/draw_util.h" #include "xenia/gpu/dxbc_shader.h" @@ -490,12 +490,12 @@ class D3D12CommandProcessor : public CommandProcessor { std::unique_ptr shared_memory_; + std::unique_ptr primitive_processor_; + std::unique_ptr pipeline_cache_; std::unique_ptr texture_cache_; - std::unique_ptr primitive_converter_; - // Mip 0 contains the normal gamma ramp (256 entries), mip 1 contains the PWL // ramp (128 entries). DXGI_FORMAT_R10G10B10A2_UNORM 1D. ID3D12Resource* gamma_ramp_texture_ = nullptr; diff --git a/src/xenia/gpu/d3d12/d3d12_primitive_processor.cc b/src/xenia/gpu/d3d12/d3d12_primitive_processor.cc new file mode 100644 index 000000000..1c008e048 --- /dev/null +++ b/src/xenia/gpu/d3d12/d3d12_primitive_processor.cc @@ -0,0 +1,173 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2021 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/gpu/d3d12/d3d12_primitive_processor.h" + +#include +#include +#include +#include + +#include "xenia/base/assert.h" +#include "xenia/base/logging.h" +#include "xenia/gpu/d3d12/d3d12_command_processor.h" +#include "xenia/gpu/d3d12/deferred_command_list.h" +#include "xenia/ui/d3d12/d3d12_provider.h" +#include "xenia/ui/d3d12/d3d12_util.h" + +namespace xe { +namespace gpu { +namespace d3d12 { + +D3D12PrimitiveProcessor::~D3D12PrimitiveProcessor() { Shutdown(true); } + +bool D3D12PrimitiveProcessor::Initialize() { + if (!InitializeCommon(true, false, false, true)) { + Shutdown(); + return false; + } + frame_index_buffer_pool_ = std::make_unique( + command_processor_.GetD3D12Context().GetD3D12Provider(), + std::max(size_t(kMinRequiredConvertedIndexBufferSize), + ui::GraphicsUploadBufferPool::kDefaultPageSize)); + return true; +} + +void D3D12PrimitiveProcessor::Shutdown(bool from_destructor) { + frame_index_buffer_pool_.reset(); + builtin_index_buffer_upload_.Reset(); + builtin_index_buffer_gpu_address_ = 0; + builtin_index_buffer_.Reset(); + if (!from_destructor) { + ShutdownCommon(); + } +} + +void D3D12PrimitiveProcessor::CompletedSubmissionUpdated() { + if (builtin_index_buffer_upload_ && + command_processor_.GetCompletedSubmission() >= + builtin_index_buffer_upload_submission_) { + builtin_index_buffer_upload_.Reset(); + } +} + +void D3D12PrimitiveProcessor::BeginSubmission() { + if (builtin_index_buffer_upload_ && + builtin_index_buffer_upload_submission_ == UINT64_MAX) { + // No need to submit deferred barriers - builtin_index_buffer_ has never + // been used yet, so it's in the initial state, and + // builtin_index_buffer_upload_ is in an upload heap, so it's GENERIC_READ. + command_processor_.GetDeferredCommandList().D3DCopyResource( + builtin_index_buffer_.Get(), builtin_index_buffer_upload_.Get()); + command_processor_.PushTransitionBarrier(builtin_index_buffer_.Get(), + D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_INDEX_BUFFER); + builtin_index_buffer_upload_submission_ = + command_processor_.GetCurrentSubmission(); + } +} + +void D3D12PrimitiveProcessor::BeginFrame() { + frame_index_buffer_pool_->Reclaim(command_processor_.GetCompletedFrame()); +} + +void D3D12PrimitiveProcessor::EndFrame() { + ClearPerFrameCache(); + frame_index_buffers_.clear(); +} + +bool D3D12PrimitiveProcessor::InitializeBuiltin16BitIndexBuffer( + uint32_t index_count, std::function fill_callback) { + assert_not_zero(index_count); + assert_null(builtin_index_buffer_); + assert_null(builtin_index_buffer_upload_); + + const ui::d3d12::D3D12Provider& provider = + command_processor_.GetD3D12Context().GetD3D12Provider(); + ID3D12Device* device = provider.GetDevice(); + + D3D12_RESOURCE_DESC resource_desc; + ui::d3d12::util::FillBufferResourceDesc( + resource_desc, UINT64(sizeof(uint16_t) * index_count), + D3D12_RESOURCE_FLAG_NONE); + Microsoft::WRL::ComPtr draw_resource; + if (FAILED(device->CreateCommittedResource( + &ui::d3d12::util::kHeapPropertiesDefault, + provider.GetHeapFlagCreateNotZeroed(), &resource_desc, + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&draw_resource)))) { + XELOGE( + "D3D12 primitive processor: Failed to create the built-in index " + "buffer GPU resource with {} 16-bit indices", + index_count); + return false; + } + Microsoft::WRL::ComPtr upload_resource; + if (FAILED(device->CreateCommittedResource( + &ui::d3d12::util::kHeapPropertiesUpload, + provider.GetHeapFlagCreateNotZeroed(), &resource_desc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + IID_PPV_ARGS(&upload_resource)))) { + XELOGE( + "D3D12 primitive processor: Failed to create the built-in index " + "buffer upload resource with {} 16-bit indices", + index_count); + return false; + } + + D3D12_RANGE upload_read_range = {}; + void* mapping; + if (FAILED(upload_resource->Map(0, &upload_read_range, &mapping))) { + XELOGE( + "D3D12 primitive processor: Failed to map the built-in index buffer " + "upload resource with {} 16-bit indices", + index_count); + return false; + } + fill_callback(reinterpret_cast(mapping)); + upload_resource->Unmap(0, nullptr); + + // Successfully created the buffer and wrote the data to upload. + builtin_index_buffer_ = std::move(draw_resource); + builtin_index_buffer_gpu_address_ = + builtin_index_buffer_->GetGPUVirtualAddress(); + builtin_index_buffer_upload_ = std::move(upload_resource); + // Schedule uploading in the first submission. + builtin_index_buffer_upload_submission_ = UINT64_MAX; + return true; +} + +void* D3D12PrimitiveProcessor::RequestHostConvertedIndexBufferForCurrentFrame( + xenos::IndexFormat format, uint32_t index_count, bool coalign_for_simd, + uint32_t coalignment_original_address, size_t& backend_handle_out) { + size_t index_size = format == xenos::IndexFormat::kInt16 ? sizeof(uint16_t) + : sizeof(uint32_t); + D3D12_GPU_VIRTUAL_ADDRESS gpu_address; + uint8_t* mapping = frame_index_buffer_pool_->Request( + command_processor_.GetCurrentFrame(), + index_size * index_count + + (coalign_for_simd ? XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE : 0), + index_size, nullptr, nullptr, &gpu_address); + if (!mapping) { + return false; + } + if (coalign_for_simd) { + ptrdiff_t coalignment_offset = + GetSimdCoalignmentOffset(mapping, coalignment_original_address); + mapping += coalignment_offset; + gpu_address = D3D12_GPU_VIRTUAL_ADDRESS(gpu_address + coalignment_offset); + } + backend_handle_out = frame_index_buffers_.size(); + frame_index_buffers_.push_back(gpu_address); + return mapping; +} + +} // namespace d3d12 +} // namespace gpu +} // namespace xe diff --git a/src/xenia/gpu/d3d12/d3d12_primitive_processor.h b/src/xenia/gpu/d3d12/d3d12_primitive_processor.h new file mode 100644 index 000000000..81e1812a6 --- /dev/null +++ b/src/xenia/gpu/d3d12/d3d12_primitive_processor.h @@ -0,0 +1,90 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2021 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_GPU_D3D12_D3D12_PRIMITIVE_PROCESSOR_H_ +#define XENIA_GPU_D3D12_D3D12_PRIMITIVE_PROCESSOR_H_ + +#include +#include +#include + +#include "xenia/base/assert.h" +#include "xenia/gpu/primitive_processor.h" +#include "xenia/ui/d3d12/d3d12_api.h" +#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h" + +namespace xe { +namespace gpu { +namespace d3d12 { + +class D3D12CommandProcessor; + +class D3D12PrimitiveProcessor final : public PrimitiveProcessor { + public: + D3D12PrimitiveProcessor(const RegisterFile& register_file, Memory& memory, + TraceWriter& trace_writer, + SharedMemory& shared_memory, + D3D12CommandProcessor& command_processor) + : PrimitiveProcessor(register_file, memory, trace_writer, shared_memory), + command_processor_(command_processor) {} + ~D3D12PrimitiveProcessor(); + + bool Initialize(); + void Shutdown(bool from_destructor = false); + void ClearCache() { frame_index_buffer_pool_->ClearCache(); } + + void CompletedSubmissionUpdated(); + void BeginSubmission(); + void BeginFrame(); + void EndFrame(); + + D3D12_GPU_VIRTUAL_ADDRESS GetBuiltinIndexBufferGpuAddress( + size_t handle) const { + assert_not_null(builtin_index_buffer_); + return D3D12_GPU_VIRTUAL_ADDRESS(builtin_index_buffer_gpu_address_ + + GetBuiltinIndexBufferOffsetBytes(handle)); + } + D3D12_GPU_VIRTUAL_ADDRESS GetConvertedIndexBufferGpuAddress( + size_t handle) const { + return frame_index_buffers_[handle]; + } + + protected: + bool InitializeBuiltin16BitIndexBuffer( + uint32_t index_count, + std::function fill_callback) override; + + void* RequestHostConvertedIndexBufferForCurrentFrame( + xenos::IndexFormat format, uint32_t index_count, bool coalign_for_simd, + uint32_t coalignment_original_address, + size_t& backend_handle_out) override; + + private: + D3D12CommandProcessor& command_processor_; + + Microsoft::WRL::ComPtr builtin_index_buffer_; + D3D12_GPU_VIRTUAL_ADDRESS builtin_index_buffer_gpu_address_ = 0; + // Temporary buffer copied in the beginning of the first submission for + // uploading to builtin_index_buffer_, destroyed when the submission when it + // was uploaded is completed. + Microsoft::WRL::ComPtr builtin_index_buffer_upload_; + // UINT64_MAX means not uploaded yet and needs uploading in the first + // submission (if the upload buffer exists at all). + uint64_t builtin_index_buffer_upload_submission_ = UINT64_MAX; + + std::unique_ptr frame_index_buffer_pool_; + // Indexed by the backend handles. + std::deque frame_index_buffers_; +}; + +} // namespace d3d12 +} // namespace gpu +} // namespace xe + +#endif // XENIA_GPU_D3D12_D3D12_PRIMITIVE_PROCESSOR_H_ diff --git a/src/xenia/gpu/d3d12/d3d12_render_target_cache.h b/src/xenia/gpu/d3d12/d3d12_render_target_cache.h index 1f552e8fe..11b5c493a 100644 --- a/src/xenia/gpu/d3d12/d3d12_render_target_cache.h +++ b/src/xenia/gpu/d3d12/d3d12_render_target_cache.h @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include diff --git a/src/xenia/gpu/d3d12/pipeline_cache.cc b/src/xenia/gpu/d3d12/pipeline_cache.cc index 6f8f260e3..6c6567642 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.cc +++ b/src/xenia/gpu/d3d12/pipeline_cache.cc @@ -864,146 +864,66 @@ D3D12Shader* PipelineCache::LoadShader(xenos::ShaderType shader_type, return shader; } -bool PipelineCache::GetCurrentShaderModification( +DxbcShaderTranslator::Modification +PipelineCache::GetCurrentVertexShaderModification( const Shader& shader, - DxbcShaderTranslator::Modification& modification_out) const { + Shader::HostVertexShaderType host_vertex_shader_type) const { + assert_true(shader.type() == xenos::ShaderType::kVertex); assert_true(shader.is_ucode_analyzed()); const auto& regs = register_file_; auto sq_program_cntl = regs.Get(); - if (shader.type() == xenos::ShaderType::kVertex) { - Shader::HostVertexShaderType host_vertex_shader_type = - GetCurrentHostVertexShaderTypeIfValid(); - if (host_vertex_shader_type == Shader::HostVertexShaderType(-1)) { - return false; - } - modification_out = DxbcShaderTranslator::Modification( - shader_translator_->GetDefaultVertexShaderModification( - shader.GetDynamicAddressableRegisterCount( - sq_program_cntl.vs_num_reg), - host_vertex_shader_type)); - } else { - assert_true(shader.type() == xenos::ShaderType::kPixel); - DxbcShaderTranslator::Modification pixel_shader_modification( - shader_translator_->GetDefaultPixelShaderModification( - shader.GetDynamicAddressableRegisterCount( - sq_program_cntl.ps_num_reg))); - if (render_target_cache_.GetPath() == - RenderTargetCache::Path::kHostRenderTargets) { - using DepthStencilMode = - DxbcShaderTranslator::Modification::DepthStencilMode; - RenderTargetCache::DepthFloat24Conversion depth_float24_conversion = - render_target_cache_.depth_float24_conversion(); - if ((depth_float24_conversion == - RenderTargetCache::DepthFloat24Conversion::kOnOutputTruncating || - depth_float24_conversion == - RenderTargetCache::DepthFloat24Conversion::kOnOutputRounding) && - draw_util::GetDepthControlForCurrentEdramMode(regs).z_enable && - regs.Get().depth_format == - xenos::DepthRenderTargetFormat::kD24FS8) { - pixel_shader_modification.pixel.depth_stencil_mode = - depth_float24_conversion == - RenderTargetCache::DepthFloat24Conversion:: - kOnOutputTruncating - ? DepthStencilMode::kFloat24Truncating - : DepthStencilMode::kFloat24Rounding; - } else { - if (shader.implicit_early_z_write_allowed() && - (!shader.writes_color_target(0) || - !draw_util::DoesCoverageDependOnAlpha( - regs.Get()))) { - pixel_shader_modification.pixel.depth_stencil_mode = - DepthStencilMode::kEarlyHint; - } else { - pixel_shader_modification.pixel.depth_stencil_mode = - DepthStencilMode::kNoModifiers; - } - } - } - modification_out = pixel_shader_modification; - } - return true; + return DxbcShaderTranslator::Modification( + shader_translator_->GetDefaultVertexShaderModification( + shader.GetDynamicAddressableRegisterCount(sq_program_cntl.vs_num_reg), + host_vertex_shader_type)); } -Shader::HostVertexShaderType -PipelineCache::GetCurrentHostVertexShaderTypeIfValid() const { - // If the values this functions returns are changed, INVALIDATE THE SHADER - // STORAGE (increase kVersion for BOTH shaders and pipelines)! The exception - // is when the function originally returned "unsupported", but started to - // return a valid value (in this case the shader wouldn't be cached in the - // first place). Otherwise games will not be able to locate shaders for draws - // for which the host vertex shader type has changed! +DxbcShaderTranslator::Modification +PipelineCache::GetCurrentPixelShaderModification(const Shader& shader) const { + assert_true(shader.type() == xenos::ShaderType::kPixel); + assert_true(shader.is_ucode_analyzed()); const auto& regs = register_file_; - auto vgt_draw_initiator = regs.Get(); - if (!xenos::IsMajorModeExplicit(vgt_draw_initiator.major_mode, - vgt_draw_initiator.prim_type)) { - // VGT_OUTPUT_PATH_CNTL and HOS registers are ignored in implicit major - // mode. - return Shader::HostVertexShaderType::kVertex; - } - if (regs.Get().path_select != - xenos::VGTOutputPath::kTessellationEnable) { - return Shader::HostVertexShaderType::kVertex; - } - xenos::TessellationMode tessellation_mode = - regs.Get().tess_mode; - switch (vgt_draw_initiator.prim_type) { - case xenos::PrimitiveType::kTriangleList: - // Also supported by triangle strips and fans according to: - // https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt - // Would need to convert those to triangle lists, but haven't seen any - // games using tessellated strips/fans so far. - switch (tessellation_mode) { - case xenos::TessellationMode::kDiscrete: - // - Call of Duty 3 - nets above barrels in the beginning of the - // first mission (turn right after the end of the intro) - - // kTriangleList. - case xenos::TessellationMode::kContinuous: - // - Viva Pinata - tree building with a beehive in the beginning - // (visible on the start screen behind the logo), waterfall in the - // beginning - kTriangleList. - return Shader::HostVertexShaderType::kTriangleDomainCPIndexed; - default: - break; + auto sq_program_cntl = regs.Get(); + DxbcShaderTranslator::Modification modification( + shader_translator_->GetDefaultPixelShaderModification( + shader.GetDynamicAddressableRegisterCount( + sq_program_cntl.ps_num_reg))); + if (render_target_cache_.GetPath() == + RenderTargetCache::Path::kHostRenderTargets) { + using DepthStencilMode = + DxbcShaderTranslator::Modification::DepthStencilMode; + RenderTargetCache::DepthFloat24Conversion depth_float24_conversion = + render_target_cache_.depth_float24_conversion(); + if ((depth_float24_conversion == + RenderTargetCache::DepthFloat24Conversion::kOnOutputTruncating || + depth_float24_conversion == + RenderTargetCache::DepthFloat24Conversion::kOnOutputRounding) && + draw_util::GetDepthControlForCurrentEdramMode(regs).z_enable && + regs.Get().depth_format == + xenos::DepthRenderTargetFormat::kD24FS8) { + modification.pixel.depth_stencil_mode = + depth_float24_conversion == + RenderTargetCache::DepthFloat24Conversion::kOnOutputTruncating + ? DepthStencilMode::kFloat24Truncating + : DepthStencilMode::kFloat24Rounding; + } else { + if (shader.implicit_early_z_write_allowed() && + (!shader.writes_color_target(0) || + !draw_util::DoesCoverageDependOnAlpha( + regs.Get()))) { + modification.pixel.depth_stencil_mode = DepthStencilMode::kEarlyHint; + } else { + modification.pixel.depth_stencil_mode = DepthStencilMode::kNoModifiers; } - break; - case xenos::PrimitiveType::kQuadList: - switch (tessellation_mode) { - // Also supported by quad strips according to: - // https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt - // Would need to convert those to quad lists, but haven't seen any games - // using tessellated strips so far. - case xenos::TessellationMode::kDiscrete: - // Not seen in games so far. - case xenos::TessellationMode::kContinuous: - // - Defender - retro screen and beams in the main menu - kQuadList. - return Shader::HostVertexShaderType::kQuadDomainCPIndexed; - default: - break; - } - break; - case xenos::PrimitiveType::kTrianglePatch: - // - Banjo-Kazooie: Nuts & Bolts - water - adaptive. - // - Halo 3 - water - adaptive. - return Shader::HostVertexShaderType::kTriangleDomainPatchIndexed; - case xenos::PrimitiveType::kQuadPatch: - // - Fable II - continuous. - // - Viva Pinata - garden ground - adaptive. - return Shader::HostVertexShaderType::kQuadDomainPatchIndexed; - default: - // TODO(Triang3l): Support line patches. - break; + } } - XELOGE( - "Unsupported tessellation mode {} for primitive type {}. Report the game " - "to Xenia developers!", - uint32_t(tessellation_mode), uint32_t(vgt_draw_initiator.prim_type)); - return Shader::HostVertexShaderType(-1); + return modification; } bool PipelineCache::ConfigurePipeline( D3D12Shader::D3D12Translation* vertex_shader, D3D12Shader::D3D12Translation* pixel_shader, - xenos::PrimitiveType primitive_type, xenos::IndexFormat index_format, + const PrimitiveProcessor::ProcessingResult& primitive_processing_result, uint32_t bound_depth_and_color_render_target_bits, const uint32_t* bound_depth_and_color_render_target_formats, void** pipeline_handle_out, ID3D12RootSignature** root_signature_out) { @@ -1074,7 +994,7 @@ bool PipelineCache::ConfigurePipeline( PipelineRuntimeDescription runtime_description; if (!GetCurrentStateDescription( - vertex_shader, pixel_shader, primitive_type, index_format, + vertex_shader, pixel_shader, primitive_processing_result, bound_depth_and_color_render_target_bits, bound_depth_and_color_render_target_formats, runtime_description)) { return false; @@ -1340,7 +1260,7 @@ bool PipelineCache::TranslateAnalyzedShader( bool PipelineCache::GetCurrentStateDescription( D3D12Shader::D3D12Translation* vertex_shader, D3D12Shader::D3D12Translation* pixel_shader, - xenos::PrimitiveType primitive_type, xenos::IndexFormat index_format, + const PrimitiveProcessor::ProcessingResult& primitive_processing_result, uint32_t bound_depth_and_color_render_target_bits, const uint32_t* bound_depth_and_color_render_target_formats, PipelineRuntimeDescription& runtime_description_out) { @@ -1357,12 +1277,11 @@ bool PipelineCache::GetCurrentStateDescription( // Initialize all unused fields to zero for comparison/hashing. std::memset(&runtime_description_out, 0, sizeof(runtime_description_out)); - bool tessellated = - DxbcShaderTranslator::Modification(vertex_shader->modification()) - .vertex.host_vertex_shader_type != - Shader::HostVertexShaderType::kVertex; - bool primitive_polygonal = - xenos::IsPrimitivePolygonal(tessellated, primitive_type); + assert_true(DxbcShaderTranslator::Modification(vertex_shader->modification()) + .vertex.host_vertex_shader_type == + primitive_processing_result.host_vertex_shader_type); + bool tessellated = primitive_processing_result.IsTessellated(); + bool primitive_polygonal = draw_util::IsPrimitivePolygonal(regs); bool rasterization_enabled = draw_util::IsRasterizationPotentiallyDone(regs, primitive_polygonal); // In Direct3D, rasterization (along with pixel counting) is disabled by @@ -1397,12 +1316,12 @@ bool PipelineCache::GetCurrentStateDescription( description_out.vertex_shader_modification = vertex_shader->modification(); // Index buffer strip cut value. - if (pa_su_sc_mode_cntl.multi_prim_ib_ena) { - // Not using 0xFFFF with 32-bit indices because in index buffers it will be - // 0xFFFF0000 anyway due to endianness. - description_out.strip_cut_index = index_format == xenos::IndexFormat::kInt32 - ? PipelineStripCutIndex::kFFFFFFFF - : PipelineStripCutIndex::kFFFF; + if (primitive_processing_result.host_primitive_reset_enabled) { + description_out.strip_cut_index = + primitive_processing_result.host_index_format == + xenos::IndexFormat::kInt16 + ? PipelineStripCutIndex::kFFFF + : PipelineStripCutIndex::kFFFFFFFF; } else { description_out.strip_cut_index = PipelineStripCutIndex::kNone; } @@ -1410,9 +1329,9 @@ bool PipelineCache::GetCurrentStateDescription( // Host vertex shader type and primitive topology. if (tessellated) { description_out.primitive_topology_type_or_tessellation_mode = - uint32_t(regs.Get().tess_mode); + uint32_t(primitive_processing_result.tessellation_mode); } else { - switch (primitive_type) { + switch (primitive_processing_result.host_primitive_type) { case xenos::PrimitiveType::kPointList: description_out.primitive_topology_type_or_tessellation_mode = uint32_t(PipelinePrimitiveTopologyType::kPoint); @@ -1431,7 +1350,7 @@ bool PipelineCache::GetCurrentStateDescription( uint32_t(PipelinePrimitiveTopologyType::kTriangle); break; } - switch (primitive_type) { + switch (primitive_processing_result.host_primitive_type) { case xenos::PrimitiveType::kPointList: description_out.geometry_shader = PipelineGeometryShader::kPointList; break; diff --git a/src/xenia/gpu/d3d12/pipeline_cache.h b/src/xenia/gpu/d3d12/pipeline_cache.h index c9727b910..b5d7a4209 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.h +++ b/src/xenia/gpu/d3d12/pipeline_cache.h @@ -29,6 +29,7 @@ #include "xenia/gpu/d3d12/d3d12_shader.h" #include "xenia/gpu/dxbc_shader_translator.h" #include "xenia/gpu/gpu_flags.h" +#include "xenia/gpu/primitive_processor.h" #include "xenia/gpu/register_file.h" #include "xenia/gpu/xenos.h" #include "xenia/ui/d3d12/d3d12_api.h" @@ -67,18 +68,21 @@ class PipelineCache { shader.AnalyzeUcode(ucode_disasm_buffer_); } - // Retrieves the shader modification for the current state, and returns - // whether it is valid. The shader must have microcode analyzed. - bool PipelineCache::GetCurrentShaderModification( + // Retrieves the shader modification for the current state. The shader must + // have microcode analyzed. + DxbcShaderTranslator::Modification + PipelineCache::GetCurrentVertexShaderModification( const Shader& shader, - DxbcShaderTranslator::Modification& modification_out) const; + Shader::HostVertexShaderType host_vertex_shader_type) const; + DxbcShaderTranslator::Modification + PipelineCache::GetCurrentPixelShaderModification(const Shader& shader) const; // If draw_util::IsRasterizationPotentiallyDone is false, the pixel shader // MUST be made nullptr BEFORE calling this! bool ConfigurePipeline( D3D12Shader::D3D12Translation* vertex_shader, D3D12Shader::D3D12Translation* pixel_shader, - xenos::PrimitiveType primitive_type, xenos::IndexFormat index_format, + const PrimitiveProcessor::ProcessingResult& primitive_processing_result, uint32_t bound_depth_and_color_render_target_bits, const uint32_t* bound_depth_and_color_render_targets_formats, void** pipeline_handle_out, ID3D12RootSignature** root_signature_out); @@ -226,10 +230,6 @@ class PipelineCache { PipelineDescription description; }; - // Returns the host vertex shader type for the current draw if it's valid and - // supported, or Shader::HostVertexShaderType(-1) if not. - Shader::HostVertexShaderType GetCurrentHostVertexShaderTypeIfValid() const; - D3D12Shader* LoadShader(xenos::ShaderType shader_type, const uint32_t* host_address, uint32_t dword_count, uint64_t data_hash); @@ -247,7 +247,7 @@ class PipelineCache { bool GetCurrentStateDescription( D3D12Shader::D3D12Translation* vertex_shader, D3D12Shader::D3D12Translation* pixel_shader, - xenos::PrimitiveType primitive_type, xenos::IndexFormat index_format, + const PrimitiveProcessor::ProcessingResult& primitive_processing_result, uint32_t bound_depth_and_color_render_target_bits, const uint32_t* bound_depth_and_color_render_target_formats, PipelineRuntimeDescription& runtime_description_out); diff --git a/src/xenia/gpu/d3d12/primitive_converter.cc b/src/xenia/gpu/d3d12/primitive_converter.cc deleted file mode 100644 index 90ba11ac5..000000000 --- a/src/xenia/gpu/d3d12/primitive_converter.cc +++ /dev/null @@ -1,762 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2018 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include "xenia/gpu/d3d12/primitive_converter.h" - -#include - -#include "xenia/base/assert.h" -#include "xenia/base/cvar.h" -#include "xenia/base/logging.h" -#include "xenia/base/math.h" -#include "xenia/base/memory.h" -#include "xenia/base/platform.h" -#include "xenia/base/profiling.h" -#include "xenia/gpu/d3d12/d3d12_command_processor.h" -#include "xenia/ui/d3d12/d3d12_util.h" - -DEFINE_bool(d3d12_convert_quads_to_triangles, false, - "Convert quad lists to triangle lists on the CPU instead of using " - "a geometry shader. Not recommended for playing, for debugging " - "primarily (because PIX fails to display vertices when a geometry " - "shader is used), and this way quads can't be discarded correctly " - "when the game uses vertex kill functionality.", - "D3D12"); - -namespace xe { -namespace gpu { -namespace d3d12 { - -PrimitiveConverter::PrimitiveConverter(D3D12CommandProcessor& command_processor, - const RegisterFile& register_file, - Memory& memory, - TraceWriter& trace_writer) - : command_processor_(command_processor), - register_file_(register_file), - memory_(memory), - trace_writer_(trace_writer) { - system_page_size_ = uint32_t(memory::page_size()); -} - -PrimitiveConverter::~PrimitiveConverter() { Shutdown(); } - -bool PrimitiveConverter::Initialize() { - auto& provider = command_processor_.GetD3D12Context().GetD3D12Provider(); - auto device = provider.GetDevice(); - D3D12_HEAP_FLAGS heap_flag_create_not_zeroed = - provider.GetHeapFlagCreateNotZeroed(); - - // There can be at most 65535 indices in a Xenos draw call (16 bit index - // count), but they can be up to 4 bytes large, and conversion can add more - // indices (almost triple the count for triangle strips or fans, for - // instance). - buffer_pool_ = std::make_unique( - provider, std::max(sizeof(uint32_t) * 3 * 65535, - ui::d3d12::D3D12UploadBufferPool::kDefaultPageSize)); - - // Create the static index buffer for non-indexed drawing. - D3D12_RESOURCE_DESC static_ib_desc; - ui::d3d12::util::FillBufferResourceDesc( - static_ib_desc, kStaticIBTotalCount * sizeof(uint16_t), - D3D12_RESOURCE_FLAG_NONE); - if (FAILED(device->CreateCommittedResource( - &ui::d3d12::util::kHeapPropertiesUpload, heap_flag_create_not_zeroed, - &static_ib_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, - IID_PPV_ARGS(&static_ib_upload_)))) { - XELOGE( - "Failed to create the upload buffer for the primitive conversion " - "static index buffer"); - Shutdown(); - return false; - } - D3D12_RANGE static_ib_read_range; - static_ib_read_range.Begin = 0; - static_ib_read_range.End = 0; - void* static_ib_mapping; - if (FAILED(static_ib_upload_->Map(0, &static_ib_read_range, - &static_ib_mapping))) { - XELOGE( - "Failed to map the upload buffer for the primitive conversion " - "static index buffer"); - Shutdown(); - return false; - } - uint16_t* static_ib_data = reinterpret_cast(static_ib_mapping); - // Triangle fans as triangle lists. - // https://docs.microsoft.com/en-us/windows/desktop/direct3d9/triangle-fans - // Ordered as (v1, v2, v0), (v2, v3, v0). - uint16_t* static_ib_data_pointer = - &static_ib_data[kStaticIBTriangleFanOffset]; - for (uint32_t i = 2; i < kMaxNonIndexedVertices; ++i) { - *(static_ib_data_pointer++) = i - 1; - *(static_ib_data_pointer++) = i; - *(static_ib_data_pointer++) = 0; - } - static_ib_data_pointer = &static_ib_data[kStaticIBQuadOffset]; - for (uint32_t i = 0; i < (kMaxNonIndexedVertices >> 2); ++i) { - uint32_t quad_index = i << 2; - *(static_ib_data_pointer++) = quad_index; - *(static_ib_data_pointer++) = quad_index + 1; - *(static_ib_data_pointer++) = quad_index + 2; - *(static_ib_data_pointer++) = quad_index; - *(static_ib_data_pointer++) = quad_index + 2; - *(static_ib_data_pointer++) = quad_index + 3; - } - static_ib_upload_->Unmap(0, nullptr); - // Not uploaded yet. - static_ib_upload_submission_ = UINT64_MAX; - if (FAILED(device->CreateCommittedResource( - &ui::d3d12::util::kHeapPropertiesDefault, heap_flag_create_not_zeroed, - &static_ib_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, - IID_PPV_ARGS(&static_ib_)))) { - XELOGE("Failed to create the primitive conversion static index buffer"); - Shutdown(); - return false; - } - static_ib_gpu_address_ = static_ib_->GetGPUVirtualAddress(); - - memory_regions_invalidated_.store(0ull, std::memory_order_relaxed); - memory_invalidation_callback_handle_ = - memory_.RegisterPhysicalMemoryInvalidationCallback( - MemoryInvalidationCallbackThunk, this); - - return true; -} - -void PrimitiveConverter::Shutdown() { - if (memory_invalidation_callback_handle_ != nullptr) { - memory_.UnregisterPhysicalMemoryInvalidationCallback( - memory_invalidation_callback_handle_); - memory_invalidation_callback_handle_ = nullptr; - } - ui::d3d12::util::ReleaseAndNull(static_ib_); - ui::d3d12::util::ReleaseAndNull(static_ib_upload_); - buffer_pool_.reset(); -} - -void PrimitiveConverter::ClearCache() { buffer_pool_->ClearCache(); } - -void PrimitiveConverter::CompletedSubmissionUpdated() { - if (static_ib_upload_ && command_processor_.GetCompletedSubmission() >= - static_ib_upload_submission_) { - // Completely uploaded - release the upload buffer. - static_ib_upload_->Release(); - static_ib_upload_ = nullptr; - } -} - -void PrimitiveConverter::BeginSubmission() { - // Got a command list now - upload and transition the static index buffer if - // needed. - if (static_ib_upload_ && static_ib_upload_submission_ == UINT64_MAX) { - command_processor_.GetDeferredCommandList().D3DCopyResource( - static_ib_, static_ib_upload_); - command_processor_.PushTransitionBarrier(static_ib_, - D3D12_RESOURCE_STATE_COPY_DEST, - D3D12_RESOURCE_STATE_INDEX_BUFFER); - static_ib_upload_submission_ = command_processor_.GetCurrentSubmission(); - } -} - -void PrimitiveConverter::BeginFrame() { - buffer_pool_->Reclaim(command_processor_.GetCompletedFrame()); - converted_indices_cache_.clear(); - memory_regions_used_ = 0; -} - -xenos::PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType( - xenos::PrimitiveType type) { - switch (type) { - case xenos::PrimitiveType::kTriangleFan: - return xenos::PrimitiveType::kTriangleList; - case xenos::PrimitiveType::kLineLoop: - return xenos::PrimitiveType::kLineStrip; - case xenos::PrimitiveType::kQuadList: - if (cvars::d3d12_convert_quads_to_triangles) { - return xenos::PrimitiveType::kTriangleList; - } - break; - default: - break; - } - return type; -} - -PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives( - xenos::PrimitiveType source_type, uint32_t address, uint32_t index_count, - xenos::IndexFormat index_format, xenos::Endian index_endianness, - D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out, uint32_t& index_count_out) { - bool index_32bit = index_format == xenos::IndexFormat::kInt32; - const auto& regs = register_file_; - bool reset = regs.Get().multi_prim_ib_ena; - // Swap the reset index because we will be comparing unswapped values to it. - uint32_t reset_index = xenos::GpuSwap( - regs[XE_GPU_REG_VGT_MULTI_PRIM_IB_RESET_INDX].u32, index_endianness); - // If the specified reset index is the same as the one used by Direct3D 12 - // (0xFFFF or 0xFFFFFFFF - in the pipeline cache, we use the former for - // 16-bit and the latter for 32-bit indices), we can use the buffer directly. - uint32_t reset_index_host = index_32bit ? 0xFFFFFFFFu : 0xFFFFu; - - // Degenerate line loops are just lines. - if (source_type == xenos::PrimitiveType::kLineLoop && index_count <= 2) { - source_type = xenos::PrimitiveType::kLineStrip; - } - - // Check if need to convert at all. - if (source_type == xenos::PrimitiveType::kTriangleStrip || - source_type == xenos::PrimitiveType::kLineStrip) { - if (!reset || reset_index == reset_index_host) { - return ConversionResult::kConversionNotNeeded; - } - } else if (source_type == xenos::PrimitiveType::kQuadList) { - if (!cvars::d3d12_convert_quads_to_triangles) { - return ConversionResult::kConversionNotNeeded; - } - } else if (source_type != xenos::PrimitiveType::kTriangleFan && - source_type != xenos::PrimitiveType::kLineLoop) { - return ConversionResult::kConversionNotNeeded; - } - -#if XE_UI_D3D12_FINE_GRAINED_DRAW_SCOPES - SCOPE_profile_cpu_f("gpu"); -#endif // XE_UI_D3D12_FINE_GRAINED_DRAW_SCOPES - - // Exit early for clearly empty draws, without even reading the memory. - uint32_t index_count_min; - if (source_type == xenos::PrimitiveType::kLineStrip || - source_type == xenos::PrimitiveType::kLineLoop) { - index_count_min = 2; - } else if (source_type == xenos::PrimitiveType::kQuadList) { - index_count_min = 4; - } else { - index_count_min = 3; - } - if (index_count < index_count_min) { - return ConversionResult::kPrimitiveEmpty; - } - - // Invalidate the cache if data behind any entry was modified. - if (memory_regions_invalidated_.exchange(0ull, std::memory_order_acquire) & - memory_regions_used_) { - converted_indices_cache_.clear(); - memory_regions_used_ = 0; - } - - address &= index_32bit ? 0x1FFFFFFC : 0x1FFFFFFE; - uint32_t index_size = index_32bit ? sizeof(uint32_t) : sizeof(uint16_t); - uint32_t index_buffer_size = index_size * index_count; - uint32_t address_last = address + index_size * (index_count - 1); - - // Create the cache entry, currently only for the key. - ConvertedIndices converted_indices; - converted_indices.key.address = address; - converted_indices.key.source_type = source_type; - converted_indices.key.format = index_format; - converted_indices.key.count = index_count; - converted_indices.key.reset = reset ? 1 : 0; - converted_indices.reset_index = reset_index; - - // Try to find the previously converted index buffer. - auto found_range = - converted_indices_cache_.equal_range(converted_indices.key.value); - for (auto iter = found_range.first; iter != found_range.second; ++iter) { - const ConvertedIndices& found_converted = iter->second; - if (reset && found_converted.reset_index != reset_index) { - continue; - } - if (found_converted.converted_index_count == 0) { - return ConversionResult::kPrimitiveEmpty; - } - if (!found_converted.gpu_address) { - return ConversionResult::kConversionNotNeeded; - } - gpu_address_out = found_converted.gpu_address; - index_count_out = found_converted.converted_index_count; - return ConversionResult::kConverted; - } - - // Get the memory usage mask for cache invalidation. - // 1 bit = (512 / 64) MB = 8 MB. - uint64_t memory_regions_used_bits = ~((1ull << (address >> 23)) - 1); - if (address_last < (63 << 23)) { - memory_regions_used_bits = (1ull << ((address_last >> 23) + 1)) - 1; - } - - union { - const void* source; - const uint8_t* source_8; - const uint16_t* source_16; - const uint32_t* source_32; - uintptr_t source_uintptr; - }; - source = memory_.TranslatePhysical(address); - - // Calculate the new index count, and also check if there's nothing to convert - // in the buffer (for instance, if not using actually primitive reset). - uint32_t converted_index_count = 0; - bool conversion_needed = false; - bool simd = false; - // Optimization specific to primitive types - if reset index not found in the - // source index buffer, can set this to false and use a faster way of copying. - bool reset_actually_used = reset; - if (source_type == xenos::PrimitiveType::kTriangleFan) { - // Triangle fans are not supported by Direct3D 12 at all. - conversion_needed = true; - trace_writer_.WriteMemoryRead(address, index_buffer_size); - if (reset) { - uint32_t current_fan_index_count = 0; - for (uint32_t i = 0; i < index_count; ++i) { - uint32_t index = index_format == xenos::IndexFormat::kInt32 - ? source_32[i] - : source_16[i]; - if (index == reset_index) { - current_fan_index_count = 0; - continue; - } - if (++current_fan_index_count >= 3) { - converted_index_count += 3; - } - } - } else { - converted_index_count = 3 * (index_count - 2); - } - } else if (source_type == xenos::PrimitiveType::kTriangleStrip || - source_type == xenos::PrimitiveType::kLineStrip) { - converted_index_count = index_count; - // Check if the restart index is used at all in this buffer because reading - // vertices from a default heap is faster than from an upload heap. - conversion_needed = false; - trace_writer_.WriteMemoryRead(address, index_buffer_size); -#if XE_ARCH_AMD64 - // Will use SIMD to copy 16-byte blocks using _mm_or_si128. - simd = true; - union { - const void* check_source; - const uint32_t* check_source_16; - const uint32_t* check_source_32; - const __m128i* check_source_128; - uintptr_t check_source_uintptr; - }; - check_source = source; - uint32_t check_indices_remaining = index_count; - alignas(16) uint64_t check_result[2]; - if (index_format == xenos::IndexFormat::kInt32) { - while (check_indices_remaining != 0 && (check_source_uintptr & 15)) { - --check_indices_remaining; - if (*(check_source_32++) == reset_index) { - conversion_needed = true; - check_indices_remaining = 0; - } - } - __m128i check_reset_index_vector = _mm_set1_epi32(reset_index); - while (check_indices_remaining >= 4) { - check_indices_remaining -= 4; - _mm_store_si128(reinterpret_cast<__m128i*>(&check_result), - _mm_cmpeq_epi32(_mm_load_si128(check_source_128++), - check_reset_index_vector)); - if (check_result[0] || check_result[1]) { - conversion_needed = true; - check_indices_remaining = 0; - } - } - while (check_indices_remaining != 0) { - --check_indices_remaining; - if (*(check_source_32++) == reset_index) { - conversion_needed = true; - check_indices_remaining = 0; - } - } - } else { - while (check_indices_remaining != 0 && (check_source_uintptr & 15)) { - --check_indices_remaining; - if (*(check_source_16++) == reset_index) { - conversion_needed = true; - check_indices_remaining = 0; - } - } - __m128i check_reset_index_vector = _mm_set1_epi16(reset_index); - while (check_indices_remaining >= 8) { - check_indices_remaining -= 8; - _mm_store_si128(reinterpret_cast<__m128i*>(&check_result), - _mm_cmpeq_epi16(_mm_load_si128(check_source_128++), - check_reset_index_vector)); - if (check_result[0] || check_result[1]) { - conversion_needed = true; - check_indices_remaining = 0; - } - } - while (check_indices_remaining != 0) { - --check_indices_remaining; - if (*(check_source_16++) == reset_index) { - conversion_needed = true; - check_indices_remaining = 0; - } - } - } -#else - if (index_format == xenos::IndexFormat::kInt32) { - for (uint32_t i = 0; i < index_count; ++i) { - if (source_32[i] == reset_index) { - conversion_needed = true; - break; - } - } - } else { - for (uint32_t i = 0; i < index_count; ++i) { - if (source_16[i] == reset_index) { - conversion_needed = true; - break; - } - } - } -#endif // XE_ARCH_AMD64 - } else if (source_type == xenos::PrimitiveType::kLineLoop) { - conversion_needed = true; - trace_writer_.WriteMemoryRead(address, index_buffer_size); - if (reset) { - reset_actually_used = false; - uint32_t current_strip_index_count = 0; - for (uint32_t i = 0; i < index_count; ++i) { - uint32_t index = index_format == xenos::IndexFormat::kInt32 - ? source_32[i] - : source_16[i]; - if (index == reset_index) { - reset_actually_used = true; - // Loop strips with more than 2 vertices. - if (current_strip_index_count > 2) { - ++converted_index_count; - } - current_strip_index_count = 0; - continue; - } - // Start a new strip if 2 vertices, add one vertex if more. - if (++current_strip_index_count >= 2) { - converted_index_count += current_strip_index_count == 2 ? 2 : 1; - } - } - } else { - converted_index_count = index_count + 1; - } - } else if (source_type == xenos::PrimitiveType::kQuadList) { - conversion_needed = true; - trace_writer_.WriteMemoryRead(address, index_buffer_size); - converted_index_count = (index_count >> 2) * 6; - } - converted_indices.converted_index_count = converted_index_count; - - // If nothing to convert, store this result so the check won't be happening - // again and again and exit. - if (!conversion_needed || converted_index_count == 0) { - converted_indices.gpu_address = 0; - converted_indices_cache_.emplace(converted_indices.key.value, - converted_indices); - memory_regions_used_ |= memory_regions_used_bits; - return converted_index_count == 0 ? ConversionResult::kPrimitiveEmpty - : ConversionResult::kConversionNotNeeded; - } - - // Convert. - - D3D12_GPU_VIRTUAL_ADDRESS gpu_address; - void* target = AllocateIndices(index_format, converted_index_count, - simd ? address & 15 : 0, gpu_address); - if (target == nullptr) { - return ConversionResult::kFailed; - } - - if (source_type == xenos::PrimitiveType::kTriangleFan) { - // https://docs.microsoft.com/en-us/windows/desktop/direct3d9/triangle-fans - // Ordered as (v1, v2, v0), (v2, v3, v0). - if (reset) { - uint32_t current_fan_index_count = 0; - uint32_t current_fan_first_index = 0; - if (index_format == xenos::IndexFormat::kInt32) { - uint32_t* target_32 = reinterpret_cast(target); - for (uint32_t i = 0; i < index_count; ++i) { - uint32_t index = source_32[i]; - if (index == reset_index) { - current_fan_index_count = 0; - continue; - } - if (current_fan_index_count == 0) { - current_fan_first_index = index; - } - if (++current_fan_index_count >= 3) { - *(target_32++) = source_32[i - 1]; - *(target_32++) = index; - *(target_32++) = current_fan_first_index; - } - } - } else { - uint16_t* target_16 = reinterpret_cast(target); - for (uint32_t i = 0; i < index_count; ++i) { - uint16_t index = source_16[i]; - if (index == reset_index) { - current_fan_index_count = 0; - continue; - } - if (current_fan_index_count == 0) { - current_fan_first_index = index; - } - if (++current_fan_index_count >= 3) { - *(target_16++) = source_16[i - 1]; - *(target_16++) = index; - *(target_16++) = uint16_t(current_fan_first_index); - } - } - } - } else { - if (index_format == xenos::IndexFormat::kInt32) { - uint32_t* target_32 = reinterpret_cast(target); - for (uint32_t i = 2; i < index_count; ++i) { - *(target_32++) = source_32[i - 1]; - *(target_32++) = source_32[i]; - *(target_32++) = source_32[0]; - } - } else { - uint16_t* target_16 = reinterpret_cast(target); - for (uint32_t i = 2; i < index_count; ++i) { - *(target_16++) = source_16[i - 1]; - *(target_16++) = source_16[i]; - *(target_16++) = source_16[0]; - } - } - } - } else if (source_type == xenos::PrimitiveType::kTriangleStrip || - source_type == xenos::PrimitiveType::kLineStrip) { -#if XE_ARCH_AMD64 - // Replace the reset index with the maximum representable value - vector OR - // gives 0 or 0xFFFF/0xFFFFFFFF, which is exactly what is needed. - // Allocations in the target index buffer are aligned with 16-byte - // granularity, and within 16-byte vectors, both the source and the target - // start at the same offset. - union { - const __m128i* source_aligned_128; - uintptr_t source_aligned_uintptr; - }; - source_aligned_uintptr = source_uintptr & ~(uintptr_t(15)); - union { - __m128i* target_aligned_128; - uintptr_t target_aligned_uintptr; - }; - target_aligned_uintptr = - reinterpret_cast(target) & ~(uintptr_t(15)); - uint32_t vector_count = (address_last >> 4) - (address >> 4) + 1; - if (index_format == xenos::IndexFormat::kInt32) { - __m128i reset_index_vector = _mm_set1_epi32(reset_index); - for (uint32_t i = 0; i < vector_count; ++i) { - __m128i indices_vector = _mm_load_si128(source_aligned_128++); - __m128i indices_are_reset_vector = - _mm_cmpeq_epi32(indices_vector, reset_index_vector); - _mm_store_si128(target_aligned_128++, - _mm_or_si128(indices_vector, indices_are_reset_vector)); - } - } else { - __m128i reset_index_vector = _mm_set1_epi16(reset_index); - for (uint32_t i = 0; i < vector_count; ++i) { - __m128i indices_vector = _mm_load_si128(source_aligned_128++); - __m128i indices_are_reset_vector = - _mm_cmpeq_epi16(indices_vector, reset_index_vector); - _mm_store_si128(target_aligned_128++, - _mm_or_si128(indices_vector, indices_are_reset_vector)); - } - } -#else - if (index_format == xenos::IndexFormat::kInt32) { - for (uint32_t i = 0; i < index_count; ++i) { - uint32_t index = source_32[i]; - reinterpret_cast(target)[i] = - index == reset_index ? 0xFFFFFFFFu : index; - } - } else { - for (uint32_t i = 0; i < index_count; ++i) { - uint16_t index = source_16[i]; - reinterpret_cast(target)[i] = - index == reset_index ? 0xFFFFu : index; - } - } -#endif // XE_ARCH_AMD64 - } else if (source_type == xenos::PrimitiveType::kLineLoop) { - if (reset_actually_used) { - uint32_t current_strip_index_count = 0; - uint32_t current_strip_first_index = 0; - if (index_format == xenos::IndexFormat::kInt32) { - uint32_t* target_32 = reinterpret_cast(target); - for (uint32_t i = 0; i < index_count; ++i) { - uint32_t index = source_32[i]; - if (index == reset_index) { - if (current_strip_index_count > 2) { - *(target_32++) = current_strip_first_index; - } - current_strip_index_count = 0; - continue; - } - if (current_strip_index_count == 0) { - current_strip_first_index = index; - } - ++current_strip_index_count; - if (current_strip_index_count >= 2) { - if (current_strip_index_count == 2) { - *(target_32++) = current_strip_first_index; - } - *(target_32++) = index; - } - } - } else { - uint16_t* target_16 = reinterpret_cast(target); - for (uint32_t i = 0; i < index_count; ++i) { - uint16_t index = source_16[i]; - if (index == reset_index) { - if (current_strip_index_count > 2) { - *(target_16++) = uint16_t(current_strip_first_index); - } - current_strip_index_count = 0; - continue; - } - if (current_strip_index_count == 0) { - current_strip_first_index = index; - } - ++current_strip_index_count; - if (current_strip_index_count >= 2) { - if (current_strip_index_count == 2) { - *(target_16++) = uint16_t(current_strip_first_index); - } - *(target_16++) = index; - } - } - } - } else { - std::memcpy(target, source, index_count * index_size); - if (converted_index_count > index_count) { - if (index_format == xenos::IndexFormat::kInt32) { - reinterpret_cast(target)[index_count] = source_32[0]; - } else { - reinterpret_cast(target)[index_count] = source_16[0]; - } - } - } - } else if (source_type == xenos::PrimitiveType::kQuadList) { - uint32_t quad_count = index_count >> 4; - if (index_format == xenos::IndexFormat::kInt32) { - uint32_t* target_32 = reinterpret_cast(target); - for (uint32_t i = 0; i < quad_count; ++i) { - uint32_t quad_index = i << 2; - *(target_32++) = source_32[quad_index]; - *(target_32++) = source_32[quad_index + 1]; - *(target_32++) = source_32[quad_index + 2]; - *(target_32++) = source_32[quad_index]; - *(target_32++) = source_32[quad_index + 2]; - *(target_32++) = source_32[quad_index + 3]; - } - } else { - uint16_t* target_16 = reinterpret_cast(target); - for (uint32_t i = 0; i < quad_count; ++i) { - uint32_t quad_index = i << 2; - *(target_16++) = source_16[quad_index]; - *(target_16++) = source_16[quad_index + 1]; - *(target_16++) = source_16[quad_index + 2]; - *(target_16++) = source_16[quad_index]; - *(target_16++) = source_16[quad_index + 2]; - *(target_16++) = source_16[quad_index + 3]; - } - } - } - - // Cache and return the indices. - converted_indices.gpu_address = gpu_address; - converted_indices_cache_.emplace(converted_indices.key.value, - converted_indices); - memory_regions_used_ |= memory_regions_used_bits; - gpu_address_out = gpu_address; - index_count_out = converted_index_count; - return ConversionResult::kConverted; -} - -void* PrimitiveConverter::AllocateIndices( - xenos::IndexFormat format, uint32_t count, uint32_t simd_offset, - D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out) { - if (count == 0) { - return nullptr; - } - uint32_t size = - count * (format == xenos::IndexFormat::kInt32 ? sizeof(uint32_t) - : sizeof(uint16_t)); - // 16-align all index data because SIMD is used to replace the reset index - // (without that, 4-alignment would be required anyway to mix 16-bit and - // 32-bit indices in one buffer page). - size = xe::align(size, uint32_t(16)); - // Add some space to align SIMD register components the same way in the source - // and the buffer. - simd_offset &= 15; - if (simd_offset != 0) { - size += 16; - } - D3D12_GPU_VIRTUAL_ADDRESS gpu_address; - uint8_t* mapping = - buffer_pool_->Request(command_processor_.GetCurrentFrame(), size, 16, - nullptr, nullptr, &gpu_address); - if (mapping == nullptr) { - XELOGE("Failed to allocate space for {} converted {}-bit vertex indices", - count, format == xenos::IndexFormat::kInt32 ? 32 : 16); - return nullptr; - } - gpu_address_out = gpu_address + simd_offset; - return mapping + simd_offset; -} - -std::pair PrimitiveConverter::MemoryInvalidationCallback( - uint32_t physical_address_start, uint32_t length, bool exact_range) { - // 1 bit = (512 / 64) MB = 8 MB. Invalidate a region of this size. - uint32_t bit_index_first = physical_address_start >> 23; - uint32_t bit_index_last = (physical_address_start + length - 1) >> 23; - uint64_t bits = ~((1ull << bit_index_first) - 1); - if (bit_index_last < 63) { - bits &= (1ull << (bit_index_last + 1)) - 1; - } - memory_regions_invalidated_ |= bits; - return std::make_pair(0, UINT32_MAX); -} - -std::pair -PrimitiveConverter::MemoryInvalidationCallbackThunk( - void* context_ptr, uint32_t physical_address_start, uint32_t length, - bool exact_range) { - return reinterpret_cast(context_ptr) - ->MemoryInvalidationCallback(physical_address_start, length, exact_range); -} - -D3D12_GPU_VIRTUAL_ADDRESS PrimitiveConverter::GetStaticIndexBuffer( - xenos::PrimitiveType source_type, uint32_t index_count, - uint32_t& index_count_out) const { - if (index_count > kMaxNonIndexedVertices) { - assert_always(); - return D3D12_GPU_VIRTUAL_ADDRESS(0); - } - if (source_type == xenos::PrimitiveType::kTriangleFan) { - index_count_out = (std::max(index_count, uint32_t(2)) - 2) * 3; - return static_ib_gpu_address_ + - kStaticIBTriangleFanOffset * sizeof(uint16_t); - } - if (source_type == xenos::PrimitiveType::kQuadList && - cvars::d3d12_convert_quads_to_triangles) { - index_count_out = (index_count >> 2) * 6; - return static_ib_gpu_address_ + kStaticIBQuadOffset * sizeof(uint16_t); - } - return D3D12_GPU_VIRTUAL_ADDRESS(0); -} - -void PrimitiveConverter::InitializeTrace() { - // WriteMemoryRead must not be skipped. - converted_indices_cache_.clear(); - memory_regions_used_ = 0; -} - -} // namespace d3d12 -} // namespace gpu -} // namespace xe diff --git a/src/xenia/gpu/d3d12/primitive_converter.h b/src/xenia/gpu/d3d12/primitive_converter.h deleted file mode 100644 index 4d5c80f2d..000000000 --- a/src/xenia/gpu/d3d12/primitive_converter.h +++ /dev/null @@ -1,189 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2018 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#ifndef XENIA_GPU_D3D12_PRIMITIVE_CONVERTER_H_ -#define XENIA_GPU_D3D12_PRIMITIVE_CONVERTER_H_ - -#include -#include -#include - -#include "xenia/gpu/register_file.h" -#include "xenia/gpu/trace_writer.h" -#include "xenia/gpu/xenos.h" -#include "xenia/memory.h" -#include "xenia/ui/d3d12/d3d12_context.h" -#include "xenia/ui/d3d12/d3d12_upload_buffer_pool.h" - -namespace xe { -namespace gpu { -namespace d3d12 { - -class D3D12CommandProcessor; - -// Index buffer cache for primitive types not natively supported by Direct3D 12: -// - Triangle and line strips with non-0xFFFF/0xFFFFFFFF reset index. -// - Triangle fans. -// - Line loops (only indexed ones - non-indexed are better handled in vertex -// shaders, otherwise a whole index buffer would have to be created for every -// vertex count value). -// - Quad lists (for debugging since geometry shaders break PIX - as an -// alternative to the geometry shader). -class PrimitiveConverter { - public: - PrimitiveConverter(D3D12CommandProcessor& command_processor, - const RegisterFile& register_file, Memory& memory, - TraceWriter& trace_writer); - ~PrimitiveConverter(); - - bool Initialize(); - void Shutdown(); - void ClearCache(); - - void CompletedSubmissionUpdated(); - void BeginSubmission(); - void BeginFrame(); - - // Returns the primitive type that the original type will be converted to. - static xenos::PrimitiveType GetReplacementPrimitiveType( - xenos::PrimitiveType type); - - enum class ConversionResult { - // Converted to a transient buffer. - kConverted, - // Conversion not required - use the index buffer in shared memory. - kConversionNotNeeded, - // No errors, but nothing to render. - kPrimitiveEmpty, - // Total failure of the draw call. - kFailed - }; - - // Converts an index buffer to the primitive type returned by - // GetReplacementPrimitiveType. If conversion has been performed, the returned - // buffer will be in the GENERIC_READ state (it's in an upload heap). Only - // writing to the outputs if returning kConverted. The restart index will be - // handled internally from the register values. - ConversionResult ConvertPrimitives(xenos::PrimitiveType source_type, - uint32_t address, uint32_t index_count, - xenos::IndexFormat index_format, - xenos::Endian index_endianness, - D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out, - uint32_t& index_count_out); - - // Returns the 16-bit index buffer for drawing unsupported non-indexed - // primitives in INDEX_BUFFER state, for non-indexed drawing. Returns 0 if - // conversion is not available (can draw natively). - D3D12_GPU_VIRTUAL_ADDRESS GetStaticIndexBuffer( - xenos::PrimitiveType source_type, uint32_t index_count, - uint32_t& index_count_out) const; - - // Callback for invalidating buffers mid-frame. - std::pair MemoryInvalidationCallback( - uint32_t physical_address_start, uint32_t length, bool exact_range); - - void InitializeTrace(); - - private: - // simd_offset is source address & 15 - if SIMD is used, the source and the - // target must have the same alignment within one register. 0 is optimal when - // not using SIMD. - void* AllocateIndices(xenos::IndexFormat format, uint32_t count, - uint32_t simd_offset, - D3D12_GPU_VIRTUAL_ADDRESS& gpu_address_out); - - static std::pair MemoryInvalidationCallbackThunk( - void* context_ptr, uint32_t physical_address_start, uint32_t length, - bool exact_range); - - D3D12CommandProcessor& command_processor_; - const RegisterFile& register_file_; - Memory& memory_; - TraceWriter& trace_writer_; - - std::unique_ptr buffer_pool_; - - // Static index buffers for emulating unsupported primitive types when drawing - // without an index buffer. - // CPU-side, used only for uploading - destroyed once the copy commands have - // been completed. - ID3D12Resource* static_ib_upload_ = nullptr; - uint64_t static_ib_upload_submission_; - // GPU-side - used for drawing. - ID3D12Resource* static_ib_ = nullptr; - D3D12_GPU_VIRTUAL_ADDRESS static_ib_gpu_address_; - // In PM4 draw packets, 16 bits are used for the vertex count. - static constexpr uint32_t kMaxNonIndexedVertices = 65535; - static constexpr uint32_t kStaticIBTriangleFanOffset = 0; - static constexpr uint32_t kStaticIBTriangleFanCount = - (kMaxNonIndexedVertices - 2) * 3; - static constexpr uint32_t kStaticIBQuadOffset = - kStaticIBTriangleFanOffset + kStaticIBTriangleFanCount; - static constexpr uint32_t kStaticIBQuadCount = - (kMaxNonIndexedVertices >> 2) * 6; - static constexpr uint32_t kStaticIBTotalCount = - kStaticIBQuadOffset + kStaticIBQuadCount; - - // Not identifying the index buffer uniquely - reset index must also be - // checked if reset is enabled. - union ConvertedIndicesKey { - uint64_t value; - struct { - uint32_t address; // 32 - xenos::PrimitiveType source_type : 6; // 38 - xenos::IndexFormat format : 1; // 39 - uint32_t count : 16; // 55 - uint32_t reset : 1; // 56 - }; - - // Clearing the unused bits. - ConvertedIndicesKey() : value(0) {} - ConvertedIndicesKey(const ConvertedIndicesKey& key) : value(key.value) {} - ConvertedIndicesKey& operator=(const ConvertedIndicesKey& key) { - value = key.value; - return *this; - } - bool operator==(const ConvertedIndicesKey& key) const { - return value == key.value; - } - bool operator!=(const ConvertedIndicesKey& key) const { - return value != key.value; - } - }; - - struct ConvertedIndices { - ConvertedIndicesKey key; - // If reset is enabled, this also must be checked to find cached indices. - uint32_t reset_index; - - // Zero GPU address if conversion not needed or the resulting index buffer - // is empty. - D3D12_GPU_VIRTUAL_ADDRESS gpu_address; - // When conversion is not needed, this must be equal to the original index - // count. - uint32_t converted_index_count; - }; - - // Cache for a single frame. - std::unordered_multimap converted_indices_cache_; - - // Very coarse cache invalidation - if something is modified in a 8 MB portion - // of the physical memory and converted indices are also there, invalidate all - // the cache. - uint64_t memory_regions_used_; - std::atomic memory_regions_invalidated_ = 0; - void* memory_invalidation_callback_handle_ = nullptr; - uint32_t system_page_size_; -}; - -} // namespace d3d12 -} // namespace gpu -} // namespace xe - -#endif // XENIA_GPU_D3D12_PRIMITIVE_CONVERTER_H_ diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.cso b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.cso index 86f4f0832f4c4cf669d9bb52941391e2ade8f34f..3485c2092c8f899474724e267c0cc70753a1c3f8 100644 GIT binary patch delta 1191 zcmaizPiPZC6vp2+$^NO0B&0RbTHLe{~!Z#R*MF@UW1qTWR`gLL%~-EJ=mX@YJPM|11yn^fhve~-(`Ax~ZlmJM@#sg*;~&C02EgwFw7U;)qsxNxo$us# z7rFw`*p7yeAY6rEdo#@wS_56{q8~xufVP|D=f=V|yR*~*-CIzWE%Td4`;C&Yz2K9kj+jj>6RY27=B?_}YcCR}NItkit;ju}}py4k14Rj84vgJ_c+6fuI z#wuvrS4GXE^K%M;SGqjsLBCpPiRB&B!aDomnC?+THY}bv5=$%?IV~BDW{fQ54DGs+ z&H^-XJeJVndXBEe64@~-vcHmQdmJs0vl)l*TNb zY(ySl1$lHJlDwKsYep`m&Byc%6}i~PmX#q}75%NtH@c@^R;IYibLAZR-c*jGczd|_ GsqH_8mh!p) delta 993 zcmZY7L1@!p6bJB^rcKgnp%F259V{CgYt+B?+`p9CUm1c@XZqsU4CHL``QA0ZmWxtocZE7z*Ah%i#UlNlRA z*AjAJb{&t_uwSk5;XM|^dyuI z<>3rX19cQGECa{;@fmOum_qVccZN2h{E_%#JoX(`WTItMu2m<1D?oSa6m-46H3{4R z>PQ~*Y}liz6=)NcYw9ZS3$XhD?|AET(Hq?E=_F=~nmUS}U1$i&BkJf~=ucFxsSChX zKQ02>KpdQK{=k>K!uxdLCMu;LKLSHQ*Nwgdb)bGQlG@HrgMOlEXm`_#?3Y(lQ_vfS z^bs@#o$gGiIK3Ot6=-+vdq;mj8;2$Y@WD2FG|KjTN#OyTkdmIaK30@2X=&58jBIY! zDpNLBq8k4!1rpe5Fsz=&Cs4MGLLO%fJNwvTTk;tu%3&6fhlMp3lc&TTiP&FxY#=wA zG4gYBwpDU2v5kURG#89}R*of<5w_&lJ*Lc_Dg*4Ca!h)NiD!vzOSS8)owN^F_ld7mRe)w5e7TNW@ZJzLdCz8`hOmEaJDjQ#bu_KK!@;I+mIVTtM-9 IG4MkC51~}N!2kdN diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.h b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.h index 4770750bd..8b7c5fa82 100644 --- a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.h +++ b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.h @@ -1,14 +1,14 @@ // generated from `xb buildhlsl` // source: continuous_quad.hs.hlsl const uint8_t continuous_quad_hs[] = { - 0x44, 0x58, 0x42, 0x43, 0xCE, 0xF4, 0xB8, 0x73, 0x74, 0x35, 0xD9, 0xE6, - 0x42, 0x49, 0xF7, 0xF8, 0xDD, 0x91, 0xC9, 0xCD, 0x01, 0x00, 0x00, 0x00, - 0xC0, 0x0D, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x8C, 0x0A, 0x00, 0x00, 0xC0, 0x0A, 0x00, 0x00, 0xF4, 0x0A, 0x00, 0x00, - 0xB8, 0x0B, 0x00, 0x00, 0x24, 0x0D, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, - 0x4C, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0x09, 0x87, 0x23, 0xAA, 0xC0, 0xBD, 0xD4, 0x13, + 0xCA, 0xC2, 0x38, 0xBB, 0xB9, 0x58, 0x55, 0x8E, 0x01, 0x00, 0x00, 0x00, + 0x18, 0x0E, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0xE4, 0x0A, 0x00, 0x00, 0x18, 0x0B, 0x00, 0x00, 0x4C, 0x0B, 0x00, 0x00, + 0x10, 0x0C, 0x00, 0x00, 0x7C, 0x0D, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, + 0xA4, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x05, 0x53, 0x48, - 0x00, 0x05, 0x00, 0x00, 0x22, 0x0A, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, + 0x00, 0x05, 0x00, 0x00, 0x7A, 0x0A, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, 0x3C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -16,283 +16,290 @@ const uint8_t continuous_quad_hs[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x5F, 0x63, 0x62, 0x75, 0x66, 0x66, 0x65, - 0x72, 0x00, 0xAB, 0xAB, 0x64, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0x72, 0x00, 0xAB, 0xAB, 0x64, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x68, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x05, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xE4, 0x05, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4F, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x16, 0x06, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x54, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x62, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x78, 0x06, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x8F, 0x06, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xAC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x07, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xD0, 0x06, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, - 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x07, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x82, 0x07, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x29, 0x07, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0x07, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x37, 0x07, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xA8, 0x07, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x47, 0x07, 0x00, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x07, 0x00, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x8C, 0x07, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE0, 0x07, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xA1, 0x07, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, - 0xDC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x08, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0x08, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x5C, 0x08, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x08, 0x00, 0x00, - 0xF4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x79, 0x08, 0x00, 0x00, + 0xE8, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x82, 0x08, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8A, 0x08, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x97, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9F, 0x08, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x08, 0x00, 0x00, - 0x08, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x08, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xCC, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x08, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x08, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x09, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x22, 0x09, 0x00, 0x00, + 0x18, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x60, 0x09, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x09, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x79, 0x09, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x09, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x09, 0x00, 0x00, - 0xA0, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC8, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x09, 0x00, 0x00, + 0x50, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xEC, 0x09, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD1, 0x09, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x0A, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x66, - 0x6C, 0x61, 0x67, 0x73, 0x00, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x00, 0xAB, - 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x44, 0x0A, 0x00, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x62, 0x0A, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, + 0x00, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x00, 0xAB, 0x00, 0x00, 0x13, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x05, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x74, 0x65, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x61, 0x74, - 0x69, 0x6F, 0x6E, 0x5F, 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x5F, 0x72, - 0x61, 0x6E, 0x67, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x32, 0x00, - 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC1, 0x05, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, + 0x65, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x5F, + 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, + 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x32, 0x00, 0x01, 0x00, 0x03, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x05, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x6C, 0x69, 0x6E, 0x65, 0x5F, 0x6C, 0x6F, 0x6F, 0x70, - 0x5F, 0x63, 0x6C, 0x6F, 0x73, 0x69, 0x6E, 0x67, 0x5F, 0x69, 0x6E, 0x64, - 0x65, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, - 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x65, 0x6E, 0x64, 0x69, 0x61, - 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, - 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x69, - 0x6E, 0x74, 0x00, 0xAB, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6C, + 0x69, 0x6E, 0x65, 0x5F, 0x6C, 0x6F, 0x6F, 0x70, 0x5F, 0x63, 0x6C, 0x6F, + 0x73, 0x69, 0x6E, 0x67, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x78, + 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, + 0x65, 0x78, 0x5F, 0x65, 0x6E, 0x64, 0x69, 0x61, 0x6E, 0x00, 0x78, 0x65, + 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, + 0x78, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, + 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, + 0x5F, 0x6D, 0x69, 0x6E, 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x75, 0x69, 0x6E, + 0x74, 0x32, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2B, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, - 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, - 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x6D, 0x69, 0x6E, 0x5F, - 0x6D, 0x61, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, - 0x5F, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6E, 0x5F, 0x74, 0x6F, 0x5F, 0x6E, - 0x64, 0x63, 0x00, 0x78, 0x65, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, 0x63, - 0x6C, 0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x00, 0x66, - 0x6C, 0x6F, 0x61, 0x74, 0x34, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, + 0x95, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, + 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x00, + 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x34, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x33, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xDD, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x5F, 0x73, 0x61, 0x6D, 0x70, - 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, - 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x6F, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x73, 0x5F, 0x70, 0x61, 0x72, - 0x61, 0x6D, 0x5F, 0x67, 0x65, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, - 0x78, 0x74, 0x75, 0x72, 0x65, 0x5F, 0x73, 0x77, 0x69, 0x7A, 0x7A, 0x6C, - 0x65, 0x64, 0x5F, 0x73, 0x69, 0x67, 0x6E, 0x73, 0x00, 0x75, 0x69, 0x6E, - 0x74, 0x34, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x0D, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, + 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x78, 0x00, 0x66, 0x6C, 0x6F, 0x61, + 0x74, 0x00, 0xAB, 0xAB, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x6F, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, + 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x79, 0x00, 0x78, 0x65, + 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, + 0x6D, 0x69, 0x6E, 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x70, + 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6E, 0x5F, + 0x74, 0x6F, 0x5F, 0x6E, 0x64, 0x63, 0x00, 0x78, 0x65, 0x5F, 0x69, 0x6E, + 0x74, 0x65, 0x72, 0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x5F, 0x73, + 0x61, 0x6D, 0x70, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x73, 0x5F, 0x70, 0x61, + 0x72, 0x61, 0x6D, 0x5F, 0x67, 0x65, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x73, + 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5F, + 0x6C, 0x6F, 0x67, 0x32, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, + 0x75, 0x72, 0x65, 0x5F, 0x73, 0x77, 0x69, 0x7A, 0x7A, 0x6C, 0x65, 0x64, + 0x5F, 0x73, 0x69, 0x67, 0x6E, 0x73, 0x00, 0x75, 0x69, 0x6E, 0x74, 0x34, + 0x00, 0xAB, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, + 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x73, 0x5F, 0x72, 0x65, 0x73, 0x6F, 0x6C, 0x76, 0x65, 0x64, - 0x00, 0x78, 0x65, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, - 0x6F, 0x75, 0x6E, 0x74, 0x5F, 0x6C, 0x6F, 0x67, 0x32, 0x00, 0x75, 0x69, - 0x6E, 0x74, 0x32, 0x00, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x65, + 0x73, 0x74, 0x5F, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, + 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x6F, + 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, + 0x61, 0x6D, 0x5F, 0x70, 0x69, 0x74, 0x63, 0x68, 0x5F, 0x74, 0x69, 0x6C, + 0x65, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, + 0x65, 0x78, 0x70, 0x5F, 0x62, 0x69, 0x61, 0x73, 0x00, 0xAB, 0xAB, 0xAB, + 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xB6, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, - 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x63, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x00, 0xAB, 0xAB, - 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, 0x65, 0x78, 0x70, - 0x5F, 0x62, 0x69, 0x61, 0x73, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, - 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, - 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x6F, 0x5F, 0x6D, 0x61, 0x73, 0x6B, - 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x69, - 0x74, 0x63, 0x68, 0x5F, 0x74, 0x69, 0x6C, 0x65, 0x73, 0x00, 0x78, 0x65, - 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, 0x74, 0x68, - 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, - 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x5F, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x00, 0x78, 0x65, - 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, - 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x62, 0x61, 0x63, 0x6B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, - 0x74, 0x68, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, 0x72, - 0x64, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, - 0x73, 0x74, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x00, 0x01, 0x00, 0x13, 0x00, - 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, - 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x61, 0x73, 0x65, - 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x5F, 0x73, 0x63, 0x61, 0x6C, - 0x65, 0x64, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, - 0x5F, 0x72, 0x74, 0x5F, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x66, - 0x6C, 0x61, 0x67, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, - 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x63, 0x6C, 0x61, 0x6D, 0x70, 0x00, 0xAB, - 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, - 0x6B, 0x65, 0x65, 0x70, 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0xAB, 0xAB, + 0x74, 0x68, 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x00, 0x78, 0x65, 0x5F, + 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x00, + 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, + 0x79, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x62, 0x61, 0x63, + 0x6B, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, + 0x6F, 0x72, 0x64, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, + 0x6D, 0x5F, 0x73, 0x74, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, - 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, - 0x73, 0x5F, 0x6F, 0x70, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, - 0x61, 0x6D, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x63, 0x6F, 0x6E, - 0x73, 0x74, 0x61, 0x6E, 0x74, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, - 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, - 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, - 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0xAB, 0xAB, - 0x49, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, - 0x49, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, + 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x5F, + 0x73, 0x63, 0x61, 0x6C, 0x65, 0x64, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, + 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x74, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, 0x00, 0x78, 0x65, 0x5F, + 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x63, 0x6C, 0x61, + 0x6D, 0x70, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, + 0x5F, 0x72, 0x74, 0x5F, 0x6B, 0x65, 0x65, 0x70, 0x5F, 0x6D, 0x61, 0x73, + 0x6B, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, + 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x66, 0x61, + 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x6F, 0x70, 0x73, 0x00, 0x78, 0x65, + 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, + 0x5F, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x00, 0x4D, 0x69, + 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, + 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, + 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, + 0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, - 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, 0x50, 0x43, 0x53, 0x47, - 0xBC, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, + 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, + 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0xA6, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x53, 0x56, 0x5F, 0x54, 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, - 0x72, 0x00, 0x53, 0x56, 0x5F, 0x49, 0x6E, 0x73, 0x69, 0x64, 0x65, 0x54, - 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x00, 0xAB, 0xAB, - 0x53, 0x48, 0x45, 0x58, 0x64, 0x01, 0x00, 0x00, 0x51, 0x00, 0x03, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x01, 0x93, 0x20, 0x00, 0x01, - 0x94, 0x20, 0x00, 0x01, 0x95, 0x18, 0x00, 0x01, 0x96, 0x20, 0x00, 0x01, - 0x97, 0x18, 0x00, 0x01, 0x6A, 0x08, 0x00, 0x01, 0x59, 0x00, 0x00, 0x07, - 0x46, 0x8E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x73, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, - 0x5F, 0x00, 0x00, 0x02, 0x00, 0x70, 0x01, 0x00, 0x67, 0x00, 0x00, 0x04, - 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0C, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, - 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x58, 0x45, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, + 0x50, 0x43, 0x53, 0x47, 0xBC, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x65, 0x73, 0x73, 0x46, + 0x61, 0x63, 0x74, 0x6F, 0x72, 0x00, 0x53, 0x56, 0x5F, 0x49, 0x6E, 0x73, + 0x69, 0x64, 0x65, 0x54, 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, + 0x72, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x45, 0x58, 0x64, 0x01, 0x00, 0x00, + 0x51, 0x00, 0x03, 0x00, 0x59, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x01, + 0x93, 0x20, 0x00, 0x01, 0x94, 0x20, 0x00, 0x01, 0x95, 0x18, 0x00, 0x01, + 0x96, 0x20, 0x00, 0x01, 0x97, 0x18, 0x00, 0x01, 0x6A, 0x08, 0x00, 0x01, + 0x59, 0x00, 0x00, 0x07, 0x46, 0x8E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x02, + 0x04, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x02, 0x00, 0x70, 0x01, 0x00, + 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, + 0x12, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x5B, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x04, 0x12, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x70, 0x01, 0x00, 0x36, 0x00, 0x00, 0x08, + 0x12, 0x20, 0x90, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, + 0x99, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x02, + 0x00, 0x70, 0x01, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, + 0x12, 0x20, 0x10, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x04, - 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x12, 0x20, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x04, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x70, 0x01, 0x00, 0x36, 0x00, 0x00, 0x08, 0x12, 0x20, 0x90, 0x00, - 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x80, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x02, - 0x02, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x02, 0x00, 0x70, 0x01, 0x00, - 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, - 0x01, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x04, - 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x70, 0x01, 0x00, - 0x36, 0x00, 0x00, 0x09, 0x12, 0x20, 0xD0, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x80, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x94, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x70, 0x01, 0x00, 0x36, 0x00, 0x00, 0x09, 0x12, 0x20, 0xD0, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, + 0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.txt b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.txt index 6220f1d0f..23c930910 100644 --- a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.txt +++ b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_quad_hs.txt @@ -11,26 +11,28 @@ // float2 xe_tessellation_factor_range;// Offset: 4 Size: 8 // uint xe_line_loop_closing_index; // Offset: 12 Size: 4 [unused] // uint xe_vertex_index_endian; // Offset: 16 Size: 4 [unused] -// int xe_vertex_base_index; // Offset: 20 Size: 4 [unused] -// float2 xe_point_size; // Offset: 24 Size: 8 [unused] -// float2 xe_point_size_min_max; // Offset: 32 Size: 8 [unused] -// float2 xe_point_screen_to_ndc; // Offset: 40 Size: 8 [unused] -// float4 xe_user_clip_planes[6]; // Offset: 48 Size: 96 [unused] -// float3 xe_ndc_scale; // Offset: 144 Size: 12 [unused] -// uint xe_interpolator_sampling_pattern;// Offset: 156 Size: 4 [unused] -// float3 xe_ndc_offset; // Offset: 160 Size: 12 [unused] -// uint xe_ps_param_gen; // Offset: 172 Size: 4 [unused] -// uint4 xe_texture_swizzled_signs[2];// Offset: 176 Size: 32 [unused] -// uint xe_textures_resolved; // Offset: 208 Size: 4 [unused] -// uint2 xe_sample_count_log2; // Offset: 212 Size: 8 [unused] -// float xe_alpha_test_reference; // Offset: 220 Size: 4 [unused] -// float4 xe_color_exp_bias; // Offset: 224 Size: 16 [unused] -// uint xe_alpha_to_mask; // Offset: 240 Size: 4 [unused] -// uint xe_edram_pitch_tiles; // Offset: 244 Size: 4 [unused] -// float2 xe_edram_depth_range; // Offset: 248 Size: 8 [unused] -// float2 xe_edram_poly_offset_front; // Offset: 256 Size: 8 [unused] -// float2 xe_edram_poly_offset_back; // Offset: 264 Size: 8 [unused] -// uint xe_edram_depth_base_dwords; // Offset: 272 Size: 4 [unused] +// uint xe_vertex_index_offset; // Offset: 20 Size: 4 [unused] +// uint2 xe_vertex_index_min_max; // Offset: 24 Size: 8 [unused] +// float4 xe_user_clip_planes[6]; // Offset: 32 Size: 96 [unused] +// float3 xe_ndc_scale; // Offset: 128 Size: 12 [unused] +// float xe_point_size_x; // Offset: 140 Size: 4 [unused] +// float3 xe_ndc_offset; // Offset: 144 Size: 12 [unused] +// float xe_point_size_y; // Offset: 156 Size: 4 [unused] +// float2 xe_point_size_min_max; // Offset: 160 Size: 8 [unused] +// float2 xe_point_screen_to_ndc; // Offset: 168 Size: 8 [unused] +// uint xe_interpolator_sampling_pattern;// Offset: 176 Size: 4 [unused] +// uint xe_ps_param_gen; // Offset: 180 Size: 4 [unused] +// uint2 xe_sample_count_log2; // Offset: 184 Size: 8 [unused] +// uint4 xe_texture_swizzled_signs[2];// Offset: 192 Size: 32 [unused] +// uint xe_textures_resolved; // Offset: 224 Size: 4 [unused] +// float xe_alpha_test_reference; // Offset: 228 Size: 4 [unused] +// uint xe_alpha_to_mask; // Offset: 232 Size: 4 [unused] +// uint xe_edram_pitch_tiles; // Offset: 236 Size: 4 [unused] +// float4 xe_color_exp_bias; // Offset: 240 Size: 16 [unused] +// float2 xe_edram_depth_range; // Offset: 256 Size: 8 [unused] +// float2 xe_edram_poly_offset_front; // Offset: 264 Size: 8 [unused] +// float2 xe_edram_poly_offset_back; // Offset: 272 Size: 8 [unused] +// uint xe_edram_depth_base_dwords; // Offset: 280 Size: 4 [unused] // uint4 xe_edram_stencil[2]; // Offset: 288 Size: 32 [unused] // uint4 xe_edram_rt_base_dwords_scaled;// Offset: 320 Size: 16 [unused] // uint4 xe_edram_rt_format_flags; // Offset: 336 Size: 16 [unused] diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.cso b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.cso index 05b8421494c8bb534ff4fd2b77c2e25a7bac4240..005d6d4e8b2358080c0ef21398cbaa7638bf7052 100644 GIT binary patch delta 1191 zcmaizPiPZC6vp3Xll@a0=+f52mg1%&Sn*;J+9HusqZL{-c&Z|7({v*N^M@pAT9B$2 zi&Qa=qKBXrJQM;_FhXypH}N1AdQeb^kb{R5>Rr%pHVG_QN*_FC-*3P9=FQCRdf#$? zFf=o9cIDB_cbe;Q>cz~|&kxrs0fC5?y+jhmQDm)y$bW!n8d*iwJBcob&Ygc-2=)t$ zg)7mc0jQoJt9)uRHav|7ceDOf_~p~;fE*}D7qW}p6MWh!tOQT%4FZ9R+IePSXgv>%WY8Gg>u6-zi~t!EK&j0kvxvE zi0IR%L93|ju456vnhoxC9t+U@w&|>^df?s15 zwB@U#=F$E+g}^Hg&pFVqHdBARGbiH7c{6XMVzI25qr7R{GBY`V z22RA2Mk11@oAG3Bm`d!gtc%YjVqc^IR+n^Pn|bAtZZGa0Gt()kjBI?-H1cdj846rz z@Z@~d=5JFius704HYEo-(^(@O$wU&ybu-DT@A^z_9z0A~ap1*+!jPWS?=Nei=^i}N_sPr4OOr~t8H&a4 z%wKbT4+b_KzwUf2UHUq+sCNY-iuj2n9HYppkEn$_Kvs?sy*N&EE5303MlBW=CTe#x zlVj*wNAB@U`?2CV{Ne7`NxDUig`veYTcm4wgM)4F@Iyr<9))6%I zHuN-<59MJGO#^il4lDzwM)5f?0!$)#Y}-TIQ2t1KF&_K2Dl*X~D#t@j1M5I%>nwD8 zv^4>20(B&h6*lhD)GD-%$}#m7@C$J803UekhUoV14s{YsiJE#AJ$ujql1J3md(dB~ z98*_;2cx(K>;ZAG!~O$b@(SaLW`o+%-AQ8^(!!o&;2b|qbWD-)|L zK~|Bc#(H?=xM3#$AYU}ha=}PvQx-KE0*P44&6g6laKm@XITrR>gQ+{-c|QD)cM(f1 M_%5S(v*we;|LDoL7ytkO diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.h b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.h index 85eac200f..0cec5a1be 100644 --- a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.h +++ b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.h @@ -1,14 +1,14 @@ // generated from `xb buildhlsl` // source: continuous_triangle.hs.hlsl const uint8_t continuous_triangle_hs[] = { - 0x44, 0x58, 0x42, 0x43, 0x02, 0xE3, 0x19, 0x10, 0x92, 0x76, 0xA5, 0xD1, - 0xC7, 0x74, 0x34, 0xD8, 0x2B, 0x4E, 0x20, 0xE1, 0x01, 0x00, 0x00, 0x00, - 0x30, 0x0D, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x8C, 0x0A, 0x00, 0x00, 0xC0, 0x0A, 0x00, 0x00, 0xF4, 0x0A, 0x00, 0x00, - 0x88, 0x0B, 0x00, 0x00, 0x94, 0x0C, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, - 0x4C, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0x8C, 0x8D, 0x98, 0xAE, 0x11, 0x02, 0x8E, 0x6F, + 0x97, 0x58, 0x4B, 0xDD, 0xB5, 0x5C, 0xC0, 0x21, 0x01, 0x00, 0x00, 0x00, + 0x88, 0x0D, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0xE4, 0x0A, 0x00, 0x00, 0x18, 0x0B, 0x00, 0x00, 0x4C, 0x0B, 0x00, 0x00, + 0xE0, 0x0B, 0x00, 0x00, 0xEC, 0x0C, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, + 0xA4, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x05, 0x53, 0x48, - 0x00, 0x05, 0x00, 0x00, 0x22, 0x0A, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, + 0x00, 0x05, 0x00, 0x00, 0x7A, 0x0A, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, 0x3C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -16,271 +16,278 @@ const uint8_t continuous_triangle_hs[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x5F, 0x63, 0x62, 0x75, 0x66, 0x66, 0x65, - 0x72, 0x00, 0xAB, 0xAB, 0x64, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0x72, 0x00, 0xAB, 0xAB, 0x64, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x68, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x05, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xE4, 0x05, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4F, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x16, 0x06, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x54, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x62, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x78, 0x06, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x8F, 0x06, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xAC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x07, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xD0, 0x06, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, - 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x07, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x82, 0x07, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x29, 0x07, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0x07, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x37, 0x07, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xA8, 0x07, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x47, 0x07, 0x00, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x07, 0x00, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x8C, 0x07, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE0, 0x07, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xA1, 0x07, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, - 0xDC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x08, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0x08, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x5C, 0x08, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x08, 0x00, 0x00, - 0xF4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x79, 0x08, 0x00, 0x00, + 0xE8, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x82, 0x08, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8A, 0x08, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x97, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9F, 0x08, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x08, 0x00, 0x00, - 0x08, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x08, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xCC, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x08, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x08, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x09, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x22, 0x09, 0x00, 0x00, + 0x18, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x60, 0x09, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x09, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x79, 0x09, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x09, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x09, 0x00, 0x00, - 0xA0, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC8, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x09, 0x00, 0x00, + 0x50, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xEC, 0x09, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD1, 0x09, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x0A, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x66, - 0x6C, 0x61, 0x67, 0x73, 0x00, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x00, 0xAB, - 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x44, 0x0A, 0x00, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x62, 0x0A, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, + 0x00, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x00, 0xAB, 0x00, 0x00, 0x13, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x05, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x74, 0x65, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x61, 0x74, - 0x69, 0x6F, 0x6E, 0x5F, 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x5F, 0x72, - 0x61, 0x6E, 0x67, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x32, 0x00, - 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC1, 0x05, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, + 0x65, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x5F, + 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, + 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x32, 0x00, 0x01, 0x00, 0x03, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x05, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x6C, 0x69, 0x6E, 0x65, 0x5F, 0x6C, 0x6F, 0x6F, 0x70, - 0x5F, 0x63, 0x6C, 0x6F, 0x73, 0x69, 0x6E, 0x67, 0x5F, 0x69, 0x6E, 0x64, - 0x65, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, - 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x65, 0x6E, 0x64, 0x69, 0x61, - 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, - 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x69, - 0x6E, 0x74, 0x00, 0xAB, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6C, + 0x69, 0x6E, 0x65, 0x5F, 0x6C, 0x6F, 0x6F, 0x70, 0x5F, 0x63, 0x6C, 0x6F, + 0x73, 0x69, 0x6E, 0x67, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x78, + 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, + 0x65, 0x78, 0x5F, 0x65, 0x6E, 0x64, 0x69, 0x61, 0x6E, 0x00, 0x78, 0x65, + 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, + 0x78, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, + 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, + 0x5F, 0x6D, 0x69, 0x6E, 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x75, 0x69, 0x6E, + 0x74, 0x32, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2B, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, - 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, - 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x6D, 0x69, 0x6E, 0x5F, - 0x6D, 0x61, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, - 0x5F, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6E, 0x5F, 0x74, 0x6F, 0x5F, 0x6E, - 0x64, 0x63, 0x00, 0x78, 0x65, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, 0x63, - 0x6C, 0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x00, 0x66, - 0x6C, 0x6F, 0x61, 0x74, 0x34, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, + 0x95, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, + 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x00, + 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x34, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x33, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xDD, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x5F, 0x73, 0x61, 0x6D, 0x70, - 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, - 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x6F, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x73, 0x5F, 0x70, 0x61, 0x72, - 0x61, 0x6D, 0x5F, 0x67, 0x65, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, - 0x78, 0x74, 0x75, 0x72, 0x65, 0x5F, 0x73, 0x77, 0x69, 0x7A, 0x7A, 0x6C, - 0x65, 0x64, 0x5F, 0x73, 0x69, 0x67, 0x6E, 0x73, 0x00, 0x75, 0x69, 0x6E, - 0x74, 0x34, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x0D, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, + 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x78, 0x00, 0x66, 0x6C, 0x6F, 0x61, + 0x74, 0x00, 0xAB, 0xAB, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x6F, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, + 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x79, 0x00, 0x78, 0x65, + 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, + 0x6D, 0x69, 0x6E, 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x70, + 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6E, 0x5F, + 0x74, 0x6F, 0x5F, 0x6E, 0x64, 0x63, 0x00, 0x78, 0x65, 0x5F, 0x69, 0x6E, + 0x74, 0x65, 0x72, 0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x5F, 0x73, + 0x61, 0x6D, 0x70, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x73, 0x5F, 0x70, 0x61, + 0x72, 0x61, 0x6D, 0x5F, 0x67, 0x65, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x73, + 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5F, + 0x6C, 0x6F, 0x67, 0x32, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, + 0x75, 0x72, 0x65, 0x5F, 0x73, 0x77, 0x69, 0x7A, 0x7A, 0x6C, 0x65, 0x64, + 0x5F, 0x73, 0x69, 0x67, 0x6E, 0x73, 0x00, 0x75, 0x69, 0x6E, 0x74, 0x34, + 0x00, 0xAB, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, + 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x73, 0x5F, 0x72, 0x65, 0x73, 0x6F, 0x6C, 0x76, 0x65, 0x64, - 0x00, 0x78, 0x65, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, - 0x6F, 0x75, 0x6E, 0x74, 0x5F, 0x6C, 0x6F, 0x67, 0x32, 0x00, 0x75, 0x69, - 0x6E, 0x74, 0x32, 0x00, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x65, + 0x73, 0x74, 0x5F, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, + 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x6F, + 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, + 0x61, 0x6D, 0x5F, 0x70, 0x69, 0x74, 0x63, 0x68, 0x5F, 0x74, 0x69, 0x6C, + 0x65, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, + 0x65, 0x78, 0x70, 0x5F, 0x62, 0x69, 0x61, 0x73, 0x00, 0xAB, 0xAB, 0xAB, + 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xB6, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, - 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x63, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x00, 0xAB, 0xAB, - 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, 0x65, 0x78, 0x70, - 0x5F, 0x62, 0x69, 0x61, 0x73, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, - 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, - 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x6F, 0x5F, 0x6D, 0x61, 0x73, 0x6B, - 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x69, - 0x74, 0x63, 0x68, 0x5F, 0x74, 0x69, 0x6C, 0x65, 0x73, 0x00, 0x78, 0x65, - 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, 0x74, 0x68, - 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, - 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x5F, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x00, 0x78, 0x65, - 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, - 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x62, 0x61, 0x63, 0x6B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, - 0x74, 0x68, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, 0x72, - 0x64, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, - 0x73, 0x74, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x00, 0x01, 0x00, 0x13, 0x00, - 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, - 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x61, 0x73, 0x65, - 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x5F, 0x73, 0x63, 0x61, 0x6C, - 0x65, 0x64, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, - 0x5F, 0x72, 0x74, 0x5F, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x66, - 0x6C, 0x61, 0x67, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, - 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x63, 0x6C, 0x61, 0x6D, 0x70, 0x00, 0xAB, - 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, - 0x6B, 0x65, 0x65, 0x70, 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0xAB, 0xAB, + 0x74, 0x68, 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x00, 0x78, 0x65, 0x5F, + 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x00, + 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, + 0x79, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x62, 0x61, 0x63, + 0x6B, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, + 0x6F, 0x72, 0x64, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, + 0x6D, 0x5F, 0x73, 0x74, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, - 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, - 0x73, 0x5F, 0x6F, 0x70, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, - 0x61, 0x6D, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x63, 0x6F, 0x6E, - 0x73, 0x74, 0x61, 0x6E, 0x74, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, - 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, - 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, - 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0xAB, 0xAB, - 0x49, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, - 0x49, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, + 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x5F, + 0x73, 0x63, 0x61, 0x6C, 0x65, 0x64, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, + 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x74, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, 0x00, 0x78, 0x65, 0x5F, + 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x63, 0x6C, 0x61, + 0x6D, 0x70, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, + 0x5F, 0x72, 0x74, 0x5F, 0x6B, 0x65, 0x65, 0x70, 0x5F, 0x6D, 0x61, 0x73, + 0x6B, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, + 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x66, 0x61, + 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x6F, 0x70, 0x73, 0x00, 0x78, 0x65, + 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, + 0x5F, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x00, 0x4D, 0x69, + 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, + 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, + 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, + 0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, - 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, 0x50, 0x43, 0x53, 0x47, - 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, + 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, + 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x53, 0x56, 0x5F, 0x54, 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, - 0x72, 0x00, 0x53, 0x56, 0x5F, 0x49, 0x6E, 0x73, 0x69, 0x64, 0x65, 0x54, - 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x00, 0xAB, 0xAB, - 0x53, 0x48, 0x45, 0x58, 0x04, 0x01, 0x00, 0x00, 0x51, 0x00, 0x03, 0x00, - 0x41, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x01, 0x93, 0x18, 0x00, 0x01, - 0x94, 0x18, 0x00, 0x01, 0x95, 0x10, 0x00, 0x01, 0x96, 0x20, 0x00, 0x01, - 0x97, 0x18, 0x00, 0x01, 0x6A, 0x08, 0x00, 0x01, 0x59, 0x00, 0x00, 0x07, - 0x46, 0x8E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x73, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, - 0x5F, 0x00, 0x00, 0x02, 0x00, 0x70, 0x01, 0x00, 0x67, 0x00, 0x00, 0x04, - 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, - 0x01, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x04, - 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x70, 0x01, 0x00, - 0x36, 0x00, 0x00, 0x08, 0x12, 0x20, 0x90, 0x00, 0x0A, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, - 0x73, 0x00, 0x00, 0x01, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x07, - 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2A, 0x80, 0x30, 0x00, + 0x58, 0x45, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, + 0x50, 0x43, 0x53, 0x47, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x65, 0x73, 0x73, 0x46, + 0x61, 0x63, 0x74, 0x6F, 0x72, 0x00, 0x53, 0x56, 0x5F, 0x49, 0x6E, 0x73, + 0x69, 0x64, 0x65, 0x54, 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, + 0x72, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x45, 0x58, 0x04, 0x01, 0x00, 0x00, + 0x51, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x01, + 0x93, 0x18, 0x00, 0x01, 0x94, 0x18, 0x00, 0x01, 0x95, 0x10, 0x00, 0x01, + 0x96, 0x20, 0x00, 0x01, 0x97, 0x18, 0x00, 0x01, 0x6A, 0x08, 0x00, 0x01, + 0x59, 0x00, 0x00, 0x07, 0x46, 0x8E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x02, 0x00, 0x70, 0x01, 0x00, + 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, + 0x12, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x04, + 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x04, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x70, 0x01, 0x00, 0x36, 0x00, 0x00, 0x08, 0x12, 0x20, 0x90, 0x00, + 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x94, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0x67, 0x00, 0x00, 0x04, + 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x07, 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, + 0x94, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.txt b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.txt index 48d869a99..ef8c122a4 100644 --- a/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.txt +++ b/src/xenia/gpu/d3d12/shaders/dxbc/continuous_triangle_hs.txt @@ -11,26 +11,28 @@ // float2 xe_tessellation_factor_range;// Offset: 4 Size: 8 // uint xe_line_loop_closing_index; // Offset: 12 Size: 4 [unused] // uint xe_vertex_index_endian; // Offset: 16 Size: 4 [unused] -// int xe_vertex_base_index; // Offset: 20 Size: 4 [unused] -// float2 xe_point_size; // Offset: 24 Size: 8 [unused] -// float2 xe_point_size_min_max; // Offset: 32 Size: 8 [unused] -// float2 xe_point_screen_to_ndc; // Offset: 40 Size: 8 [unused] -// float4 xe_user_clip_planes[6]; // Offset: 48 Size: 96 [unused] -// float3 xe_ndc_scale; // Offset: 144 Size: 12 [unused] -// uint xe_interpolator_sampling_pattern;// Offset: 156 Size: 4 [unused] -// float3 xe_ndc_offset; // Offset: 160 Size: 12 [unused] -// uint xe_ps_param_gen; // Offset: 172 Size: 4 [unused] -// uint4 xe_texture_swizzled_signs[2];// Offset: 176 Size: 32 [unused] -// uint xe_textures_resolved; // Offset: 208 Size: 4 [unused] -// uint2 xe_sample_count_log2; // Offset: 212 Size: 8 [unused] -// float xe_alpha_test_reference; // Offset: 220 Size: 4 [unused] -// float4 xe_color_exp_bias; // Offset: 224 Size: 16 [unused] -// uint xe_alpha_to_mask; // Offset: 240 Size: 4 [unused] -// uint xe_edram_pitch_tiles; // Offset: 244 Size: 4 [unused] -// float2 xe_edram_depth_range; // Offset: 248 Size: 8 [unused] -// float2 xe_edram_poly_offset_front; // Offset: 256 Size: 8 [unused] -// float2 xe_edram_poly_offset_back; // Offset: 264 Size: 8 [unused] -// uint xe_edram_depth_base_dwords; // Offset: 272 Size: 4 [unused] +// uint xe_vertex_index_offset; // Offset: 20 Size: 4 [unused] +// uint2 xe_vertex_index_min_max; // Offset: 24 Size: 8 [unused] +// float4 xe_user_clip_planes[6]; // Offset: 32 Size: 96 [unused] +// float3 xe_ndc_scale; // Offset: 128 Size: 12 [unused] +// float xe_point_size_x; // Offset: 140 Size: 4 [unused] +// float3 xe_ndc_offset; // Offset: 144 Size: 12 [unused] +// float xe_point_size_y; // Offset: 156 Size: 4 [unused] +// float2 xe_point_size_min_max; // Offset: 160 Size: 8 [unused] +// float2 xe_point_screen_to_ndc; // Offset: 168 Size: 8 [unused] +// uint xe_interpolator_sampling_pattern;// Offset: 176 Size: 4 [unused] +// uint xe_ps_param_gen; // Offset: 180 Size: 4 [unused] +// uint2 xe_sample_count_log2; // Offset: 184 Size: 8 [unused] +// uint4 xe_texture_swizzled_signs[2];// Offset: 192 Size: 32 [unused] +// uint xe_textures_resolved; // Offset: 224 Size: 4 [unused] +// float xe_alpha_test_reference; // Offset: 228 Size: 4 [unused] +// uint xe_alpha_to_mask; // Offset: 232 Size: 4 [unused] +// uint xe_edram_pitch_tiles; // Offset: 236 Size: 4 [unused] +// float4 xe_color_exp_bias; // Offset: 240 Size: 16 [unused] +// float2 xe_edram_depth_range; // Offset: 256 Size: 8 [unused] +// float2 xe_edram_poly_offset_front; // Offset: 264 Size: 8 [unused] +// float2 xe_edram_poly_offset_back; // Offset: 272 Size: 8 [unused] +// uint xe_edram_depth_base_dwords; // Offset: 280 Size: 4 [unused] // uint4 xe_edram_stencil[2]; // Offset: 288 Size: 32 [unused] // uint4 xe_edram_rt_base_dwords_scaled;// Offset: 320 Size: 16 [unused] // uint4 xe_edram_rt_format_flags; // Offset: 336 Size: 16 [unused] diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.cso b/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.cso index 73102e1b90f358047124d3f18ba6980d09852ee4..590c8094f88da70e014db49ce74c6e3351f760a0 100644 GIT binary patch delta 1191 zcmaizPiPZC6vp2+$^MB=NoZ@LwYaG$R=pU6wn((pXcdbFPwHixrW*;EKO|ApqEx*I z;=wp79)eczP{>6vhk&5zO*|BZA{IPE2QzC%*(9)JDShymeZT$Yn>RDN)q!Wb zf}x8OCk_UDfA+myJL5e5#rNY~&u@WTTyW|AMCCAL*cvE(*Wc^Ms^|H?2h2|9KlNPHQrz#LwX+2-3eoW zeVyd=H#?6x=zf}X##P=2Y;?jGfE$4Pj(L=g#lM0Qz9K&GXl{QU zrEH|Rd}bR4wZ!efJ0K*JXL8FU(SyyZ~m+A$fw z#v*9jS4GXE^K%M;S1q11pr1^%%nFW4VVSKtCc6}o4T;AN#gnsoUQ5MdSv^O2UAwMl zasW-7h$po~Bv04k$y|U+?60KSo`}Ri{&RbiF6q>)}1?jAGKDX6q;d|ub`Y(yUR zpKkKxY}Dj$Qq8fK;$e1H@^`1RS~`-6B(y7flGUW`?4IOTN+p4MNgz8DJ0u?1z&wu=6i*{v5586FhGH0?51*xK4msDhWB z{8MoCfqEF&v14}_6J&yidJzvEI`AS)*kHqp2ZbR$so!7LLeo8Xr0Z@hDNzCHQ4-*^;F3XHLOkTD6z7_uBdjXXeZ9%F0(=cW=9lUFP8h|piT zl^N_s*AjAvU)qXU-{B8$t1eY`HFX)tK|y+ub&h+$<0xF6|A3)xJcX4`cHjtY37UEX zdK$`y@^FTxfjSBomViUu_#8L_Od)x!IYS#z{z!Z=9(#@|GGoiAT&oTPt3Y?_D0Hp6 zH3?h?>PQ~5)aTLEGPHrpHFX8}71(}&54`n-=nZanbTTqUO&vhb4m5=15p(o5^cO1E z)Op}RH!cF3KpdQK{=iqf!uxdL1}dc+zW_r(*NuJvb)bGYk~N*3qJGB4pzTdB(QmJ& zrl8l4=mTg9I@X#{c6!&LRcL$eXGecR>qjO8@WD1ZG)B9=q;QXhrKIP*kBZV|Ep6JC zk)Cup0j?1t!o+Fsz=%Cs4ACLLO%fJNwY0E%_XYa+o4=pRh`Cc~tx^G5RYH z_T;8BMt)|-wicXAY@=Wn&3WUlm7|2xPfLE?W6JbY>7fhC3F$s2o@cZz>Eb(?QB?`k zV|l2ziC2yrX7Y3SqG6Q^MmlTStX314h^4%IDRC7y+*Hm`#BaB!ZurOf@IU@*SZX40 L5yjiZz)SHz5~{iU diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.h b/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.h index d2130b9d6..177fe74b2 100644 --- a/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.h +++ b/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.h @@ -1,14 +1,14 @@ // generated from `xb buildhlsl` // source: discrete_quad.hs.hlsl const uint8_t discrete_quad_hs[] = { - 0x44, 0x58, 0x42, 0x43, 0xC6, 0x8B, 0x46, 0x52, 0x9F, 0x04, 0x6C, 0x5E, - 0xD9, 0x89, 0xC1, 0xE5, 0xD0, 0x7D, 0x1C, 0x47, 0x01, 0x00, 0x00, 0x00, - 0xC0, 0x0D, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x8C, 0x0A, 0x00, 0x00, 0xC0, 0x0A, 0x00, 0x00, 0xF4, 0x0A, 0x00, 0x00, - 0xB8, 0x0B, 0x00, 0x00, 0x24, 0x0D, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, - 0x4C, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0x2B, 0x32, 0x18, 0xFB, 0x26, 0xBB, 0xD9, 0x49, + 0x0A, 0x3F, 0xD6, 0x18, 0xE7, 0xBE, 0x0E, 0xF2, 0x01, 0x00, 0x00, 0x00, + 0x18, 0x0E, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0xE4, 0x0A, 0x00, 0x00, 0x18, 0x0B, 0x00, 0x00, 0x4C, 0x0B, 0x00, 0x00, + 0x10, 0x0C, 0x00, 0x00, 0x7C, 0x0D, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, + 0xA4, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x05, 0x53, 0x48, - 0x00, 0x05, 0x00, 0x00, 0x22, 0x0A, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, + 0x00, 0x05, 0x00, 0x00, 0x7A, 0x0A, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, 0x3C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -16,283 +16,290 @@ const uint8_t discrete_quad_hs[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x5F, 0x63, 0x62, 0x75, 0x66, 0x66, 0x65, - 0x72, 0x00, 0xAB, 0xAB, 0x64, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0x72, 0x00, 0xAB, 0xAB, 0x64, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x68, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x05, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xE4, 0x05, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4F, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x16, 0x06, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x54, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x62, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x78, 0x06, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x8F, 0x06, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xAC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x07, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xD0, 0x06, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, - 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x07, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x82, 0x07, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x29, 0x07, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0x07, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x37, 0x07, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xA8, 0x07, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x47, 0x07, 0x00, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x07, 0x00, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x8C, 0x07, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE0, 0x07, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xA1, 0x07, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, - 0xDC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x08, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0x08, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x5C, 0x08, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x08, 0x00, 0x00, - 0xF4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x79, 0x08, 0x00, 0x00, + 0xE8, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x82, 0x08, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8A, 0x08, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x97, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9F, 0x08, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x08, 0x00, 0x00, - 0x08, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x08, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xCC, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xED, 0x08, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x08, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x09, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x22, 0x09, 0x00, 0x00, + 0x18, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x60, 0x09, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x09, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x79, 0x09, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x09, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x09, 0x00, 0x00, - 0xA0, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC8, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x09, 0x00, 0x00, + 0x50, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xEC, 0x09, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD1, 0x09, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x0A, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x66, - 0x6C, 0x61, 0x67, 0x73, 0x00, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x00, 0xAB, - 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x44, 0x0A, 0x00, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x62, 0x0A, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, + 0x00, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x00, 0xAB, 0x00, 0x00, 0x13, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x05, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x74, 0x65, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x61, 0x74, - 0x69, 0x6F, 0x6E, 0x5F, 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x5F, 0x72, - 0x61, 0x6E, 0x67, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x32, 0x00, - 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC1, 0x05, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, + 0x65, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x5F, + 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, + 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x32, 0x00, 0x01, 0x00, 0x03, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x05, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x6C, 0x69, 0x6E, 0x65, 0x5F, 0x6C, 0x6F, 0x6F, 0x70, - 0x5F, 0x63, 0x6C, 0x6F, 0x73, 0x69, 0x6E, 0x67, 0x5F, 0x69, 0x6E, 0x64, - 0x65, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, - 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x65, 0x6E, 0x64, 0x69, 0x61, - 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, - 0x62, 0x61, 0x73, 0x65, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x69, - 0x6E, 0x74, 0x00, 0xAB, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6C, + 0x69, 0x6E, 0x65, 0x5F, 0x6C, 0x6F, 0x6F, 0x70, 0x5F, 0x63, 0x6C, 0x6F, + 0x73, 0x69, 0x6E, 0x67, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x78, + 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, + 0x65, 0x78, 0x5F, 0x65, 0x6E, 0x64, 0x69, 0x61, 0x6E, 0x00, 0x78, 0x65, + 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, + 0x78, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, + 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, + 0x5F, 0x6D, 0x69, 0x6E, 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x75, 0x69, 0x6E, + 0x74, 0x32, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2B, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, - 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, - 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x6D, 0x69, 0x6E, 0x5F, - 0x6D, 0x61, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, - 0x5F, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6E, 0x5F, 0x74, 0x6F, 0x5F, 0x6E, - 0x64, 0x63, 0x00, 0x78, 0x65, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, 0x63, - 0x6C, 0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x00, 0x66, - 0x6C, 0x6F, 0x61, 0x74, 0x34, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, + 0x95, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, + 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x00, + 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x34, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x33, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xDD, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72, - 0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x5F, 0x73, 0x61, 0x6D, 0x70, - 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, - 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x6F, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x73, 0x5F, 0x70, 0x61, 0x72, - 0x61, 0x6D, 0x5F, 0x67, 0x65, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, - 0x78, 0x74, 0x75, 0x72, 0x65, 0x5F, 0x73, 0x77, 0x69, 0x7A, 0x7A, 0x6C, - 0x65, 0x64, 0x5F, 0x73, 0x69, 0x67, 0x6E, 0x73, 0x00, 0x75, 0x69, 0x6E, - 0x74, 0x34, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x0D, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, + 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x78, 0x00, 0x66, 0x6C, 0x6F, 0x61, + 0x74, 0x00, 0xAB, 0xAB, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x6F, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, + 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x79, 0x00, 0x78, 0x65, + 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, + 0x6D, 0x69, 0x6E, 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x70, + 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6E, 0x5F, + 0x74, 0x6F, 0x5F, 0x6E, 0x64, 0x63, 0x00, 0x78, 0x65, 0x5F, 0x69, 0x6E, + 0x74, 0x65, 0x72, 0x70, 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x5F, 0x73, + 0x61, 0x6D, 0x70, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x73, 0x5F, 0x70, 0x61, + 0x72, 0x61, 0x6D, 0x5F, 0x67, 0x65, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x73, + 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5F, + 0x6C, 0x6F, 0x67, 0x32, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, + 0x75, 0x72, 0x65, 0x5F, 0x73, 0x77, 0x69, 0x7A, 0x7A, 0x6C, 0x65, 0x64, + 0x5F, 0x73, 0x69, 0x67, 0x6E, 0x73, 0x00, 0x75, 0x69, 0x6E, 0x74, 0x34, + 0x00, 0xAB, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, + 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x73, 0x5F, 0x72, 0x65, 0x73, 0x6F, 0x6C, 0x76, 0x65, 0x64, - 0x00, 0x78, 0x65, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, - 0x6F, 0x75, 0x6E, 0x74, 0x5F, 0x6C, 0x6F, 0x67, 0x32, 0x00, 0x75, 0x69, - 0x6E, 0x74, 0x32, 0x00, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x65, + 0x73, 0x74, 0x5F, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, + 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x6F, + 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, + 0x61, 0x6D, 0x5F, 0x70, 0x69, 0x74, 0x63, 0x68, 0x5F, 0x74, 0x69, 0x6C, + 0x65, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, + 0x65, 0x78, 0x70, 0x5F, 0x62, 0x69, 0x61, 0x73, 0x00, 0xAB, 0xAB, 0xAB, + 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xB6, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, - 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6E, 0x63, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x00, 0xAB, 0xAB, - 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, 0x65, 0x78, 0x70, - 0x5F, 0x62, 0x69, 0x61, 0x73, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, - 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, - 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x6F, 0x5F, 0x6D, 0x61, 0x73, 0x6B, - 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x69, - 0x74, 0x63, 0x68, 0x5F, 0x74, 0x69, 0x6C, 0x65, 0x73, 0x00, 0x78, 0x65, - 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, 0x74, 0x68, - 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, - 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x5F, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x00, 0x78, 0x65, - 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, - 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x62, 0x61, 0x63, 0x6B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, - 0x74, 0x68, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, 0x72, - 0x64, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, - 0x73, 0x74, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x00, 0x01, 0x00, 0x13, 0x00, - 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, - 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x61, 0x73, 0x65, - 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x5F, 0x73, 0x63, 0x61, 0x6C, - 0x65, 0x64, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, - 0x5F, 0x72, 0x74, 0x5F, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x66, - 0x6C, 0x61, 0x67, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, - 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x63, 0x6C, 0x61, 0x6D, 0x70, 0x00, 0xAB, - 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, - 0x6B, 0x65, 0x65, 0x70, 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0xAB, 0xAB, + 0x74, 0x68, 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x00, 0x78, 0x65, 0x5F, + 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x00, + 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, + 0x79, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, 0x62, 0x61, 0x63, + 0x6B, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, + 0x6F, 0x72, 0x64, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, + 0x6D, 0x5F, 0x73, 0x74, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, - 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, - 0x73, 0x5F, 0x6F, 0x70, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, - 0x61, 0x6D, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x63, 0x6F, 0x6E, - 0x73, 0x74, 0x61, 0x6E, 0x74, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, - 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, - 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, - 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0xAB, 0xAB, - 0x49, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, - 0x49, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, + 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x5F, + 0x73, 0x63, 0x61, 0x6C, 0x65, 0x64, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, + 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x74, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, 0x00, 0x78, 0x65, 0x5F, + 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x63, 0x6C, 0x61, + 0x6D, 0x70, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, + 0x5F, 0x72, 0x74, 0x5F, 0x6B, 0x65, 0x65, 0x70, 0x5F, 0x6D, 0x61, 0x73, + 0x6B, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, + 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x66, 0x61, + 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x6F, 0x70, 0x73, 0x00, 0x78, 0x65, + 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, + 0x5F, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x00, 0x4D, 0x69, + 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, + 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, + 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, + 0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, - 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, 0x50, 0x43, 0x53, 0x47, - 0xBC, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x58, 0x45, 0x56, 0x45, + 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, 0x4F, 0x53, 0x47, 0x4E, + 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0xA6, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, - 0x53, 0x56, 0x5F, 0x54, 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, - 0x72, 0x00, 0x53, 0x56, 0x5F, 0x49, 0x6E, 0x73, 0x69, 0x64, 0x65, 0x54, - 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x00, 0xAB, 0xAB, - 0x53, 0x48, 0x45, 0x58, 0x64, 0x01, 0x00, 0x00, 0x51, 0x00, 0x03, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x01, 0x93, 0x20, 0x00, 0x01, - 0x94, 0x20, 0x00, 0x01, 0x95, 0x18, 0x00, 0x01, 0x96, 0x08, 0x00, 0x01, - 0x97, 0x18, 0x00, 0x01, 0x6A, 0x08, 0x00, 0x01, 0x59, 0x00, 0x00, 0x07, - 0x46, 0x8E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x73, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, - 0x5F, 0x00, 0x00, 0x02, 0x00, 0x70, 0x01, 0x00, 0x67, 0x00, 0x00, 0x04, - 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0C, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, - 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x58, 0x45, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x49, 0x44, 0x00, 0xAB, + 0x50, 0x43, 0x53, 0x47, 0xBC, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x0E, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x65, 0x73, 0x73, 0x46, + 0x61, 0x63, 0x74, 0x6F, 0x72, 0x00, 0x53, 0x56, 0x5F, 0x49, 0x6E, 0x73, + 0x69, 0x64, 0x65, 0x54, 0x65, 0x73, 0x73, 0x46, 0x61, 0x63, 0x74, 0x6F, + 0x72, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x45, 0x58, 0x64, 0x01, 0x00, 0x00, + 0x51, 0x00, 0x03, 0x00, 0x59, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x01, + 0x93, 0x20, 0x00, 0x01, 0x94, 0x20, 0x00, 0x01, 0x95, 0x18, 0x00, 0x01, + 0x96, 0x08, 0x00, 0x01, 0x97, 0x18, 0x00, 0x01, 0x6A, 0x08, 0x00, 0x01, + 0x59, 0x00, 0x00, 0x07, 0x46, 0x8E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x02, + 0x04, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x02, 0x00, 0x70, 0x01, 0x00, + 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, + 0x12, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x5B, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x04, 0x12, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x70, 0x01, 0x00, 0x36, 0x00, 0x00, 0x08, + 0x12, 0x20, 0x90, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, + 0x99, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x02, + 0x00, 0x70, 0x01, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, + 0x12, 0x20, 0x10, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x04, - 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x12, 0x20, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x04, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x70, 0x01, 0x00, 0x36, 0x00, 0x00, 0x08, 0x12, 0x20, 0x90, 0x00, - 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x80, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x00, 0x00, 0x01, 0x73, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x02, - 0x02, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x02, 0x00, 0x70, 0x01, 0x00, - 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, - 0x01, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x04, 0x12, 0x20, 0x10, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x04, - 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x70, 0x01, 0x00, - 0x36, 0x00, 0x00, 0x09, 0x12, 0x20, 0xD0, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x80, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x94, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x70, 0x01, 0x00, 0x36, 0x00, 0x00, 0x09, 0x12, 0x20, 0xD0, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, + 0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.txt b/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.txt index c996f805f..77bd70bd1 100644 --- a/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.txt +++ b/src/xenia/gpu/d3d12/shaders/dxbc/discrete_quad_hs.txt @@ -11,26 +11,28 @@ // float2 xe_tessellation_factor_range;// Offset: 4 Size: 8 // uint xe_line_loop_closing_index; // Offset: 12 Size: 4 [unused] // uint xe_vertex_index_endian; // Offset: 16 Size: 4 [unused] -// int xe_vertex_base_index; // Offset: 20 Size: 4 [unused] -// float2 xe_point_size; // Offset: 24 Size: 8 [unused] -// float2 xe_point_size_min_max; // Offset: 32 Size: 8 [unused] -// float2 xe_point_screen_to_ndc; // Offset: 40 Size: 8 [unused] -// float4 xe_user_clip_planes[6]; // Offset: 48 Size: 96 [unused] -// float3 xe_ndc_scale; // Offset: 144 Size: 12 [unused] -// uint xe_interpolator_sampling_pattern;// Offset: 156 Size: 4 [unused] -// float3 xe_ndc_offset; // Offset: 160 Size: 12 [unused] -// uint xe_ps_param_gen; // Offset: 172 Size: 4 [unused] -// uint4 xe_texture_swizzled_signs[2];// Offset: 176 Size: 32 [unused] -// uint xe_textures_resolved; // Offset: 208 Size: 4 [unused] -// uint2 xe_sample_count_log2; // Offset: 212 Size: 8 [unused] -// float xe_alpha_test_reference; // Offset: 220 Size: 4 [unused] -// float4 xe_color_exp_bias; // Offset: 224 Size: 16 [unused] -// uint xe_alpha_to_mask; // Offset: 240 Size: 4 [unused] -// uint xe_edram_pitch_tiles; // Offset: 244 Size: 4 [unused] -// float2 xe_edram_depth_range; // Offset: 248 Size: 8 [unused] -// float2 xe_edram_poly_offset_front; // Offset: 256 Size: 8 [unused] -// float2 xe_edram_poly_offset_back; // Offset: 264 Size: 8 [unused] -// uint xe_edram_depth_base_dwords; // Offset: 272 Size: 4 [unused] +// uint xe_vertex_index_offset; // Offset: 20 Size: 4 [unused] +// uint2 xe_vertex_index_min_max; // Offset: 24 Size: 8 [unused] +// float4 xe_user_clip_planes[6]; // Offset: 32 Size: 96 [unused] +// float3 xe_ndc_scale; // Offset: 128 Size: 12 [unused] +// float xe_point_size_x; // Offset: 140 Size: 4 [unused] +// float3 xe_ndc_offset; // Offset: 144 Size: 12 [unused] +// float xe_point_size_y; // Offset: 156 Size: 4 [unused] +// float2 xe_point_size_min_max; // Offset: 160 Size: 8 [unused] +// float2 xe_point_screen_to_ndc; // Offset: 168 Size: 8 [unused] +// uint xe_interpolator_sampling_pattern;// Offset: 176 Size: 4 [unused] +// uint xe_ps_param_gen; // Offset: 180 Size: 4 [unused] +// uint2 xe_sample_count_log2; // Offset: 184 Size: 8 [unused] +// uint4 xe_texture_swizzled_signs[2];// Offset: 192 Size: 32 [unused] +// uint xe_textures_resolved; // Offset: 224 Size: 4 [unused] +// float xe_alpha_test_reference; // Offset: 228 Size: 4 [unused] +// uint xe_alpha_to_mask; // Offset: 232 Size: 4 [unused] +// uint xe_edram_pitch_tiles; // Offset: 236 Size: 4 [unused] +// float4 xe_color_exp_bias; // Offset: 240 Size: 16 [unused] +// float2 xe_edram_depth_range; // Offset: 256 Size: 8 [unused] +// float2 xe_edram_poly_offset_front; // Offset: 264 Size: 8 [unused] +// float2 xe_edram_poly_offset_back; // Offset: 272 Size: 8 [unused] +// uint xe_edram_depth_base_dwords; // Offset: 280 Size: 4 [unused] // uint4 xe_edram_stencil[2]; // Offset: 288 Size: 32 [unused] // uint4 xe_edram_rt_base_dwords_scaled;// Offset: 320 Size: 16 [unused] // uint4 xe_edram_rt_format_flags; // Offset: 336 Size: 16 [unused] diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/discrete_triangle_hs.cso b/src/xenia/gpu/d3d12/shaders/dxbc/discrete_triangle_hs.cso index fa5efe8494981909b0a89a5f372b30409959e729..94b81f710bc36e4b9874df9720c2bf812e0d1ace 100644 GIT binary patch delta 1191 zcmaizPiPZC6vp3Xll@a0XlQFXtn^|K+EOB=Mk81>cv3IhZMrD|^M@pAT9j%p z7V%&ly+y5}P{^fV4mk)-Z{k4|dQk8XAqNjB)VrYHY!X-!N*_FC-*3P9=FQCR*3kNJ zFm!$PeE8+kJtOeG{C0bKEmIx;C=k)Qn@GYqiLCb!`Hm3HA#2D+FVVHog^TYB!C_&g za3gxs57kp-jZbYw#npUpw(3uXUtUiGkOKwjK=!eRg4c5vE5XxxgMlpRRlvSZ7y}&W zg!ch`fZUWv(K4-qYN+OsJbrSzN;1&{RD3xe1E_iYL)gbj@FxK6?jr~2a^QUDhxx5R zS0oA?YWNJo4H&jJ(>$R~(9JHo4Y~!|ZjzrHi-=BlxdVFkp{&^EH;>4LMXI10lE*1# zh+fYeXbqL!b; zsG{P17aaxlf!f>m1OYWb%`zp5us=?(CkHwM+HT>wMJu3@F8U309(1PVQ0Lky1;54y zXxmpq&7<>k3V~O-Tw!5{{cwdHs>DX6bK~*kqM6rIu~^p3QQp+=n3)_v z6DQ(HJz?bOc08F2P>KDOHSvW+?29zQ8j>dLGPgX@@5bF@W;z9xo{g`VdY(-vWByA` zo?MLD{B5db_C`9xF3bMjbXHFr86%-DnMqcYkFrOyUoDjc>L-DmOi+$Fjw|f5Jj6~Y zgRH2G4MtP9QW@RMr}c%nk);wBi)>XL5qHtwj&iqq`b~9~yS!4bpzl3(8pVgxJ(Bnz D6pQn0 delta 993 zcmZY7L1@!p6bJB^rcKgnp%JmR6_yPLn;xuASV1eJcJ?A7vV($T#zc zMOQz;%MO(uJamUrK@>dnDB__5j}tZ+=)r@+ka}_czpRC(d+jG5w($f$np`Qmq&?iC1p%_)(uHhu+y!E!eF6uvJNJQsVLXAAjt^jzZ3;nk z4tf&Ghw`w8&I2_R4lDsDhVeNt3QQw;Y}i9PQ2t1KF&?|NDl*YJD#t@j0&75L>ojy@ zxHScA0yQL$B{u2`sugGlm1F8_;8$S(0Y3897oyw0HPA`S5QFMz^lU=|NFFg;??Qi} za!g$Y?hWHAunWY&4*L&$#Vfo|2ewct!}tXl06K2;9jF1dgOSv=cRJ-Int}E=z07{Q zgK8Rj^N>Du zq4g$27`hpCD^W`&(HlF_x`*gWS9i~gY-_DB znY|in@FC(MkK$=1Tj8m&isD8aB5N0`ouHh^CF+o}-;Oz(BqEzJHv6^O*$?O_hhe~~ zGN?`gx&ik^=eel53hD(N!s7O&K*>Th4UZqkt;)hC3+OF~VhRdBEDhQLx?jTM0$l+eI7B~!4uN)*6t)YoGCtk~ z(0yI6mFsqau9hn}Z-9O<&}B9&_6lq4lh|ugBvvQ2pN_w7cyRXYRsGH z;;lTvOjf_CUS`*n0NsPxjpO89a-|KdWYP*!=$)kD=pF%B?h(bbCs9l0nnTF1n737%sIipUcH= XyKI7W>7MJgB22JuPrqPdbDqw>F|90%~Joi~5FvAt$=owmaa3HaL~1&H@{OLkK>WcvW8(%J0Na#>bAmmm(9*VdcD) z?=)~8Se)7lT`EoO1Fir=2tLMSeuEik7OSGFPk|qShwthwPxa-XpB<^Ba6N^j9Mp^8 zqm8RJ2>pqbv#d4_{9TIof%`yA_OSc%gs;%iB7A|BQi|_^UZ8U$-*;dL7|NHVefy-x zRH82E;YmAHe*Pio^&(}i(xzW@)u+N?v{*p|Cb zxWnqDKG$nEOGp>|!(q$NV~MDdrdT3Hi}-}ttQ^$NqWx(@PnuBOirqEXhTOysq-xKi zKq3jatHi!Y0bzl)%dO&;MC`9zUz3PNbaQ0HGE(-_mYxhxgva$!Bf+|qIyR$*TEpld zDyNKeYI4G`bc7k7GNK%<@OUzA=n-=gyT;AYW}3wQ&DhS*`lX=wN+vd^RI>+iL*;(H zPQ;9x6S|R3>cg?HMQm586Blrrm&zFyP%XZtD=f2RwVO|S>NTABqNf9k)q9?9x0*dl zbOZlQimjK|3gYV5azi{m>AYFZSG>tV%+?PO@(pu6fO-8*(jhM7|@0>pfuy; Mk3zze-w34u042{J9smFU delta 776 zcmcJMy-LJD6ot=BHk--%!w|Kxa1#qfZPq0SLJ(1L5iGQ`)k^Hd#$qAZYUvAXWiPQ2 z`~jc9!ot=^a4SpiHFMp(KmwP0a&l(AJCl#(eWAN^w6*a*YTo)v(D zDZrjOJ(PABFo6tL*p!Nld?m4-_D(nY)ATI z*N2AZejFXXcxm?Gt3P9R&9|{T5)o}T6UmtSFgC(Otp|ukG2-wmv2*8Nmir^pO!;cE zCyIBnpllvaD4NWLPWQ*;^R14L!5gWdLOI$1>&B%P;P5)?i_Ss zU+!b*BD8)7uQ6i@y40xpd+2Ll1+TLWV6_2_9pJKWf2}hahpa$N431+e|B0i}4Xo-t za8)A#-1K2QBz`xwwLrIg>RsR-aJvDG7r-4LKLkgWk21bO32)64N3GdkSgQL})$n_x z>fO+G=$^}-1)4z9D~biwMACPhZ^te1TsbL5LeXfxVC552iL5ng=eTSkkyLFin&m?R^j`Q zL`_0cI@-JNUP#5=-Qtv8urQp=v^^mrYKM5L9v4YfSFt1L?T9va1lQ2TJN2drgu4S> Ys<@^N@$^g^Lr*`oGg!Ro3Fm_U01<}PoB#j- delta 1026 zcmZ9~Pe>F|90%~;f3U=0TGm{o+!RlfXs1#vl?L{i0phGZ@yQ40wGpn;3OF;+e zU?AA?1TT9qJSrj?LEyn|9t!r*v6T&kAS5I_EM4sT8#QM9!H>uL@O!`a-n`jun{VqI zd^&LF*XQ-2t(RNV#W#C1li3A1L`3svh{71JBWEH+8_0cR<22Eu!Mpc{%6)C2j`EXq z@**nUBI~^DD8_jy;?&_lrE)EW3bm^rpt=ABH{*s92TaI&>J?f7D^tt6hUGLXZ1yLA}z=Km+~&5&W%HpZ1DcI2D={ zNjcT@DJ*RHR`ZDIT1M8+SS8BZ1zN^`Ddv=R{VJZnWEpt}YPi`KmiVe%69;l@WI03< zg>Y9{{E*|JCDEt!NHv+nUnP0o&ZG@zbkwy9-fGv#n^We5F=pAKU+oaHTB66q3!-zu zDiw-TmTMrL+;c0#=$aGxoMoh)B6iI=W8GB5{@vKFSv-*2rH=}UirOk(E1fNk!#-&z y=S&$^DQ}EqO_#)PwL@CMX+Ee|L|k)u%O+D1tJ(k$f3*8J@$JYBOx9mTZ0R3}NXr@k diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_adaptive_vs.h b/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_adaptive_vs.h index 168e23419..a2567ef54 100644 --- a/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_adaptive_vs.h +++ b/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_adaptive_vs.h @@ -1,14 +1,14 @@ // generated from `xb buildhlsl` // source: tessellation_adaptive.vs.hlsl const uint8_t tessellation_adaptive_vs[] = { - 0x44, 0x58, 0x42, 0x43, 0xEA, 0xC1, 0xB3, 0x4C, 0xC8, 0x7B, 0xC8, 0x82, - 0x75, 0x89, 0xF0, 0x88, 0x71, 0x69, 0x97, 0x06, 0x01, 0x00, 0x00, 0x00, - 0x94, 0x0D, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x88, 0x0A, 0x00, 0x00, 0xBC, 0x0A, 0x00, 0x00, 0xF4, 0x0A, 0x00, 0x00, - 0xF8, 0x0C, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x4C, 0x0A, 0x00, 0x00, + 0x44, 0x58, 0x42, 0x43, 0x82, 0xE6, 0x23, 0x43, 0x49, 0x4A, 0x7D, 0x8F, + 0xAF, 0xF1, 0x4E, 0x88, 0x20, 0xB6, 0x44, 0x86, 0x01, 0x00, 0x00, 0x00, + 0xEC, 0x0D, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0xE0, 0x0A, 0x00, 0x00, 0x14, 0x0B, 0x00, 0x00, 0x4C, 0x0B, 0x00, 0x00, + 0x50, 0x0D, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xA4, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x05, 0xFE, 0xFF, 0x00, 0x05, 0x00, 0x00, - 0x22, 0x0A, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, 0x3C, 0x00, 0x00, 0x00, + 0x7A, 0x0A, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, 0x3C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -16,279 +16,286 @@ const uint8_t tessellation_adaptive_vs[] = { 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x5F, 0x63, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x00, 0xAB, 0xAB, - 0x64, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xB8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xEC, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x05, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x34, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0x05, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4F, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x06, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x54, 0x06, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x9C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x62, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x06, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x06, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xAC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, + 0x8C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xD0, 0x06, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x74, 0x07, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x07, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x29, 0x07, 0x00, 0x00, - 0xA0, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xE4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x92, 0x07, 0x00, 0x00, + 0xA0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x37, 0x07, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA8, 0x07, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x07, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xBF, 0x07, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x07, 0x00, 0x00, - 0xD0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, + 0xB4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xA1, 0x07, 0x00, 0x00, 0xD4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xBC, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0x07, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x00, 0x00, - 0xE0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x08, 0x00, 0x00, + 0xE0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x5C, 0x08, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x61, 0x08, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x6D, 0x08, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x79, 0x08, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x82, 0x08, 0x00, 0x00, - 0xF8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x08, 0x00, 0x00, + 0xEC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x97, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9F, 0x08, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xB2, 0x08, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD8, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x08, 0x00, 0x00, - 0x10, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xED, 0x08, 0x00, 0x00, + 0x08, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xE7, 0x08, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x09, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x1C, 0x09, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x22, 0x09, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, - 0x50, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x09, 0x00, 0x00, + 0x20, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x09, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x74, 0x09, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xB0, 0x09, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB8, 0x09, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x09, 0x00, 0x00, - 0xC0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3C, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x09, 0x00, 0x00, + 0x60, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE4, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x0A, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x0A, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, - 0x00, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x00, 0xAB, 0x00, 0x00, 0x13, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x0A, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x62, 0x0A, 0x00, 0x00, + 0xD0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xB4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, 0x00, 0x64, 0x77, 0x6F, + 0x72, 0x64, 0x00, 0xAB, 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x71, 0x05, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, - 0x65, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x5F, - 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, - 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x32, 0x00, 0x01, 0x00, 0x03, 0x00, - 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xB9, 0x05, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6C, - 0x69, 0x6E, 0x65, 0x5F, 0x6C, 0x6F, 0x6F, 0x70, 0x5F, 0x63, 0x6C, 0x6F, - 0x73, 0x69, 0x6E, 0x67, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x78, - 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, - 0x65, 0x78, 0x5F, 0x65, 0x6E, 0x64, 0x69, 0x61, 0x6E, 0x00, 0x78, 0x65, - 0x5F, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5F, 0x62, 0x61, 0x73, 0x65, - 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x69, 0x6E, 0x74, 0x00, 0xAB, - 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC1, 0x05, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x73, 0x73, 0x65, + 0x6C, 0x6C, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x5F, 0x66, 0x61, 0x63, 0x74, + 0x6F, 0x72, 0x5F, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x00, 0x66, 0x6C, 0x6F, + 0x61, 0x74, 0x32, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x06, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, - 0x65, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, - 0x69, 0x7A, 0x65, 0x5F, 0x6D, 0x69, 0x6E, 0x5F, 0x6D, 0x61, 0x78, 0x00, - 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x63, 0x72, - 0x65, 0x65, 0x6E, 0x5F, 0x74, 0x6F, 0x5F, 0x6E, 0x64, 0x63, 0x00, 0x78, - 0x65, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, 0x63, 0x6C, 0x69, 0x70, 0x5F, - 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, - 0x34, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6C, 0x69, 0x6E, 0x65, 0x5F, + 0x6C, 0x6F, 0x6F, 0x70, 0x5F, 0x63, 0x6C, 0x6F, 0x73, 0x69, 0x6E, 0x67, + 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, + 0x72, 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x65, + 0x6E, 0x64, 0x69, 0x61, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x6F, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x65, 0x72, 0x74, + 0x65, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 0x6D, 0x69, 0x6E, + 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x75, 0x69, 0x6E, 0x74, 0x32, 0x00, 0xAB, + 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x06, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, 0x63, 0x6C, 0x69, 0x70, + 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x73, 0x00, 0x66, 0x6C, 0x6F, 0x61, + 0x74, 0x34, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x73, + 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x33, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x06, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x6F, 0x6C, 0x61, - 0x74, 0x6F, 0x72, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x69, 0x6E, 0x67, - 0x5F, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, 0x00, 0x78, 0x65, 0x5F, - 0x6E, 0x64, 0x63, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x78, - 0x65, 0x5F, 0x70, 0x73, 0x5F, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x5F, 0x67, - 0x65, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, - 0x65, 0x5F, 0x73, 0x77, 0x69, 0x7A, 0x7A, 0x6C, 0x65, 0x64, 0x5F, 0x73, - 0x69, 0x67, 0x6E, 0x73, 0x00, 0x75, 0x69, 0x6E, 0x74, 0x34, 0x00, 0xAB, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x07, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, + 0x65, 0x5F, 0x78, 0x00, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x00, 0xAB, 0xAB, + 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x07, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x6E, 0x64, 0x63, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x5F, 0x73, + 0x69, 0x7A, 0x65, 0x5F, 0x79, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, + 0x6E, 0x74, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x6D, 0x69, 0x6E, 0x5F, + 0x6D, 0x61, 0x78, 0x00, 0x78, 0x65, 0x5F, 0x70, 0x6F, 0x69, 0x6E, 0x74, + 0x5F, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6E, 0x5F, 0x74, 0x6F, 0x5F, 0x6E, + 0x64, 0x63, 0x00, 0x78, 0x65, 0x5F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x70, + 0x6F, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, + 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, 0x00, + 0x78, 0x65, 0x5F, 0x70, 0x73, 0x5F, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x5F, + 0x67, 0x65, 0x6E, 0x00, 0x78, 0x65, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, + 0x65, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5F, 0x6C, 0x6F, 0x67, 0x32, + 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x5F, + 0x73, 0x77, 0x69, 0x7A, 0x7A, 0x6C, 0x65, 0x64, 0x5F, 0x73, 0x69, 0x67, + 0x6E, 0x73, 0x00, 0x75, 0x69, 0x6E, 0x74, 0x34, 0x00, 0xAB, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x73, 0x5F, 0x72, 0x65, 0x73, 0x6F, 0x6C, 0x76, 0x65, 0x64, 0x00, 0x78, 0x65, 0x5F, - 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x5F, 0x63, 0x6F, 0x75, 0x6E, 0x74, - 0x5F, 0x6C, 0x6F, 0x67, 0x32, 0x00, 0x75, 0x69, 0x6E, 0x74, 0x32, 0x00, - 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, 0x00, 0x78, 0x65, 0x5F, + 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x6F, 0x5F, 0x6D, 0x61, 0x73, + 0x6B, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, + 0x69, 0x74, 0x63, 0x68, 0x5F, 0x74, 0x69, 0x6C, 0x65, 0x73, 0x00, 0x78, + 0x65, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x5F, 0x65, 0x78, 0x70, 0x5F, + 0x62, 0x69, 0x61, 0x73, 0x00, 0xAB, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x07, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x5F, 0x74, 0x65, 0x73, - 0x74, 0x5F, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, 0x00, - 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x00, 0xAB, 0xAB, 0x00, 0x00, 0x03, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x63, - 0x6F, 0x6C, 0x6F, 0x72, 0x5F, 0x65, 0x78, 0x70, 0x5F, 0x62, 0x69, 0x61, - 0x73, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, 0x6C, 0x70, 0x68, 0x61, - 0x5F, 0x74, 0x6F, 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0x78, 0x65, 0x5F, - 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x69, 0x74, 0x63, 0x68, 0x5F, - 0x74, 0x69, 0x6C, 0x65, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, - 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, 0x74, 0x68, 0x5F, 0x72, 0x61, 0x6E, - 0x67, 0x65, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, - 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5F, - 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, - 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x5F, 0x62, 0x61, 0x63, 0x6B, 0x00, 0x78, 0x65, 0x5F, 0x65, - 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, 0x74, 0x68, 0x5F, 0x62, - 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x00, 0x78, - 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x73, 0x74, 0x65, 0x6E, - 0x63, 0x69, 0x6C, 0x00, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, - 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, - 0x72, 0x64, 0x73, 0x5F, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x64, 0x00, 0xAB, - 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, - 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, - 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x66, 0x6C, 0x61, 0x67, 0x73, - 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, - 0x5F, 0x63, 0x6C, 0x61, 0x6D, 0x70, 0x00, 0xAB, 0x01, 0x00, 0x03, 0x00, - 0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xA3, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, - 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x6B, 0x65, 0x65, 0x70, - 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD4, 0x06, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, + 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, 0x74, 0x68, 0x5F, 0x72, + 0x61, 0x6E, 0x67, 0x65, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, + 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x5F, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x00, 0x78, 0x65, 0x5F, 0x65, + 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x70, 0x6F, 0x6C, 0x79, 0x5F, 0x6F, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x5F, 0x62, 0x61, 0x63, 0x6B, 0x00, 0x78, 0x65, + 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x64, 0x65, 0x70, 0x74, 0x68, + 0x5F, 0x62, 0x61, 0x73, 0x65, 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, + 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x73, 0x74, + 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x00, 0xAB, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x61, 0x07, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, - 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x6C, 0x65, 0x6E, - 0x64, 0x5F, 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x5F, 0x6F, 0x70, - 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x62, - 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, - 0x74, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, - 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, - 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, - 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E, - 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, - 0x53, 0x56, 0x5F, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x49, 0x44, 0x00, - 0x4F, 0x53, 0x47, 0x4E, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, + 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x62, 0x61, 0x73, 0x65, + 0x5F, 0x64, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x5F, 0x73, 0x63, 0x61, 0x6C, + 0x65, 0x64, 0x00, 0xAB, 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x08, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, + 0x5F, 0x72, 0x74, 0x5F, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x66, + 0x6C, 0x61, 0x67, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, + 0x6D, 0x5F, 0x72, 0x74, 0x5F, 0x63, 0x6C, 0x61, 0x6D, 0x70, 0x00, 0xAB, + 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x06, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, + 0x6B, 0x65, 0x65, 0x70, 0x5F, 0x6D, 0x61, 0x73, 0x6B, 0x00, 0xAB, 0xAB, + 0x01, 0x00, 0x13, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, 0x61, 0x6D, 0x5F, 0x72, 0x74, 0x5F, + 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x66, 0x61, 0x63, 0x74, 0x6F, 0x72, + 0x73, 0x5F, 0x6F, 0x70, 0x73, 0x00, 0x78, 0x65, 0x5F, 0x65, 0x64, 0x72, + 0x61, 0x6D, 0x5F, 0x62, 0x6C, 0x65, 0x6E, 0x64, 0x5F, 0x63, 0x6F, 0x6E, + 0x73, 0x74, 0x61, 0x6E, 0x74, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, + 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, + 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, + 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0xAB, 0xAB, + 0x49, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x0E, 0x00, 0x00, 0x58, 0x45, 0x54, 0x45, 0x53, 0x53, 0x46, 0x41, - 0x43, 0x54, 0x4F, 0x52, 0x00, 0xAB, 0xAB, 0xAB, 0x53, 0x48, 0x45, 0x58, - 0xFC, 0x01, 0x00, 0x00, 0x51, 0x00, 0x01, 0x00, 0x7F, 0x00, 0x00, 0x00, - 0x6A, 0x08, 0x00, 0x01, 0x59, 0x00, 0x00, 0x07, 0x46, 0x8E, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x04, - 0x12, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x03, 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x0C, - 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x07, - 0x32, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x05, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x00, 0x04, 0x03, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x29, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x07, 0x42, 0x00, 0x10, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x56, 0x65, 0x72, 0x74, 0x65, + 0x78, 0x49, 0x44, 0x00, 0x4F, 0x53, 0x47, 0x4E, 0x30, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, 0x58, 0x45, 0x54, 0x45, + 0x53, 0x53, 0x46, 0x41, 0x43, 0x54, 0x4F, 0x52, 0x00, 0xAB, 0xAB, 0xAB, + 0x53, 0x48, 0x45, 0x58, 0xFC, 0x01, 0x00, 0x00, 0x51, 0x00, 0x01, 0x00, + 0x7F, 0x00, 0x00, 0x00, 0x6A, 0x08, 0x00, 0x01, 0x59, 0x00, 0x00, 0x07, + 0x46, 0x8E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x04, 0x12, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x12, 0x20, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x0C, 0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0x07, 0x32, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x96, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x04, 0x03, 0x0A, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0A, - 0x52, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1E, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x01, 0x36, 0x00, 0x00, 0x05, - 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x10, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x01, 0x1F, 0x00, 0x04, 0x03, - 0x1A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x07, - 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x8C, 0x00, 0x00, 0x0B, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x07, + 0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x0A, 0x52, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x01, + 0x36, 0x00, 0x00, 0x05, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x01, + 0x1F, 0x00, 0x04, 0x03, 0x1A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x00, 0x00, 0x07, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x3F, 0x34, 0x00, 0x00, 0x09, 0x12, 0x00, 0x10, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x0B, 0x12, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x01, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x09, 0x12, 0x20, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, - 0x94, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x34, 0x00, 0x00, 0x09, + 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x09, + 0x12, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2A, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, + 0x53, 0x54, 0x41, 0x54, 0x94, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_adaptive_vs.txt b/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_adaptive_vs.txt index a9c34dff1..f2f47f9b2 100644 --- a/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_adaptive_vs.txt +++ b/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_adaptive_vs.txt @@ -11,26 +11,28 @@ // float2 xe_tessellation_factor_range;// Offset: 4 Size: 8 // uint xe_line_loop_closing_index; // Offset: 12 Size: 4 [unused] // uint xe_vertex_index_endian; // Offset: 16 Size: 4 -// int xe_vertex_base_index; // Offset: 20 Size: 4 [unused] -// float2 xe_point_size; // Offset: 24 Size: 8 [unused] -// float2 xe_point_size_min_max; // Offset: 32 Size: 8 [unused] -// float2 xe_point_screen_to_ndc; // Offset: 40 Size: 8 [unused] -// float4 xe_user_clip_planes[6]; // Offset: 48 Size: 96 [unused] -// float3 xe_ndc_scale; // Offset: 144 Size: 12 [unused] -// uint xe_interpolator_sampling_pattern;// Offset: 156 Size: 4 [unused] -// float3 xe_ndc_offset; // Offset: 160 Size: 12 [unused] -// uint xe_ps_param_gen; // Offset: 172 Size: 4 [unused] -// uint4 xe_texture_swizzled_signs[2];// Offset: 176 Size: 32 [unused] -// uint xe_textures_resolved; // Offset: 208 Size: 4 [unused] -// uint2 xe_sample_count_log2; // Offset: 212 Size: 8 [unused] -// float xe_alpha_test_reference; // Offset: 220 Size: 4 [unused] -// float4 xe_color_exp_bias; // Offset: 224 Size: 16 [unused] -// uint xe_alpha_to_mask; // Offset: 240 Size: 4 [unused] -// uint xe_edram_pitch_tiles; // Offset: 244 Size: 4 [unused] -// float2 xe_edram_depth_range; // Offset: 248 Size: 8 [unused] -// float2 xe_edram_poly_offset_front; // Offset: 256 Size: 8 [unused] -// float2 xe_edram_poly_offset_back; // Offset: 264 Size: 8 [unused] -// uint xe_edram_depth_base_dwords; // Offset: 272 Size: 4 [unused] +// uint xe_vertex_index_offset; // Offset: 20 Size: 4 [unused] +// uint2 xe_vertex_index_min_max; // Offset: 24 Size: 8 [unused] +// float4 xe_user_clip_planes[6]; // Offset: 32 Size: 96 [unused] +// float3 xe_ndc_scale; // Offset: 128 Size: 12 [unused] +// float xe_point_size_x; // Offset: 140 Size: 4 [unused] +// float3 xe_ndc_offset; // Offset: 144 Size: 12 [unused] +// float xe_point_size_y; // Offset: 156 Size: 4 [unused] +// float2 xe_point_size_min_max; // Offset: 160 Size: 8 [unused] +// float2 xe_point_screen_to_ndc; // Offset: 168 Size: 8 [unused] +// uint xe_interpolator_sampling_pattern;// Offset: 176 Size: 4 [unused] +// uint xe_ps_param_gen; // Offset: 180 Size: 4 [unused] +// uint2 xe_sample_count_log2; // Offset: 184 Size: 8 [unused] +// uint4 xe_texture_swizzled_signs[2];// Offset: 192 Size: 32 [unused] +// uint xe_textures_resolved; // Offset: 224 Size: 4 [unused] +// float xe_alpha_test_reference; // Offset: 228 Size: 4 [unused] +// uint xe_alpha_to_mask; // Offset: 232 Size: 4 [unused] +// uint xe_edram_pitch_tiles; // Offset: 236 Size: 4 [unused] +// float4 xe_color_exp_bias; // Offset: 240 Size: 16 [unused] +// float2 xe_edram_depth_range; // Offset: 256 Size: 8 [unused] +// float2 xe_edram_poly_offset_front; // Offset: 264 Size: 8 [unused] +// float2 xe_edram_poly_offset_back; // Offset: 272 Size: 8 [unused] +// uint xe_edram_depth_base_dwords; // Offset: 280 Size: 4 [unused] // uint4 xe_edram_stencil[2]; // Offset: 288 Size: 32 [unused] // uint4 xe_edram_rt_base_dwords_scaled;// Offset: 320 Size: 16 [unused] // uint4 xe_edram_rt_format_flags; // Offset: 336 Size: 16 [unused] diff --git a/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_indexed_vs.cso b/src/xenia/gpu/d3d12/shaders/dxbc/tessellation_indexed_vs.cso index 5273cd2607c0c90ebf26a07f259d4ff652adbbc7..21b43c45a43633ae385e20e7852845ec0823aef7 100644 GIT binary patch delta 1258 zcmZvcUr1AN6vxlqpZjNR;cla8X4`y_>ZKB)EE2KRe285Cq_^vucQV*N+_WVGB0WWd z^H&gIW3$IQ z!}ofwxFVZvyUUZ``d0ra8||Mu1tJO_CUU}e;B2{we20j7aUOe!ZiTO2dsFIc7RE|< z<82`*rnriy)ohWc!W>mcD^Aws^m{=$k!!R;ENve3c8El7v$nM1_x1rc)SwN1g~J4( z&jQs)fQ^8>C|Az#qUsW85YYe*x9HB8ItMyurQQ#qZ%q}9$+iF&EKuD8Tr}lZCv)PGCD0%ax05n|iPu555Y=bk zRn-{awh2Zh_RHaK0NpWBqk$)YyB4Uv2HXSWi{Q4vuTsB)5_ZiUH)D(HPlWOTDl2$y zrQTN1M$moDUIq*T292UbQH5Vt0PO~?xA4rMi=fd1bPaR>w7XVe+tAARcxOTDb%QQm zHw?ODt>C>6`q@Mm*rYQeEVD1ph)ogM39;);GBcr9c(2Rv9Ul5<%IwS00+*NT)#Wn%>@mx=5w zE4GAstD4MU+;p8O;~{$`o?{Uy6w2kbTx>X&)`s*9FPo30b17YmXGc&yl^tql6H=>E z=KYXB4kn0AjREWnQuJOJ8P@X}PBt~F53**tiM^0dvAFD&kzqG7e!H9O>zLxb{D9e9 zt+s&7`jsB;UMe>*(+}km587O-N(X*~H<2_s|JOAy=y;owT3es1<^^o1QmN2wBE|ab t^!VA@`izf^?)*n{(W2>R@7w{w$JX3_2``QR4PeIRX^&c(a5l*a delta 1075 zcmZA0Pe>F|90%~!yR$iKEFB7> zLxiQvJ9IHHJakY*GJ?Q^M-LSqI=W(EbPI_NQV09~#uaA$!H>uL@O!`a-n`wphMl^e z{=0pbzjvH!`f)Az`rpgvkKMOzhD1ck2vG>*Ipni2(JFEmxqh7JcK?;D*NZ*%Qgd-A z(b9y98RRxEE5|r5MN}OOR4A5W`Yez^E#n&F4iGIXEBArXG6pd6a-&8jI^n|(xwuuM z-+`Wl`kNXfz_=enVk;DjLRo%04@XLNRDxZZ!iVjz^tO{8{k*q;k8z|)Yyh@`btS8S%6dI83ixznx z@G&H^^2O>A%eBo^Hfa|qmCe%vQ9w*9je0wtzhIj=2Wq;hhqm~voE7_WZFoVVAW68Z zEWXJxX?lF_v?xwLI2oJs7OcE&ns68m>zyJ~S$ZVY} 0.0f ? xe_in[0].post_gs.pre_ps.point_params.zz - : xe_point_size; + : float2(xe_point_size_x, xe_point_size_y); point_size = clamp(point_size, xe_point_size_min_max.xx, xe_point_size_min_max.yy) * xe_point_screen_to_ndc * xe_in[0].post_gs.position.w; diff --git a/src/xenia/gpu/d3d12/shaders/primitive_quad_list.gs.hlsl b/src/xenia/gpu/d3d12/shaders/primitive_quad_list.gs.hlsl index b7d4422ac..874ee4247 100644 --- a/src/xenia/gpu/d3d12/shaders/primitive_quad_list.gs.hlsl +++ b/src/xenia/gpu/d3d12/shaders/primitive_quad_list.gs.hlsl @@ -3,15 +3,13 @@ [maxvertexcount(4)] void main(lineadj XeVertexPreGS xe_in[4], inout TriangleStream xe_stream) { - // Must kill the whole quad if need to kill. - if (max(max(xe_in[0].cull_distance, xe_in[1].cull_distance), - max(xe_in[2].cull_distance, xe_in[3].cull_distance)) < 0.0f || - any(isnan(xe_in[0].post_gs.position)) || - any(isnan(xe_in[1].post_gs.position)) || - any(isnan(xe_in[2].post_gs.position)) || - any(isnan(xe_in[3].post_gs.position))) { - return; - } + // Culling should probably be done per-triangle - while there's no + // RETAIN_QUADS on Adreno 2xx, on R6xx it's always disabled for + // non-tessellated quads, so they are always decomposed into triangles. + // Therefore, not doing any cull distance or NaN position checks here. + // TODO(Triang3l): Find whether vertex killing should actually work for each + // triangle or for the entire quad. + // TODO(Triang3l): Find the correct order. XeVertexPostGS xe_out; xe_out = xe_in[0].post_gs; xe_stream.Append(xe_out); diff --git a/src/xenia/gpu/d3d12/shaders/tessellation_adaptive.vs.hlsl b/src/xenia/gpu/d3d12/shaders/tessellation_adaptive.vs.hlsl index dc004a403..fff6c501c 100644 --- a/src/xenia/gpu/d3d12/shaders/tessellation_adaptive.vs.hlsl +++ b/src/xenia/gpu/d3d12/shaders/tessellation_adaptive.vs.hlsl @@ -3,8 +3,8 @@ XeHSControlPointInputAdaptive main(uint xe_edge_factor : SV_VertexID) { XeHSControlPointInputAdaptive output; - // The Xbox 360's GPU accepts the tessellation factors for edges through a - // special kind of an index buffer. + // The Xbox 360's GPU accepts the float32 tessellation factors for edges + // through a special kind of an index buffer. // While Viva Pinata sets the factors to 0 for frustum-culled (quad) patches, // in Halo 3 only allowing patches with factors above 0 makes distant // (triangle) patches disappear - it appears that there are no special values diff --git a/src/xenia/gpu/d3d12/shaders/tessellation_indexed.vs.hlsl b/src/xenia/gpu/d3d12/shaders/tessellation_indexed.vs.hlsl index 7982a2fbf..9ecf576ee 100644 --- a/src/xenia/gpu/d3d12/shaders/tessellation_indexed.vs.hlsl +++ b/src/xenia/gpu/d3d12/shaders/tessellation_indexed.vs.hlsl @@ -3,8 +3,13 @@ XeHSControlPointInputIndexed main(uint xe_vertex_id : SV_VertexID) { XeHSControlPointInputIndexed output; + // Only the lower 24 bits of the vertex index are used (tested on an Adreno + // 200 phone). `((index & 0xFFFFFF) + offset) & 0xFFFFFF` is the same as + // `(index + offset) & 0xFFFFFF`. output.index = - float(asint(XeEndianSwap32(xe_vertex_id, xe_vertex_index_endian)) + - xe_vertex_base_index); + float(clamp((XeEndianSwap32(xe_vertex_id, xe_vertex_index_endian) + + xe_vertex_index_offset) & + 0xFFFFFFu, + xe_vertex_index_min_max.x, xe_vertex_index_min_max.y)); return output; } diff --git a/src/xenia/gpu/d3d12/shaders/xenos_draw.hlsli b/src/xenia/gpu/d3d12/shaders/xenos_draw.hlsli index b1756cf44..e2a45cd39 100644 --- a/src/xenia/gpu/d3d12/shaders/xenos_draw.hlsli +++ b/src/xenia/gpu/d3d12/shaders/xenos_draw.hlsli @@ -7,35 +7,37 @@ cbuffer xe_system_cbuffer : register(b0) { uint xe_line_loop_closing_index; uint xe_vertex_index_endian; - int xe_vertex_base_index; - float2 xe_point_size; - - float2 xe_point_size_min_max; - float2 xe_point_screen_to_ndc; + uint xe_vertex_index_offset; + uint2 xe_vertex_index_min_max; float4 xe_user_clip_planes[6]; float3 xe_ndc_scale; - uint xe_interpolator_sampling_pattern; + float xe_point_size_x; float3 xe_ndc_offset; + float xe_point_size_y; + + float2 xe_point_size_min_max; + float2 xe_point_screen_to_ndc; + + uint xe_interpolator_sampling_pattern; uint xe_ps_param_gen; + uint2 xe_sample_count_log2; uint4 xe_texture_swizzled_signs[2]; uint xe_textures_resolved; - uint2 xe_sample_count_log2; float xe_alpha_test_reference; + uint xe_alpha_to_mask; + uint xe_edram_pitch_tiles; float4 xe_color_exp_bias; - uint xe_alpha_to_mask; - uint xe_edram_pitch_tiles; float2 xe_edram_depth_range; - float2 xe_edram_poly_offset_front; - float2 xe_edram_poly_offset_back; + float2 xe_edram_poly_offset_back; uint xe_edram_depth_base_dwords; uint4 xe_edram_stencil[2]; diff --git a/src/xenia/gpu/draw_util.h b/src/xenia/gpu/draw_util.h index 4b95441f8..3729f4f77 100644 --- a/src/xenia/gpu/draw_util.h +++ b/src/xenia/gpu/draw_util.h @@ -34,6 +34,50 @@ namespace draw_util { // for use with the top-left rasterization rule later. int32_t FloatToD3D11Fixed16p8(float f32); +// Polygonal primitive types (not including points and lines) are rasterized as +// triangles, have front and back faces, and also support face culling and fill +// modes (polymode_front_ptype, polymode_back_ptype). Other primitive types are +// always "front" (but don't support front face and back face culling, according +// to OpenGL and Vulkan specifications - even if glCullFace is +// GL_FRONT_AND_BACK, points and lines are still drawn), and may in some cases +// use the "para" registers instead of "front" or "back" (for "parallelogram" - +// like poly_offset_para_enable). +constexpr bool IsPrimitivePolygonal(bool vgt_output_path_is_tessellation_enable, + xenos::PrimitiveType type) { + if (vgt_output_path_is_tessellation_enable && + (type == xenos::PrimitiveType::kTrianglePatch || + type == xenos::PrimitiveType::kQuadPatch)) { + // For patch primitive types, the major mode is always explicit, so just + // checking if VGT_OUTPUT_PATH_CNTL::path_select is kTessellationEnable is + // enough. + return true; + } + switch (type) { + case xenos::PrimitiveType::kTriangleList: + case xenos::PrimitiveType::kTriangleFan: + case xenos::PrimitiveType::kTriangleStrip: + case xenos::PrimitiveType::kTriangleWithWFlags: + case xenos::PrimitiveType::kQuadList: + case xenos::PrimitiveType::kQuadStrip: + case xenos::PrimitiveType::kPolygon: + return true; + default: + break; + } + // TODO(Triang3l): Investigate how kRectangleList should be treated - possibly + // actually drawn as two polygons on the console, however, the current + // geometry shader doesn't care about the winding order - allowing backface + // culling for rectangles currently breaks Gears of War 2. + return false; +} + +inline bool IsPrimitivePolygonal(const RegisterFile& regs) { + return IsPrimitivePolygonal( + regs.Get().path_select == + xenos::VGTOutputPath::kTessellationEnable, + regs.Get().prim_type); +} + // Whether with the current state, any samples to rasterize (for any reason, not // only to write something to a render target, but also to do sample counting or // pixel shader memexport) can be generated. Finally dropping draw calls can diff --git a/src/xenia/gpu/dxbc_shader_translator.cc b/src/xenia/gpu/dxbc_shader_translator.cc index 78da5e09e..cc337f12b 100644 --- a/src/xenia/gpu/dxbc_shader_translator.cc +++ b/src/xenia/gpu/dxbc_shader_translator.cc @@ -293,7 +293,7 @@ void DxbcShaderTranslator::StartVertexShader_LoadVertexIndex() { a_.OpINE( index_dest, dxbc::Src::V(uint32_t(InOutRegister::kVSInVertexIndex), dxbc::Src::kXXXX), - LoadSystemConstant(SystemConstantIndex::kLineLoopClosingIndex, + LoadSystemConstant(SystemConstants::Index::kLineLoopClosingIndex, offsetof(SystemConstants, line_loop_closing_index), dxbc::Src::kXXXX)); // Zero the index if processing the closing vertex of a line loop, or do @@ -306,7 +306,7 @@ void DxbcShaderTranslator::StartVertexShader_LoadVertexIndex() { { // Swap the vertex index's endianness. dxbc::Src endian_src(LoadSystemConstant( - SystemConstantIndex::kVertexIndexEndian, + SystemConstants::Index::kVertexIndexEndian, offsetof(SystemConstants, vertex_index_endian), dxbc::Src::kXXXX)); dxbc::Dest swap_temp_dest(dxbc::Dest::R(reg, 0b0010)); dxbc::Src swap_temp_src(dxbc::Src::R(reg, dxbc::Src::kYYYY)); @@ -346,12 +346,27 @@ void DxbcShaderTranslator::StartVertexShader_LoadVertexIndex() { // Add the base vertex index. a_.OpIAdd(index_dest, index_src, - LoadSystemConstant(SystemConstantIndex::kVertexBaseIndex, - offsetof(SystemConstants, vertex_base_index), + LoadSystemConstant(SystemConstants::Index::kVertexIndexOffset, + offsetof(SystemConstants, vertex_index_offset), + dxbc::Src::kXXXX)); + + // Mask since the GPU only uses the lower 24 bits of the vertex index (tested + // on an Adreno 200 phone). `((index & 0xFFFFFF) + offset) & 0xFFFFFF` is the + // same as `(index + offset) & 0xFFFFFF`. + a_.OpAnd(index_dest, index_src, dxbc::Src::LU(xenos::kVertexIndexMask)); + + // Clamp the vertex index after offsetting. + a_.OpUMax(index_dest, index_src, + LoadSystemConstant(SystemConstants::Index::kVertexIndexMinMax, + offsetof(SystemConstants, vertex_index_min), + dxbc::Src::kXXXX)); + a_.OpUMin(index_dest, index_src, + LoadSystemConstant(SystemConstants::Index::kVertexIndexMinMax, + offsetof(SystemConstants, vertex_index_max), dxbc::Src::kXXXX)); // Convert to float. - a_.OpIToF(index_dest, index_src); + a_.OpUToF(index_dest, index_src); if (uses_register_dynamic_addressing) { // Store to indexed GPR 0 in x0[0]. @@ -568,7 +583,7 @@ void DxbcShaderTranslator::StartPixelShader() { uint32_t centroid_temp = uses_register_dynamic_addressing ? PushSystemTemp() : UINT32_MAX; dxbc::Src sampling_pattern_src(LoadSystemConstant( - SystemConstantIndex::kInterpolatorSamplingPattern, + SystemConstants::Index::kInterpolatorSamplingPattern, offsetof(SystemConstants, interpolator_sampling_pattern), dxbc::Src::kXXXX)); for (uint32_t i = 0; i < interpolator_count; ++i) { @@ -606,7 +621,7 @@ void DxbcShaderTranslator::StartPixelShader() { // absolute value) coordinates, facing (X sign bit) - to the specified // interpolator register (ps_param_gen). dxbc::Src param_gen_index_src(LoadSystemConstant( - SystemConstantIndex::kPSParamGen, + SystemConstants::Index::kPSParamGen, offsetof(SystemConstants, ps_param_gen), dxbc::Src::kXXXX)); uint32_t param_gen_temp = PushSystemTemp(); // Check if pixel parameters need to be written. @@ -660,7 +675,7 @@ void DxbcShaderTranslator::StartPixelShader() { a_.OpUBFE(dxbc::Dest::R(param_gen_temp, 0b0100), dxbc::Src::LU(1), param_gen_index_src, LoadSystemConstant( - SystemConstantIndex::kInterpolatorSamplingPattern, + SystemConstants::Index::kInterpolatorSamplingPattern, offsetof(SystemConstants, interpolator_sampling_pattern), dxbc::Src::kXXXX)); a_.OpIf(bool(xenos::SampleLocation::kCenter), @@ -896,7 +911,7 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() { uint32_t(InOutRegister::kVSDSOutClipDistance0123) + (i >> 2), 1 << (i & 3)), dxbc::Src::R(system_temp_position_), - LoadSystemConstant(SystemConstantIndex::kUserClipPlanes, + LoadSystemConstant(SystemConstants::Index::kUserClipPlanes, offsetof(SystemConstants, user_clip_planes) + sizeof(float) * 4 * i, dxbc::Src::kXYZW)); @@ -908,12 +923,12 @@ void DxbcShaderTranslator::CompleteVertexOrDomainShader() { // position to NaN to kill all primitives. a_.OpMul(dxbc::Dest::R(system_temp_position_, 0b0111), dxbc::Src::R(system_temp_position_), - LoadSystemConstant(SystemConstantIndex::kNDCScale, + LoadSystemConstant(SystemConstants::Index::kNDCScale, offsetof(SystemConstants, ndc_scale), 0b100100)); // Apply offset (multiplied by W) used for the same purposes. a_.OpMAd(dxbc::Dest::R(system_temp_position_, 0b0111), - LoadSystemConstant(SystemConstantIndex::kNDCOffset, + LoadSystemConstant(SystemConstants::Index::kNDCOffset, offsetof(SystemConstants, ndc_offset), 0b100100), dxbc::Src::R(system_temp_position_, dxbc::Src::kWWWW), dxbc::Src::R(system_temp_position_)); @@ -1889,9 +1904,6 @@ const DxbcShaderTranslator::ShaderRdefType {"float4", dxbc::RdefVariableClass::kVector, dxbc::RdefVariableType::kFloat, 1, 4, 0, ShaderRdefTypeIndex::kUnknown}, - // kInt - {"int", dxbc::RdefVariableClass::kScalar, dxbc::RdefVariableType::kInt, - 1, 1, 0, ShaderRdefTypeIndex::kUnknown}, // kUint {"dword", dxbc::RdefVariableClass::kScalar, dxbc::RdefVariableType::kUInt, 1, 1, 0, ShaderRdefTypeIndex::kUnknown}, @@ -1928,7 +1940,7 @@ const DxbcShaderTranslator::ShaderRdefType const DxbcShaderTranslator::SystemConstantRdef DxbcShaderTranslator::system_constant_rdef_[size_t( - DxbcShaderTranslator::SystemConstantIndex::kCount)] = { + DxbcShaderTranslator::SystemConstants::Index::kCount)] = { {"xe_flags", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, {"xe_tessellation_factor_range", ShaderRdefTypeIndex::kFloat2, sizeof(float) * 2}, @@ -1937,46 +1949,49 @@ const DxbcShaderTranslator::SystemConstantRdef {"xe_vertex_index_endian", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, - {"xe_vertex_base_index", ShaderRdefTypeIndex::kInt, sizeof(int32_t)}, - {"xe_point_size", ShaderRdefTypeIndex::kFloat2, sizeof(float) * 2}, + {"xe_vertex_index_offset", ShaderRdefTypeIndex::kUint, sizeof(int32_t)}, + {"xe_vertex_index_min_max", ShaderRdefTypeIndex::kUint2, + sizeof(uint32_t) * 2}, + + {"xe_user_clip_planes", ShaderRdefTypeIndex::kFloat4Array6, + sizeof(float) * 4 * 6}, + + {"xe_ndc_scale", ShaderRdefTypeIndex::kFloat3, sizeof(float) * 3}, + {"xe_point_size_x", ShaderRdefTypeIndex::kFloat, sizeof(float)}, + + {"xe_ndc_offset", ShaderRdefTypeIndex::kFloat3, sizeof(float) * 3}, + {"xe_point_size_y", ShaderRdefTypeIndex::kFloat, sizeof(float)}, {"xe_point_size_min_max", ShaderRdefTypeIndex::kFloat2, sizeof(float) * 2}, {"xe_point_screen_to_ndc", ShaderRdefTypeIndex::kFloat2, sizeof(float) * 2}, - {"xe_user_clip_planes", ShaderRdefTypeIndex::kFloat4Array6, - sizeof(float) * 4 * 6}, - - {"xe_ndc_scale", ShaderRdefTypeIndex::kFloat3, sizeof(float) * 3}, {"xe_interpolator_sampling_pattern", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, - - {"xe_ndc_offset", ShaderRdefTypeIndex::kFloat3, sizeof(float) * 3}, {"xe_ps_param_gen", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, + {"xe_sample_count_log2", ShaderRdefTypeIndex::kUint2, + sizeof(uint32_t) * 2}, {"xe_texture_swizzled_signs", ShaderRdefTypeIndex::kUint4Array2, sizeof(uint32_t) * 4 * 2}, {"xe_textures_resolved", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, - {"xe_sample_count_log2", ShaderRdefTypeIndex::kUint2, - sizeof(uint32_t) * 2}, {"xe_alpha_test_reference", ShaderRdefTypeIndex::kFloat, sizeof(float)}, + {"xe_alpha_to_mask", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, + {"xe_edram_pitch_tiles", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, {"xe_color_exp_bias", ShaderRdefTypeIndex::kFloat4, sizeof(float) * 4}, - {"xe_alpha_to_mask", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, - {"xe_edram_pitch_tiles", ShaderRdefTypeIndex::kUint, sizeof(uint32_t)}, {"xe_edram_depth_range", ShaderRdefTypeIndex::kFloat2, sizeof(float) * 2}, - {"xe_edram_poly_offset_front", ShaderRdefTypeIndex::kFloat2, sizeof(float) * 2}, + {"xe_edram_poly_offset_back", ShaderRdefTypeIndex::kFloat2, sizeof(float) * 2}, - {"xe_edram_depth_base_dwords", ShaderRdefTypeIndex::kUint, - sizeof(uint32_t), sizeof(float) * 3}, + sizeof(uint32_t), sizeof(float)}, {"xe_edram_stencil", ShaderRdefTypeIndex::kUint4Array2, sizeof(uint32_t) * 4 * 2}, @@ -2078,9 +2093,9 @@ void DxbcShaderTranslator::WriteResourceDefinition() { // Names. name_ptr = (uint32_t(shader_object_.size()) - blob_position_dwords) * sizeof(uint32_t); - uint32_t constant_name_ptrs_system[size_t(SystemConstantIndex::kCount)]; + uint32_t constant_name_ptrs_system[size_t(SystemConstants::Index::kCount)]; if (cbuffer_index_system_constants_ != kBindingIndexUnallocated) { - for (size_t i = 0; i < size_t(SystemConstantIndex::kCount); ++i) { + for (size_t i = 0; i < size_t(SystemConstants::Index::kCount); ++i) { constant_name_ptrs_system[i] = name_ptr; name_ptr += dxbc::AppendAlignedString(shader_object_, system_constant_rdef_[i].name); @@ -2112,11 +2127,11 @@ void DxbcShaderTranslator::WriteResourceDefinition() { if (cbuffer_index_system_constants_ != kBindingIndexUnallocated) { shader_object_.resize(constant_position_dwords_system + sizeof(dxbc::RdefVariable) / sizeof(uint32_t) * - size_t(SystemConstantIndex::kCount)); + size_t(SystemConstants::Index::kCount)); auto constants_system = reinterpret_cast( shader_object_.data() + constant_position_dwords_system); uint32_t constant_offset_system = 0; - for (size_t i = 0; i < size_t(SystemConstantIndex::kCount); ++i) { + for (size_t i = 0; i < size_t(SystemConstants::Index::kCount); ++i) { dxbc::RdefVariable& constant_system = constants_system[i]; const SystemConstantRdef& translator_constant_system = system_constant_rdef_[i]; @@ -2271,7 +2286,7 @@ void DxbcShaderTranslator::WriteResourceDefinition() { cbuffer.type = dxbc::RdefCbufferType::kCbuffer; if (i == cbuffer_index_system_constants_) { cbuffer.name_ptr = cbuffer_name_ptr_system; - cbuffer.variable_count = uint32_t(SystemConstantIndex::kCount); + cbuffer.variable_count = uint32_t(SystemConstants::Index::kCount); cbuffer.variables_ptr = (constant_position_dwords_system - blob_position_dwords) * sizeof(uint32_t); diff --git a/src/xenia/gpu/dxbc_shader_translator.h b/src/xenia/gpu/dxbc_shader_translator.h index f809f8e79..29d4ab01e 100644 --- a/src/xenia/gpu/dxbc_shader_translator.h +++ b/src/xenia/gpu/dxbc_shader_translator.h @@ -202,7 +202,7 @@ class DxbcShaderTranslator : public ShaderTranslator { }; // IF SYSTEM CONSTANTS ARE CHANGED OR ADDED, THE FOLLOWING MUST BE UPDATED: - // - SystemConstantIndex enum. + // - SystemConstants::Index enum. // - system_constant_rdef_. // - d3d12/shaders/xenos_draw.hlsli (for geometry shaders). struct SystemConstants { @@ -217,20 +217,38 @@ class DxbcShaderTranslator : public ShaderTranslator { uint32_t line_loop_closing_index; xenos::Endian vertex_index_endian; - int32_t vertex_base_index; - float point_size[2]; - - float point_size_min_max[2]; - // Screen point size * 2 (but not supersampled) -> size in NDC. - float point_screen_to_ndc[2]; + uint32_t vertex_index_offset; + union { + struct { + uint32_t vertex_index_min; + uint32_t vertex_index_max; + }; + uint32_t vertex_index_min_max[2]; + }; float user_clip_planes[6][4]; float ndc_scale[3]; - uint32_t interpolator_sampling_pattern; + float point_size_x; float ndc_offset[3]; + float point_size_y; + + union { + struct { + float point_size_min; + float point_size_max; + }; + float point_size_min_max[2]; + }; + // Screen point size * 2 (but not supersampled) -> size in NDC. + float point_screen_to_ndc[2]; + + uint32_t interpolator_sampling_pattern; uint32_t ps_param_gen; + // Log2 of X and Y sample size. Used for alpha to mask, and for MSAA with + // ROV, this is used for EDRAM address calculation. + uint32_t sample_count_log2[2]; // Each byte contains post-swizzle TextureSign values for each of the needed // components of each of the 32 used texture fetch constants. @@ -239,18 +257,15 @@ class DxbcShaderTranslator : public ShaderTranslator { // Whether the contents of each texture in fetch constants comes from a // resolve operation. uint32_t textures_resolved; - // Log2 of X and Y sample size. Used for alpha to mask, and for MSAA with - // ROV, this is used for EDRAM address calculation. - uint32_t sample_count_log2[2]; float alpha_test_reference; - - float color_exp_bias[4]; - // If alpha to mask is disabled, the entire alpha_to_mask value must be 0. // If alpha to mask is enabled, bits 0:7 are sample offsets, and bit 8 must // be 1. uint32_t alpha_to_mask; uint32_t edram_pitch_tiles; + + float color_exp_bias[4]; + union { struct { float edram_depth_range_scale; @@ -258,7 +273,6 @@ class DxbcShaderTranslator : public ShaderTranslator { }; float edram_depth_range[2]; }; - union { struct { float edram_poly_offset_front_scale; @@ -266,6 +280,7 @@ class DxbcShaderTranslator : public ShaderTranslator { }; float edram_poly_offset_front[2]; }; + union { struct { float edram_poly_offset_back_scale; @@ -273,9 +288,8 @@ class DxbcShaderTranslator : public ShaderTranslator { }; float edram_poly_offset_back[2]; }; - uint32_t edram_depth_base_dwords; - uint32_t padding_edram_depth_base_dwords[3]; + uint32_t padding_edram_depth_base_dwords; // In stencil function/operations (they match the layout of the // function/operations in RB_DEPTHCONTROL): @@ -326,6 +340,68 @@ class DxbcShaderTranslator : public ShaderTranslator { // The constant blend factor for the respective modes. float edram_blend_constant[4]; + + private: + friend class DxbcShaderTranslator; + + enum class Index : uint32_t { + kFlags, + kTessellationFactorRange, + kLineLoopClosingIndex, + + kVertexIndexEndian, + kVertexIndexOffset, + kVertexIndexMinMax, + + kUserClipPlanes, + + kNDCScale, + kPointSizeX, + + kNDCOffset, + kPointSizeY, + + kPointSizeMinMax, + kPointScreenToNDC, + + kInterpolatorSamplingPattern, + kPSParamGen, + kSampleCountLog2, + + kTextureSwizzledSigns, + + kTexturesResolved, + kAlphaTestReference, + kAlphaToMask, + kEdramPitchTiles, + + kColorExpBias, + + kEdramDepthRange, + kEdramPolyOffsetFront, + + kEdramPolyOffsetBack, + kEdramDepthBaseDwords, + + kEdramStencil, + + kEdramRTBaseDwordsScaled, + + kEdramRTFormatFlags, + + kEdramRTClamp, + + kEdramRTKeepMask, + + kEdramRTBlendFactorsOps, + + kEdramBlendConstant, + + kCount, + }; + static_assert( + uint32_t(Index::kCount) <= 64, + "Too many system constants, can't use uint64_t for usage bits"); }; // Shader resource view binding spaces. @@ -507,44 +583,6 @@ class DxbcShaderTranslator : public ShaderTranslator { void ProcessAluInstruction(const ParsedAluInstruction& instr) override; private: - enum class SystemConstantIndex : uint32_t { - kFlags, - kTessellationFactorRange, - kLineLoopClosingIndex, - kVertexIndexEndian, - kVertexBaseIndex, - kPointSize, - kPointSizeMinMax, - kPointScreenToNDC, - kUserClipPlanes, - kNDCScale, - kInterpolatorSamplingPattern, - kNDCOffset, - kPSParamGen, - kTextureSwizzledSigns, - kTexturesResolved, - kSampleCountLog2, - kAlphaTestReference, - kColorExpBias, - kAlphaToMask, - kEdramPitchTiles, - kEdramDepthRange, - kEdramPolyOffsetFront, - kEdramPolyOffsetBack, - kEdramDepthBaseDwords, - kEdramStencil, - kEdramRTBaseDwordsScaled, - kEdramRTFormatFlags, - kEdramRTClamp, - kEdramRTKeepMask, - kEdramRTBlendFactorsOps, - kEdramBlendConstant, - - kCount, - }; - static_assert(uint32_t(SystemConstantIndex::kCount) <= 64, - "Too many system constants, can't use uint64_t for usage bits"); - static constexpr uint32_t kPointParametersTexCoord = xenos::kMaxInterpolators; static constexpr uint32_t kClipSpaceZWTexCoord = kPointParametersTexCoord + 1; @@ -580,7 +618,7 @@ class DxbcShaderTranslator : public ShaderTranslator { // GetSystemConstantSrc + MarkSystemConstantUsed is for special cases of // building the source unconditionally - in general, LoadSystemConstant must // be used instead. - void MarkSystemConstantUsed(SystemConstantIndex index) { + void MarkSystemConstantUsed(SystemConstants::Index index) { system_constants_used_ |= uint64_t(1) << uint32_t(index); } // Offset should be offsetof(SystemConstants, field). Swizzle values are @@ -599,13 +637,13 @@ class DxbcShaderTranslator : public ShaderTranslator { std::min(((swizzle >> 4) & 3) + first_component, uint32_t(3)) << 4 | std::min(((swizzle >> 6) & 3) + first_component, uint32_t(3)) << 6); } - dxbc::Src LoadSystemConstant(SystemConstantIndex index, size_t offset, + dxbc::Src LoadSystemConstant(SystemConstants::Index index, size_t offset, uint32_t swizzle) { MarkSystemConstantUsed(index); return GetSystemConstantSrc(offset, swizzle); } dxbc::Src LoadFlagsSystemConstant() { - return LoadSystemConstant(SystemConstantIndex::kFlags, + return LoadSystemConstant(SystemConstants::Index::kFlags, offsetof(SystemConstants, flags), dxbc::Src::kXXXX); } @@ -928,7 +966,6 @@ class DxbcShaderTranslator : public ShaderTranslator { kFloat2, kFloat3, kFloat4, - kInt, kUint, kUint2, kUint4, @@ -982,9 +1019,9 @@ class DxbcShaderTranslator : public ShaderTranslator { uint32_t padding_after; }; static const SystemConstantRdef - system_constant_rdef_[size_t(SystemConstantIndex::kCount)]; - // Mask of system constants (1 << SystemConstantIndex) used in the shader, so - // the remaining ones can be marked as unused in RDEF. + system_constant_rdef_[size_t(SystemConstants::Index::kCount)]; + // Mask of system constants (1 << SystemConstants::Index) used in the shader, + // so the remaining ones can be marked as unused in RDEF. uint64_t system_constants_used_; // Mask of domain location actually used in the domain shader. diff --git a/src/xenia/gpu/dxbc_shader_translator_fetch.cc b/src/xenia/gpu/dxbc_shader_translator_fetch.cc index a0fd92c64..cb2d529da 100644 --- a/src/xenia/gpu/dxbc_shader_translator_fetch.cc +++ b/src/xenia/gpu/dxbc_shader_translator_fetch.cc @@ -945,7 +945,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( // calculations. assert_zero(used_result_nonzero_components & 0b1000); a_.OpAnd(dxbc::Dest::R(system_temp_result_, 0b1000), - LoadSystemConstant(SystemConstantIndex::kTexturesResolved, + LoadSystemConstant(SystemConstants::Index::kTexturesResolved, offsetof(SystemConstants, textures_resolved), dxbc::Src::kXXXX), dxbc::Src::LU(uint32_t(1) << tfetch_index)); @@ -1006,7 +1006,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( uint32_t signs_temp = UINT32_MAX; if (instr.opcode == FetchOpcode::kTextureFetch) { signs_temp = PushSystemTemp(); - MarkSystemConstantUsed(SystemConstantIndex::kTextureSwizzledSigns); + MarkSystemConstantUsed(SystemConstants::Index::kTextureSwizzledSigns); a_.OpUBFE(dxbc::Dest::R(signs_temp, used_result_nonzero_components), dxbc::Src::LU(2), dxbc::Src::LU(signs_shift, signs_shift + 2, signs_shift + 4, @@ -1069,7 +1069,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( // resolution scale inverse - sampler not loaded yet. a_.OpAnd( dxbc::Dest::R(coord_and_sampler_temp, 0b1000), - LoadSystemConstant(SystemConstantIndex::kTexturesResolved, + LoadSystemConstant(SystemConstants::Index::kTexturesResolved, offsetof(SystemConstants, textures_resolved), dxbc::Src::kXXXX), dxbc::Src::LU(uint32_t(1) << tfetch_index)); @@ -1135,7 +1135,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( // resolution scale inverse - sampler not loaded yet. a_.OpAnd( dxbc::Dest::R(coord_and_sampler_temp, 0b1000), - LoadSystemConstant(SystemConstantIndex::kTexturesResolved, + LoadSystemConstant(SystemConstants::Index::kTexturesResolved, offsetof(SystemConstants, textures_resolved), dxbc::Src::kXXXX), dxbc::Src::LU(uint32_t(1) << tfetch_index)); @@ -1312,7 +1312,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( // Check which SRV needs to be accessed - signed or unsigned. If there is // at least one non-signed component, will be using the unsigned one. uint32_t is_unsigned_temp = PushSystemTemp(); - MarkSystemConstantUsed(SystemConstantIndex::kTextureSwizzledSigns); + MarkSystemConstantUsed(SystemConstants::Index::kTextureSwizzledSigns); a_.OpUBFE(dxbc::Dest::R(is_unsigned_temp, 0b0001), dxbc::Src::LU(8), dxbc::Src::LU(signs_shift), signs_uint_src); a_.OpINE( @@ -2055,7 +2055,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( // `if`, with `else` for sRGB resolved render targets. a_.OpAnd( dxbc::Dest::R(gamma_temp, 0b0001), - LoadSystemConstant(SystemConstantIndex::kTexturesResolved, + LoadSystemConstant(SystemConstants::Index::kTexturesResolved, offsetof(SystemConstants, textures_resolved), dxbc::Src::kXXXX), dxbc::Src::LU(uint32_t(1) << tfetch_index)); diff --git a/src/xenia/gpu/dxbc_shader_translator_om.cc b/src/xenia/gpu/dxbc_shader_translator_om.cc index 13c009973..bc22f6205 100644 --- a/src/xenia/gpu/dxbc_shader_translator_om.cc +++ b/src/xenia/gpu/dxbc_shader_translator_om.cc @@ -224,7 +224,7 @@ void DxbcShaderTranslator::StartPixelShader_LoadROVParameters() { // system_temp_rov_params_.w = Y guest sample 0 position a_.OpIShL(dxbc::Dest::R(system_temp_rov_params_, 0b1100), dxbc::Src::R(system_temp_rov_params_), - LoadSystemConstant(SystemConstantIndex::kSampleCountLog2, + LoadSystemConstant(SystemConstants::Index::kSampleCountLog2, offsetof(SystemConstants, sample_count_log2), 0b0100 << 4)); // Get 80x16 samples tile index - start dividing X by 80 by getting the high @@ -251,7 +251,7 @@ void DxbcShaderTranslator::StartPixelShader_LoadROVParameters() { // system_temp_rov_params_.w = Y guest sample 0 position a_.OpUMAd(dxbc::Dest::R(system_temp_rov_params_, 0b0010), dxbc::Src::R(system_temp_rov_params_, dxbc::Src::kYYYY), - LoadSystemConstant(SystemConstantIndex::kEdramPitchTiles, + LoadSystemConstant(SystemConstants::Index::kEdramPitchTiles, offsetof(SystemConstants, edram_pitch_tiles), dxbc::Src::kXXXX), dxbc::Src::R(system_temp_rov_params_, dxbc::Src::kXXXX)); @@ -330,7 +330,7 @@ void DxbcShaderTranslator::StartPixelShader_LoadROVParameters() { a_.OpIAdd( dxbc::Dest::R(system_temp_rov_params_, 0b0010), dxbc::Src::R(system_temp_rov_params_, dxbc::Src::kYYYY), - LoadSystemConstant(SystemConstantIndex::kEdramDepthBaseDwords, + LoadSystemConstant(SystemConstants::Index::kEdramDepthBaseDwords, offsetof(SystemConstants, edram_depth_base_dwords), dxbc::Src::kXXXX)); if (draw_resolution_scale_ > 1) { @@ -371,7 +371,7 @@ void DxbcShaderTranslator::StartPixelShader_LoadROVParameters() { // MSAA, handling samples 0 and 3 (upper-left and lower-right) as 0 and 1. // Check if 4x MSAA is enabled. - a_.OpIf(true, LoadSystemConstant(SystemConstantIndex::kSampleCountLog2, + a_.OpIf(true, LoadSystemConstant(SystemConstants::Index::kSampleCountLog2, offsetof(SystemConstants, sample_count_log2), dxbc::Src::kXXXX)); { @@ -473,11 +473,11 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { // temp.x? = first sample's viewport space Z a_.OpMAd(sample_depth_stencil_dest, sample_depth_stencil_src, LoadSystemConstant( - SystemConstantIndex::kEdramDepthRange, + SystemConstants::Index::kEdramDepthRange, offsetof(SystemConstants, edram_depth_range_scale), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramDepthRange, + SystemConstants::Index::kEdramDepthRange, offsetof(SystemConstants, edram_depth_range_offset), dxbc::Src::kXXXX), true); @@ -508,11 +508,11 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { dxbc::Src::V(uint32_t(InOutRegister::kPSInFrontFaceAndSampleIndex), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramPolyOffsetFront, + SystemConstants::Index::kEdramPolyOffsetFront, offsetof(SystemConstants, edram_poly_offset_front), 0b0100 << 4), LoadSystemConstant( - SystemConstantIndex::kEdramPolyOffsetBack, + SystemConstants::Index::kEdramPolyOffsetBack, offsetof(SystemConstants, edram_poly_offset_back), 0b0100 << 4)); // Apply the slope scale and the constant bias to the offset. @@ -528,11 +528,11 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { // temp.z = viewport maximum depth a_.OpAdd(temp_z_dest, LoadSystemConstant( - SystemConstantIndex::kEdramDepthRange, + SystemConstants::Index::kEdramDepthRange, offsetof(SystemConstants, edram_depth_range_offset), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramDepthRange, + SystemConstants::Index::kEdramDepthRange, offsetof(SystemConstants, edram_depth_range_scale), dxbc::Src::kXXXX)); } @@ -583,7 +583,7 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { if (i == 1) { a_.OpMovC( sample_depth_stencil_dest, - LoadSystemConstant(SystemConstantIndex::kSampleCountLog2, + LoadSystemConstant(SystemConstants::Index::kSampleCountLog2, offsetof(SystemConstants, sample_count_log2), dxbc::Src::kXXXX), dxbc::Src::LU(3), dxbc::Src::LU(2)); @@ -611,11 +611,11 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { // temp.z = viewport maximum depth if not writing to oDepth a_.OpMAd(sample_depth_stencil_dest, sample_depth_stencil_src, LoadSystemConstant( - SystemConstantIndex::kEdramDepthRange, + SystemConstants::Index::kEdramDepthRange, offsetof(SystemConstants, edram_depth_range_scale), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramDepthRange, + SystemConstants::Index::kEdramDepthRange, offsetof(SystemConstants, edram_depth_range_offset), dxbc::Src::kXXXX), true); @@ -631,7 +631,7 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { // temp.z = viewport maximum depth if not writing to oDepth a_.OpMax(sample_depth_stencil_dest, sample_depth_stencil_src, LoadSystemConstant( - SystemConstantIndex::kEdramDepthRange, + SystemConstants::Index::kEdramDepthRange, offsetof(SystemConstants, edram_depth_range_offset), dxbc::Src::kXXXX)); // Clamp the biased depth to the upper viewport depth bound. @@ -763,7 +763,7 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { a_.OpElse(); } dxbc::Src stencil_read_mask_src(LoadSystemConstant( - SystemConstantIndex::kEdramStencil, + SystemConstants::Index::kEdramStencil, j ? offsetof(SystemConstants, edram_stencil_back_read_mask) : offsetof(SystemConstants, edram_stencil_front_read_mask), dxbc::Src::kXXXX)); @@ -772,7 +772,7 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { a_.OpAnd( sample_temp_x_dest, LoadSystemConstant( - SystemConstantIndex::kEdramStencil, + SystemConstants::Index::kEdramStencil, j ? offsetof(SystemConstants, edram_stencil_back_reference) : offsetof(SystemConstants, edram_stencil_front_reference), dxbc::Src::kXXXX), @@ -813,11 +813,11 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { dxbc::Src::V(uint32_t(InOutRegister::kPSInFrontFaceAndSampleIndex), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramStencil, + SystemConstants::Index::kEdramStencil, offsetof(SystemConstants, edram_stencil_front_func_ops), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramStencil, + SystemConstants::Index::kEdramStencil, offsetof(SystemConstants, edram_stencil_back_func_ops), dxbc::Src::kXXXX)); // Mask the resulting bits with the ones that should pass (the comparison @@ -885,11 +885,11 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { dxbc::Src::V(uint32_t(InOutRegister::kPSInFrontFaceAndSampleIndex), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramStencil, + SystemConstants::Index::kEdramStencil, offsetof(SystemConstants, edram_stencil_front_reference), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramStencil, + SystemConstants::Index::kEdramStencil, offsetof(SystemConstants, edram_stencil_back_reference), dxbc::Src::kXXXX)); a_.OpBreak(); @@ -945,11 +945,11 @@ void DxbcShaderTranslator::ROV_DepthStencilTest() { dxbc::Src::V(uint32_t(InOutRegister::kPSInFrontFaceAndSampleIndex), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramStencil, + SystemConstants::Index::kEdramStencil, offsetof(SystemConstants, edram_stencil_front_write_mask), dxbc::Src::kXXXX), LoadSystemConstant( - SystemConstantIndex::kEdramStencil, + SystemConstants::Index::kEdramStencil, offsetof(SystemConstants, edram_stencil_back_write_mask), dxbc::Src::kXXXX)); // Apply the write mask to the new stencil, also dropping the upper 24 @@ -1138,7 +1138,7 @@ void DxbcShaderTranslator::ROV_UnpackColor( // Choose the packing based on the render target's format. a_.OpSwitch( - LoadSystemConstant(SystemConstantIndex::kEdramRTFormatFlags, + LoadSystemConstant(SystemConstants::Index::kEdramRTFormatFlags, offsetof(SystemConstants, edram_rt_format_flags) + sizeof(uint32_t) * rt_index, dxbc::Src::kXXXX)); @@ -1299,7 +1299,7 @@ void DxbcShaderTranslator::ROV_PackPreClampedColor( // Choose the packing based on the render target's format. a_.OpSwitch( - LoadSystemConstant(SystemConstantIndex::kEdramRTFormatFlags, + LoadSystemConstant(SystemConstants::Index::kEdramRTFormatFlags, offsetof(SystemConstants, edram_rt_format_flags) + sizeof(uint32_t) * rt_index, dxbc::Src::kXXXX)); @@ -1515,7 +1515,7 @@ void DxbcShaderTranslator::ROV_HandleColorBlendFactorCases( // kConstantColor a_.OpCase(dxbc::Src::LU(uint32_t(xenos::BlendFactor::kConstantColor))); a_.OpMov(factor_dest, - LoadSystemConstant(SystemConstantIndex::kEdramBlendConstant, + LoadSystemConstant(SystemConstants::Index::kEdramBlendConstant, offsetof(SystemConstants, edram_blend_constant), dxbc::Src::kXYZW)); a_.OpBreak(); @@ -1524,7 +1524,7 @@ void DxbcShaderTranslator::ROV_HandleColorBlendFactorCases( a_.OpCase( dxbc::Src::LU(uint32_t(xenos::BlendFactor::kOneMinusConstantColor))); a_.OpAdd(factor_dest, one_src, - -LoadSystemConstant(SystemConstantIndex::kEdramBlendConstant, + -LoadSystemConstant(SystemConstants::Index::kEdramBlendConstant, offsetof(SystemConstants, edram_blend_constant), dxbc::Src::kXYZW)); a_.OpBreak(); @@ -1532,7 +1532,7 @@ void DxbcShaderTranslator::ROV_HandleColorBlendFactorCases( // kConstantAlpha a_.OpCase(dxbc::Src::LU(uint32_t(xenos::BlendFactor::kConstantAlpha))); a_.OpMov(factor_dest, - LoadSystemConstant(SystemConstantIndex::kEdramBlendConstant, + LoadSystemConstant(SystemConstants::Index::kEdramBlendConstant, offsetof(SystemConstants, edram_blend_constant), dxbc::Src::kWWWW)); a_.OpBreak(); @@ -1541,7 +1541,7 @@ void DxbcShaderTranslator::ROV_HandleColorBlendFactorCases( a_.OpCase( dxbc::Src::LU(uint32_t(xenos::BlendFactor::kOneMinusConstantAlpha))); a_.OpAdd(factor_dest, one_src, - -LoadSystemConstant(SystemConstantIndex::kEdramBlendConstant, + -LoadSystemConstant(SystemConstants::Index::kEdramBlendConstant, offsetof(SystemConstants, edram_blend_constant), dxbc::Src::kWWWW)); a_.OpBreak(); @@ -1606,7 +1606,7 @@ void DxbcShaderTranslator::ROV_HandleAlphaBlendFactorCases( a_.OpCase(dxbc::Src::LU(uint32_t(xenos::BlendFactor::kConstantColor))); a_.OpCase(dxbc::Src::LU(uint32_t(xenos::BlendFactor::kConstantAlpha))); a_.OpMov(factor_dest, - LoadSystemConstant(SystemConstantIndex::kEdramBlendConstant, + LoadSystemConstant(SystemConstants::Index::kEdramBlendConstant, offsetof(SystemConstants, edram_blend_constant), dxbc::Src::kWWWW)); a_.OpBreak(); @@ -1617,7 +1617,7 @@ void DxbcShaderTranslator::ROV_HandleAlphaBlendFactorCases( a_.OpCase( dxbc::Src::LU(uint32_t(xenos::BlendFactor::kOneMinusConstantAlpha))); a_.OpAdd(factor_dest, one_src, - -LoadSystemConstant(SystemConstantIndex::kEdramBlendConstant, + -LoadSystemConstant(SystemConstants::Index::kEdramBlendConstant, offsetof(SystemConstants, edram_blend_constant), dxbc::Src::kWWWW)); a_.OpBreak(); @@ -1644,7 +1644,7 @@ void DxbcShaderTranslator::CompletePixelShader_WriteToRTVs() { // unbiased alpha from the shader a_.OpMul(dxbc::Dest::R(system_temps_color_[i]), dxbc::Src::R(system_temps_color_[i]), - LoadSystemConstant(SystemConstantIndex::kColorExpBias, + LoadSystemConstant(SystemConstants::Index::kColorExpBias, offsetof(SystemConstants, color_exp_bias) + sizeof(uint32_t) * i, dxbc::Src::kXXXX)); @@ -1834,7 +1834,7 @@ void DxbcShaderTranslator::CompletePixelShader_AlphaToMask() { // Check if alpha to coverage is enabled. dxbc::Src alpha_to_mask_constant_src(LoadSystemConstant( - SystemConstantIndex::kAlphaToMask, + SystemConstants::Index::kAlphaToMask, offsetof(SystemConstants, alpha_to_mask), dxbc::Src::kXXXX)); a_.OpIf(true, alpha_to_mask_constant_src); @@ -1866,13 +1866,13 @@ void DxbcShaderTranslator::CompletePixelShader_AlphaToMask() { uint32_t coverage_temp_component = edram_rov_used_ ? 0 : 2; // Check if MSAA is enabled. - a_.OpIf(true, LoadSystemConstant(SystemConstantIndex::kSampleCountLog2, + a_.OpIf(true, LoadSystemConstant(SystemConstants::Index::kSampleCountLog2, offsetof(SystemConstants, sample_count_log2), dxbc::Src::kYYYY)); { // Check if MSAA is 4x or 2x. a_.OpIf(true, - LoadSystemConstant(SystemConstantIndex::kSampleCountLog2, + LoadSystemConstant(SystemConstants::Index::kSampleCountLog2, offsetof(SystemConstants, sample_count_log2), dxbc::Src::kXXXX)); // 4x MSAA. @@ -2010,7 +2010,7 @@ void DxbcShaderTranslator::CompletePixelShader_WriteToROV() { // This includes a swizzle to choose XY for even render targets or ZW for // odd ones - use SelectFromSwizzled and SwizzleSwizzled. dxbc::Src keep_mask_src( - LoadSystemConstant(SystemConstantIndex::kEdramRTKeepMask, + LoadSystemConstant(SystemConstants::Index::kEdramRTKeepMask, offsetof(SystemConstants, edram_rt_keep_mask) + sizeof(uint32_t) * 2 * i, 0b0100)); @@ -2044,7 +2044,7 @@ void DxbcShaderTranslator::CompletePixelShader_WriteToROV() { // unbiased alpha from the shader. a_.OpMul(dxbc::Dest::R(system_temps_color_[i]), dxbc::Src::R(system_temps_color_[i]), - LoadSystemConstant(SystemConstantIndex::kColorExpBias, + LoadSystemConstant(SystemConstants::Index::kColorExpBias, offsetof(SystemConstants, color_exp_bias) + sizeof(uint32_t) * i, dxbc::Src::kXXXX)); @@ -2053,22 +2053,22 @@ void DxbcShaderTranslator::CompletePixelShader_WriteToROV() { a_.OpIAdd(dxbc::Dest::R(system_temp_rov_params_, 0b1100), dxbc::Src::R(system_temp_rov_params_), LoadSystemConstant( - SystemConstantIndex::kEdramRTBaseDwordsScaled, + SystemConstants::Index::kEdramRTBaseDwordsScaled, offsetof(SystemConstants, edram_rt_base_dwords_scaled) + sizeof(uint32_t) * i, dxbc::Src::kXXXX)); dxbc::Src rt_blend_factors_ops_src(LoadSystemConstant( - SystemConstantIndex::kEdramRTBlendFactorsOps, + SystemConstants::Index::kEdramRTBlendFactorsOps, offsetof(SystemConstants, edram_rt_blend_factors_ops) + sizeof(uint32_t) * i, dxbc::Src::kXXXX)); dxbc::Src rt_clamp_vec_src(LoadSystemConstant( - SystemConstantIndex::kEdramRTClamp, + SystemConstants::Index::kEdramRTClamp, offsetof(SystemConstants, edram_rt_clamp) + sizeof(uint32_t) * 4 * i, dxbc::Src::kXYZW)); dxbc::Src rt_format_flags_src(LoadSystemConstant( - SystemConstantIndex::kEdramRTFormatFlags, + SystemConstants::Index::kEdramRTFormatFlags, offsetof(SystemConstants, edram_rt_format_flags) + sizeof(uint32_t) * i, dxbc::Src::kXXXX)); // Get if not blending to pack the color once for all 4 samples. @@ -2800,7 +2800,7 @@ void DxbcShaderTranslator::CompletePixelShader_WriteToROV() { a_.OpIAdd(dxbc::Dest::R(system_temp_rov_params_, 0b1100), dxbc::Src::R(system_temp_rov_params_), -LoadSystemConstant( - SystemConstantIndex::kEdramRTBaseDwordsScaled, + SystemConstants::Index::kEdramRTBaseDwordsScaled, offsetof(SystemConstants, edram_rt_base_dwords_scaled) + sizeof(uint32_t) * i, dxbc::Src::kXXXX)); @@ -2853,7 +2853,7 @@ void DxbcShaderTranslator::CompletePixelShader() { dxbc::Src alpha_src( dxbc::Src::R(system_temps_color_[0], dxbc::Src::kWWWW)); dxbc::Src alpha_test_reference_src(LoadSystemConstant( - SystemConstantIndex::kAlphaTestReference, + SystemConstants::Index::kAlphaTestReference, offsetof(SystemConstants, alpha_test_reference), dxbc::Src::kXXXX)); // Less than. a_.OpLT(alpha_test_op_dest, alpha_src, alpha_test_reference_src); diff --git a/src/xenia/gpu/primitive_processor.cc b/src/xenia/gpu/primitive_processor.cc new file mode 100644 index 000000000..62864a256 --- /dev/null +++ b/src/xenia/gpu/primitive_processor.cc @@ -0,0 +1,1512 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2021 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/gpu/primitive_processor.h" + +#include +#include +#include + +#include "xenia/base/assert.h" +#include "xenia/base/byte_order.h" +#include "xenia/base/cvar.h" +#include "xenia/base/logging.h" +#include "xenia/base/math.h" +#include "xenia/base/profiling.h" +#include "xenia/gpu/register_file.h" +#include "xenia/gpu/registers.h" +#include "xenia/gpu/shader.h" +#include "xenia/gpu/trace_writer.h" +#include "xenia/gpu/xenos.h" + +// All these overrides are always safe to use as all backends are expected to +// support triangle lists and line strips. +DEFINE_bool( + force_convert_triangle_fans_to_lists, false, + "For host graphics API downlevel support testing only, force CPU " + "conversion of triangle fans to triangle lists even if the host supports " + "triangle fan primitives natively.", + "GPU"); +DEFINE_bool( + force_convert_line_loops_to_strips, false, + "For host graphics API downlevel support testing only, force CPU " + "conversion of line loops to line strips even if the host supports line " + "loop primitives natively.", + "GPU"); +DEFINE_bool( + force_convert_quad_lists_to_triangle_lists, false, + "For host graphics API downlevel support testing only, force CPU " + "conversion of quad lists to quad strips even if the host supports quad " + "list primitives natively or via geometry shader emulation.\n" + "May also be useful for graphics debugging when the debugger doesn't " + "display the geometry generated by geometry shaders properly.", + "GPU"); +DEFINE_bool( + ignore_32bit_vertex_index_support, false, + "For host graphics API downlevel testing only (useful only for Qualcomm " + "Adreno 4xx-level host GPU testing), force indirection or pre-masking and " + "pre-swapping of 32-bit vertex indices as if the host only supports 24-bit " + "indices.", + "GPU"); +// TODO(Triang3l): More investigation of the cache threshold as cache lookups +// and insertions require global critical region locking, and insertions also +// require protecting pages. At 1024, the cache only made the performance worse +// (Tony Hawk's American Wasteland, 16-bit primitive reset index replacement). +DEFINE_int32( + primitive_processor_cache_min_indices, 4096, + "Smallest number of guest indices to store in the cache to try reusing " + "later in the same frame if processing (such as primitive type conversion " + "or reset index replacement) is performed.\n" + "Setting this to a very high value may result in excessive CPU processing, " + "while a very low value may result in excessive locking and lookups.\n" + "Negative values disable caching.", + "GPU"); + +namespace xe { +namespace gpu { + +// SIMD processing here assumes that alignment is not required (neither AVX nor +// Neon requires it) and there's no punishment for using an unaligned access +// instruction when the data is actually aligned (AVX has separate aligned / +// unaligned movs, but they have the same performance nowadays; Neon dropped the +// alignment specifier in AArch64), but truly unaligned access may result in two +// hardware memory operations if some boundary that is >= vector size is +// crossed. +// +// Therefore, to minimize unaligned access (primarily reads - since we depend on +// the data immediately), SIMD usage here is performed according to the +// following pattern (though we try to co-align the destination and the source +// prior to calling, but still doing all the operations for more code +// correctness and fewer unobvious conditions): +// - Until the source pointer is vector-aligned, process the first indices +// without SIMD. +// - The best possible outcome of this is that both the source and the +// destination will be vector-aligned (if they were co-aligned prior to the +// call), in this case, neither load nor store instructions will be crossing +// cache lines. +// - The other possible outcome is that the source will be aligned (1 memory +// read per load), while the destination will be unaligned (1-2 memory +// writes per store). +// - Process whole vectors with SIMD. +// - If there are less elements than a vector can hold remaining, process them +// without SIMD. +// +// We assume that indices are at least aligned to their natural alignment (2 or +// 4 bytes depending on the format) - the R6xx documentation says that in +// DRAW_INDEX, INDEX_BASE_LO is word-aligned, and that's required by host +// graphics APIs. + +PrimitiveProcessor::~PrimitiveProcessor() { ShutdownCommon(); } + +bool PrimitiveProcessor::InitializeCommon( + bool full_32bit_vertex_indices_supported, bool triangle_fans_supported, + bool line_loops_supported, bool quad_lists_supported) { + full_32bit_vertex_indices_used_ = full_32bit_vertex_indices_supported; + convert_triangle_fans_to_lists_ = + !triangle_fans_supported || cvars::force_convert_triangle_fans_to_lists; + convert_line_loops_to_strips_ = + !line_loops_supported || cvars::force_convert_line_loops_to_strips; + convert_quad_lists_to_triangle_lists_ = + !quad_lists_supported || + cvars::force_convert_quad_lists_to_triangle_lists; + + // Initialize the index buffer for conversion of auto-indexed primitive types. + uint32_t builtin_index_count = 0; + if (convert_triangle_fans_to_lists_) { + builtin_ib_offset_triangle_fans_to_lists_ = + sizeof(uint16_t) * builtin_index_count; + builtin_index_count += GetTriangleFanListIndexCount(UINT16_MAX); + } else { + builtin_ib_offset_triangle_fans_to_lists_ = SIZE_MAX; + } + if (convert_quad_lists_to_triangle_lists_) { + builtin_ib_offset_quad_lists_to_triangle_lists_ = + sizeof(uint16_t) * builtin_index_count; + builtin_index_count += GetQuadListTriangleListIndexCount(UINT16_MAX); + } else { + builtin_ib_offset_quad_lists_to_triangle_lists_ = SIZE_MAX; + } + if (builtin_index_count) { + if (!InitializeBuiltin16BitIndexBuffer( + builtin_index_count, [this](uint16_t* mapping) { + if (builtin_ib_offset_triangle_fans_to_lists_ != SIZE_MAX) { + // Triangle fans as triangle lists. + // Ordered as (v1, v2, v0), (v2, v3, v0) in Direct3D. + // https://docs.microsoft.com/en-us/windows/desktop/direct3d9/triangle-fans + uint16_t* triangle_list_ptr = + mapping + builtin_ib_offset_triangle_fans_to_lists_ / + sizeof(uint16_t); + for (uint32_t i = 2; i < UINT16_MAX; ++i) { + *(triangle_list_ptr++) = uint16_t(i - 1); + *(triangle_list_ptr++) = uint16_t(i); + *(triangle_list_ptr++) = 0; + } + } + if (builtin_ib_offset_quad_lists_to_triangle_lists_ != SIZE_MAX) { + uint16_t* triangle_list_ptr = + mapping + builtin_ib_offset_quad_lists_to_triangle_lists_ / + sizeof(uint16_t); + // TODO(Triang3l): SIMD for faster initialization? + for (uint32_t i = 0; i < UINT16_MAX / 4; ++i) { + uint16_t quad_first_index = uint16_t(i * 4); + // TODO(Triang3l): Find the correct order. + // v0, v1, v2. + *(triangle_list_ptr++) = quad_first_index; + *(triangle_list_ptr++) = quad_first_index + 1; + *(triangle_list_ptr++) = quad_first_index + 2; + // v0, v2, v3. + *(triangle_list_ptr++) = quad_first_index; + *(triangle_list_ptr++) = quad_first_index + 2; + *(triangle_list_ptr++) = quad_first_index + 3; + } + } + })) { + ShutdownCommon(); + return false; + } + } + + return true; +} + +void PrimitiveProcessor::ShutdownCommon() { + if (memory_invalidation_callback_handle_) { + // Clear the cache if it has ever been used and unregister the invalidation + // callback. + { + auto global_lock = global_critical_region_.Acquire(); + cache_map_.clear(); + cache_bucket_free_first_entry_ = SIZE_MAX; + std::memset(cache_buckets_non_empty_l1_, 0, + sizeof(cache_buckets_non_empty_l1_)); + std::memset(cache_buckets_non_empty_l2_, 0, + sizeof(cache_buckets_non_empty_l2_)); + } + memory_.UnregisterPhysicalMemoryInvalidationCallback( + memory_invalidation_callback_handle_); + memory_invalidation_callback_handle_ = nullptr; + cache_entry_pool_.clear(); + } +} + +void PrimitiveProcessor::ClearPerFrameCache() { + if (!memory_invalidation_callback_handle_) { + // Only do clearing if cache has ever been used. + return; + } + auto global_lock = global_critical_region_.Acquire(); + for (const std::pair& cache_map_entry : cache_map_) { + cache_entry_pool_[cache_map_entry.second].free_next = + cache_bucket_free_first_entry_; + cache_bucket_free_first_entry_ = cache_map_entry.second; + } + cache_map_.clear(); + std::memset(cache_buckets_non_empty_l1_, 0, + sizeof(cache_buckets_non_empty_l1_)); + std::memset(cache_buckets_non_empty_l2_, 0, + sizeof(cache_buckets_non_empty_l2_)); +} + +bool PrimitiveProcessor::Process(ProcessingResult& result_out) { + SCOPE_profile_cpu_f("gpu"); + + const RegisterFile& regs = register_file_; + auto vgt_draw_initiator = regs.Get(); + + // Parse the primitive type and the tessellation state (VGT_OUTPUT_PATH_CNTL + // is only used in the explicit major mode) - there are cases in games when + // this register is left over after usage of tessellation in draws that don't + // need it. + xenos::PrimitiveType guest_primitive_type = vgt_draw_initiator.prim_type; + xenos::PrimitiveType host_primitive_type = guest_primitive_type; + bool tessellation_enabled = + xenos::IsMajorModeExplicit(vgt_draw_initiator.major_mode, + vgt_draw_initiator.prim_type) && + regs.Get().path_select == + xenos::VGTOutputPath::kTessellationEnable; + xenos::TessellationMode tessellation_mode = + regs.Get().tess_mode; + Shader::HostVertexShaderType host_vertex_shader_type; + if (tessellation_enabled) { + // Currently only supporting tessellation in known cases for safety, and not + // yet converting patch strips / fans to patch lists until games using them + // are found for easier debugging when it actually happens. + // TODO(Triang3l): Conversion of patch strips / fans if found. + host_vertex_shader_type = Shader::HostVertexShaderType(-1); + switch (guest_primitive_type) { + case xenos::PrimitiveType::kTriangleList: + // Also supported by triangle strips and fans according to: + // https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt + // Would need to convert those to triangle lists, but haven't seen any + // games using tessellated strips / fans so far. + switch (tessellation_mode) { + case xenos::TessellationMode::kDiscrete: + // - Call of Duty 3 - nets above barrels in the beginning of the + // first mission (turn right after the end of the intro) - + // kTriangleList. + host_vertex_shader_type = + Shader::HostVertexShaderType::kTriangleDomainCPIndexed; + break; + case xenos::TessellationMode::kContinuous: + // - Viva Pinata - tree building with a beehive in the beginning + // (visible on the start screen behind the logo), waterfall in the + // beginning - kTriangleList. + host_vertex_shader_type = + Shader::HostVertexShaderType::kTriangleDomainCPIndexed; + break; + default: + break; + } + break; + case xenos::PrimitiveType::kQuadList: + switch (tessellation_mode) { + // Also supported by quad strips according to: + // https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt + // Would need to convert those to quad lists, but haven't seen any + // games using tessellated strips so far. + case xenos::TessellationMode::kDiscrete: + // Not seen in games so far. + host_vertex_shader_type = + Shader::HostVertexShaderType::kQuadDomainCPIndexed; + break; + case xenos::TessellationMode::kContinuous: + // - Defender - retro screen and beams in the main menu - kQuadList. + host_vertex_shader_type = + Shader::HostVertexShaderType::kQuadDomainCPIndexed; + break; + default: + break; + } + break; + case xenos::PrimitiveType::kTrianglePatch: + // - Banjo-Kazooie: Nuts & Bolts - water - adaptive. + // - Halo 3 - water - adaptive. + host_vertex_shader_type = + Shader::HostVertexShaderType::kTriangleDomainPatchIndexed; + break; + case xenos::PrimitiveType::kQuadPatch: + // - Fable II - continuous. + // - Viva Pinata - garden ground - adaptive. + host_vertex_shader_type = + Shader::HostVertexShaderType::kQuadDomainPatchIndexed; + break; + default: + // TODO(Triang3l): Support line patches. + break; + } + if (host_vertex_shader_type == Shader::HostVertexShaderType(-1)) { + XELOGE( + "Primitive processor: Unsupported tessellation mode {} for primitive " + "type {}. Report the game to Xenia developers!", + uint32_t(tessellation_mode), uint32_t(guest_primitive_type)); + assert_always(); + return false; + } + } else { + switch (guest_primitive_type) { + case xenos::PrimitiveType::kPointList: + case xenos::PrimitiveType::kLineList: + case xenos::PrimitiveType::kLineStrip: + case xenos::PrimitiveType::kTriangleList: + case xenos::PrimitiveType::kTriangleStrip: + case xenos::PrimitiveType::kRectangleList: + // Supported natively or through geometry or compute shaders on all + // backends. + break; + case xenos::PrimitiveType::kTriangleFan: + if (convert_triangle_fans_to_lists_) { + host_primitive_type = xenos::PrimitiveType::kTriangleList; + } + break; + case xenos::PrimitiveType::kLineLoop: + if (convert_line_loops_to_strips_) { + host_primitive_type = xenos::PrimitiveType::kLineStrip; + } + break; + case xenos::PrimitiveType::kQuadList: + if (convert_quad_lists_to_triangle_lists_) { + host_primitive_type = xenos::PrimitiveType::kQuadList; + } + break; + default: + XELOGE( + "Primitive processor: Unsupported primitive type {}. Report the " + "game to Xenia developers!", + uint32_t(guest_primitive_type)); + assert_always(); + return false; + } + host_vertex_shader_type = Shader::HostVertexShaderType::kVertex; + } + + // Process the indices. + uint32_t guest_draw_vertex_count = vgt_draw_initiator.num_indices; + uint32_t line_loop_closing_index = 0; + uint32_t guest_index_base; + CachedResult cacheable; + cacheable.host_draw_vertex_count = guest_draw_vertex_count; + cacheable.host_primitive_reset_enabled = false; + cacheable.host_index_buffer_handle = SIZE_MAX; + if (vgt_draw_initiator.source_select == xenos::SourceSelect::kAutoIndex) { + // Auto-indexed - use a remapping index buffer if needed to change the + // primitive type. + if (tessellation_enabled && + tessellation_mode == xenos::TessellationMode::kAdaptive) { + XELOGE( + "Primitive processor: Adaptive tessellation requires 32-bit " + "floating-point edge tessellation factors in the index buffer, but " + "no index buffer is provided by the guest."); + assert_always(); + return false; + } + guest_index_base = 0; + cacheable.host_index_format = xenos::IndexFormat::kInt16; + cacheable.host_index_endian = xenos::Endian::kNone; + cacheable.host_primitive_reset_enabled = false; + cacheable.index_buffer_type = ProcessedIndexBufferType::kNone; + if (host_primitive_type != guest_primitive_type) { + switch (guest_primitive_type) { + case xenos::PrimitiveType::kTriangleFan: + assert_true(host_primitive_type == + xenos::PrimitiveType::kTriangleList); + cacheable.host_draw_vertex_count = + GetTriangleFanListIndexCount(cacheable.host_draw_vertex_count); + cacheable.index_buffer_type = ProcessedIndexBufferType::kHostBuiltin; + assert_true(builtin_ib_offset_triangle_fans_to_lists_ != SIZE_MAX); + cacheable.host_index_buffer_handle = + builtin_ib_offset_triangle_fans_to_lists_; + break; + case xenos::PrimitiveType::kLineLoop: + // Plus 1 element (if there's anything to draw) in the strip, still + // auto-indexed, but the added excess index should be treated as 0 by + // the vertex shaders. + assert_true(host_primitive_type == xenos::PrimitiveType::kLineStrip); + cacheable.host_draw_vertex_count = + GetLineLoopStripIndexCount(cacheable.host_draw_vertex_count); + if (cacheable.host_draw_vertex_count) { + line_loop_closing_index = cacheable.host_draw_vertex_count - 1; + } + break; + case xenos::PrimitiveType::kQuadList: + assert_true(host_primitive_type == + xenos::PrimitiveType::kTriangleList); + cacheable.host_draw_vertex_count = GetQuadListTriangleListIndexCount( + cacheable.host_draw_vertex_count); + cacheable.index_buffer_type = ProcessedIndexBufferType::kHostBuiltin; + assert_true(builtin_ib_offset_quad_lists_to_triangle_lists_ != + SIZE_MAX); + cacheable.host_index_buffer_handle = + builtin_ib_offset_quad_lists_to_triangle_lists_; + break; + default: + assert_always(); + return false; + } + } + } else { + // There is an index buffer. + assert_true(vgt_draw_initiator.source_select == xenos::SourceSelect::kDMA); + if (vgt_draw_initiator.source_select != xenos::SourceSelect::kDMA) { + // TODO(Triang3l): Support immediate-indexed vertices. + XELOGE( + "Primitive processor: Unsupported vertex index source {}. Report the " + "game to Xenia developers!", + uint32_t(vgt_draw_initiator.source_select)); + return false; + } + + auto vgt_dma_size = regs.Get(); + + xenos::IndexFormat guest_index_format = vgt_draw_initiator.index_size; + cacheable.host_index_format = guest_index_format; + // Normalize the endian and the reset index. + xenos::Endian guest_index_endian = vgt_dma_size.swap_mode; + if (guest_index_format == xenos::IndexFormat::kInt16 && + (guest_index_endian != xenos::Endian::kNone && + guest_index_endian != xenos::Endian::k8in16)) { + XELOGW( + "Primitive processor: 32-bit endian swap mode {} is used for 16-bit " + "indices. This shouldn't normally be happening, but report the game " + "to Xenia developers for investigation of the intended behavior " + "(ignore or actually swap across adjacent indices)! Currently " + "disabling the swap for 16-and-32 and replacing 8-in-32 with " + "8-in-16.", + uint32_t(guest_index_endian)); + guest_index_endian = guest_index_endian == xenos::Endian::k8in32 + ? xenos::Endian::k8in16 + : xenos::Endian::kNone; + } + bool guest_primitive_reset_enabled = false; + uint32_t guest_primitive_reset_index_guest_endian = 0; + if (tessellation_enabled && + tessellation_mode == xenos::TessellationMode::kAdaptive) { + // Adaptive tessellation uses the index buffer not for indices, but for + // 32-bit floating-point edge factors - no primitive reset. + if (guest_index_format != xenos::IndexFormat::kInt32) { + XELOGE( + "Primitive processor: Adaptive tessellation requires 32-bit " + "floating-point edge tessellation factors in the index buffer, but " + "16-bit index buffer is provided by the guest."); + assert_always(); + return false; + } + } else { + if (regs.Get().multi_prim_ib_ena) { + guest_primitive_reset_index_guest_endian = xenos::GpuSwap( + regs.Get().reset_indx, + guest_index_endian); + // - VGT, what does the guest say about its primitive reset index? + // - It's over 0xFFFF!!! + // - What!? 0xFFFF!? There's no way that can be stored in 16 bits! + guest_primitive_reset_enabled = + guest_index_format == xenos::IndexFormat::kInt16 + ? guest_primitive_reset_index_guest_endian <= UINT16_MAX + : true; + } + } + + // Get the index buffer memory range. + if (guest_draw_vertex_count > vgt_dma_size.num_words) { + XELOGW( + "Primitive processor: {} vertices attempted to be drawn with an " + "index buffer only containing {}. Should be fetching zero indices " + "instead of overflowing ones, but this is a rare situation, so not " + "handled yet. Report the game to Xenia developers!", + guest_draw_vertex_count, vgt_dma_size.num_words); + guest_draw_vertex_count = vgt_dma_size.num_words; + } + uint32_t index_size_log2 = + guest_index_format == xenos::IndexFormat::kInt16 ? 1 : 2; + // The base should already be aligned, but aligning here too for safety. + guest_index_base = regs[XE_GPU_REG_VGT_DMA_BASE].u32 & + ~uint32_t((1 << index_size_log2) - 1); + uint32_t guest_index_buffer_needed_bytes = guest_draw_vertex_count + << index_size_log2; + if (guest_index_base > SharedMemory::kBufferSize || + SharedMemory::kBufferSize - guest_index_base < + guest_index_buffer_needed_bytes) { + XELOGE( + "Primitive processor: Index buffer at 0x{:8X}, 0x{:X} bytes " + "required, is out of the physical memory bounds", + guest_index_base, guest_index_buffer_needed_bytes); + assert_always(); + return false; + } + + cacheable.host_index_format = guest_index_format; + cacheable.host_index_endian = guest_index_endian; + uint32_t guest_index_mask_guest_endian = + guest_index_format == xenos::IndexFormat::kInt16 + ? UINT16_MAX + : GpuSwap(xenos::kVertexIndexMask, guest_index_endian); + if (host_primitive_type != guest_primitive_type) { + // Already converting to a different index type - primitive reset is + // performed during conversion here. Also doing the endian swap here for + // hosts not supporting 32-bit indices because indirection is only used + // for the shared memory buffer. + // Writing to the trace irrespective of the cache lookup result because + // cache behavior depends on runtime configuration and state. + trace_writer_.WriteMemoryRead(guest_index_base, + guest_index_buffer_needed_bytes); + CacheTransaction cache_transaction( + *this, CacheKey(guest_index_base, guest_draw_vertex_count, + guest_index_format, guest_index_endian, + guest_primitive_reset_enabled, guest_primitive_type)); + if (cache_transaction.GetFoundResult()) { + cacheable = *cache_transaction.GetFoundResult(); + } else { + const void* guest_indices_ptr = + memory_.TranslatePhysical(guest_index_base); + cacheable.index_buffer_type = ProcessedIndexBufferType::kHostConverted; + cacheable.host_primitive_reset_enabled = false; + std::function host_index_count_getter; + switch (guest_primitive_type) { + case xenos::PrimitiveType::kTriangleFan: + host_index_count_getter = GetTriangleFanListIndexCount; + break; + case xenos::PrimitiveType::kLineLoop: + host_index_count_getter = GetLineLoopStripIndexCount; + break; + case xenos::PrimitiveType::kQuadList: + host_index_count_getter = GetQuadListTriangleListIndexCount; + break; + default: + assert_unhandled_case(guest_primitive_type); + return false; + } + single_primitive_ranges_.clear(); + if (guest_index_format == xenos::IndexFormat::kInt16) { + // 16-bit indices - just convert the primitive (or multiple + // primitives) to the host topology. + // TODO(Triang3l): 16-bit > 32-bit primitive type conversion for + // Metal, where primitive reset is always enabled, if UINT16_MAX is + // used as a real vertex index. + auto guest_indices = + reinterpret_cast(guest_indices_ptr); + if (guest_primitive_reset_enabled && + IsResetUsed(guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian)) { + // Multiple primitives in the index buffer - gather all single + // primitives. + cacheable.host_draw_vertex_count = + GetMultiPrimitiveHostIndexCountAndRanges( + host_index_count_getter, guest_indices, + guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + single_primitive_ranges_); + } else { + cacheable.host_draw_vertex_count = + host_index_count_getter(guest_draw_vertex_count); + single_primitive_ranges_.emplace_back( + 0, guest_draw_vertex_count, cacheable.host_draw_vertex_count); + } + auto host_indices = reinterpret_cast( + RequestHostConvertedIndexBufferForCurrentFrame( + xenos::IndexFormat::kInt16, cacheable.host_draw_vertex_count, + false, guest_index_base, cacheable.host_index_buffer_handle)); + if (!host_indices) { + return false; + } + ConvertSinglePrimitiveRanges( + host_indices, guest_indices, guest_primitive_type, + PassthroughIndexTransform(), single_primitive_ranges_.cbegin(), + single_primitive_ranges_.cend()); + } else { + // 32-bit indices - may need to pre-swap and pre-mask also if the host + // doesn't support full 32-bit vertex indices. + auto guest_indices = + reinterpret_cast(guest_indices_ptr); + if (guest_primitive_reset_enabled && + IsResetUsed(guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + guest_index_mask_guest_endian)) { + // Multiple primitives in the index buffer - gather all single + // primitives. + cacheable.host_draw_vertex_count = + GetMultiPrimitiveHostIndexCountAndRanges( + host_index_count_getter, guest_indices, + guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + guest_index_mask_guest_endian, single_primitive_ranges_); + } else { + cacheable.host_draw_vertex_count = + host_index_count_getter(guest_draw_vertex_count); + single_primitive_ranges_.emplace_back( + 0, guest_draw_vertex_count, cacheable.host_draw_vertex_count); + } + auto host_indices = reinterpret_cast( + RequestHostConvertedIndexBufferForCurrentFrame( + xenos::IndexFormat::kInt32, cacheable.host_draw_vertex_count, + false, guest_index_base, cacheable.host_index_buffer_handle)); + if (!host_indices) { + return false; + } + auto single_primitive_ranges_beginning = + single_primitive_ranges_.cbegin(); + auto single_primitive_ranges_end = single_primitive_ranges_.cend(); + if (full_32bit_vertex_indices_used_) { + ConvertSinglePrimitiveRanges( + host_indices, guest_indices, guest_primitive_type, + PassthroughIndexTransform(), single_primitive_ranges_beginning, + single_primitive_ranges_end); + } else { + switch (guest_index_endian) { + case xenos::Endian::kNone: + ConvertSinglePrimitiveRanges(host_indices, guest_indices, + guest_primitive_type, + To24NonSwappingIndexTransform(), + single_primitive_ranges_beginning, + single_primitive_ranges_end); + break; + case xenos::Endian::k8in16: + ConvertSinglePrimitiveRanges(host_indices, guest_indices, + guest_primitive_type, + To24Swapping8In16IndexTransform(), + single_primitive_ranges_beginning, + single_primitive_ranges_end); + break; + case xenos::Endian::k8in32: + ConvertSinglePrimitiveRanges(host_indices, guest_indices, + guest_primitive_type, + To24Swapping8In32IndexTransform(), + single_primitive_ranges_beginning, + single_primitive_ranges_end); + break; + case xenos::Endian::k16in32: + ConvertSinglePrimitiveRanges(host_indices, guest_indices, + guest_primitive_type, + To24Swapping16In32IndexTransform(), + single_primitive_ranges_beginning, + single_primitive_ranges_end); + break; + default: + assert_unhandled_case(guest_index_endian); + return false; + } + cacheable.host_index_endian = xenos::Endian::kNone; + } + } + cache_transaction.SetNewResult(cacheable); + } + } else { + // Using the same indices on the host as on the guest, either directly or + // (for backends not supporting full 32-bit indices, thus unable to + // endian-swap, or even to safely drop the upper 8 bits if no swap is even + // needed) indirectly. + cacheable.host_draw_vertex_count = guest_draw_vertex_count; + cacheable.index_buffer_type = ProcessedIndexBufferType::kGuest; + cacheable.host_primitive_reset_enabled = guest_primitive_reset_enabled; + if (guest_primitive_reset_enabled) { + if (guest_index_format == xenos::IndexFormat::kInt16) { + // The whole 16-bit index is compared to the primitive reset index. + // Does not need indirection on backends not supporting full 32-bit + // indices. + if (guest_primitive_reset_index_guest_endian != UINT16_MAX) { + // If primitive reset is with a non-0xFFFF index is used, replace + // with 0xFFFF if 0xFFFF is not used as a real index, or with + // 0xFFFFFFFF if it is. + // Writing to the trace irrespective of the cache lookup result + // because cache behavior depends on runtime configuration and + // state. + trace_writer_.WriteMemoryRead(guest_index_base, + guest_index_buffer_needed_bytes); + // Not specifying the primitive type in the cache key because not + // replacing it, only the reset index in a type-independent way. + CacheTransaction cache_transaction( + *this, CacheKey(guest_index_base, guest_draw_vertex_count, + guest_index_format, guest_index_endian, + guest_primitive_reset_enabled)); + if (cache_transaction.GetFoundResult()) { + cacheable = *cache_transaction.GetFoundResult(); + } else { + auto guest_indices = + memory_.TranslatePhysical(guest_index_base); + bool is_reset_index_used, is_ffff_used_as_vertex_index; + Get16BitResetIndexUsage(guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + is_reset_index_used, + is_ffff_used_as_vertex_index); + if (is_reset_index_used) { + cacheable.index_buffer_type = + ProcessedIndexBufferType::kHostConverted; + cacheable.host_index_format = is_ffff_used_as_vertex_index + ? xenos::IndexFormat::kInt32 + : xenos::IndexFormat::kInt16; + void* host_indices_ptr = + RequestHostConvertedIndexBufferForCurrentFrame( + cacheable.host_index_format, guest_draw_vertex_count, + true, guest_index_base, + cacheable.host_index_buffer_handle); + if (!host_indices_ptr) { + return false; + } + if (is_ffff_used_as_vertex_index) { + ReplaceResetIndex16To24( + reinterpret_cast(host_indices_ptr), + guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian); + } else { + ReplaceResetIndex16To16( + reinterpret_cast(host_indices_ptr), + guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian); + } + } + cache_transaction.SetNewResult(cacheable); + } + } + } else { + // Low 24 bits of the guest index are compared to the primitive reset + // index. If the backend doesn't support full 32-bit indices, for + // ProcessedIndexBufferType::kGuest, the host needs to read the buffer + // indirectly in the vertex shaders and swap, and for + // ProcessedIndexBufferType::kHostConverted (if primitive reset is + // actually used, thus exactly 0xFFFFFFFF must be sent to the host for + // it in a true index buffer), no indirection is done, but + // pre-swapping and pre-masking is done here. + // Writing to the trace irrespective of the cache lookup result + // because cache behavior depends on runtime configuration and state. + trace_writer_.WriteMemoryRead(guest_index_base, + guest_index_buffer_needed_bytes); + // Not specifying the primitive type in the cache key because not + // replacing it, only the reset index in a type-independent way. + CacheTransaction cache_transaction( + *this, CacheKey(guest_index_base, guest_draw_vertex_count, + guest_index_format, guest_index_endian, + guest_primitive_reset_enabled)); + if (cache_transaction.GetFoundResult()) { + cacheable = *cache_transaction.GetFoundResult(); + } else { + auto guest_indices = + memory_.TranslatePhysical(guest_index_base); + if (IsResetUsed(guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + guest_index_mask_guest_endian)) { + cacheable.index_buffer_type = + ProcessedIndexBufferType::kHostConverted; + auto host_indices = reinterpret_cast( + RequestHostConvertedIndexBufferForCurrentFrame( + xenos::IndexFormat::kInt32, guest_draw_vertex_count, true, + guest_index_base, cacheable.host_index_buffer_handle)); + if (!host_indices) { + return false; + } + if (full_32bit_vertex_indices_used_ || + guest_index_endian == xenos::Endian::kNone) { + ReplaceResetIndex32To24( + host_indices, guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + guest_index_mask_guest_endian); + } else if (guest_index_endian == xenos::Endian::k8in16) { + ReplaceResetIndex32To24( + host_indices, guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + guest_index_mask_guest_endian); + } else if (guest_index_endian == xenos::Endian::k8in32) { + ReplaceResetIndex32To24( + host_indices, guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + guest_index_mask_guest_endian); + } else if (guest_index_endian == xenos::Endian::k16in32) { + ReplaceResetIndex32To24( + host_indices, guest_indices, guest_draw_vertex_count, + guest_primitive_reset_index_guest_endian, + guest_index_mask_guest_endian); + } else { + assert_unhandled_case(guest_index_endian); + return false; + } + cacheable.host_index_endian = full_32bit_vertex_indices_used_ + ? guest_index_endian + : xenos::Endian::kNone; + } + cache_transaction.SetNewResult(cacheable); + } + } + } + if (cacheable.index_buffer_type == ProcessedIndexBufferType::kGuest) { + // Request the index buffer memory. + // TODO(Triang3l): Shared memory request cache. + if (!shared_memory_.RequestRange(guest_index_base, + guest_index_buffer_needed_bytes)) { + XELOGE( + "PrimitiveProcessor: Failed to request index buffer 0x{:8X}, " + "0x{:X} bytes needed, in the shared memory", + guest_index_base, guest_index_buffer_needed_bytes); + return false; + } + } + } + } + + result_out.guest_primitive_type = guest_primitive_type; + result_out.host_primitive_type = host_primitive_type; + result_out.host_vertex_shader_type = host_vertex_shader_type; + result_out.tessellation_mode = tessellation_mode; + result_out.host_draw_vertex_count = cacheable.host_draw_vertex_count; + result_out.line_loop_closing_index = line_loop_closing_index; + result_out.index_buffer_type = cacheable.index_buffer_type; + result_out.guest_index_base = guest_index_base; + result_out.host_index_format = cacheable.host_index_format; + result_out.host_index_endian = cacheable.host_index_endian; + result_out.host_primitive_reset_enabled = + cacheable.host_primitive_reset_enabled; + result_out.host_index_buffer_handle = cacheable.host_index_buffer_handle; + return true; +} + +bool PrimitiveProcessor::IsResetUsed(const uint16_t* source, uint32_t count, + uint16_t reset_index_guest_endian) { +#if XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count && (reinterpret_cast(source) & + (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1))) { + --count; + if (*(source++) == reset_index_guest_endian) { + return true; + } + } + if (count >= kSimdVectorU16Elements) { + SimdVectorU16 reset_index_guest_endian_simd = + ReplicateU16(reset_index_guest_endian); + while (count >= kSimdVectorU16Elements) { + count -= kSimdVectorU16Elements; + SimdVectorU16 source_simd = LoadAlignedVectorU16(source); + source += kSimdVectorU16Elements; +#if XE_ARCH_AMD64 + if (_mm_movemask_epi8( + _mm_cmpeq_epi16(source_simd, reset_index_guest_endian_simd))) { + return true; + } +#elif XE_ARCH_ARM64 + uint64x1_t is_any = vreinterpret_u64_u32(vqmovn_u64(vreinterpretq_u64_u16( + vceqq_u16(source_simd, reset_index_guest_endian_simd)))); + if (*reinterpret_cast(&is_any)) { + return true; + } +#else +#error SIMD 16-bit IsResetUsed not implemented. +#endif // XE_ARCH + } + } +#endif // XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count--) { + if (*(source++) == reset_index_guest_endian) { + return true; + } + } + return false; +} + +void PrimitiveProcessor::Get16BitResetIndexUsage( + const uint16_t* source, uint32_t count, uint16_t reset_index_guest_endian, + bool& is_reset_index_used_out, bool& is_ffff_used_as_vertex_index_out) { + // Optimized for the more common case (reset index not used at all), therefore + // not doing early-outs if both conditions are true for a simpler loop body. + // Using the index 0xFFFF is likely not that common in general. + // TODO(Triang3l): Revisit this - maybe the early-out will be free if this + // function is bandwidth-bound. + is_ffff_used_as_vertex_index_out = false; + if (reset_index_guest_endian == UINT16_MAX) { + is_reset_index_used_out = + IsResetUsed(source, count, reset_index_guest_endian); + return; + } + is_reset_index_used_out = false; +#if XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count && (reinterpret_cast(source) & + (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1))) { + --count; + uint16_t index = *(source++); + if (index == reset_index_guest_endian) { + is_reset_index_used_out = true; + } + if (index == UINT16_MAX) { + is_ffff_used_as_vertex_index_out = true; + } + } + if (count >= kSimdVectorU16Elements) { + SimdVectorU16 reset_index_guest_endian_simd = + ReplicateU16(reset_index_guest_endian); + SimdVectorU16 ffff_simd = ReplicateU16(UINT16_MAX); + SimdVectorU16 is_reset_simd = ReplicateU16(0); + SimdVectorU16 is_ffff_simd = ReplicateU16(0); + while (count >= kSimdVectorU16Elements) { + count -= kSimdVectorU16Elements; + SimdVectorU16 source_simd = LoadAlignedVectorU16(source); + source += kSimdVectorU16Elements; +#if XE_ARCH_AMD64 + is_reset_simd = _mm_or_si128( + is_reset_simd, + _mm_cmpeq_epi16(source_simd, reset_index_guest_endian_simd)); + is_ffff_simd = + _mm_or_si128(is_ffff_simd, _mm_cmpeq_epi16(source_simd, ffff_simd)); +#elif XE_ARCH_ARM64 + is_reset_simd = vcorrq_u16( + is_reset_simd, vceqq_u16(source_simd, reset_index_guest_endian_simd)); + is_ffff_simd = vmaxq_u16(is_ffff_simd, source_simd); +#else +#error SIMD Get16BitResetIndexUsage not implemented. +#endif // XE_ARCH + } +#if XE_ARCH_AMD64 + if (_mm_movemask_epi8(is_reset_simd)) { + is_reset_index_used_out = true; + } + if (_mm_movemask_epi8(is_ffff_simd)) { + is_ffff_used_as_vertex_index_out = true; + } +#elif XE_ARCH_ARM64 + uint64x1_t is_reset_any = + vreinterpret_u64_u32(vqmovn_u64(vreinterpretq_u64_u16(is_reset_simd))); + if (*reinterpret_cast(&is_reset_any)) { + is_reset_index_used_out = true; + } + uint64x1_t is_ffff_any = vreinterpret_u64_u32( + vqmovn_u64(vreinterpretq_u64_u16(vceqq_u16(is_ffff_simd, ffff_simd)))); + if (*reinterpret_cast(&is_ffff_any)) { + is_ffff_used_as_vertex_index_out = true; + } +#else +#error SIMD Get16BitResetIndexUsage not implemented. +#endif // XE_ARCH + } +#endif // XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count--) { + uint16_t index = *(source++); + if (index == reset_index_guest_endian) { + is_reset_index_used_out = true; + } + if (index == UINT16_MAX) { + is_ffff_used_as_vertex_index_out = true; + } + } +} + +bool PrimitiveProcessor::IsResetUsed(const uint32_t* source, uint32_t count, + uint32_t reset_index_guest_endian, + uint32_t low_bits_mask_guest_endian) { + // The Xbox 360's GPU only uses the low 24 bits of the index - masking before + // comparing. +#if XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count && (reinterpret_cast(source) & + (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1))) { + --count; + if ((*(source++) & low_bits_mask_guest_endian) == + reset_index_guest_endian) { + return true; + } + } + if (count >= kSimdVectorU32Elements) { + SimdVectorU32 reset_index_guest_endian_simd = + ReplicateU32(reset_index_guest_endian); + while (count >= kSimdVectorU32Elements) { + count -= kSimdVectorU32Elements; + SimdVectorU32 source_simd = LoadAlignedVectorU32(source); + source += kSimdVectorU32Elements; + SimdVectorU32 low_bits_mask_guest_endian_simd = + ReplicateU32(low_bits_mask_guest_endian); +#if XE_ARCH_AMD64 + source_simd = _mm_and_si128(source_simd, low_bits_mask_guest_endian_simd); + if (_mm_movemask_epi8( + _mm_cmpeq_epi32(source_simd, reset_index_guest_endian_simd))) { + return true; + } +#elif XE_ARCH_ARM64 + source_simd = vandq_u32(source_simd, low_bits_mask_guest_endian_simd); + uint64x1_t is_any = vreinterpret_u64_u32(vqmovn_u64(vreinterpretq_u64_u32( + vceqq_u32(source_simd, reset_index_guest_endian_simd)))); + if (*reinterpret_cast(&is_any)) { + return true; + } +#else +#error SIMD 32-bit IsResetUsed not implemented. +#endif // XE_ARCH + } + } +#endif // XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count--) { + if ((*(source++) & low_bits_mask_guest_endian) == + reset_index_guest_endian) { + return true; + } + } + return false; +} + +void PrimitiveProcessor::ReplaceResetIndex16To16( + uint16_t* dest, const uint16_t* source, uint32_t count, + uint16_t reset_index_guest_endian) { +#if XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count && (reinterpret_cast(source) & + (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1))) { + --count; + uint16_t index = *(source++); + *(dest++) = index != reset_index_guest_endian ? index : UINT16_MAX; + } + if (count >= kSimdVectorU16Elements) { + SimdVectorU16 reset_index_guest_endian_simd = + ReplicateU16(reset_index_guest_endian); + while (count >= kSimdVectorU16Elements) { + count -= kSimdVectorU16Elements; + // Comparison produces 0 or 0xFFFF on AVX and Neon - we need 0xFFFF as the + // result for the primitive reset indices, so the result is + // `index | (index == reset_index)`. + SimdVectorU16 source_simd = LoadAlignedVectorU16(source); + source += kSimdVectorU16Elements; + SimdVectorU16 result_simd; +#if XE_ARCH_AMD64 + result_simd = _mm_or_si128( + source_simd, + _mm_cmpeq_epi16(source_simd, reset_index_guest_endian_simd)); +#elif XE_ARCH_ARM64 + result_simd = vorrq_u16( + source_simd, vceqq_u16(source_simd, reset_index_guest_endian_simd)); +#else +#error SIMD ReplaceResetIndex16To16 not implemented. +#endif // XE_ARCH + StoreUnalignedVectorU16(dest, result_simd); + dest += kSimdVectorU16Elements; + } + } +#endif // XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count--) { + uint16_t index = *(source++); + *(dest++) = index != reset_index_guest_endian ? index : UINT16_MAX; + } +} + +void PrimitiveProcessor::ReplaceResetIndex16To24( + uint32_t* dest, const uint16_t* source, uint32_t count, + uint16_t reset_index_guest_endian) { +#if XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count && (reinterpret_cast(source) & + (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1))) { + --count; + uint16_t index = *(source++); + *(dest++) = index != reset_index_guest_endian ? index : UINT32_MAX; + } + if (count >= kSimdVectorU16Elements) { + SimdVectorU16 reset_index_guest_endian_simd = + ReplicateU16(reset_index_guest_endian); + while (count >= kSimdVectorU16Elements) { + count -= kSimdVectorU16Elements; + SimdVectorU16 source_simd = LoadAlignedVectorU16(source); + source += kSimdVectorU16Elements; + // 1) Compare to the reset index as uint16, getting 0 or 0xFFFF. + // 2) For primitive reset indices, replace the lower 16 bits with 0xFFFF + // via OR with the comparison result. + // 3) Expand to 32-bit, putting 0xFFFF in the upper 16 bits where + // the comparison has passed, creating 0xFFFFFFFF for primitive reset + // or 0x0000#### for non-primitive-reset indices (including + // 0x0000FFFF if the original index buffer had 0xFFFF, but the + // primitive reset index is different). + // 4) Store. +#if XE_ARCH_AMD64 + __m128i are_reset = + _mm_cmpeq_epi16(source_simd, reset_index_guest_endian_simd); + __m128i result = _mm_or_si128(source_simd, are_reset); + StoreUnalignedVectorU32(dest, _mm_unpacklo_epi16(result, are_reset)); + // Expecting kSimdVectorU16Elements / 2 to be in the immediate offset + // part of the address. + StoreUnalignedVectorU32(dest + kSimdVectorU16Elements / 2, + _mm_unpackhi_epi16(result, are_reset)); +#elif XE_ARCH_ARM64 + // Interleaving the indices and 0 / 0xFFFF via st2. + uint16x8x2_t result; + result.val[1] = vceqq_u16(source_simd, reset_index_guest_endian_simd); + result.val[0] = vorrq_u16(source_simd, result.val[1]); + vst2q_u16(reinterpret_cast(dest), result); +#else +#error SIMD ReplaceResetIndex16To24 not implemented. +#endif // XE_ARCH + dest += kSimdVectorU16Elements; + } + } +#endif // XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count--) { + uint16_t index = *(source++); + *(dest++) = index != reset_index_guest_endian ? index : UINT32_MAX; + } +} + +template void PrimitiveProcessor::ReplaceResetIndex32To24( + uint32_t* dest, const uint32_t* source, uint32_t count, + uint32_t reset_index_guest_endian, uint32_t low_bits_mask_guest_endian); +template void +PrimitiveProcessor::ReplaceResetIndex32To24( + uint32_t* dest, const uint32_t* source, uint32_t count, + uint32_t reset_index_guest_endian, uint32_t low_bits_mask_guest_endian); +template void +PrimitiveProcessor::ReplaceResetIndex32To24( + uint32_t* dest, const uint32_t* source, uint32_t count, + uint32_t reset_index_guest_endian, uint32_t low_bits_mask_guest_endian); +template void +PrimitiveProcessor::ReplaceResetIndex32To24( + uint32_t* dest, const uint32_t* source, uint32_t count, + uint32_t reset_index_guest_endian, uint32_t low_bits_mask_guest_endian); + +#define XE_GPU_PRIMITIVE_PROCESSOR_INSTANTIATE_CONVERSION_NO_PASSTHROUGH( \ + ConverterName) \ + template void PrimitiveProcessor::ConverterName( \ + uint32_t* dest, const uint32_t* source, uint32_t source_index_count, \ + const To24NonSwappingIndexTransform& index_transform); \ + template void PrimitiveProcessor::ConverterName( \ + uint32_t* dest, const uint32_t* source, uint32_t source_index_count, \ + const To24Swapping8In16IndexTransform& index_transform); \ + template void PrimitiveProcessor::ConverterName( \ + uint32_t* dest, const uint32_t* source, uint32_t source_index_count, \ + const To24Swapping8In32IndexTransform& index_transform); \ + template void PrimitiveProcessor::ConverterName( \ + uint32_t* dest, const uint32_t* source, uint32_t source_index_count, \ + const To24Swapping16In32IndexTransform& index_transform); +#define XE_GPU_PRIMITIVE_PROCESSOR_INSTANTIATE_CONVERSION(ConverterName) \ + template void PrimitiveProcessor::ConverterName( \ + uint16_t* dest, const uint16_t* source, uint32_t source_index_count, \ + const PassthroughIndexTransform& index_transform); \ + template void PrimitiveProcessor::ConverterName( \ + uint32_t* dest, const uint32_t* source, uint32_t source_index_count, \ + const PassthroughIndexTransform& index_transform); \ + XE_GPU_PRIMITIVE_PROCESSOR_INSTANTIATE_CONVERSION_NO_PASSTHROUGH( \ + ConverterName) +XE_GPU_PRIMITIVE_PROCESSOR_INSTANTIATE_CONVERSION(TriangleFanToList) +XE_GPU_PRIMITIVE_PROCESSOR_INSTANTIATE_CONVERSION_NO_PASSTHROUGH( + LineLoopToStrip) +// TODO(Triang3l): SIMD quad conversion maybe - 2 vectors to 3 vectors (though +// multiple quads are rarely drawn anyway). +XE_GPU_PRIMITIVE_PROCESSOR_INSTANTIATE_CONVERSION(QuadListToTriangleList) +#undef XE_GPU_PRIMITIVE_PROCESSOR_INSTANTIATE_CONVERSION_NO_PASSTHROUGH +#undef XE_GPU_PRIMITIVE_PROCESSOR_INSTANTIATE_CONVERSION + +void PrimitiveProcessor::LineLoopToStrip( + uint16_t* dest, const uint16_t* source, uint32_t source_index_count, + const PassthroughIndexTransform& index_transform) { + if (source_index_count <= 1) { + // To match GetLineLoopStripIndexCount. + return; + } + std::memcpy(dest, source, sizeof(*source) * source_index_count); + dest[source_index_count] = source[0]; +} +void PrimitiveProcessor::LineLoopToStrip( + uint32_t* dest, const uint32_t* source, uint32_t source_index_count, + const PassthroughIndexTransform& index_transform) { + if (source_index_count <= 1) { + // To match GetLineLoopStripIndexCount. + return; + } + std::memcpy(dest, source, sizeof(*source) * source_index_count); + dest[source_index_count] = source[0]; +} + +uint32_t PrimitiveProcessor::GetMultiPrimitiveHostIndexCountAndRanges( + std::function single_primitive_guest_to_host_count, + const uint16_t* source, uint32_t source_index_count, + uint16_t reset_index_guest_endian, + std::deque& ranges_append_out) { + uint32_t host_total_index_count = 0; + uint32_t guest_index_offset = 0; + for (;;) { + uint32_t guest_primitive_offset = guest_index_offset; + while (guest_index_offset < source_index_count) { + if (source[guest_index_offset] == reset_index_guest_endian) { + break; + } + ++guest_index_offset; + } + // Reset encountered or end of the index buffer - add the range. + uint32_t guest_primitive_index_count = + guest_index_offset - guest_primitive_offset; + uint32_t host_primitive_index_count = + single_primitive_guest_to_host_count(guest_primitive_index_count); + if (host_primitive_index_count) { + ranges_append_out.emplace_back(guest_primitive_offset, + guest_primitive_index_count, + host_primitive_index_count); + host_total_index_count += host_primitive_index_count; + } + if (guest_index_offset >= source_index_count) { + // End of the index buffer. + break; + } + // Reset index encountered - skip. + ++guest_index_offset; + } + return host_total_index_count; +} + +uint32_t PrimitiveProcessor::GetMultiPrimitiveHostIndexCountAndRanges( + std::function single_primitive_guest_to_host_count, + const uint32_t* source, uint32_t source_index_count, + uint32_t reset_index_guest_endian, uint32_t low_bits_mask_guest_endian, + std::deque& ranges_append_out) { + uint32_t host_total_index_count = 0; + uint32_t guest_index_offset = 0; + for (;;) { + uint32_t guest_primitive_offset = guest_index_offset; + while (guest_index_offset < source_index_count) { + if ((source[guest_index_offset] & low_bits_mask_guest_endian) == + reset_index_guest_endian) { + break; + } + ++guest_index_offset; + } + // Reset encountered or end of the index buffer - add the range. + uint32_t guest_primitive_index_count = + guest_index_offset - guest_primitive_offset; + uint32_t host_primitive_index_count = + single_primitive_guest_to_host_count(guest_primitive_index_count); + if (host_primitive_index_count) { + ranges_append_out.emplace_back(guest_primitive_offset, + guest_primitive_index_count, + host_primitive_index_count); + host_total_index_count += host_primitive_index_count; + } + if (guest_index_offset >= source_index_count) { + // End of the index buffer. + break; + } + // Reset index encountered - skip. + ++guest_index_offset; + } + return host_total_index_count; +} + +PrimitiveProcessor::CacheTransaction::CacheTransaction( + PrimitiveProcessor& processor, CacheKey key) + : processor_(processor), key_(key) { + assert_zero(processor_.cache_currently_processing_size_bytes_); + if (cvars::primitive_processor_cache_min_indices < 0 || + key_.count < uint32_t(cvars::primitive_processor_cache_min_indices)) { + // Don't cache if the vertex count is too small. + key_.key = 0; + } + if (!key_.count) { + return; + } + uint32_t size_bytes = + (key_.format == xenos::IndexFormat::kInt16 ? sizeof(uint16_t) + : sizeof(uint32_t)) * + key_.count; + { + auto global_lock = processor_.global_critical_region_.Acquire(); + auto cache_map_it = processor_.cache_map_.find(key_); + if (cache_map_it != processor_.cache_map_.end()) { + result_ = processor_.cache_entry_pool_[cache_map_it->second].result; + result_type_ = ResultType::kExisting; + } else { + // Inhibit writing the new result if the range happens to be modified + // during the processing outside the lock. + processor_.cache_currently_processing_base_ = key_.base; + processor_.cache_currently_processing_size_bytes_ = size_bytes; + } + } + if (result_type_ != ResultType::kExisting) { + // Enable the invalidation callback before reading the indices. + // Also, only enable invalidation callbacks if anything needed processing at + // all - don't waste time in the access violation handler doing nothing if + // the guest doesn't use anything requiring host conversion. + if (!processor_.memory_invalidation_callback_handle_) { + processor_.memory_invalidation_callback_handle_ = + processor_.memory_.RegisterPhysicalMemoryInvalidationCallback( + MemoryInvalidationCallbackThunk, &processor_); + } + processor_.memory_.EnablePhysicalMemoryAccessCallbacks( + key_.base, size_bytes, true, false); + } +} + +PrimitiveProcessor::CacheTransaction::~CacheTransaction() { + if (!key_.count || result_type_ == ResultType::kExisting) { + return; + } + + auto global_lock = processor_.global_critical_region_.Acquire(); + + processor_.cache_currently_processing_base_ = 0; + processor_.cache_currently_processing_size_bytes_ = 0; + + if (result_type_ == ResultType::kNewSet) { + size_t new_entry_index; + if (processor_.cache_bucket_free_first_entry_ != SIZE_MAX) { + new_entry_index = processor_.cache_bucket_free_first_entry_; + processor_.cache_bucket_free_first_entry_ = + processor_.cache_entry_pool_[new_entry_index].free_next; + } else { + new_entry_index = processor_.cache_entry_pool_.size(); + processor_.cache_entry_pool_.emplace_back(); + } + CacheEntry& new_entry = processor_.cache_entry_pool_[new_entry_index]; + + // Put the entry in 1 or 2 buckets. + uint32_t bucket_start_index = key_.base >> kCacheBucketSizeBytesLog2; + uint32_t bucket_count = CacheEntry::GetBucketCount(key_); + for (uint32_t link_index = 0; link_index < bucket_count; ++link_index) { + new_entry.buckets_prev[link_index] = SIZE_MAX; + uint32_t bucket_index = bucket_start_index + link_index; + uint64_t& bucket_non_empty_l1_ref = + processor_.cache_buckets_non_empty_l1_[bucket_index >> 6]; + uint64_t bucket_non_empty_l1_bit = uint64_t(1) << (bucket_index & 63); + size_t& bucket_first_entry_ref = + processor_.cache_bucket_first_entries_[bucket_index]; + if (bucket_non_empty_l1_ref & bucket_non_empty_l1_bit) { + // There is at least one entry already in the bucket - link to the + // first. + new_entry.buckets_next[link_index] = bucket_first_entry_ref; + CacheEntry& bucket_first_entry = + processor_.cache_entry_pool_[bucket_first_entry_ref]; + // If the start ([0]) bucket of bucket_first_entry is bucket_index, + // update its link [0]. Otherwise, since a cache entry may belong only + // to at most 2 buckets, bucket_index must be its [1] bucket. + bucket_first_entry + .buckets_prev[size_t((bucket_first_entry.key.base >> + kCacheBucketSizeBytesLog2) != bucket_index)] = + new_entry_index; + } else { + new_entry.buckets_next[link_index] = SIZE_MAX; + bucket_non_empty_l1_ref |= bucket_non_empty_l1_bit; + processor_.UpdateCacheBucketsNonEmptyL2(bucket_index >> 6, global_lock); + } + bucket_first_entry_ref = new_entry_index; + } + + new_entry.key = key_; + new_entry.result = result_; + + processor_.cache_map_.emplace(key_, new_entry_index); + } +} + +std::pair PrimitiveProcessor::MemoryInvalidationCallback( + uint32_t physical_address_start, uint32_t length, bool exact_range) { + if (length == 0 || physical_address_start >= SharedMemory::kBufferSize) { + return std::make_pair(uint32_t(0), UINT32_MAX); + } + length = std::min(length, SharedMemory::kBufferSize - physical_address_start); + uint32_t physical_address_end = physical_address_start + length; + if (!exact_range) { + // Invalidate entire buckets if this is an access callback rather than + // something like a file read to disable access violation handling for a + // bigger range for higher performance. + physical_address_start &= ~(kCacheBucketSizeBytes - 1); + physical_address_end = + xe::align(physical_address_end, kCacheBucketSizeBytes); + } + bool any_invalidated = false; + uint32_t bucket_index_first = + physical_address_start >> kCacheBucketSizeBytesLog2; + uint32_t bucket_index_last = + (physical_address_end - 1) >> kCacheBucketSizeBytesLog2; + uint32_t bucket_l1_bits_index_first = bucket_index_first >> 6; + uint32_t bucket_l1_bits_index_last = bucket_index_last >> 6; + uint32_t bucket_l2_bits_index_first = bucket_index_first >> 12; + uint32_t bucket_l2_bits_index_last = bucket_index_last >> 12; + auto global_lock = global_critical_region_.Acquire(); + for (uint32_t bucket_l2_bits_index = bucket_l2_bits_index_first; + bucket_l2_bits_index <= bucket_l2_bits_index_last; + ++bucket_l2_bits_index) { + uint64_t bucket_l2_bits_mask = UINT64_MAX; + if (bucket_l2_bits_index == bucket_l2_bits_index_first) { + bucket_l2_bits_mask &= + ~((uint64_t(1) << (bucket_l1_bits_index_first & 63)) - 1); + } + if (bucket_l2_bits_index == bucket_l2_bits_index_last && + (bucket_l1_bits_index_last & 63) != 63) { + bucket_l2_bits_mask &= + (uint64_t(1) << ((bucket_l1_bits_index_last & 63) + 1)) - 1; + } + // Not caching L2 bits because they may be modified by unlinking. + // Loop until any bits in the 64-bit portion of the L2 bit set are left. + while (bucket_l2_bits_mask) { + uint32_t bucket_l2_bit_shift; + if (!xe::bit_scan_forward( + cache_buckets_non_empty_l2_[bucket_l2_bits_index] & + bucket_l2_bits_mask, + &bucket_l2_bit_shift)) { + break; + } + bucket_l2_bits_mask &= ~(uint64_t(1) << bucket_l2_bit_shift); + uint32_t bucket_l1_bits_index = + (bucket_l2_bits_index << 6) | bucket_l2_bit_shift; + uint64_t bucket_l1_bits_mask = UINT64_MAX; + if (bucket_l1_bits_index == bucket_l1_bits_index_first) { + bucket_l1_bits_mask &= + ~((uint64_t(1) << (bucket_index_first & 63)) - 1); + } + if (bucket_l1_bits_index == bucket_l1_bits_index_last && + (bucket_index_last & 63) != 63) { + bucket_l1_bits_mask &= + (uint64_t(1) << ((bucket_index_last & 63) + 1)) - 1; + } + // Not caching L1 bits because they may be modified by unlinking. + // Loop over buckets until any bits in the 64-bit portion of the L1 bit + // set are left. + while (bucket_l1_bits_mask) { + uint32_t bucket_l1_bit_shift; + if (!xe::bit_scan_forward( + cache_buckets_non_empty_l1_[bucket_l1_bits_index] & + bucket_l1_bits_mask, + &bucket_l1_bit_shift)) { + break; + } + bucket_l1_bits_mask &= ~(uint64_t(1) << bucket_l1_bit_shift); + uint32_t bucket_index = + (bucket_l1_bits_index << 6) | bucket_l1_bit_shift; + // Invalidate the entries in the bucket, fully or partially. + size_t entry_index = cache_bucket_first_entries_[bucket_index]; + do { + CacheEntry& entry = cache_entry_pool_[entry_index]; + CacheKey entry_key = entry.key; + // If the start ([0]) bucket of the entry is bucket_index, the link + // within this bucket is its link [0]. Otherwise, since a cache entry + // may belong only to at most 2 buckets, bucket_index must be its [1] + // bucket. + uint32_t entry_bucket_index_first = + entry_key.base >> kCacheBucketSizeBytesLog2; + assert_true((bucket_index - entry_bucket_index_first) <= 1, + "Cache entries only store list links within two buckets"); + size_t next_entry_index = + entry.buckets_next[bucket_index - entry_bucket_index_first]; + // For exact_range, don't invalidate bucket entries that are outside + // the specified range. + if (entry_key.base < physical_address_end) { + uint32_t entry_end = entry_key.base + entry_key.GetSizeBytes(); + if (entry_end > physical_address_end) { + // Invalidate the entry. + any_invalidated = true; + // Remove the entry from the cache map. + auto entry_map_it = cache_map_.find(entry_key); + assert_true(entry_map_it != cache_map_.end()); + if (entry_map_it != cache_map_.end()) { + cache_map_.erase(entry_map_it); + } + // Unlink the entry from the bucket's list. + uint32_t entry_link_index_last = + ((entry_end - 1) >> kCacheBucketSizeBytesLog2) - + entry_bucket_index_first; + assert_true( + entry_link_index_last <= 1, + "Cache entries only store list links within two buckets"); + for (uint32_t entry_link_index = 0; + entry_link_index <= entry_link_index_last; + ++entry_link_index) { + uint32_t entry_bucket_index = + entry_bucket_index_first + entry_link_index; + size_t entry_link_prev = entry.buckets_prev[entry_link_index]; + size_t entry_link_next = entry.buckets_next[entry_link_index]; + if (entry_link_prev != SIZE_MAX) { + CacheEntry& entry_prev = cache_entry_pool_[entry_link_prev]; + entry_prev.buckets_next[size_t( + (entry_prev.key.base >> kCacheBucketSizeBytesLog2) != + entry_bucket_index)] = entry_link_next; + } else { + if (entry_link_next != SIZE_MAX) { + cache_bucket_first_entries_[entry_bucket_index] = + entry_link_next; + } else { + // The only entry that was remaining in the bucket - it's + // empty now. + cache_buckets_non_empty_l1_[entry_bucket_index >> 6] &= + ~(uint64_t(1) << (entry_bucket_index & 63)); + UpdateCacheBucketsNonEmptyL2(entry_bucket_index >> 6, + global_lock); + } + } + if (entry_link_next != SIZE_MAX) { + CacheEntry& entry_next = cache_entry_pool_[entry_link_next]; + entry_next.buckets_prev[size_t( + (entry_next.key.base >> kCacheBucketSizeBytesLog2) != + entry_bucket_index)] = entry_link_prev; + } + } + // Make the entry free for reuse. + entry.free_next = cache_bucket_free_first_entry_; + cache_bucket_free_first_entry_ = entry_index; + } + } + entry_index = next_entry_index; + } while (entry_index != SIZE_MAX); + } + } + } + return any_invalidated + ? std::make_pair(physical_address_start, + physical_address_end - physical_address_start) + : std::make_pair(uint32_t(0), UINT32_MAX); +} + +std::pair +PrimitiveProcessor::MemoryInvalidationCallbackThunk( + void* context_ptr, uint32_t physical_address_start, uint32_t length, + bool exact_range) { + return reinterpret_cast(context_ptr) + ->MemoryInvalidationCallback(physical_address_start, length, exact_range); +} + +} // namespace gpu +} // namespace xe diff --git a/src/xenia/gpu/primitive_processor.h b/src/xenia/gpu/primitive_processor.h new file mode 100644 index 000000000..762b7f1f9 --- /dev/null +++ b/src/xenia/gpu/primitive_processor.h @@ -0,0 +1,869 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2021 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_GPU_PRIMITIVE_PROCESSOR_H_ +#define XENIA_GPU_PRIMITIVE_PROCESSOR_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xenia/base/assert.h" +#include "xenia/base/cvar.h" +#include "xenia/base/math.h" +#include "xenia/base/mutex.h" +#include "xenia/base/platform.h" +#include "xenia/gpu/register_file.h" +#include "xenia/gpu/shader.h" +#include "xenia/gpu/shared_memory.h" +#include "xenia/gpu/trace_writer.h" +#include "xenia/gpu/xenos.h" +#include "xenia/memory.h" + +#if XE_ARCH_AMD64 +// 128-bit SSSE3-level (SSE2+ for integer comparison, SSSE3 for pshufb) or AVX +// (256-bit AVX only got integer operations such as comparison in AVX2, which is +// above the minimum requirements of Xenia). +#include +#define XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE 16 +#elif XE_ARCH_ARM64 +#include +#define XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE 16 +#else +#define XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE 0 +#endif // XE_ARCH + +// The idea behind this config variable is to force both indirection without +// primitive reset and pre-masking / pre-swapping with primitive reset, +// therefore this is supposed to be checked only by the host if it supports +// indirection. It's pretty pointless to do only half of this on backends that +// support full 32-bit indices unconditionally. +DECLARE_bool(ignore_32bit_vertex_index_support); + +namespace xe { +namespace gpu { + +// Normalizes primitive data in various ways for use with Direct3D 12 and Vulkan +// (down to its minimum requirements plus the portability subset). +// +// This solves various issues: +// - Triangle fans not supported on Direct3D 10+ and the Vulkan portability +// subset. +// - Converts to triangle lists, both with and without primitive reset. +// - Line loops are not supported on Direct3D 12 or Vulkan. +// - Converts to line strips. +// - Quads not reproducible with line lists with adjacency without geometry +// shaders (some Vulkan implementations), as well as being hard to debug in +// PIX due to "catastrophic failures". +// - Converts to triangle lists. +// - Vulkan requiring 0xFFFF primitive restart index for 16-bit indices and +// 0xFFFFFFFF for 32-bit (Direct3D 12 slightly relaxes this, allowing 0xFFFF +// for 32-bit also, but it's of no use to Xenia since guest indices are +// big-endian usually. Also, only 24 lower bits of the vertex index being used +// on the guest (tested on an Adreno 200 phone with drawing, though not with +// primitive restart as OpenGL ES 2.0 doesn't expose it), so the upper 8 bits +// likely shouldn't have effect on primitive restart (guest reset index +// 0xFFFFFF likely working for 0xFFFFFF, 0xFFFFFFFF, and 254 more indices), +// while Vulkan and Direct3D 12 require exactly 0xFFFFFFFF. +// - For 16-bit indices with guest reset index other than 0xFFFF (passing +// 0xFFFF directly to the host is fine because it's the same irrespective of +// endianness), there are two possible solutions: +// - If the index buffer otherwise doesn't contain 0xFFFF otherwise (since +// it's a valid vertex index in this case), replacing the primitive reset +// index with 0xFFFF in the 16-bit buffer. +// - If the index buffer contains any usage of 0xFFFF as a real vertex +// index, converting the index buffer to 32-bit, and replacing the +// primitive reset index with 0xFFFFFFFF. +// - For 32-bit indices, there are two paths: +// - If the guest reset index is 0xFFFFFF, and the index buffer actually +// uses only 0xFFFFFFFF for reset, using it without changes. +// - If the guest uses something other than 0xFFFFFFFF for primitive reset, +// replacing elements with (index & 0xFFFFFF) == reset_index with +// 0xFFFFFFFF. +// - Some Vulkan implementations only support 24-bit indices. The guests usually +// pass big-endian vertices, so we need all 32 bits (as the least significant +// bits will be in 24...31) to perform the byte swapping. For this reason, we +// load 32-bit indices indirectly, doing non-indexed draws and fetching the +// indices from the shared memory. This, however, is not compatible with +// primitive restart. +// - Pre-swapping, masking to 24 bits, and converting the reset index to +// 0xFFFFFFFF, resulting in an index buffer that can be used directly. + +class PrimitiveProcessor { + public: + enum ProcessedIndexBufferType { + // Auto-indexed on the host. + kNone, + // GPU DMA, from the shared memory. + // For 32-bit, indirection is needed if the host only supports 24-bit + // indices (even for non-endian-swapped, as the GPU should be ignoring the + // upper 8 bits completely, rather than exhibiting undefined behavior. + kGuest, + // Converted and stored in the primitive converter for the current draw + // command. For 32-bit indices, if the host doesn't support all 32 bits, + // this kind of an index buffer will always be pre-masked and pre-swapped. + kHostConverted, + // Auto-indexed on the guest, but with an adapter index buffer on the host. + kHostBuiltin, + }; + + struct ProcessingResult { + xenos::PrimitiveType guest_primitive_type; + xenos::PrimitiveType host_primitive_type; + // Includes whether tessellation is enabled (not kVertex) and the type of + // tessellation. + Shader::HostVertexShaderType host_vertex_shader_type; + // Only used for non-kVertex host_vertex_shader_type. For kAdaptive, the + // index buffer is always from the guest and fully 32-bit, and contains the + // floating-point tessellation factors. + xenos::TessellationMode tessellation_mode; + // TODO(Triang3l): If important, split into the index count and the actual + // index buffer size, using zeros for out-of-bounds indices. + uint32_t host_draw_vertex_count; + uint32_t line_loop_closing_index; + ProcessedIndexBufferType index_buffer_type; + uint32_t guest_index_base; + xenos::IndexFormat host_index_format; + xenos::Endian host_index_endian; + // The reset index, if enabled, is always 0xFFFF for host_index_format + // kInt16 and 0xFFFFFFFF for kInt32. + bool host_primitive_reset_enabled; + // Backend-specific handle for the index buffer valid for the current draw, + // only valid for index_buffer_type kHostConverted and kHostBuiltin. + size_t host_index_buffer_handle; + bool IsTessellated() const { + return host_vertex_shader_type != Shader::HostVertexShaderType::kVertex; + } + }; + + virtual ~PrimitiveProcessor(); + + bool AreFull32BitVertexIndicesUsed() const { + return full_32bit_vertex_indices_used_; + } + bool IsConvertingTriangleFansToLists() const { + return convert_triangle_fans_to_lists_; + } + bool IsConvertingLineLoopsToStrips() const { + return convert_line_loops_to_strips_; + } + // Quad lists may be emulated as line lists with adjacency and a geometry + // shader, but geometry shaders must be supported for this. + bool IsConvertingQuadListsToTriangleLists() const { + return convert_quad_lists_to_triangle_lists_; + } + + // Submission must be open to call (may request the index buffer in the shared + // memory). + bool Process(ProcessingResult& result_out); + + // Invalidates the cache within the range. + std::pair MemoryInvalidationCallback( + uint32_t physical_address_start, uint32_t length, bool exact_range); + + protected: + // For host-side index buffer creation, the biggest possibly needed contiguous + // allocation, in indices. + // - No conversion: up to 0xFFFF vertices (as the vertex count in + // VGT_DRAW_INITIATOR is 16-bit). + // - Triangle fans to lists: since the 3rd vertex, every guest vertex creates + // a triangle, thus the maximum is 3 * (UINT16_MAX - 2), or 0x2FFF7. + // Primitive reset can only slow down the amplification - the 3 vertices + // after a reset add 1 host vertex each, not 3 each. + // - Line loops to strips: adding 1 vertex if there are at least 2 vertices in + // the original primitive, either replacing the primitive reset index with + // this new closing vertex, or in case of the final primitive, just adding a + // vertex - thus the absolute limit is UINT16_MAX + 1, or 0x10000. + // - Quad lists to triangle lists: vertices are processed in groups of 4, each + // group converted to 6 vertices, so the limit is 1.5 * 0xFFFC, or 0x17FFA. + // Thus, the maximum vertex count is defined by triangle fan to list + // conversion. + // Also include padding for co-alignment of the source and the destination for + // SIMD. + static constexpr uint32_t kMinRequiredConvertedIndexBufferSize = + sizeof(uint32_t) * (UINT16_MAX - 2) * 3 * + +XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE; + + PrimitiveProcessor(const RegisterFile& register_file, Memory& memory, + TraceWriter& trace_writer, SharedMemory& shared_memory) + : register_file_(register_file), + memory_(memory), + trace_writer_(trace_writer), + shared_memory_(shared_memory) {} + + // Call from the backend-specific initialization function. + // - full_32bit_vertex_indices_supported: + // - If the backend supports 32-bit indices unconditionally, and doesn't + // generate indirection logic in vertex shaders, pass hard-coded `true`. + // - Otherwise: + // - If the host doesn't support full 32-bit indices (but supports at + // least 24-bit indices), pass `false`. + // - If the host supports 32-bit indices, but the backend can handle both + // cases, pass `cvars::ignore_32bit_vertex_index_support`, and + // afterwards, check `AreFull32BitVertexIndicesUsed()` externally to see + // if indirection may be needed. + // - When full 32-bit indices are not supported, the host must be using + // auto-indexed draws for 32-bit indices of ProcessedIndexBufferType + // kGuest, while fetching the index data manually from the shared memory + // buffer and endian-swapping it. + // - Indirection, however, precludes primitive reset usage - so if + // primitive reset is needed, the primitive processor will pre-swap and + // pre-mask the index buffer so there are only host-endian 0x00###### or + // 0xFFFFFFFF values in it. In this case, a kHostConverted index buffer + // is returned from Process, and indirection is not needed (and + // impossible since the index buffer is not in the shared memory buffer + // anymore), though byte swap is still needed as 16-bit indices may also + // be kHostConverted, while they are completely unaffected by this. The + // same applies to primitive type conversion - if it happens for 32-bit + // guest indices, and kHostConverted is returned, they will be + // pre-swapped and pre-masked. + // - triangle_fans_supported, line_loops_supported, quad_lists_supported: + // - Pass true or false depending on whether the host actually supports + // those guest primitive types directly or through geometry shader + // emulation. Debug overriding will be resolved in the common code if + // needed. + bool InitializeCommon(bool full_32bit_vertex_indices_supported, + bool triangle_fans_supported, bool line_loops_supported, + bool quad_lists_supported); + // If any primitive type conversion is needed for auto-indexed draws, called + // from InitializeCommon (thus only once in the primitive processor's + // lifetime) to set up the backend's index buffer containing indices for + // primitive type remapping. The backend must allocate a `sizeof(uint16_t) * + // index_count` buffer and call fill_callback for its mapping if creation is + // successful. 16-bit indices are enough even if the backend has primitive + // reset enabled all the time (Metal) as auto-indexed draws are limited to + // UINT16_MAX vertices, not UINT16_MAX + 1. + virtual bool InitializeBuiltin16BitIndexBuffer( + uint32_t index_count, std::function fill_callback) = 0; + // Call last in implementation-specific shutdown, also callable from the + // destructor. + void ShutdownCommon(); + + // Call at boundaries of lifespans of converted data (between frames, + // preferably in the end of a frame so between the swap and the next draw, + // access violation handlers need to do less work). + void ClearPerFrameCache(); + + static constexpr size_t GetBuiltinIndexBufferOffsetBytes(size_t handle) { + // For simplicity, just using the handles as byte offsets. + return handle; + } + + // The destination allocation must have XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + // excess bytes. + static ptrdiff_t GetSimdCoalignmentOffset(const void* host_index_ptr, + uint32_t guest_index_base) { +#if XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + // Always moving the host pointer only forward into the allocation padding + // space of XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE bytes. Without relying on + // two's complement wrapping overflow behavior, the logic would look like: + // uintptr_t host_subalignment = + // reinterpret_cast(host_index_ptr) & + // (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1); + // uint32_t guest_subalignment = guest_index_base & + // (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1); + // uintptr_t host_index_address_aligned = host_index_address; + // if (guest_subalignment >= host_subalignment) { + // return guest_subalignment - host_subalignment; + // } + // return XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - + // (host_subalignment - guest_subalignment); + return ptrdiff_t( + (guest_index_base - reinterpret_cast(host_index_ptr)) & + (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1)); +#else + return 0; +#endif + } + + // Requests a buffer to write the new transformed indices to. The lifetime of + // the returned buffer must be that of the current frame. Returns the mapping + // of the buffer to write to, or nullptr in case of failure, in addition to, + // if successful, a handle that can be used by the backend's command processor + // to access the backend-specific data for binding the buffer. + virtual void* RequestHostConvertedIndexBufferForCurrentFrame( + xenos::IndexFormat format, uint32_t index_count, bool coalign_for_simd, + uint32_t coalignment_original_address, size_t& backend_handle_out) = 0; + + private: +#if XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE +#if XE_ARCH_AMD64 + // SSSE3 or AVX. + using SimdVectorU16 = __m128i; + using SimdVectorU32 = __m128i; + static SimdVectorU16 ReplicateU16(uint16_t value) { + return _mm_set1_epi16(int16_t(value)); + } + static SimdVectorU32 ReplicateU32(uint32_t value) { + return _mm_set1_epi32(int32_t(value)); + } + static SimdVectorU16 LoadAlignedVectorU16(const uint16_t* source) { + return _mm_load_si128(reinterpret_cast(source)); + } + static SimdVectorU32 LoadAlignedVectorU32(const uint32_t* source) { + return _mm_load_si128(reinterpret_cast(source)); + } + static void StoreUnalignedVectorU16(uint16_t* dest, SimdVectorU16 source) { + _mm_storeu_si128(reinterpret_cast<__m128i*>(dest), source); + } + static void StoreUnalignedVectorU32(uint32_t* dest, SimdVectorU32 source) { + _mm_storeu_si128(reinterpret_cast<__m128i*>(dest), source); + } +#elif XE_ARCH_ARM64 + // NEON. + using SimdVectorU16 = uint16x8_t; + using SimdVectorU32 = uint32x4_t; + static SimdVectorU16 ReplicateU16(uint16_t value) { + return vdupq_n_u16(value); + } + static SimdVectorU32 ReplicateU32(uint32_t value) { + return vdupq_n_u32(value); + } + static SimdVectorU16 LoadAlignedVectorU16(const uint16_t* source) { +#if XE_COMPILER_MSVC + return vld1q_u16_ex(source, sizeof(uint16x8_t) * CHAR_BIT); +#else + return vld1q_u16(reinterpret_cast( + __builtin_assume_aligned(source, sizeof(uint16x8_t)))); +#endif + } + static SimdVectorU32 LoadAlignedVectorU32(const uint32_t* source) { +#if XE_COMPILER_MSVC + return vld1q_u32_ex(source, sizeof(uint16x8_t) * CHAR_BIT); +#else + return vld1q_u32(reinterpret_cast( + __builtin_assume_aligned(source, sizeof(uint32x4_t)))); +#endif + } + static void StoreUnalignedVectorU16(uint16_t* dest, SimdVectorU16 source) { + vst1q_u16(dest, source); + } + static void StoreUnalignedVectorU32(uint32_t* dest, SimdVectorU32 source) { + vst1q_u32(dest, source); + } +#else +#error SIMD vector types and constant loads not specified. +#endif // XE_ARCH + static_assert( + sizeof(SimdVectorU16) == XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE, + "XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE must reflect the vector size " + "actually used"); + static_assert( + sizeof(SimdVectorU32) == XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE, + "XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE must reflect the vector size " + "actually used"); + static constexpr uint32_t kSimdVectorU16Elements = + sizeof(SimdVectorU16) / sizeof(uint16_t); + static constexpr uint32_t kSimdVectorU32Elements = + sizeof(SimdVectorU32) / sizeof(uint32_t); +#endif // XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + + static bool IsResetUsed(const uint16_t* source, uint32_t count, + uint16_t reset_index_guest_endian); + static void Get16BitResetIndexUsage(const uint16_t* source, uint32_t count, + uint16_t reset_index_guest_endian, + bool& is_reset_index_used_out, + bool& is_ffff_used_as_vertex_index_out); + static bool IsResetUsed(const uint32_t* source, uint32_t count, + uint32_t reset_index_guest_endian, + uint32_t low_bits_mask_guest_endian); + static void ReplaceResetIndex16To16(uint16_t* dest, const uint16_t* source, + uint32_t count, + uint16_t reset_index_guest_endian); + // For use when the reset index is not 0xFFFF, and 0xFFFF is also used as a + // valid index - keeps 0xFFFF as a real index and replaces the reset index + // with 0xFFFFFFFF instead. + static void ReplaceResetIndex16To24(uint32_t* dest, const uint16_t* source, + uint32_t count, + uint16_t reset_index_guest_endian); + // The reset index and the low 24 bits mask are taken explicitly because this + // function may be used two ways: + // - Passthrough - when the vertex shader swaps the indices (when 32-bit + // indices are supported on the host), in this case HostSwap is kNone, but + // the reset index and the guest low bits mask can be swapped according to + // the guest endian. + // - Swapping for the host - when only 24 bits of an index are supported on + // the host. In this case, masking and comparison are done before applying + // HostSwap, but according to HostSwap, if needed, the data is swapped from + // the PowerPC's big endianness to the host GPU little endianness that we + // assume, which matches the Xenos's little endianness. + template + static void ReplaceResetIndex32To24(uint32_t* dest, const uint32_t* source, + uint32_t count, + uint32_t reset_index_guest_endian, + uint32_t low_bits_mask_guest_endian) { + // The Xbox 360's GPU only uses the low 24 bits of the index - masking. +#if XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count && (reinterpret_cast(source) & + (XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE - 1))) { + --count; + uint32_t index = *(source++) & low_bits_mask_guest_endian; + *(dest++) = index != reset_index_guest_endian + ? xenos::GpuSwap(index, HostSwap) + : UINT32_MAX; + } + if (count >= kSimdVectorU32Elements) { + SimdVectorU32 reset_index_guest_endian_simd = + ReplicateU32(reset_index_guest_endian); + SimdVectorU32 low_bits_mask_guest_endian_simd = + ReplicateU32(low_bits_mask_guest_endian); +#if XE_ARCH_AMD64 + __m128i host_swap_shuffle; + if constexpr (HostSwap != xenos::Endian::kNone) { + host_swap_shuffle = _mm_set_epi32( + int32_t(xenos::GpuSwap(uint32_t(0x0F0E0D0C), HostSwap)), + int32_t(xenos::GpuSwap(uint32_t(0x0B0A0908), HostSwap)), + int32_t(xenos::GpuSwap(uint32_t(0x07060504), HostSwap)), + int32_t(xenos::GpuSwap(uint32_t(0x03020100), HostSwap))); + } +#endif // XE_ARCH_AMD64 + while (count >= kSimdVectorU32Elements) { + count -= kSimdVectorU32Elements; + // Comparison produces 0 or 0xFFFF on AVX and Neon - we need 0xFFFF as + // the result for the primitive reset indices, so the result is + // `index | (index == reset_index)`. + SimdVectorU32 source_simd = LoadAlignedVectorU32(source); + source += kSimdVectorU32Elements; + SimdVectorU32 result_simd; +#if XE_ARCH_AMD64 + source_simd = + _mm_and_si128(source_simd, low_bits_mask_guest_endian_simd); + result_simd = _mm_or_si128( + source_simd, + _mm_cmpeq_epi32(source_simd, reset_index_guest_endian_simd)); + if constexpr (HostSwap != xenos::Endian::kNone) { + result_simd = _mm_shuffle_epi8(result_simd, host_swap_shuffle); + } +#elif XE_ARCH_ARM64 + source_simd = vandq_u32(source_simd, low_bits_mask_guest_endian_simd); + result_simd = vorrq_u32( + source_simd, vceqq_u32(source_simd, reset_index_guest_endian_simd)); + if constexpr (HostSwap == xenos::Endian::k8in16) { + result_simd = vreinterpretq_u32_u8( + vrev16q_u8(vreinterpretq_u8_u32(result_simd))); + } else if constexpr (HostSwap == xenos::Endian::k8in32) { + result_simd = vreinterpretq_u32_u8( + vrev32q_u8(vreinterpretq_u8_u32(result_simd))); + } else if constexpr (HostSwap == xenos::Endian::k16in32) { + result_simd = vreinterpretq_u32_u16( + vrev32q_u16(vreinterpretq_u16_u32(result_simd))); + } +#else +#error SIMD ReplaceResetIndex32To24 not implemented. +#endif // XE_ARCH + StoreUnalignedVectorU32(dest, result_simd); + dest += kSimdVectorU32Elements; + } + } +#endif // XE_GPU_PRIMITIVE_PROCESSOR_SIMD_SIZE + while (count--) { + uint32_t index = *(source++) & low_bits_mask_guest_endian; + *(dest++) = index != reset_index_guest_endian + ? xenos::GpuSwap(index, HostSwap) + : UINT32_MAX; + } + } + + // TODO(Triang3l): 16-bit > 32-bit primitive type conversion for Metal, where + // primitive reset is always enabled, if UINT16_MAX is used as a real vertex + // index. + + struct PassthroughIndexTransform { + uint16_t operator()(uint16_t index) const { return index; } + uint32_t operator()(uint32_t index) const { return index; } + }; + struct To24NonSwappingIndexTransform { + uint32_t operator()(uint32_t index) const { + return index & xenos::kVertexIndexMask; + } + }; + struct To24Swapping8In16IndexTransform { + uint32_t operator()(uint32_t index) const { + return xenos::GpuSwap(index, xenos::Endian::k8in16) & + xenos::kVertexIndexMask; + } + }; + struct To24Swapping8In32IndexTransform { + uint32_t operator()(uint32_t index) const { + return xenos::GpuSwap(index, xenos::Endian::k8in32) & + xenos::kVertexIndexMask; + } + }; + struct To24Swapping16In32IndexTransform { + uint32_t operator()(uint32_t index) const { + return xenos::GpuSwap(index, xenos::Endian::k16in32) & + xenos::kVertexIndexMask; + } + }; + + // Triangle fans as triangle lists. + // Ordered as (v1, v2, v0), (v2, v3, v0) in Direct3D. + // https://docs.microsoft.com/en-us/windows/desktop/direct3d9/triangle-fans + static constexpr uint32_t GetTriangleFanListIndexCount( + uint32_t fan_index_count) { + return fan_index_count > 2 ? (fan_index_count - 2) * 3 : 0; + } + template + static void TriangleFanToList(Index* dest, const Index* source, + uint32_t source_index_count, + const IndexTransform& index_transform) { + if (source_index_count <= 2) { + // To match GetTriangleFanListIndexCount. + return; + } + Index index_first = index_transform(source[0]); + Index index_previous = index_transform(source[1]); + for (uint32_t i = 2; i < source_index_count; ++i) { + Index index_current = index_transform(source[i]); + *(dest++) = index_previous; + *(dest++) = index_current; + *(dest++) = index_first; + index_previous = index_current; + } + } + + static constexpr uint32_t GetLineLoopStripIndexCount( + uint32_t loop_index_count) { + // Even if 2 vertices are supplied, two lines are still drawn between them. + // https://www.khronos.org/opengl/wiki/Primitive + // "You get n lines for n input vertices" + // "If the user only specifies 1 vertex, the drawing command is ignored" + return loop_index_count > 1 ? loop_index_count + 1 : 0; + } + template + static void LineLoopToStrip(Index* dest, const Index* source, + uint32_t source_index_count, + const IndexTransform& index_transform) { + if (source_index_count <= 1) { + // To match GetLineLoopStripIndexCount. + return; + } + Index index_first = index_transform(source[0]); + dest[0] = index_first; + for (uint32_t i = 1; i < source_index_count; ++i) { + dest[i] = index_transform(source[i]); + } + dest[source_index_count] = index_first; + } + static void LineLoopToStrip(uint16_t* dest, const uint16_t* source, + uint32_t source_index_count, + const PassthroughIndexTransform& index_transform); + static void LineLoopToStrip(uint32_t* dest, const uint32_t* source, + uint32_t source_index_count, + const PassthroughIndexTransform& index_transform); + + static constexpr uint32_t GetQuadListTriangleListIndexCount( + uint32_t quad_list_index_count) { + return (quad_list_index_count / 4) * 6; + } + template + static void QuadListToTriangleList(Index* dest, const Index* source, + uint32_t source_index_count, + const IndexTransform& index_transform) { + uint32_t quad_count = source_index_count / 4; + for (uint32_t i = 0; i < quad_count; ++i) { + // TODO(Triang3l): Find the correct order. + // v0, v1, v2. + Index common_index_0 = index_transform(*(source++)); + *(dest++) = common_index_0; + *(dest++) = index_transform(*(source++)); + Index common_index_2 = index_transform(*(source++)); + *(dest++) = common_index_2; + // v0, v2, v3. + *(dest++) = common_index_0; + *(dest++) = common_index_2; + *(dest++) = index_transform(*(source++)); + } + } + + // Pre-gathering the ranges allows for usage of the same functions for + // conversion with and without reset. In addition, this increases safety in + // weird cases - there won't be mismatch between the pre-calculation of the + // post-conversion index count and the actual conversion if the game for some + // reason modifies the index buffer between the two and adds or removes reset + // indices in it. + struct SinglePrimitiveRange { + SinglePrimitiveRange(uint32_t guest_offset, uint32_t guest_index_count, + uint32_t host_index_count) + : guest_offset(guest_offset), + guest_index_count(guest_index_count), + host_index_count(host_index_count) {} + uint32_t guest_offset; + uint32_t guest_index_count; + uint32_t host_index_count; + }; + static uint32_t GetMultiPrimitiveHostIndexCountAndRanges( + std::function single_primitive_guest_to_host_count, + const uint16_t* source, uint32_t source_index_count, + uint16_t reset_index_guest_endian, + std::deque& ranges_append_out); + static uint32_t GetMultiPrimitiveHostIndexCountAndRanges( + std::function single_primitive_guest_to_host_count, + const uint32_t* source, uint32_t source_index_count, + uint32_t reset_index_guest_endian, uint32_t low_bits_mask_guest_endian, + std::deque& ranges_append_out); + + template + static void ConvertSinglePrimitiveRanges( + Index* dest, const Index* source, + xenos::PrimitiveType source_primitive_type, + const IndexTransform& index_transform, + PrimitiveRangeIterator ranges_beginning, + PrimitiveRangeIterator ranges_end) { + Index* dest_write_ptr = dest; + switch (source_primitive_type) { + case xenos::PrimitiveType::kTriangleFan: + for (PrimitiveRangeIterator range_it = ranges_beginning; + range_it != ranges_end; ++range_it) { + TriangleFanToList(dest_write_ptr, source + range_it->guest_offset, + range_it->guest_index_count, index_transform); + dest_write_ptr += range_it->host_index_count; + } + break; + case xenos::PrimitiveType::kLineLoop: + for (PrimitiveRangeIterator range_it = ranges_beginning; + range_it != ranges_end; ++range_it) { + LineLoopToStrip(dest_write_ptr, source + range_it->guest_offset, + range_it->guest_index_count, index_transform); + dest_write_ptr += range_it->host_index_count; + } + break; + case xenos::PrimitiveType::kQuadList: + for (PrimitiveRangeIterator range_it = ranges_beginning; + range_it != ranges_end; ++range_it) { + QuadListToTriangleList(dest_write_ptr, + source + range_it->guest_offset, + range_it->guest_index_count, index_transform); + dest_write_ptr += range_it->host_index_count; + } + break; + default: + assert_unhandled_case(source_primitive_type); + } + } + + const RegisterFile& register_file_; + Memory& memory_; + TraceWriter& trace_writer_; + SharedMemory& shared_memory_; + + bool full_32bit_vertex_indices_used_ = false; + bool convert_triangle_fans_to_lists_ = false; + bool convert_line_loops_to_strips_ = false; + bool convert_quad_lists_to_triangle_lists_ = false; + + // Byte offsets used, for simplicity, directly as handles. + size_t builtin_ib_offset_triangle_fans_to_lists_ = SIZE_MAX; + size_t builtin_ib_offset_quad_lists_to_triangle_lists_ = SIZE_MAX; + + std::deque single_primitive_ranges_; + + // Caching for reuse of converted indices within a frame. + + // 256 KB as the largest possible guest index buffer - 0xFFFF 32-bit indices - + // is slightly smaller than 256 KB, thus cache entries need store links within + // at most 2 buckets. + static constexpr uint32_t kCacheBucketSizeBytesLog2 = 18; + static constexpr uint32_t kCacheBucketSizeBytes = + uint32_t(1) << kCacheBucketSizeBytesLog2; + static constexpr uint32_t kCacheBucketCount = + xe::align(SharedMemory::kBufferSize, kCacheBucketSizeBytes) / + kCacheBucketSizeBytes; + + union CacheKey { + struct { + uint32_t base; // 32 total + uint32_t count : 16; // 48 + xenos::IndexFormat format : 1; // 49 + xenos::Endian endian : 2; // 52 + uint32_t is_reset_enabled : 1; // 53 + // kNone if not changing the type (like only processing the reset index). + xenos::PrimitiveType conversion_guest_primitive_type : 6; // 59 + }; + uint64_t key = 0; + + CacheKey() = default; + CacheKey(uint32_t base, uint32_t count, xenos::IndexFormat format, + xenos::Endian endian, bool is_reset_enabled, + xenos::PrimitiveType conversion_guest_primitive_type = + xenos::PrimitiveType::kNone) + : base(base), + count(count), + format(format), + endian(endian), + is_reset_enabled(is_reset_enabled), + conversion_guest_primitive_type(conversion_guest_primitive_type) {} + + struct Hasher { + size_t operator()(const CacheKey& key) const { + return std::hash{}(key.key); + } + }; + bool operator==(const CacheKey& other_key) const { + return key == other_key.key; + } + + uint32_t GetSizeBytes() const { + return count * (format == xenos::IndexFormat::kInt16 ? sizeof(uint16_t) + : sizeof(uint32_t)); + } + }; + + // Subset of ConversionResult that can be reused for different primitive types + // if the same result is used irrespective of one (like when only processing + // the reset index). + struct CachedResult { + uint32_t host_draw_vertex_count; + ProcessedIndexBufferType index_buffer_type; + xenos::IndexFormat host_index_format; + xenos::Endian host_index_endian; + bool host_primitive_reset_enabled; + size_t host_index_buffer_handle; + }; + + struct CacheEntry { + static_assert( + UINT16_MAX * sizeof(uint32_t) <= + (size_t(1) << kCacheBucketSizeBytesLog2), + "Assuming that primitive processor cache entries need to store to the " + "previous and to the next entries only within up to 2 buckets, so the " + "size of the cache buckets must be not smaller than the maximum guest " + "index buffer size"); + union { + size_t free_next; + size_t buckets_prev[2]; + }; + size_t buckets_next[2]; + CacheKey key; + CachedResult result; + static uint32_t GetBucketCount(CacheKey key) { + uint32_t count = + ((key.base + (key.GetSizeBytes() - 1)) >> kCacheBucketSizeBytesLog2) - + (key.base >> kCacheBucketSizeBytesLog2) + 1; + assert_true(count <= 2, + "Cache entries only store list links within two buckets"); + return count; + } + uint32_t GetBucketCount() const { return GetBucketCount(key); } + }; + + // A cache transaction performs a few operations in a RAII-like way (so + // processing may return an error for any reason, and won't have to clean up + // cache_currently_processing_base_ / size_bytes_ explicitly): + // - Transaction initialization: + // - Lookup of previously processed indices in the cache. + // - If not found, beginning to add a new entry that is going to be + // processed: + // - Marking the range as currently being processed, for slightly safer + // race condition handling if one happens - if invalidation happens + // during the transaction (but outside a global critical region lock, + // since processing may take a long time), the new cache entry won't be + // stored as it will already be invalid at the time of the completion of + // the transaction. + // - Enabling an access callback for the range. + // - Setting the new result after processing (if not found in the cache + // previously). + // - Transaction completion: + // - If the range wasn't invalidated during the transaction, storing the new + // entry in the cache. + // If an entry was found in the cache (GetFoundResult results non-null), it + // MUST be used instead of processing - this class doesn't provide the + // possibility replace existing entries. + class CacheTransaction final { + public: + CacheTransaction(PrimitiveProcessor& processor, CacheKey key); + const CachedResult* GetFoundResult() const { + return result_type_ == ResultType::kExisting ? &result_ : nullptr; + } + void SetNewResult(const CachedResult& new_result) { + // Replacement of an existing entry is not allowed. + assert_true(result_type_ != ResultType::kExisting); + result_ = new_result; + result_type_ = ResultType::kNewSet; + } + ~CacheTransaction(); + + private: + PrimitiveProcessor& processor_; + // If key_.count == 0, this transaction shouldn't do anything - for empty + // ranges it's pointless, and it's unsafe to get the end pointer without + // special logic, and count == 0 is also used as a special indicator for + // vertex count below the cache usage threshold. + CacheKey key_; + CachedResult result_; + enum class ResultType { + kNewUnset, + kNewSet, + kExisting, + }; + ResultType result_type_ = ResultType::kNewUnset; + }; + + std::deque cache_entry_pool_; + + void* memory_invalidation_callback_handle_ = nullptr; + + xe::global_critical_region global_critical_region_; + // Modified by both the processor and the invalidation callback. + std::unordered_map cache_map_; + // The conversion is performed while the lock is released since it may take a + // long time. + // If during the conversion the region currently being converted is + // invalidated, the current entry will not be added to the cache. + // Modified by the processor, read by the invalidation callback. + uint32_t cache_currently_processing_base_ = 0; + // 0 if not in a cache transaction that hasn't found an existing entry + // currently. + uint32_t cache_currently_processing_size_bytes_ = 0; + // Modified by both the processor and the invalidation callback. + size_t cache_bucket_free_first_entry_ = SIZE_MAX; + // Modified by both the processor and the invalidation callback. + uint64_t cache_buckets_non_empty_l1_[(kCacheBucketCount + 63) / 64] = {}; + // For even faster handling of memory invalidation - whether any bit is set in + // each cache_buckets_non_empty_l1_. + // Modified by both the processor and the invalidation callback. + uint64_t cache_buckets_non_empty_l2_[(kCacheBucketCount + (64 * 64 - 1)) / + (64 * 64)] = {}; + // Must be called in a global critical region. + void UpdateCacheBucketsNonEmptyL2( + uint32_t bucket_index_div_64, + [[maybe_unused]] const std::unique_lock& + global_lock) { + uint64_t& cache_buckets_non_empty_l2_ref = + cache_buckets_non_empty_l2_[bucket_index_div_64 >> 6]; + uint64_t cache_buckets_non_empty_l2_bit = uint64_t(1) + << (bucket_index_div_64 & 63); + if (cache_buckets_non_empty_l1_[bucket_index_div_64]) { + cache_buckets_non_empty_l2_ref |= cache_buckets_non_empty_l2_bit; + } else { + cache_buckets_non_empty_l2_ref &= ~cache_buckets_non_empty_l2_bit; + } + } + // cache_buckets_non_empty_l1_ (along with cache_buckets_non_empty_l2_, which + // must be kept in sync) used for indication whether each entry is non-empty, + // for faster clearing (there's no special index here for an empty entry). + // Huge, so it's the last in the class. + // Modified by both the processor and the invalidation callback. + size_t cache_bucket_first_entries_[kCacheBucketCount]; + static std::pair MemoryInvalidationCallbackThunk( + void* context_ptr, uint32_t physical_address_start, uint32_t length, + bool exact_range); +}; + +} // namespace gpu +} // namespace xe + +#endif // XENIA_GPU_PRIMITIVE_PROCESSOR_H_ diff --git a/src/xenia/gpu/register_table.inc b/src/xenia/gpu/register_table.inc index 31e08e60e..5066432ab 100644 --- a/src/xenia/gpu/register_table.inc +++ b/src/xenia/gpu/register_table.inc @@ -342,6 +342,8 @@ 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(0x21FA, kDword, VGT_DMA_BASE) +XE_GPU_REGISTER(0x21FB, kDword, VGT_DMA_SIZE) XE_GPU_REGISTER(0x21FC, kDword, VGT_DRAW_INITIATOR) XE_GPU_REGISTER(0x21FD, kDword, VGT_IMMED_DATA) diff --git a/src/xenia/gpu/registers.h b/src/xenia/gpu/registers.h index 9d1ce4886..e8c3ee127 100644 --- a/src/xenia/gpu/registers.h +++ b/src/xenia/gpu/registers.h @@ -185,6 +185,16 @@ static_assert_size(SQ_INTERPOLATOR_CNTL, sizeof(uint32_t)); *******************************************************************************/ +union alignas(uint32_t) VGT_DMA_SIZE { + struct { + uint32_t num_words : 24; // +0 + uint32_t : 6; // +24 + xenos::Endian swap_mode : 2; // +30 + }; + uint32_t value; + static constexpr Register register_index = XE_GPU_REG_VGT_DMA_SIZE; +}; + union alignas(uint32_t) VGT_DRAW_INITIATOR { // Different than on A2xx and R6xx/R7xx. struct { @@ -202,6 +212,69 @@ union alignas(uint32_t) VGT_DRAW_INITIATOR { }; static_assert_size(VGT_DRAW_INITIATOR, sizeof(uint32_t)); +// Unlike on R6xx (but closer to R5xx), and according to the Adreno 200 header, +// the registers related to the vertex index are 24-bit. Vertex indices are +// unsigned, and only the lower 24 bits of them are actually used by the GPU - +// this has been verified on an Adreno 200 phone (LG Optimus L7) on OpenGL ES +// using a GL_UNSIGNED_INT element array buffer with junk in the upper 8 bits +// that had no effect on drawing. + +// The order of operations is primitive reset index checking -> offsetting -> +// clamping. + +union alignas(uint32_t) VGT_MULTI_PRIM_IB_RESET_INDX { + struct { + // The upper 8 bits of the value from the index buffer are confirmed to be + // ignored. So, though this specifically is untested (because + // GL_PRIMITIVE_RESTART_FIXED_INDEX was added only in OpenGL ES 3.0, though + // it behaves conceptually close to our expectations anyway - uses the + // 0xFFFFFFFF restart index while GL_MAX_ELEMENT_INDEX may be 0xFFFFFF), + // the restart index check likely only involves the lower 24 bit of the + // vertex index - therefore, if reset_indx is 0xFFFFFF, likely 0xFFFFFF, + // 0x1FFFFFF, 0xFFFFFFFF all cause primitive reset. + uint32_t reset_indx : 24; + }; + uint32_t value; + static constexpr Register register_index = + XE_GPU_REG_VGT_MULTI_PRIM_IB_RESET_INDX; +}; +static_assert_size(VGT_MULTI_PRIM_IB_RESET_INDX, sizeof(uint32_t)); + +union alignas(uint32_t) VGT_INDX_OFFSET { + struct { + // Unlike R5xx's VAP_INDEX_OFFSET, which is signed 25-bit, this is 24-bit - + // and signedness doesn't matter as index calculations are done in 24-bit + // integers, and ((0xFFFFFE + 3) & 0xFFFFFF) == 1 anyway, just like + // ((0xFFFFFFFE + 3) & 0xFFFFFF) == 1 if we treated it as signed by + // sign-extending on the host. Direct3D 9 just writes BaseVertexIndex as a + // signed int32 to the entire register, but the upper 8 bits are ignored + // anyway, and that has no effect on offsets that fit in 24 bits. + uint32_t indx_offset : 24; + }; + uint32_t value; + static constexpr Register register_index = XE_GPU_REG_VGT_INDX_OFFSET; +}; +static_assert_size(VGT_INDX_OFFSET, sizeof(uint32_t)); + +union alignas(uint32_t) VGT_MIN_VTX_INDX { + struct { + uint32_t min_indx : 24; + }; + uint32_t value; + static constexpr Register register_index = XE_GPU_REG_VGT_MIN_VTX_INDX; +}; +static_assert_size(VGT_MIN_VTX_INDX, sizeof(uint32_t)); + +union alignas(uint32_t) VGT_MAX_VTX_INDX { + struct { + // Usually 0xFFFF or 0xFFFFFF. + uint32_t max_indx : 24; + }; + uint32_t value; + static constexpr Register register_index = XE_GPU_REG_VGT_MAX_VTX_INDX; +}; +static_assert_size(VGT_MAX_VTX_INDX, sizeof(uint32_t)); + union alignas(uint32_t) VGT_OUTPUT_PATH_CNTL { struct { xenos::VGTOutputPath path_select : 2; // +0 diff --git a/src/xenia/gpu/render_target_cache.h b/src/xenia/gpu/render_target_cache.h index 600e248f7..74207a58c 100644 --- a/src/xenia/gpu/render_target_cache.h +++ b/src/xenia/gpu/render_target_cache.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/src/xenia/gpu/shared_memory.h b/src/xenia/gpu/shared_memory.h index 7e6bcb9a0..386997bab 100644 --- a/src/xenia/gpu/shared_memory.h +++ b/src/xenia/gpu/shared_memory.h @@ -129,11 +129,11 @@ class SharedMemory { bool written_by_gpu_resolve); // Uploads a range of host pages - only called if host GPU sparse memory - // allocation succeeded if needed. While uploading, MarkRangeValid must be + // allocation succeeded if needed. While uploading, MakeRangeValid must be // called for each successfully uploaded range as early as possible, before // the memcpy, to make sure invalidation that happened during the CPU -> GPU // memcpy isn't missed (upload_page_ranges is in pages because of this - - // MarkRangeValid has page granularity). upload_page_ranges are sorted in + // MakeRangeValid has page granularity). upload_page_ranges are sorted in // ascending address order, so front and back can be used to determine the // overall bounds of pages to be uploaded. virtual bool UploadRanges( diff --git a/src/xenia/gpu/xenos.h b/src/xenia/gpu/xenos.h index 00c9c4f8a..4da491772 100644 --- a/src/xenia/gpu/xenos.h +++ b/src/xenia/gpu/xenos.h @@ -35,6 +35,12 @@ enum class ShaderType : uint32_t { kPixel = 1, }; +// Only the lower 24 bits of the vertex index are used (tested on an Adreno 200 +// phone using a GL_UNSIGNED_INT element array buffer with junk in the upper 8 +// bits that had no effect on drawing). +constexpr uint32_t kVertexIndexBits = 24; +constexpr uint32_t kVertexIndexMask = (uint32_t(1) << kVertexIndexBits) - 1; + enum class PrimitiveType : uint32_t { kNone = 0x00, kPointList = 0x01, @@ -73,38 +79,6 @@ enum class PrimitiveType : uint32_t { kQuadPatch = 0x12, }; -// Polygonal primitive types (not including points and lines) are rasterized as -// triangles, have front and back faces, and also support face culling and fill -// modes (polymode_front_ptype, polymode_back_ptype). Other primitive types are -// always "front" (but don't support front face and back face culling, according -// to OpenGL and Vulkan specifications - even if glCullFace is -// GL_FRONT_AND_BACK, points and lines are still drawn), and may in some cases -// use the "para" registers instead of "front" or "back" (for "parallelogram" - -// like poly_offset_para_enable). -constexpr bool IsPrimitivePolygonal(bool tessellated, PrimitiveType type) { - if (tessellated && (type == PrimitiveType::kTrianglePatch || - type == PrimitiveType::kQuadPatch)) { - return true; - } - switch (type) { - case PrimitiveType::kTriangleList: - case PrimitiveType::kTriangleFan: - case PrimitiveType::kTriangleStrip: - case PrimitiveType::kTriangleWithWFlags: - case PrimitiveType::kQuadList: - case PrimitiveType::kQuadStrip: - case PrimitiveType::kPolygon: - return true; - default: - break; - } - // TODO(Triang3l): Investigate how kRectangleList should be treated - possibly - // actually drawn as two polygons on the console, however, the current - // geometry shader doesn't care about the winding order - allowing backface - // culling for rectangles currently breaks Gears of War 2. - return false; -} - // For the texture fetch constant (not the tfetch instruction), stacked stored // as 2D. enum class DataDimension : uint32_t {