[D3D12] DXBC texture bindings (but no samplers and fetch)

This commit is contained in:
Triang3l
2018-09-09 23:33:08 +03:00
parent 091d51f841
commit 4268466383
5 changed files with 308 additions and 20 deletions

View File

@@ -19,6 +19,7 @@
#include "xenia/base/assert.h"
#include "xenia/base/math.h"
#include "xenia/base/string.h"
DEFINE_bool(dxbc_indexable_temps, true,
"Use indexable temporary registers in translated DXBC shaders for "
@@ -69,6 +70,8 @@ void DxbcShaderTranslator::Reset() {
system_temp_count_current_ = 0;
system_temp_count_max_ = 0;
writes_depth_ = false;
texture_srvs_.clear();
sampler_bindings_.clear();
std::memset(&stat_, 0, sizeof(stat_));
}
@@ -474,6 +477,8 @@ void DxbcShaderTranslator::StartTranslation() {
system_temp_ps_pc_p0_a0_ = PushSystemTemp(true);
system_temp_aL_ = PushSystemTemp(true);
system_temp_loop_count_ = PushSystemTemp(true);
system_temp_grad_h_lod_ = PushSystemTemp(true);
system_temp_grad_v_ = PushSystemTemp(true);
if (is_vertex_shader()) {
system_temp_position_ = PushSystemTemp(true);
} else if (is_pixel_shader()) {
@@ -653,7 +658,9 @@ void DxbcShaderTranslator::CompleteShaderCode() {
// - system_temp_ps_pc_p0_a0_.
// - system_temp_aL_.
// - system_temp_loop_count_.
PopSystemTemp(4);
// - system_temp_grad_h_lod_.
// - system_temp_grad_v_.
PopSystemTemp(6);
// Write stage-specific epilogue.
if (is_vertex_shader()) {
@@ -2298,6 +2305,126 @@ void DxbcShaderTranslator::ProcessVertexFetchInstruction(
StoreResult(instr.result, system_temp_pv_, false);
}
uint32_t DxbcShaderTranslator::FindOrAddTextureSRV(uint32_t fetch_constant,
TextureDimension dimension) {
// 1D and 2D textures (including stacked ones) are treated as 2D arrays for
// binding and coordinate simplicity.
if (dimension == TextureDimension::k1D) {
dimension = TextureDimension::k2D;
}
// 1 is added to the return value because T0/t0 is shared memory.
for (uint32_t i = 0; i < uint32_t(texture_srvs_.size()); ++i) {
const TextureSRV& texture_srv = texture_srvs_[i];
if (texture_srv.fetch_constant == fetch_constant &&
texture_srv.dimension == dimension) {
return 1 + i;
}
}
TextureSRV new_texture_srv;
new_texture_srv.fetch_constant = fetch_constant;
new_texture_srv.dimension = dimension;
const char* dimension_name;
switch (dimension) {
case TextureDimension::k3D:
dimension_name = "3d";
break;
case TextureDimension::kCube:
dimension_name = "cube";
break;
default:
dimension_name = "2d";
}
new_texture_srv.name =
xe::format_string("xe_texture%u_%s", fetch_constant, dimension_name);
uint32_t srv_register = 1 + uint32_t(texture_srvs_.size());
texture_srvs_.push_back(new_texture_srv);
return srv_register;
}
void DxbcShaderTranslator::ProcessTextureFetchInstruction(
const ParsedTextureFetchInstruction& instr) {
// TODO(Triang3l): Predicate.
bool store_result = false;
DxbcSourceOperand operand;
uint32_t operand_length = 0;
if (instr.operand_count >= 1) {
LoadDxbcSourceOperand(instr.operands[0], operand);
operand_length = DxbcSourceOperandLength(operand);
}
uint32_t tfetch_index = instr.operands[1].storage_index;
// Fetch constants are laid out like:
// tf0[0] tf0[1] tf0[2] tf0[3]
// tf0[4] tf0[5] tf1[0] tf1[1]
// tf1[2] tf1[3] tf1[4] tf1[5]
uint32_t tfetch_pair_offset = (tfetch_index >> 1) * 3;
// TODO(Triang3l): kTextureFetch, kGetTextureBorderColorFrac,
// kGetTextureComputedLod, kGetTextureGradients, kGetTextureWeights,
if (instr.opcode == FetchOpcode::kTextureFetch ||
instr.opcode == FetchOpcode::kGetTextureComputedLod) {
store_result = true;
uint32_t srv_register = FindOrAddTextureSRV(tfetch_index, instr.dimension);
// 3D or 2D stacked is selected dynamically.
uint32_t srv_register_3d;
if (instr.dimension == TextureDimension::k3D) {
srv_register_3d =
FindOrAddTextureSRV(tfetch_index, TextureDimension::k2D);
} else {
srv_register_3d = UINT32_MAX;
}
// TODO(Triang3l): Sampler, actually sample instead of this stub.
shader_code_.push_back(ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(8));
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_TEMP, 0b1111, 1));
shader_code_.push_back(system_temp_pv_);
shader_code_.push_back(EncodeVectorSwizzledOperand(
D3D10_SB_OPERAND_TYPE_IMMEDIATE32, kSwizzleXYZW, 0));
shader_code_.push_back(0x3F800000);
shader_code_.push_back(0x3F800000);
shader_code_.push_back(0x3F800000);
shader_code_.push_back(0x3F800000);
++stat_.instruction_count;
++stat_.mov_instruction_count;
} else if (instr.opcode == FetchOpcode::kSetTextureLod) {
shader_code_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(3 + operand_length));
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_TEMP, 0b1000, 1));
shader_code_.push_back(system_temp_grad_h_lod_);
UseDxbcSourceOperand(operand, kSwizzleXYZW, 0);
++stat_.instruction_count;
++stat_.mov_instruction_count;
} else if (instr.opcode == FetchOpcode::kSetTextureGradientsHorz ||
instr.opcode == FetchOpcode::kSetTextureGradientsVert) {
shader_code_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_MOV) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(3 + operand_length));
shader_code_.push_back(
EncodeVectorMaskedOperand(D3D10_SB_OPERAND_TYPE_TEMP, 0b0111, 1));
shader_code_.push_back(instr.opcode == FetchOpcode::kSetTextureGradientsVert
? system_temp_grad_v_
: system_temp_grad_h_lod_);
UseDxbcSourceOperand(operand, kSwizzleXYZW);
++stat_.instruction_count;
++stat_.mov_instruction_count;
}
if (instr.operand_count >= 1) {
UnloadDxbcSourceOperand(operand);
}
if (store_result) {
StoreResult(instr.result, system_temp_pv_, false);
}
}
void DxbcShaderTranslator::ProcessVectorAluInstruction(
const ParsedAluInstruction& instr) {
// TODO(Triang3l): Predicate.
@@ -4362,29 +4489,62 @@ void DxbcShaderTranslator::WriteResourceDefinitions() {
}
// ***************************************************************************
// Bindings, in t#, cb# order
// Bindings, in s#, t#, cb# order
// ***************************************************************************
// Write used resource names, except for constant buffers because we have
// their names already.
new_offset = (uint32_t(shader_object_.size()) - chunk_position_dwords) *
sizeof(uint32_t);
uint32_t sampler_name_offset = new_offset;
for (uint32_t i = 0; i < uint32_t(sampler_bindings_.size()); ++i) {
new_offset +=
AppendString(shader_object_, sampler_bindings_[i].name.c_str());
}
uint32_t shared_memory_name_offset = new_offset;
new_offset += AppendString(shader_object_, "xe_shared_memory");
// TODO(Triang3l): Texture and sampler names.
uint32_t texture_name_offset = new_offset;
for (uint32_t i = 0; i < uint32_t(texture_srvs_.size()); ++i) {
new_offset += AppendString(shader_object_, texture_srvs_[i].name.c_str());
}
// Write the offset to the header.
shader_object_[chunk_position_dwords + 3] = new_offset;
// Samplers.
for (uint32_t i = 0; i < uint32_t(sampler_bindings_.size()); ++i) {
const SamplerBinding& sampler_binding = sampler_bindings_[i];
shader_object_.push_back(sampler_name_offset);
// D3D_SIT_SAMPLER.
shader_object_.push_back(3);
// No D3D_RESOURCE_RETURN_TYPE.
shader_object_.push_back(0);
// D3D_SRV_DIMENSION_UNKNOWN (not an SRV).
shader_object_.push_back(0);
// Multisampling not applicable.
shader_object_.push_back(0);
// Register s[i].
shader_object_.push_back(i);
// One binding.
shader_object_.push_back(1);
// No D3D_SHADER_INPUT_FLAGS.
shader_object_.push_back(0);
// Register space 0.
shader_object_.push_back(0);
// Sampler ID S[i].
shader_object_.push_back(i);
sampler_name_offset += GetStringLength(sampler_binding.name.c_str());
}
// Shared memory.
shader_object_.push_back(shared_memory_name_offset);
// D3D_SIT_BYTEADDRESS.
shader_object_.push_back(7);
// D3D_RETURN_TYPE_MIXED.
shader_object_.push_back(6);
// D3D_SRV_DIMENSION_UNKNOWN.
// D3D_SRV_DIMENSION_BUFFER.
shader_object_.push_back(1);
// Not multisampled.
// Multisampling not applicable.
shader_object_.push_back(0);
// Register t0.
shader_object_.push_back(0);
@@ -4397,7 +4557,40 @@ void DxbcShaderTranslator::WriteResourceDefinitions() {
// SRV ID T0.
shader_object_.push_back(0);
// TODO(Triang3l): Textures and samplers.
for (uint32_t i = 0; i < uint32_t(texture_srvs_.size()); ++i) {
const TextureSRV& texture_srv = texture_srvs_[i];
shader_object_.push_back(texture_name_offset);
// D3D_SIT_TEXTURE.
shader_object_.push_back(2);
// D3D_RETURN_TYPE_FLOAT.
shader_object_.push_back(5);
switch (texture_srv.dimension) {
case TextureDimension::k3D:
// D3D_SRV_DIMENSION_TEXTURE3D.
shader_object_.push_back(8);
break;
case TextureDimension::kCube:
// D3D_SRV_DIMENSION_TEXTURECUBE.
shader_object_.push_back(9);
break;
default:
// D3D_SRV_DIMENSION_TEXTURE2DARRAY.
shader_object_.push_back(5);
}
// Not multisampled.
shader_object_.push_back(0xFFFFFFFFu);
// Register t[1 + i] - t0 is shared memory.
shader_object_.push_back(1 + i);
// One binding.
shader_object_.push_back(1);
// D3D_SIF_TEXTURE_COMPONENTS (4-component).
shader_object_.push_back(0xC);
// Register space 0.
shader_object_.push_back(0);
// SRV ID T[1 + i] - T0 is shared memory.
shader_object_.push_back(1 + i);
texture_name_offset += GetStringLength(texture_srv.name.c_str());
}
// Constant buffers.
for (uint32_t i = 0; i < uint32_t(RdefConstantBufferIndex::kCount); ++i) {
@@ -4409,6 +4602,7 @@ void DxbcShaderTranslator::WriteResourceDefinitions() {
shader_object_.push_back(0);
// D3D_SRV_DIMENSION_UNKNOWN (not an SRV).
shader_object_.push_back(0);
// Multisampling not applicable.
shader_object_.push_back(0);
shader_object_.push_back(uint32_t(cbuffer.register_index));
shader_object_.push_back(cbuffer.binding_count);
@@ -4416,6 +4610,7 @@ void DxbcShaderTranslator::WriteResourceDefinitions() {
shader_object_.push_back(cbuffer.user_packed ? 1 : 0);
// Register space 0.
shader_object_.push_back(0);
// CBV ID CB[i].
shader_object_.push_back(i);
}
}
@@ -4680,7 +4875,9 @@ void DxbcShaderTranslator::WriteShaderCode() {
shader_object_.push_back(EncodeVectorSwizzledOperand(
D3D10_SB_OPERAND_TYPE_CONSTANT_BUFFER, kSwizzleXYZW, 3));
shader_object_.push_back(cbuffer_index);
// Lower register bound in the space.
shader_object_.push_back(uint32_t(cbuffer.register_index));
// Upper register bound in the space.
shader_object_.push_back(uint32_t(cbuffer.register_index) +
cbuffer.binding_count - 1);
shader_object_.push_back((cbuffer.size + 15) >> 4);
@@ -4688,6 +4885,21 @@ void DxbcShaderTranslator::WriteShaderCode() {
shader_object_.push_back(0);
}
// Samplers.
for (uint32_t i = 0; i < uint32_t(sampler_bindings_.size()); ++i) {
const SamplerBinding& sampler_binding = sampler_bindings_[i];
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_SAMPLER) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(6) |
ENCODE_D3D10_SB_SAMPLER_MODE(D3D10_SB_SAMPLER_MODE_DEFAULT));
shader_object_.push_back(EncodeVectorSwizzledOperand(
D3D10_SB_OPERAND_TYPE_SAMPLER, kSwizzleXYZW, 3));
shader_object_.push_back(i);
shader_object_.push_back(i);
shader_object_.push_back(i);
shader_object_.push_back(0);
}
// Shader resources.
// Shared memory ByteAddressBuffer (T0, at t0, space0).
shader_object_.push_back(
@@ -4700,6 +4912,39 @@ void DxbcShaderTranslator::WriteShaderCode() {
shader_object_.push_back(0);
shader_object_.push_back(0);
// Textures.
for (uint32_t i = 0; i < uint32_t(texture_srvs_.size()); ++i) {
const TextureSRV& texture_srv = texture_srvs_[i];
D3D10_SB_RESOURCE_DIMENSION texture_srv_dimension;
switch (texture_srv.dimension) {
case TextureDimension::k3D:
texture_srv_dimension = D3D10_SB_RESOURCE_DIMENSION_TEXTURE3D;
break;
case TextureDimension::kCube:
texture_srv_dimension = D3D10_SB_RESOURCE_DIMENSION_TEXTURECUBE;
break;
default:
texture_srv_dimension = D3D10_SB_RESOURCE_DIMENSION_TEXTURE2DARRAY;
}
shader_object_.push_back(
ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_DCL_RESOURCE) |
ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(7) |
ENCODE_D3D10_SB_RESOURCE_DIMENSION(texture_srv_dimension));
shader_object_.push_back(EncodeVectorSwizzledOperand(
D3D10_SB_OPERAND_TYPE_RESOURCE, kSwizzleXYZW, 3));
// T0 is shared memory.
shader_object_.push_back(1 + i);
// t0 is shared memory.
shader_object_.push_back(1 + i);
shader_object_.push_back(1 + i);
shader_object_.push_back(
ENCODE_D3D10_SB_RESOURCE_RETURN_TYPE(D3D10_SB_RETURN_TYPE_FLOAT, 0) |
ENCODE_D3D10_SB_RESOURCE_RETURN_TYPE(D3D10_SB_RETURN_TYPE_FLOAT, 1) |
ENCODE_D3D10_SB_RESOURCE_RETURN_TYPE(D3D10_SB_RETURN_TYPE_FLOAT, 2) |
ENCODE_D3D10_SB_RESOURCE_RETURN_TYPE(D3D10_SB_RETURN_TYPE_FLOAT, 3));
shader_object_.push_back(0);
}
// Inputs and outputs.
if (is_vertex_shader()) {
// Unswapped vertex index input (only X component).