[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

@ -27,18 +27,20 @@ D3D12Shader::~D3D12Shader() {
}
}
#if 0
void D3D12Shader::SetTexturesAndSamplers(
const HlslShaderTranslator::TextureSRV* texture_srvs,
const DxbcShaderTranslator::TextureSRV* texture_srvs,
uint32_t texture_srv_count, const uint32_t* sampler_fetch_constants,
uint32_t sampler_count) {
used_texture_mask_ = 0;
for (uint32_t i = 0; i < texture_srv_count; ++i) {
TextureSRV& srv = texture_srvs_[i];
const HlslShaderTranslator::TextureSRV& translator_srv = texture_srvs[i];
const DxbcShaderTranslator::TextureSRV& translator_srv = texture_srvs[i];
srv.fetch_constant = translator_srv.fetch_constant;
srv.dimension = translator_srv.dimension;
used_texture_mask_ |= 1u << translator_srv.fetch_constant;
}
texture_srv_count_ = texture_srv_count;
#if 0
// If there's a texture, there's a sampler for it.
used_texture_mask_ = 0;
for (uint32_t i = 0; i < sampler_count; ++i) {
@ -47,8 +49,8 @@ void D3D12Shader::SetTexturesAndSamplers(
used_texture_mask_ |= 1u << sampler_fetch_constant;
}
sampler_count_ = sampler_count;
}
#endif
}
bool D3D12Shader::DisassembleDXBC() {
if (!host_disassembly_.empty()) {

View File

@ -10,8 +10,7 @@
#ifndef XENIA_GPU_D3D12_D3D12_SHADER_H_
#define XENIA_GPU_D3D12_D3D12_SHADER_H_
// TODO(Triang3l): Remove hlsl_shader_translator.
#include "xenia/gpu/hlsl_shader_translator.h"
#include "xenia/gpu/dxbc_shader_translator.h"
#include "xenia/gpu/shader.h"
#include "xenia/ui/d3d12/d3d12_api.h"
@ -25,12 +24,10 @@ class D3D12Shader : public Shader {
const uint32_t* dword_ptr, uint32_t dword_count);
~D3D12Shader() override;
#if 0
void SetTexturesAndSamplers(
const HlslShaderTranslator::TextureSRV* texture_srvs,
const DxbcShaderTranslator::TextureSRV* texture_srvs,
uint32_t texture_srv_count, const uint32_t* sampler_fetch_constants,
uint32_t sampler_count);
#endif
bool DisassembleDXBC();

View File

@ -198,15 +198,15 @@ bool PipelineCache::TranslateShader(D3D12Shader* shader,
// TODO(Triang3l): Re-enable this when the DXBC shader translators supports
// textures.
#if 0
uint32_t texture_srv_count, sampler_count;
const HlslShaderTranslator::TextureSRV* texture_srvs =
uint32_t texture_srv_count;
const DxbcShaderTranslator::TextureSRV* texture_srvs =
shader_translator_->GetTextureSRVs(texture_srv_count);
#if 0
uint32_t sampler_count;
const uint32_t* sampler_fetch_constants =
shader_translator_->GetSamplerFetchConstants(sampler_count);
shader->SetTexturesAndSamplers(texture_srvs, texture_srv_count,
sampler_fetch_constants, sampler_count);
#endif
shader->SetTexturesAndSamplers(texture_srvs, texture_srv_count, nullptr, 0);
if (shader->is_valid()) {
XELOGGPU("Generated %s shader (%db) - hash %.16" PRIX64 ":\n%s\n",

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).

View File

@ -10,8 +10,11 @@
#ifndef XENIA_GPU_DXBC_SHADER_TRANSLATOR_H_
#define XENIA_GPU_DXBC_SHADER_TRANSLATOR_H_
#include <cstring>
#include <string>
#include <vector>
#include "xenia/base/math.h"
#include "xenia/gpu/shader_translator.h"
namespace xe {
@ -59,6 +62,30 @@ class DxbcShaderTranslator : public ShaderTranslator {
uint32_t color_output_map[4];
};
struct TextureSRV {
uint32_t fetch_constant;
TextureDimension dimension;
std::string name;
};
// The first binding returned is at t1 because t0 is shared memory.
const TextureSRV* GetTextureSRVs(uint32_t& count_out) const {
count_out = uint32_t(texture_srvs_.size());
return texture_srvs_.data();
}
struct SamplerBinding {
uint32_t fetch_constant;
TextureFilter mag_filter;
TextureFilter min_filter;
TextureFilter mip_filter;
AnisoFilter aniso_filter;
std::string name;
};
const SamplerBinding* GetSamplerBindings(uint32_t& count_out) const {
count_out = uint32_t(sampler_bindings_.size());
return sampler_bindings_.data();
}
protected:
void Reset() override;
@ -68,6 +95,8 @@ class DxbcShaderTranslator : public ShaderTranslator {
void ProcessVertexFetchInstruction(
const ParsedVertexFetchInstruction& instr) override;
void ProcessTextureFetchInstruction(
const ParsedTextureFetchInstruction& instr) override;
void ProcessAluInstruction(const ParsedAluInstruction& instr) override;
private:
@ -272,11 +301,20 @@ class DxbcShaderTranslator : public ShaderTranslator {
// Emits copde for endian swapping of the data located in pv.
void SwapVertexData(uint32_t vfetch_index, uint32_t write_mask);
// Returns T#/t# index (they are the same in this translator).
uint32_t FindOrAddTextureSRV(uint32_t fetch_constant,
TextureDimension dimension);
void ProcessVectorAluInstruction(const ParsedAluInstruction& instr);
void ProcessScalarAluInstruction(const ParsedAluInstruction& instr);
// Appends a string to a DWORD stream, returns the DWORD-aligned length.
static uint32_t AppendString(std::vector<uint32_t>& dest, const char* source);
// Returns the length of a string as if it was appended to a DWORD stream, in
// bytes.
static inline uint32_t GetStringLength(const char* source) {
return uint32_t(xe::align(std::strlen(source) + 1, sizeof(uint32_t)));
}
void WriteResourceDefinitions();
void WriteInputSignature();
@ -418,6 +456,9 @@ class DxbcShaderTranslator : public ShaderTranslator {
// Loop counter stack, .x is the active loop. Represents number of times
// remaining to loop.
uint32_t system_temp_loop_count_;
// Explicitly set texture gradients and LOD.
uint32_t system_temp_grad_h_lod_;
uint32_t system_temp_grad_v_;
// Position in vertex shaders (because viewport and W transformations can be
// applied in the end of the shader).
@ -429,6 +470,9 @@ class DxbcShaderTranslator : public ShaderTranslator {
bool writes_depth_;
std::vector<TextureSRV> texture_srvs_;
std::vector<SamplerBinding> sampler_bindings_;
// The STAT chunk (based on Wine d3dcompiler_parse_stat).
struct Statistics {
uint32_t instruction_count;