|
|
|
@ -439,13 +439,12 @@ public:
|
|
|
|
|
}
|
|
|
|
|
declarations.AddNewLine();
|
|
|
|
|
|
|
|
|
|
// Append the sampler2D array for the used textures.
|
|
|
|
|
size_t num_samplers = GetSamplers().size();
|
|
|
|
|
if (num_samplers > 0) {
|
|
|
|
|
declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' +
|
|
|
|
|
std::to_string(num_samplers) + "];");
|
|
|
|
|
declarations.AddNewLine();
|
|
|
|
|
const auto& samplers = GetSamplers();
|
|
|
|
|
for (const auto& sampler : samplers) {
|
|
|
|
|
declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() +
|
|
|
|
|
';');
|
|
|
|
|
}
|
|
|
|
|
declarations.AddNewLine();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns a list of constant buffer declarations
|
|
|
|
@ -457,13 +456,14 @@ public:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns a list of samplers used in the shader
|
|
|
|
|
std::vector<SamplerEntry> GetSamplers() const {
|
|
|
|
|
const std::vector<SamplerEntry>& GetSamplers() const {
|
|
|
|
|
return used_samplers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
|
|
|
|
|
/// necessary.
|
|
|
|
|
std::string AccessSampler(const Sampler& sampler) {
|
|
|
|
|
std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
|
|
|
|
|
bool is_array) {
|
|
|
|
|
size_t offset = static_cast<size_t>(sampler.index.Value());
|
|
|
|
|
|
|
|
|
|
// If this sampler has already been used, return the existing mapping.
|
|
|
|
@ -472,12 +472,13 @@ public:
|
|
|
|
|
[&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
|
|
|
|
|
|
|
|
|
|
if (itr != used_samplers.end()) {
|
|
|
|
|
ASSERT(itr->GetType() == type && itr->IsArray() == is_array);
|
|
|
|
|
return itr->GetName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise create a new mapping for this sampler
|
|
|
|
|
size_t next_index = used_samplers.size();
|
|
|
|
|
SamplerEntry entry{stage, offset, next_index};
|
|
|
|
|
SamplerEntry entry{stage, offset, next_index, type, is_array};
|
|
|
|
|
used_samplers.emplace_back(entry);
|
|
|
|
|
return entry.GetName();
|
|
|
|
|
}
|
|
|
|
@ -638,8 +639,8 @@ private:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Generates code representing a texture sampler.
|
|
|
|
|
std::string GetSampler(const Sampler& sampler) {
|
|
|
|
|
return regs.AccessSampler(sampler);
|
|
|
|
|
std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) {
|
|
|
|
|
return regs.AccessSampler(sampler, type, is_array);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -1507,10 +1508,29 @@ private:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OpCode::Id::TEX: {
|
|
|
|
|
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
|
|
|
|
const std::string sampler = GetSampler(instr.sampler);
|
|
|
|
|
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
|
|
|
|
ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented");
|
|
|
|
|
std::string coord{};
|
|
|
|
|
|
|
|
|
|
switch (instr.tex.texture_type) {
|
|
|
|
|
case Tegra::Shader::TextureType::Texture2D: {
|
|
|
|
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
std::string y = regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
|
|
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Tegra::Shader::TextureType::Texture3D: {
|
|
|
|
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
|
|
|
|
std::string z = regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
|
|
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string sampler =
|
|
|
|
|
GetSampler(instr.sampler, instr.tex.texture_type, instr.tex.array);
|
|
|
|
|
// Add an extra scope and declare the texture coords inside to prevent
|
|
|
|
|
// overwriting them in case they are used as outputs of the texs instruction.
|
|
|
|
|
shader.AddLine("{");
|
|
|
|
@ -1532,24 +1552,115 @@ private:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OpCode::Id::TEXS: {
|
|
|
|
|
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
|
|
const std::string sampler = GetSampler(instr.sampler);
|
|
|
|
|
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
|
|
|
|
std::string coord{};
|
|
|
|
|
|
|
|
|
|
switch (instr.texs.GetTextureType()) {
|
|
|
|
|
case Tegra::Shader::TextureType::Texture2D: {
|
|
|
|
|
if (instr.texs.IsArrayTexture()) {
|
|
|
|
|
std::string index = regs.GetRegisterAsInteger(instr.gpr8);
|
|
|
|
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
|
|
|
|
std::string y = regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
|
|
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
|
|
|
|
|
} else {
|
|
|
|
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
std::string y = regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
|
|
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Tegra::Shader::TextureType::TextureCube: {
|
|
|
|
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
|
|
|
|
std::string z = regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
|
|
coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
}
|
|
|
|
|
const std::string sampler = GetSampler(instr.sampler, instr.texs.GetTextureType(),
|
|
|
|
|
instr.texs.IsArrayTexture());
|
|
|
|
|
|
|
|
|
|
const std::string texture = "texture(" + sampler + ", coords)";
|
|
|
|
|
WriteTexsInstruction(instr, coord, texture);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OpCode::Id::TLDS: {
|
|
|
|
|
const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8);
|
|
|
|
|
const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20);
|
|
|
|
|
const std::string sampler = GetSampler(instr.sampler);
|
|
|
|
|
const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");";
|
|
|
|
|
ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D);
|
|
|
|
|
ASSERT(instr.tlds.IsArrayTexture() == false);
|
|
|
|
|
std::string coord{};
|
|
|
|
|
|
|
|
|
|
switch (instr.tlds.GetTextureType()) {
|
|
|
|
|
case Tegra::Shader::TextureType::Texture2D: {
|
|
|
|
|
if (instr.tlds.IsArrayTexture()) {
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
} else {
|
|
|
|
|
std::string x = regs.GetRegisterAsInteger(instr.gpr8);
|
|
|
|
|
std::string y = regs.GetRegisterAsInteger(instr.gpr20);
|
|
|
|
|
coord = "ivec2 coords = ivec2(" + x + ", " + y + ");";
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
}
|
|
|
|
|
const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(),
|
|
|
|
|
instr.tlds.IsArrayTexture());
|
|
|
|
|
const std::string texture = "texelFetch(" + sampler + ", coords, 0)";
|
|
|
|
|
WriteTexsInstruction(instr, coord, texture);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OpCode::Id::TLD4: {
|
|
|
|
|
ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
|
|
|
|
|
ASSERT(instr.tld4.array == 0);
|
|
|
|
|
std::string coord{};
|
|
|
|
|
|
|
|
|
|
switch (instr.tld4.texture_type) {
|
|
|
|
|
case Tegra::Shader::TextureType::Texture2D: {
|
|
|
|
|
std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
|
|
|
|
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string sampler =
|
|
|
|
|
GetSampler(instr.sampler, instr.tld4.texture_type, instr.tld4.array);
|
|
|
|
|
// Add an extra scope and declare the texture coords inside to prevent
|
|
|
|
|
// overwriting them in case they are used as outputs of the texs instruction.
|
|
|
|
|
shader.AddLine("{");
|
|
|
|
|
++shader.scope;
|
|
|
|
|
shader.AddLine(coord);
|
|
|
|
|
const std::string texture = "textureGather(" + sampler + ", coords, " +
|
|
|
|
|
std::to_string(instr.tld4.component) + ')';
|
|
|
|
|
|
|
|
|
|
size_t dest_elem{};
|
|
|
|
|
for (size_t elem = 0; elem < 4; ++elem) {
|
|
|
|
|
if (!instr.tex.IsComponentEnabled(elem)) {
|
|
|
|
|
// Skip disabled components
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
|
|
|
|
|
++dest_elem;
|
|
|
|
|
}
|
|
|
|
|
--shader.scope;
|
|
|
|
|
shader.AddLine("}");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case OpCode::Id::TLD4S: {
|
|
|
|
|
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
|
|
|
|
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
|
|
|
|
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
|
|
|
|
|
const std::string sampler =
|
|
|
|
|
GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false);
|
|
|
|
|
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
|
|
|
|
const std::string texture = "textureGather(" + sampler + ", coords, " +
|
|
|
|
|
std::to_string(instr.tld4s.component) + ')';
|
|
|
|
|
WriteTexsInstruction(instr, coord, texture);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName());
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|