333 lines
9.7 KiB
C++
333 lines
9.7 KiB
C++
/**
|
|
******************************************************************************
|
|
* 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 <vector>
|
|
|
|
#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<uint8_t> 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<uint32_t>& dest, const char* source);
|
|
|
|
void WriteResourceDefinitions();
|
|
void WriteInputSignature();
|
|
void WriteOutputSignature();
|
|
void WriteShaderCode();
|
|
|
|
// Executable instructions - generated during translation.
|
|
std::vector<uint32_t> shader_code_;
|
|
// Complete shader object, with all the needed chunks and dcl_ instructions -
|
|
// generated in the end of translation.
|
|
std::vector<uint32_t> 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<T>`.
|
|
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_
|