/** ****************************************************************************** * 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_DXBC_SHADER_TRANSLATOR_H_ #define XENIA_GPU_DXBC_SHADER_TRANSLATOR_H_ #include #include "xenia/gpu/shader_translator.h" namespace xe { namespace gpu { // Generates shader model 5_1 byte code (for Direct3D 12). class DxbcShaderTranslator : public ShaderTranslator { public: DxbcShaderTranslator(); ~DxbcShaderTranslator() override; // IF SYSTEM CONSTANTS ARE CHANGED OR ADDED, THE FOLLOWING MUST BE UPDATED: // - kSysConst enum (registers and first components). // - rdef_constants_. // - rdef_constant_buffers_ system constant buffer size. // - d3d12/shaders/xenos_draw.hlsli (for geometry shaders). struct SystemConstants { // vec4 0 float mul_rcp_w[3]; uint32_t vertex_base_index; // vec4 1 float ndc_scale[3]; uint32_t vertex_index_endian; // vec4 2 float ndc_offset[3]; float pixel_half_pixel_offset; // vec4 3 float point_size[2]; float ssaa_inv_scale[2]; // vec3 4 uint32_t pixel_pos_reg; // 0 - disabled, 1 - passes if in range, -1 - fails if in range. int32_t alpha_test; // The range is floats as uints so it's easier to pass infinity. uint32_t alpha_test_range[2]; // vec4 5 float color_exp_bias[4]; // vec4 6 uint32_t color_output_map[4]; }; protected: void Reset() override; std::vector CompleteTranslation() override; private: static constexpr uint32_t kFloatConstantsPerPage = 32; static constexpr uint32_t kFloatConstantPageCount = 8; // Constant buffer bindings in space 0. enum class CbufferRegister { kSystemConstants, kBoolLoopConstants, kFetchConstants, kFloatConstantsFirst, kFloatConstantsLast = kFloatConstantsFirst + kFloatConstantPageCount - 1, }; enum : uint32_t { kSysConst_MulRcpW_Vec = 0, kSysConst_MulRcpW_Comp = 0, kSysConst_VertexBaseIndex_Vec = 0, kSysConst_VertexBaseIndex_Comp = 3, kSysConst_NDCScale_Vec = 1, kSysConst_NDCScale_Comp = 0, kSysConst_VertexIndexEndian_Vec = 1, kSysConst_VertexIndexEndian_Comp = 3, kSysConst_NDCOffset_Vec = 2, kSysConst_NDCOffset_Comp = 0, kSysConst_PixelHalfPixelOffset_Vec = 2, kSysConst_PixelHalfPixelOffset_Comp = 3, kSysConst_PointSize_Vec = 3, kSysConst_PointSize_Comp = 0, kSysConst_SSAAInvScale_Vec = 0, kSysConst_SSAAInvScale_Comp = 2, kSysConst_PixelPosReg_Vec = 4, kSysConst_PixelPosReg_Comp = 0, kSysConst_AlphaTest_Vec = 4, kSysConst_AlphaTest_Comp = 1, kSysConst_AlphaTestRange_Vec = 4, kSysConst_AlphaTestRange_Comp = 2, kSysConst_ColorExpBias_Vec = 5, kSysConst_ColorOutputMap_Vec = 6, }; static constexpr uint32_t kInterpolatorCount = 16; static constexpr uint32_t kPointParametersTexCoord = kInterpolatorCount; // IF ANY OF THESE ARE CHANGED, WriteInputSignature and WriteOutputSignature // MUST BE UPDATED! static constexpr uint32_t kVSInVertexIndexRegister = 0; static constexpr uint32_t kVSOutInterpolatorRegister = 0; static constexpr uint32_t kVSOutPointParametersRegister = kVSOutInterpolatorRegister + kInterpolatorCount; static constexpr uint32_t kVSOutPositionRegister = kVSOutPointParametersRegister + 1; static constexpr uint32_t kPSInInterpolatorRegister = 0; static constexpr uint32_t kPSInPointParametersRegister = kPSInInterpolatorRegister + kInterpolatorCount; static constexpr uint32_t kPSInPositionRegister = kPSInPointParametersRegister + 1; // Allocates a new r# register for internal use and returns its index. uint32_t PushSystemTemp(); // Frees the last allocated internal r# registers for later reuse. void PopSystemTemp(uint32_t count = 1); // Writing the epilogue. void CompleteVertexShaderCode(); void CompletePixelShaderCode(); void CompleteShaderCode(); // Appends a string to a DWORD stream, returns the DWORD-aligned length. static uint32_t AppendString(std::vector& dest, const char* source); void WriteResourceDefinitions(); void WriteInputSignature(); void WriteOutputSignature(); void WriteShaderCode(); // Executable instructions - generated during translation. std::vector shader_code_; // Complete shader object, with all the needed chunks and dcl_ instructions - // generated in the end of translation. std::vector shader_object_; // Data types used in constants buffers. Listed in dependency order. enum class RdefTypeIndex { kFloat, kFloat2, kFloat3, kFloat4, kInt, kUint, kUint4, // Bool constants. kUint4Array8, // Loop constants. kUint4Array32, // Fetch constants. kUint4Array48, // Float constants in one page. kFloatConstantPageArray, kFloatConstantPageStruct, kCount, kUnknown = kCount }; struct RdefStructMember { const char* name; RdefTypeIndex type; uint32_t offset; }; static const RdefStructMember rdef_float_constant_page_member_; struct RdefType { // Name ignored for arrays. const char* name; // D3D10_SHADER_VARIABLE_CLASS. uint32_t type_class; // D3D10_SHADER_VARIABLE_TYPE. uint32_t type; uint32_t row_count; uint32_t column_count; // 0 for primitive types, 1 for structures, array size for arrays. uint32_t element_count; uint32_t struct_member_count; RdefTypeIndex array_element_type; const RdefStructMember* struct_members; }; static const RdefType rdef_types_[size_t(RdefTypeIndex::kCount)]; enum class RdefConstantIndex { kSystemConstantFirst, kSysMulRcpW = kSystemConstantFirst, kSysVertexBaseIndex, kSysNDCScale, kSysVertexIndexEndian, kSysNDCOffset, kSysPixelHalfPixelOffset, kSysPointSize, kSysSSAAInvScale, kSysPixelPosReg, kSysAlphaTest, kSysAlphaTestRange, kSysColorExpBias, kSysColorOutputMap, kSystemConstantLast = kSysColorOutputMap, kBoolConstants, kLoopConstants, kFetchConstants, kFloatConstants, kCount, kSystemConstantCount = kSystemConstantLast - kSystemConstantFirst + 1, }; struct RdefConstant { const char* name; RdefTypeIndex type; uint32_t offset; uint32_t size; }; static const RdefConstant rdef_constants_[size_t(RdefConstantIndex::kCount)]; static_assert(uint32_t(RdefConstantIndex::kCount) <= 64, "Too many constants in all constant buffers - can't use a 64 " "bit vector to store which constants are used"); uint64_t rdef_constants_used_; enum class RdefConstantBufferIndex { kSystemConstants, kBoolLoopConstants, kFetchConstants, kFloatConstants, kCount }; struct RdefConstantBuffer { const char* name; RdefConstantIndex first_constant; uint32_t constant_count; uint32_t size; CbufferRegister register_index; uint32_t binding_count; // True if created like `cbuffer`, false for `ConstantBuffer`. bool user_packed; bool dynamic_indexed; }; static const RdefConstantBuffer rdef_constant_buffers_[size_t(RdefConstantBufferIndex::kCount)]; // Order of dcl_constantbuffer instructions, from most frequenly accessed to // least frequently accessed (hint to driver according to the DXBC header). static const RdefConstantBufferIndex constant_buffer_dcl_order_[size_t(RdefConstantBufferIndex::kCount)]; // Number of currently allocated Xenia internal r# registers. uint32_t system_temp_count_current_; // Total maximum number of temporary registers ever used during this // translation (for the declaration). uint32_t system_temp_count_max_; bool writes_depth_; // The STAT chunk (based on Wine d3dcompiler_parse_stat). struct Statistics { uint32_t instruction_count; uint32_t temp_register_count; // Unknown in Wine. uint32_t def_count; // Only inputs and outputs. uint32_t dcl_count; uint32_t float_instruction_count; uint32_t int_instruction_count; uint32_t uint_instruction_count; uint32_t static_flow_control_count; uint32_t dynamic_flow_control_count; // Unknown in Wine. uint32_t macro_instruction_count; uint32_t temp_array_count; uint32_t array_instruction_count; uint32_t cut_instruction_count; uint32_t emit_instruction_count; uint32_t texture_normal_instructions; uint32_t texture_load_instructions; uint32_t texture_comp_instructions; uint32_t texture_bias_instructions; uint32_t texture_gradient_instructions; // Not including indexable temp load/store. uint32_t mov_instruction_count; // Unknown in Wine. uint32_t movc_instruction_count; uint32_t conversion_instruction_count; // Unknown in Wine. uint32_t unknown_22; uint32_t input_primitive; uint32_t gs_output_topology; uint32_t gs_max_output_vertex_count; uint32_t unknown_26; uint32_t unknown_27; uint32_t unknown_28; uint32_t unknown_29; uint32_t c_control_points; uint32_t hs_output_primitive; uint32_t hs_partitioning; uint32_t tessellator_domain; // Unknown in Wine. uint32_t c_barrier_instructions; // Unknown in Wine. uint32_t c_interlocked_instructions; // Unknown in Wine. uint32_t c_texture_store_instructions; }; Statistics stat_; }; } // namespace gpu } // namespace xe #endif // XENIA_GPU_DXBC_SHADER_TRANSLATOR_H_