[D3D12] Fake per-edge tessellation with continuous

This commit is contained in:
Triang3l
2018-12-12 22:08:20 +03:00
parent 19d7e0ce3d
commit 2b646ff425
38 changed files with 3382 additions and 598 deletions

View File

@@ -833,7 +833,7 @@ void DxbcShaderTranslator::StartVertexShader_LoadVertexIndex() {
}
}
void DxbcShaderTranslator::StartVertexShader() {
void DxbcShaderTranslator::StartVertexOrDomainShader() {
// Zero the interpolators.
for (uint32_t i = 0; i < kInterpolatorCount; ++i) {
shader_code_.push_back(ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
@@ -870,8 +870,157 @@ void DxbcShaderTranslator::StartVertexShader() {
++stat_.instruction_count;
++stat_.mov_instruction_count;
// Write the vertex index to GPR 0.
StartVertexShader_LoadVertexIndex();
if (IsDXBCVertexShader()) {
// Write the vertex index to GPR 0.
StartVertexShader_LoadVertexIndex();
} else if (IsDXBCDomainShader()) {
uint32_t temp_register_operand_length = IndexableGPRsUsed() ? 3 : 2;
// Copy the domain location to r0.yz (for quad patches) or r0.xyz (for
// triangle patches), and also set the domain in STAT.
uint32_t domain_location_mask, domain_location_swizzle;
if (vertex_shader_type_ == VertexShaderType::kTriangleDomain) {
domain_location_mask = 0b0111;
// ZYX swizzle with r1.y == 0, according to the water shader in
// Banjo-Kazooie: Nuts & Bolts.
domain_location_swizzle = 0b00000110;
stat_.tessellator_domain = D3D11_SB_TESSELLATOR_DOMAIN_TRI;
} else {
assert_true(vertex_shader_type_ == VertexShaderType::kQuadDomain);
// According to the ground shader in Viva Pinata, though it's impossible
// (as of December 12th, 2018) to test there since it possibly requires
// memexport for ground control points (the memory region with them is
// filled with zeros).
domain_location_mask = 0b0110;
domain_location_swizzle = 0b00000100;
stat_.tessellator_domain = D3D11_SB_TESSELLATOR_DOMAIN_QUAD;
}
shader_code_.push_back(ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(
2 + temp_register_operand_length));
if (IndexableGPRsUsed()) {
shader_code_.push_back(EncodeVectorMaskedOperand(
D3D10_SB_OPERAND_TYPE_INDEXABLE_TEMP, domain_location_mask, 2));
shader_code_.push_back(0);
} else {
shader_code_.push_back(EncodeVectorMaskedOperand(
D3D10_SB_OPERAND_TYPE_TEMP, domain_location_mask, 1));
}
shader_code_.push_back(0);
shader_code_.push_back(EncodeVectorSwizzledOperand(
D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT, domain_location_swizzle, 0));
++stat_.instruction_count;
if (IndexableGPRsUsed()) {
++stat_.array_instruction_count;
} else {
++stat_.mov_instruction_count;
}
assert_true(register_count() >= 2);
// Copy the primitive index to r0.x (for quad patches) or r1.x (for
// triangle patches) as a float.
// When using indexable temps, copy through a r# because x# are apparently
// only accessible via mov.
// TODO(Triang3l): Investigate what should be written for primitives (or
// even control points) for non-per-edge tessellation modes (they may
// possibly have an index buffer).
uint32_t primitive_id_gpr_index =
vertex_shader_type_ == VertexShaderType::kTriangleDomain ? 1 : 0;
if (register_count() > primitive_id_gpr_index) {
uint32_t primitive_id_temp =
IndexableGPRsUsed() ? PushSystemTemp() : primitive_id_gpr_index;
shader_code_.push_back(ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_UTOF) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4));
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_TEMP, 0b0001, 1));
shader_code_.push_back(primitive_id_temp);
shader_code_.push_back(
EncodeScalarOperand(D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID, 0));
++stat_.instruction_count;
++stat_.conversion_instruction_count;
if (IndexableGPRsUsed()) {
shader_code_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(6));
shader_code_.push_back(EncodeVectorMaskedOperand(
D3D10_SB_OPERAND_TYPE_INDEXABLE_TEMP, 0b0001, 2));
shader_code_.push_back(0);
shader_code_.push_back(primitive_id_gpr_index);
shader_code_.push_back(
EncodeVectorSelectOperand(D3D10_SB_OPERAND_TYPE_TEMP, 0, 1));
shader_code_.push_back(primitive_id_temp);
++stat_.instruction_count;
++stat_.array_instruction_count;
// Release primitive_id_temp.
PopSystemTemp();
}
}
if (register_count() >= 2) {
// Write the swizzle of the barycentric/UV coordinates to r1.x (for quad
// patches) or r1.y (for triangle patches). It appears that the
// tessellator offloads the reordering of coordinates for edges to game
// shaders.
//
// In Banjo-Kazooie: Nuts & Bolts (triangle patches with per-edge
// factors), the shader multiplies the first control point's position by
// r0.z, the second CP's by r0.y, and the third CP's by r0.x. But before
// doing that it swizzles r0.xyz the following way depending on the value
// in r1.y:
// - ZXY for 1.0.
// - YZX for 2.0.
// - XZY for 4.0.
// - YXZ for 5.0.
// - ZYX for 6.0.
// Possibly, the logic here is that the value itself is the amount of
// rotation of the swizzle to the right, and 1 << 2 is set when the
// swizzle needs to be flipped before rotating.
//
// In Viva Pinata (quad patches with per-edge factors - not possible to
// test however as of December 12th, 2018), if we assume that r0.y is V
// and r0.z is U, the factors each control point value is multiplied by
// are the following:
// - (1-v)*(1-u), v*(1-u), (1-v)*u, v*u for 0.0 (base swizzle).
// - v*(1-u), (1-v)*(1-u), v*u, (1-v)*u for 1.0 (YXWZ).
// - v*u, (1-v)*u, v*(1-u), (1-v)*(1-u) for 2.0 (WZYX).
// - (1-v)*u, v*u, (1-v)*(1-u), v*(1-u) for 3.0 (ZWXY).
// According to the control point order at
// https://www.khronos.org/registry/OpenGL/extensions/AMD/AMD_vertex_shader_tessellator.txt
// the first is located at (0,0), the second at (0,1), the third at (1,0)
// and the fourth at (1,1). So, swizzle index 0 appears to be the correct
// one. But, this hasn't been tested yet.
//
// Direct3D 12 appears to be passing the coordinates in a consistent
// order, so we can just use ZYX for triangle patches.
uint32_t domain_location_swizzle_mask =
vertex_shader_type_ == VertexShaderType::kTriangleDomain ? 0b0010
: 0b0001;
shader_code_.push_back(ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(
3 + temp_register_operand_length));
if (IndexableGPRsUsed()) {
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INDEXABLE_TEMP,
domain_location_swizzle_mask, 2));
shader_code_.push_back(0);
} else {
shader_code_.push_back(EncodeVectorMaskedOperand(
D3D10_SB_OPERAND_TYPE_TEMP, domain_location_swizzle_mask, 1));
}
shader_code_.push_back(1);
shader_code_.push_back(
EncodeScalarOperand(D3D10_SB_OPERAND_TYPE_IMMEDIATE32, 0));
shader_code_.push_back(0);
++stat_.instruction_count;
if (IndexableGPRsUsed()) {
++stat_.array_instruction_count;
} else {
++stat_.mov_instruction_count;
}
}
}
}
void DxbcShaderTranslator::StartPixelShader() {
@@ -918,19 +1067,7 @@ void DxbcShaderTranslator::StartPixelShader() {
// Copy interpolants to GPRs.
uint32_t interpolator_count = std::min(kInterpolatorCount, register_count());
if (IndexableGPRsUsed()) {
// Copy through r# to x0[#].
uint32_t interpolator_temp_register = PushSystemTemp();
for (uint32_t i = 0; i < interpolator_count; ++i) {
shader_code_.push_back(ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(5));
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_TEMP, 0b1111, 1));
shader_code_.push_back(interpolator_temp_register);
shader_code_.push_back(EncodeVectorSwizzledOperand(
D3D10_SB_OPERAND_TYPE_INPUT, kSwizzleXYZW, 1));
shader_code_.push_back(uint32_t(InOutRegister::kPSInInterpolators) + i);
++stat_.instruction_count;
++stat_.mov_instruction_count;
shader_code_.push_back(ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(6));
shader_code_.push_back(EncodeVectorMaskedOperand(
@@ -938,14 +1075,12 @@ void DxbcShaderTranslator::StartPixelShader() {
shader_code_.push_back(0);
shader_code_.push_back(i);
shader_code_.push_back(EncodeVectorSwizzledOperand(
D3D10_SB_OPERAND_TYPE_TEMP, kSwizzleXYZW, 1));
shader_code_.push_back(interpolator_temp_register);
D3D10_SB_OPERAND_TYPE_INPUT, kSwizzleXYZW, 1));
shader_code_.push_back(uint32_t(InOutRegister::kPSInInterpolators) + i);
++stat_.instruction_count;
++stat_.array_instruction_count;
}
PopSystemTemp();
} else {
// Copy directly to r#.
for (uint32_t i = 0; i < interpolator_count; ++i) {
shader_code_.push_back(ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(5));
@@ -1204,7 +1339,7 @@ void DxbcShaderTranslator::StartPixelShader() {
void DxbcShaderTranslator::StartTranslation() {
// Allocate global system temporary registers that may also be used in the
// epilogue.
if (IsDXBCVertexShader()) {
if (IsDXBCVertexOrDomainShader()) {
system_temp_position_ = PushSystemTemp(true);
} else if (IsDXBCPixelShader()) {
if (!is_depth_only_pixel_shader_) {
@@ -1237,8 +1372,8 @@ void DxbcShaderTranslator::StartTranslation() {
}
// Write stage-specific prologue.
if (IsDXBCVertexShader()) {
StartVertexShader();
if (IsDXBCVertexOrDomainShader()) {
StartVertexOrDomainShader();
} else if (IsDXBCPixelShader()) {
StartPixelShader();
}
@@ -1282,7 +1417,7 @@ void DxbcShaderTranslator::StartTranslation() {
}
}
void DxbcShaderTranslator::CompleteVertexShader() {
void DxbcShaderTranslator::CompleteVertexOrDomainShader() {
// Get what we need to do with the position.
uint32_t ndc_control_temp = PushSystemTemp();
system_constants_used_ |= 1ull << kSysConst_Flags_Index;
@@ -6735,13 +6870,13 @@ void DxbcShaderTranslator::CompleteShaderCode() {
}
// Write stage-specific epilogue.
if (IsDXBCVertexShader()) {
CompleteVertexShader();
if (IsDXBCVertexOrDomainShader()) {
CompleteVertexOrDomainShader();
} else if (IsDXBCPixelShader()) {
CompletePixelShader();
}
if (IsDXBCVertexShader()) {
if (IsDXBCVertexOrDomainShader()) {
// Release system_temp_position_.
PopSystemTemp();
} else if (IsDXBCPixelShader()) {
@@ -6795,6 +6930,8 @@ std::vector<uint8_t> DxbcShaderTranslator::CompleteTranslation() {
shader_object_.clear();
uint32_t has_pcsg = IsDXBCDomainShader() ? 1 : 0;
// Write the shader object header.
shader_object_.push_back('CBXD');
// Checksum (set later).
@@ -6804,8 +6941,8 @@ std::vector<uint8_t> DxbcShaderTranslator::CompleteTranslation() {
shader_object_.push_back(1);
// Size (set later).
shader_object_.push_back(0);
// 5 chunks - RDEF, ISGN, OSGN, SHEX, STAT.
shader_object_.push_back(5);
// 5 or 6 chunks - RDEF, ISGN, optionally PCSG, OSGN, SHEX, STAT.
shader_object_.push_back(5 + has_pcsg);
// Chunk offsets (set later).
for (uint32_t i = 0; i < shader_object_[7]; ++i) {
shader_object_.push_back(0);
@@ -6833,9 +6970,21 @@ std::vector<uint8_t> DxbcShaderTranslator::CompleteTranslation() {
(uint32_t(shader_object_.size()) - chunk_position_dwords - 2) *
sizeof(uint32_t);
// Write Patch Constant SiGnature.
if (has_pcsg) {
chunk_position_dwords = uint32_t(shader_object_.size());
shader_object_[10] = chunk_position_dwords * sizeof(uint32_t);
shader_object_.push_back('GSCP');
shader_object_.push_back(0);
WritePatchConstantSignature();
shader_object_[chunk_position_dwords + 1] =
(uint32_t(shader_object_.size()) - chunk_position_dwords - 2) *
sizeof(uint32_t);
}
// Write Output SiGNature.
chunk_position_dwords = uint32_t(shader_object_.size());
shader_object_[10] = chunk_position_dwords * sizeof(uint32_t);
shader_object_[10 + has_pcsg] = chunk_position_dwords * sizeof(uint32_t);
shader_object_.push_back('NGSO');
shader_object_.push_back(0);
WriteOutputSignature();
@@ -6845,7 +6994,7 @@ std::vector<uint8_t> DxbcShaderTranslator::CompleteTranslation() {
// Write SHader EXtended.
chunk_position_dwords = uint32_t(shader_object_.size());
shader_object_[11] = chunk_position_dwords * sizeof(uint32_t);
shader_object_[11 + has_pcsg] = chunk_position_dwords * sizeof(uint32_t);
shader_object_.push_back('XEHS');
shader_object_.push_back(0);
WriteShaderCode();
@@ -6855,7 +7004,7 @@ std::vector<uint8_t> DxbcShaderTranslator::CompleteTranslation() {
// Write STATistics.
chunk_position_dwords = uint32_t(shader_object_.size());
shader_object_[12] = chunk_position_dwords * sizeof(uint32_t);
shader_object_[12 + has_pcsg] = chunk_position_dwords * sizeof(uint32_t);
shader_object_.push_back('TATS');
shader_object_.push_back(sizeof(stat_));
shader_object_.resize(shader_object_.size() +
@@ -13313,15 +13462,16 @@ const DxbcShaderTranslator::SystemConstantRdef DxbcShaderTranslator::
// vec4 7
{"xe_color_output_map", RdefTypeIndex::kUint4, 112, 16},
// vec4 8
{"xe_edram_depth_range", RdefTypeIndex::kFloat2, 128, 8},
{"xe_edram_poly_offset_front", RdefTypeIndex::kFloat2, 136, 8},
{"xe_tessellation_factor_range", RdefTypeIndex::kFloat2, 128, 8},
{"xe_edram_depth_range", RdefTypeIndex::kFloat2, 136, 8},
// vec4 9
{"xe_edram_poly_offset_back", RdefTypeIndex::kFloat2, 144, 8},
{"xe_edram_resolution_scale_log2", RdefTypeIndex::kUint, 152, 4},
{"xe_edram_poly_offset_front", RdefTypeIndex::kFloat2, 144, 8},
{"xe_edram_poly_offset_back", RdefTypeIndex::kFloat2, 152, 8},
// vec4 10
{"xe_edram_stencil_reference", RdefTypeIndex::kUint, 160, 4},
{"xe_edram_stencil_read_mask", RdefTypeIndex::kUint, 164, 4},
{"xe_edram_stencil_write_mask", RdefTypeIndex::kUint, 168, 4},
{"xe_edram_resolution_scale_log2", RdefTypeIndex::kUint, 160, 4},
{"xe_edram_stencil_reference", RdefTypeIndex::kUint, 164, 4},
{"xe_edram_stencil_read_mask", RdefTypeIndex::kUint, 168, 4},
{"xe_edram_stencil_write_mask", RdefTypeIndex::kUint, 172, 4},
// vec4 11
{"xe_edram_stencil_front", RdefTypeIndex::kUint4, 176, 16},
// vec4 12
@@ -13409,6 +13559,9 @@ void DxbcShaderTranslator::WriteResourceDefinitions() {
if (IsDXBCVertexShader()) {
// vs_5_1
shader_object_.push_back(0xFFFE0501u);
} else if (IsDXBCDomainShader()) {
// ds_5_1
shader_object_.push_back(0x44530501u);
} else {
assert_true(IsDXBCPixelShader());
// ps_5_1
@@ -13901,6 +14054,11 @@ void DxbcShaderTranslator::WriteInputSignature() {
// Vertex index semantic name.
AppendString(shader_object_, "SV_VertexID");
} else if (IsDXBCDomainShader()) {
// No inputs - tessellation factors specified in PCSG.
shader_object_.push_back(0);
// Unknown.
shader_object_.push_back(8);
} else {
assert_true(IsDXBCPixelShader());
// Interpolators, point parameters (coordinates, size), clip space ZW,
@@ -13983,13 +14141,11 @@ void DxbcShaderTranslator::WriteInputSignature() {
shader_object_[texcoord_name_position_dwords] = new_offset;
}
new_offset += AppendString(shader_object_, "TEXCOORD");
uint32_t position_name_position_dwords =
chunk_position_dwords + signature_position_dwords +
(kInterpolatorCount + 2) * signature_size_dwords;
shader_object_[position_name_position_dwords] = new_offset;
new_offset += AppendString(shader_object_, "SV_Position");
uint32_t front_face_name_position_dwords =
position_name_position_dwords + signature_size_dwords;
shader_object_[front_face_name_position_dwords] = new_offset;
@@ -13997,6 +14153,83 @@ void DxbcShaderTranslator::WriteInputSignature() {
}
}
void DxbcShaderTranslator::WritePatchConstantSignature() {
assert_true(IsDXBCDomainShader());
uint32_t chunk_position_dwords = uint32_t(shader_object_.size());
const uint32_t signature_position_dwords = 2;
const uint32_t signature_size_dwords = 6;
// FXC refuses to compile without SV_TessFactor and SV_InsideTessFactor input,
// so this is required.
uint32_t tess_factor_count_edge, tess_factor_count_inside;
if (vertex_shader_type_ == VertexShaderType::kTriangleDomain) {
tess_factor_count_edge = 3;
tess_factor_count_inside = 1;
} else {
assert_true(vertex_shader_type_ == VertexShaderType::kQuadDomain);
tess_factor_count_edge = 4;
tess_factor_count_inside = 2;
}
uint32_t tess_factor_count_total =
tess_factor_count_edge + tess_factor_count_inside;
shader_object_.push_back(tess_factor_count_total);
// Unknown.
shader_object_.push_back(8);
for (uint32_t i = 0; i < tess_factor_count_total; ++i) {
// Reserve space for the semantic name (SV_TessFactor or
// SV_InsideTessFactor).
shader_object_.push_back(0);
shader_object_.push_back(
i < tess_factor_count_edge ? i : (i - tess_factor_count_edge));
if (vertex_shader_type_ == VertexShaderType::kTriangleDomain) {
if (i < tess_factor_count_edge) {
// D3D_NAME_FINAL_TRI_EDGE_TESSFACTOR.
shader_object_.push_back(13);
} else {
// D3D_NAME_FINAL_TRI_INSIDE_TESSFACTOR.
shader_object_.push_back(14);
}
} else {
assert_true(vertex_shader_type_ == VertexShaderType::kQuadDomain);
if (i < tess_factor_count_edge) {
// D3D_NAME_FINAL_QUAD_EDGE_TESSFACTOR.
shader_object_.push_back(11);
} else {
// D3D_NAME_FINAL_QUAD_INSIDE_TESSFACTOR.
shader_object_.push_back(12);
}
}
// D3D_REGISTER_COMPONENT_FLOAT32.
shader_object_.push_back(3);
// Not using any of these, and just assigning consecutive registers.
shader_object_.push_back(i);
// 1 component, none used.
shader_object_.push_back(1);
}
// Write the semantic names.
uint32_t new_offset =
(uint32_t(shader_object_.size()) - chunk_position_dwords) *
sizeof(uint32_t);
for (uint32_t i = 0; i < tess_factor_count_edge; ++i) {
uint32_t name_position_dwords = chunk_position_dwords +
signature_position_dwords +
i * signature_size_dwords;
shader_object_[name_position_dwords] = new_offset;
}
new_offset += AppendString(shader_object_, "SV_TessFactor");
for (uint32_t i = 0; i < tess_factor_count_inside; ++i) {
uint32_t name_position_dwords =
chunk_position_dwords + signature_position_dwords +
(tess_factor_count_edge + i) * signature_size_dwords;
shader_object_[name_position_dwords] = new_offset;
}
new_offset += AppendString(shader_object_, "SV_InsideTessFactor");
}
void DxbcShaderTranslator::WriteOutputSignature() {
uint32_t chunk_position_dwords = uint32_t(shader_object_.size());
uint32_t new_offset;
@@ -14004,7 +14237,7 @@ void DxbcShaderTranslator::WriteOutputSignature() {
const uint32_t signature_position_dwords = 2;
const uint32_t signature_size_dwords = 6;
if (IsDXBCVertexShader()) {
if (IsDXBCVertexOrDomainShader()) {
// Interpolators, point parameters (coordinates, size), clip space ZW,
// screen position.
shader_object_.push_back(kInterpolatorCount + 3);
@@ -14137,9 +14370,17 @@ void DxbcShaderTranslator::WriteOutputSignature() {
void DxbcShaderTranslator::WriteShaderCode() {
uint32_t chunk_position_dwords = uint32_t(shader_object_.size());
shader_object_.push_back(ENCODE_D3D10_SB_TOKENIZED_PROGRAM_VERSION_TOKEN(
IsDXBCVertexShader() ? D3D10_SB_VERTEX_SHADER : D3D10_SB_PIXEL_SHADER, 5,
1));
uint32_t shader_type;
if (IsDXBCVertexShader()) {
shader_type = D3D10_SB_VERTEX_SHADER;
} else if (IsDXBCDomainShader()) {
shader_type = D3D11_SB_DOMAIN_SHADER;
} else {
assert_true(IsDXBCPixelShader());
shader_type = D3D10_SB_PIXEL_SHADER;
}
shader_object_.push_back(
ENCODE_D3D10_SB_TOKENIZED_PROGRAM_VERSION_TOKEN(shader_type, 5, 1));
// Reserve space for the length token.
shader_object_.push_back(0);
@@ -14155,6 +14396,31 @@ void DxbcShaderTranslator::WriteShaderCode() {
// Inputs/outputs have 1D-indexed operands with a component mask and a
// register index.
if (IsDXBCDomainShader()) {
// Not using control point data since Xenos only has a vertex shader acting
// as both vertex shader and domain shader.
uint32_t control_point_count;
D3D11_SB_TESSELLATOR_DOMAIN domain;
if (vertex_shader_type_ == VertexShaderType::kTriangleDomain) {
control_point_count = 3;
domain = D3D11_SB_TESSELLATOR_DOMAIN_TRI;
} else {
assert_true(vertex_shader_type_ == VertexShaderType::kQuadDomain);
control_point_count = 4;
domain = D3D11_SB_TESSELLATOR_DOMAIN_QUAD;
}
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(
D3D11_SB_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT) |
ENCODE_D3D11_SB_INPUT_CONTROL_POINT_COUNT(control_point_count) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(1));
stat_.c_control_points = control_point_count;
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D11_SB_OPCODE_DCL_TESS_DOMAIN) |
ENCODE_D3D11_SB_TESS_DOMAIN(domain) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(1));
}
// Don't allow refactoring when converting to native code to maintain position
// invariance (needed even in pixel shaders for oDepth invariance).
shader_object_.push_back(
@@ -14312,16 +14578,40 @@ void DxbcShaderTranslator::WriteShaderCode() {
}
// Inputs and outputs.
if (IsDXBCVertexShader()) {
// Unswapped vertex index input (only X component).
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_SGV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4));
shader_object_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INPUT, 0b0001, 1));
shader_object_.push_back(uint32_t(InOutRegister::kVSInVertexIndex));
shader_object_.push_back(ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_VERTEX_ID));
++stat_.dcl_count;
if (IsDXBCVertexOrDomainShader()) {
if (IsDXBCDomainShader()) {
// Domain location input (barycentric for triangles, UV for quads).
uint32_t domain_location_mask;
if (vertex_shader_type_ == VertexShaderType::kTriangleDomain) {
domain_location_mask = 0b0111;
} else {
assert_true(vertex_shader_type_ == VertexShaderType::kQuadDomain);
domain_location_mask = 0b0011;
}
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(2));
shader_object_.push_back(EncodeVectorMaskedOperand(
D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT, domain_location_mask, 0));
++stat_.dcl_count;
// Primitive index input.
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(2));
shader_object_.push_back(
EncodeScalarOperand(D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID, 0));
++stat_.dcl_count;
} else {
// Unswapped vertex index input (only X component).
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_INPUT_SGV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(4));
shader_object_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_INPUT, 0b0001, 1));
shader_object_.push_back(uint32_t(InOutRegister::kVSInVertexIndex));
shader_object_.push_back(ENCODE_D3D10_SB_NAME(D3D10_SB_NAME_VERTEX_ID));
++stat_.dcl_count;
}
// Interpolator output.
for (uint32_t i = 0; i < kInterpolatorCount; ++i) {
shader_object_.push_back(