shader: Decode SUST and implement backing image functionality
This commit is contained in:
parent
007ffbef1c
commit
06c4ce8645
|
@ -70,6 +70,7 @@ set(HASH_FILES
|
||||||
"${VIDEO_CORE}/shader/decode/half_set.cpp"
|
"${VIDEO_CORE}/shader/decode/half_set.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
|
"${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/hfma2.cpp"
|
"${VIDEO_CORE}/shader/decode/hfma2.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/decode/image.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/integer_set.cpp"
|
"${VIDEO_CORE}/shader/decode/integer_set.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
|
"${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/memory.cpp"
|
"${VIDEO_CORE}/shader/decode/memory.cpp"
|
||||||
|
|
|
@ -44,6 +44,7 @@ add_custom_command(OUTPUT scm_rev.cpp
|
||||||
"${VIDEO_CORE}/shader/decode/half_set.cpp"
|
"${VIDEO_CORE}/shader/decode/half_set.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
|
"${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/hfma2.cpp"
|
"${VIDEO_CORE}/shader/decode/hfma2.cpp"
|
||||||
|
"${VIDEO_CORE}/shader/decode/image.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/integer_set.cpp"
|
"${VIDEO_CORE}/shader/decode/integer_set.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
|
"${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
|
||||||
"${VIDEO_CORE}/shader/decode/memory.cpp"
|
"${VIDEO_CORE}/shader/decode/memory.cpp"
|
||||||
|
|
|
@ -90,6 +90,7 @@ add_library(video_core STATIC
|
||||||
shader/decode/conversion.cpp
|
shader/decode/conversion.cpp
|
||||||
shader/decode/memory.cpp
|
shader/decode/memory.cpp
|
||||||
shader/decode/texture.cpp
|
shader/decode/texture.cpp
|
||||||
|
shader/decode/image.cpp
|
||||||
shader/decode/float_set_predicate.cpp
|
shader/decode/float_set_predicate.cpp
|
||||||
shader/decode/integer_set_predicate.cpp
|
shader/decode/integer_set_predicate.cpp
|
||||||
shader/decode/half_set_predicate.cpp
|
shader/decode/half_set_predicate.cpp
|
||||||
|
|
|
@ -126,6 +126,15 @@ union Sampler {
|
||||||
u64 value{};
|
u64 value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union Image {
|
||||||
|
Image() = default;
|
||||||
|
|
||||||
|
constexpr explicit Image(u64 value) : value{value} {}
|
||||||
|
|
||||||
|
BitField<36, 13, u64> index;
|
||||||
|
u64 value;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Tegra::Shader
|
} // namespace Tegra::Shader
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
@ -344,6 +353,26 @@ enum class TextureMiscMode : u64 {
|
||||||
PTP,
|
PTP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SurfaceDataMode : u64 {
|
||||||
|
P = 0,
|
||||||
|
D_BA = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OutOfBoundsStore : u64 {
|
||||||
|
Ignore = 0,
|
||||||
|
Clamp = 1,
|
||||||
|
Trap = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ImageType : u64 {
|
||||||
|
Texture1D = 0,
|
||||||
|
TextureBuffer = 1,
|
||||||
|
Texture1DArray = 2,
|
||||||
|
Texture2D = 3,
|
||||||
|
Texture2DArray = 4,
|
||||||
|
Texture3D = 5,
|
||||||
|
};
|
||||||
|
|
||||||
enum class IsberdMode : u64 {
|
enum class IsberdMode : u64 {
|
||||||
None = 0,
|
None = 0,
|
||||||
Patch = 1,
|
Patch = 1,
|
||||||
|
@ -398,7 +427,7 @@ enum class LmemLoadCacheManagement : u64 {
|
||||||
CV = 3,
|
CV = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LmemStoreCacheManagement : u64 {
|
enum class StoreCacheManagement : u64 {
|
||||||
Default = 0,
|
Default = 0,
|
||||||
CG = 1,
|
CG = 1,
|
||||||
CS = 2,
|
CS = 2,
|
||||||
|
@ -811,7 +840,7 @@ union Instruction {
|
||||||
} ld_l;
|
} ld_l;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
BitField<44, 2, LmemStoreCacheManagement> cache_management;
|
BitField<44, 2, StoreCacheManagement> cache_management;
|
||||||
} st_l;
|
} st_l;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -1294,6 +1323,35 @@ union Instruction {
|
||||||
}
|
}
|
||||||
} tlds;
|
} tlds;
|
||||||
|
|
||||||
|
union {
|
||||||
|
BitField<24, 2, StoreCacheManagement> cache_management;
|
||||||
|
BitField<33, 3, ImageType> image_type;
|
||||||
|
BitField<49, 2, OutOfBoundsStore> out_of_bounds_store;
|
||||||
|
BitField<51, 1, u64> is_immediate;
|
||||||
|
BitField<52, 1, SurfaceDataMode> mode;
|
||||||
|
|
||||||
|
BitField<20, 3, StoreType> store_data_layout;
|
||||||
|
BitField<20, 4, u64> component_mask_selector;
|
||||||
|
|
||||||
|
bool IsComponentEnabled(std::size_t component) const {
|
||||||
|
ASSERT(mode == SurfaceDataMode::P);
|
||||||
|
constexpr u8 R = 0b0001;
|
||||||
|
constexpr u8 G = 0b0010;
|
||||||
|
constexpr u8 B = 0b0100;
|
||||||
|
constexpr u8 A = 0b1000;
|
||||||
|
constexpr std::array<u8, 16> mask = {
|
||||||
|
0, (R), (G), (R | G), (B), (R | B),
|
||||||
|
(G | B), (R | G | B), (A), (R | A), (G | A), (R | G | A),
|
||||||
|
(B | A), (R | B | A), (G | B | A), (R | G | B | A)};
|
||||||
|
return std::bitset<4>{mask.at(component_mask_selector)}.test(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreType GetStoreDataLayout() const {
|
||||||
|
ASSERT(mode == SurfaceDataMode::D_BA);
|
||||||
|
return store_data_layout;
|
||||||
|
}
|
||||||
|
} sust;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
BitField<20, 24, u64> target;
|
BitField<20, 24, u64> target;
|
||||||
BitField<5, 1, u64> constant_buffer;
|
BitField<5, 1, u64> constant_buffer;
|
||||||
|
@ -1385,6 +1443,7 @@ union Instruction {
|
||||||
|
|
||||||
Attribute attribute;
|
Attribute attribute;
|
||||||
Sampler sampler;
|
Sampler sampler;
|
||||||
|
Image image;
|
||||||
|
|
||||||
u64 value;
|
u64 value;
|
||||||
};
|
};
|
||||||
|
@ -1428,6 +1487,7 @@ public:
|
||||||
TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations
|
TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations
|
||||||
TMML_B, // Texture Mip Map Level
|
TMML_B, // Texture Mip Map Level
|
||||||
TMML, // Texture Mip Map Level
|
TMML, // Texture Mip Map Level
|
||||||
|
SUST, // Surface Store
|
||||||
EXIT,
|
EXIT,
|
||||||
IPA,
|
IPA,
|
||||||
OUT_R, // Emit vertex/primitive
|
OUT_R, // Emit vertex/primitive
|
||||||
|
@ -1558,6 +1618,7 @@ public:
|
||||||
Synch,
|
Synch,
|
||||||
Memory,
|
Memory,
|
||||||
Texture,
|
Texture,
|
||||||
|
Image,
|
||||||
FloatSet,
|
FloatSet,
|
||||||
FloatSetPredicate,
|
FloatSetPredicate,
|
||||||
IntegerSet,
|
IntegerSet,
|
||||||
|
@ -1703,6 +1764,7 @@ private:
|
||||||
INST("1101111100------", Id::TLD4S, Type::Texture, "TLD4S"),
|
INST("1101111100------", Id::TLD4S, Type::Texture, "TLD4S"),
|
||||||
INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"),
|
INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"),
|
||||||
INST("1101111101011---", Id::TMML, Type::Texture, "TMML"),
|
INST("1101111101011---", Id::TMML, Type::Texture, "TMML"),
|
||||||
|
INST("11101011001-----", Id::SUST, Type::Image, "SUST"),
|
||||||
INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
|
INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
|
||||||
INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"),
|
INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"),
|
||||||
INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"),
|
INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"),
|
||||||
|
|
|
@ -180,6 +180,7 @@ public:
|
||||||
DeclareGlobalMemory();
|
DeclareGlobalMemory();
|
||||||
DeclareSamplers();
|
DeclareSamplers();
|
||||||
DeclarePhysicalAttributeReader();
|
DeclarePhysicalAttributeReader();
|
||||||
|
DeclareImages();
|
||||||
|
|
||||||
code.AddLine("void execute_{}() {{", suffix);
|
code.AddLine("void execute_{}() {{", suffix);
|
||||||
++code.scope;
|
++code.scope;
|
||||||
|
@ -531,6 +532,36 @@ private:
|
||||||
code.AddNewLine();
|
code.AddNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeclareImages() {
|
||||||
|
const auto& images{ir.GetImages()};
|
||||||
|
for (const auto& image : images) {
|
||||||
|
const std::string image_type = [&]() {
|
||||||
|
switch (image.GetType()) {
|
||||||
|
case Tegra::Shader::ImageType::Texture1D:
|
||||||
|
return "image1D";
|
||||||
|
case Tegra::Shader::ImageType::TextureBuffer:
|
||||||
|
return "bufferImage";
|
||||||
|
case Tegra::Shader::ImageType::Texture1DArray:
|
||||||
|
return "image1DArray";
|
||||||
|
case Tegra::Shader::ImageType::Texture2D:
|
||||||
|
return "image2D";
|
||||||
|
case Tegra::Shader::ImageType::Texture2DArray:
|
||||||
|
return "image2DArray";
|
||||||
|
case Tegra::Shader::ImageType::Texture3D:
|
||||||
|
return "image3D";
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
return "image1D";
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
code.AddLine("layout (binding = IMAGE_BINDING_" + std::to_string(image.GetIndex()) +
|
||||||
|
") coherent volatile writeonly uniform " + image_type + ' ' +
|
||||||
|
GetImage(image) + ';');
|
||||||
|
}
|
||||||
|
if (!images.empty())
|
||||||
|
code.AddNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
void VisitBlock(const NodeBlock& bb) {
|
void VisitBlock(const NodeBlock& bb) {
|
||||||
for (const auto& node : bb) {
|
for (const auto& node : bb) {
|
||||||
if (const std::string expr = Visit(node); !expr.empty()) {
|
if (const std::string expr = Visit(node); !expr.empty()) {
|
||||||
|
@ -1478,6 +1509,39 @@ private:
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ImageStore(Operation operation) {
|
||||||
|
constexpr std::array<const char*, 4> constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
|
||||||
|
const auto meta{std::get<MetaImage>(operation.GetMeta())};
|
||||||
|
|
||||||
|
std::string expr = "imageStore(";
|
||||||
|
expr += GetImage(meta.image);
|
||||||
|
expr += ", ";
|
||||||
|
|
||||||
|
const std::size_t coords_count{operation.GetOperandsCount()};
|
||||||
|
expr += constructors.at(coords_count - 1);
|
||||||
|
for (std::size_t i = 0; i < coords_count; ++i) {
|
||||||
|
expr += VisitOperand(operation, i, Type::Int);
|
||||||
|
if (i + 1 < coords_count) {
|
||||||
|
expr += ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expr += "), ";
|
||||||
|
|
||||||
|
const std::size_t values_count{meta.values.size()};
|
||||||
|
UNIMPLEMENTED_IF(values_count != 4);
|
||||||
|
expr += "vec4(";
|
||||||
|
for (std::size_t i = 0; i < values_count; ++i) {
|
||||||
|
expr += Visit(meta.values.at(i));
|
||||||
|
if (i + 1 < values_count) {
|
||||||
|
expr += ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expr += "));";
|
||||||
|
|
||||||
|
code.AddLine(expr);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::string Branch(Operation operation) {
|
std::string Branch(Operation operation) {
|
||||||
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
|
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
|
||||||
UNIMPLEMENTED_IF(!target);
|
UNIMPLEMENTED_IF(!target);
|
||||||
|
@ -1718,6 +1782,8 @@ private:
|
||||||
&GLSLDecompiler::TextureQueryLod,
|
&GLSLDecompiler::TextureQueryLod,
|
||||||
&GLSLDecompiler::TexelFetch,
|
&GLSLDecompiler::TexelFetch,
|
||||||
|
|
||||||
|
&GLSLDecompiler::ImageStore,
|
||||||
|
|
||||||
&GLSLDecompiler::Branch,
|
&GLSLDecompiler::Branch,
|
||||||
&GLSLDecompiler::PushFlowStack,
|
&GLSLDecompiler::PushFlowStack,
|
||||||
&GLSLDecompiler::PopFlowStack,
|
&GLSLDecompiler::PopFlowStack,
|
||||||
|
@ -1786,6 +1852,10 @@ private:
|
||||||
return GetDeclarationWithSuffix(static_cast<u32>(sampler.GetIndex()), "sampler");
|
return GetDeclarationWithSuffix(static_cast<u32>(sampler.GetIndex()), "sampler");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetImage(const Image& image) const {
|
||||||
|
return GetDeclarationWithSuffix(static_cast<u32>(image.GetIndex()), "image");
|
||||||
|
}
|
||||||
|
|
||||||
void EmitIfdefIsBuffer(const Sampler& sampler) {
|
void EmitIfdefIsBuffer(const Sampler& sampler) {
|
||||||
code.AddLine(fmt::format("#ifdef SAMPLER_{}_IS_BUFFER", sampler.GetIndex()));
|
code.AddLine(fmt::format("#ifdef SAMPLER_{}_IS_BUFFER", sampler.GetIndex()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -935,6 +935,11 @@ private:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Id ImageStore(Operation operation) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Id Branch(Operation operation) {
|
Id Branch(Operation operation) {
|
||||||
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
|
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
|
||||||
UNIMPLEMENTED_IF(!target);
|
UNIMPLEMENTED_IF(!target);
|
||||||
|
@ -1326,6 +1331,8 @@ private:
|
||||||
&SPIRVDecompiler::TextureQueryLod,
|
&SPIRVDecompiler::TextureQueryLod,
|
||||||
&SPIRVDecompiler::TexelFetch,
|
&SPIRVDecompiler::TexelFetch,
|
||||||
|
|
||||||
|
&SPIRVDecompiler::ImageStore,
|
||||||
|
|
||||||
&SPIRVDecompiler::Branch,
|
&SPIRVDecompiler::Branch,
|
||||||
&SPIRVDecompiler::PushFlowStack,
|
&SPIRVDecompiler::PushFlowStack,
|
||||||
&SPIRVDecompiler::PopFlowStack,
|
&SPIRVDecompiler::PopFlowStack,
|
||||||
|
|
|
@ -169,6 +169,7 @@ u32 ShaderIR::DecodeInstr(NodeBlock& bb, u32 pc) {
|
||||||
{OpCode::Type::Conversion, &ShaderIR::DecodeConversion},
|
{OpCode::Type::Conversion, &ShaderIR::DecodeConversion},
|
||||||
{OpCode::Type::Memory, &ShaderIR::DecodeMemory},
|
{OpCode::Type::Memory, &ShaderIR::DecodeMemory},
|
||||||
{OpCode::Type::Texture, &ShaderIR::DecodeTexture},
|
{OpCode::Type::Texture, &ShaderIR::DecodeTexture},
|
||||||
|
{OpCode::Type::Image, &ShaderIR::DecodeImage},
|
||||||
{OpCode::Type::FloatSetPredicate, &ShaderIR::DecodeFloatSetPredicate},
|
{OpCode::Type::FloatSetPredicate, &ShaderIR::DecodeFloatSetPredicate},
|
||||||
{OpCode::Type::IntegerSetPredicate, &ShaderIR::DecodeIntegerSetPredicate},
|
{OpCode::Type::IntegerSetPredicate, &ShaderIR::DecodeIntegerSetPredicate},
|
||||||
{OpCode::Type::HalfSetPredicate, &ShaderIR::DecodeHalfSetPredicate},
|
{OpCode::Type::HalfSetPredicate, &ShaderIR::DecodeHalfSetPredicate},
|
||||||
|
|
89
src/video_core/shader/decode/image.cpp
Normal file
89
src/video_core/shader/decode/image.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright 2019 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/engines/shader_bytecode.h"
|
||||||
|
#include "video_core/shader/shader_ir.h"
|
||||||
|
|
||||||
|
namespace VideoCommon::Shader {
|
||||||
|
|
||||||
|
using Tegra::Shader::Instruction;
|
||||||
|
using Tegra::Shader::OpCode;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) {
|
||||||
|
switch (image_type) {
|
||||||
|
case Tegra::Shader::ImageType::Texture1D:
|
||||||
|
case Tegra::Shader::ImageType::TextureBuffer:
|
||||||
|
return 1;
|
||||||
|
case Tegra::Shader::ImageType::Texture1DArray:
|
||||||
|
case Tegra::Shader::ImageType::Texture2D:
|
||||||
|
return 2;
|
||||||
|
case Tegra::Shader::ImageType::Texture2DArray:
|
||||||
|
case Tegra::Shader::ImageType::Texture3D:
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
|
||||||
|
const Instruction instr = {program_code[pc]};
|
||||||
|
const auto opcode = OpCode::Decode(instr);
|
||||||
|
|
||||||
|
switch (opcode->get().GetId()) {
|
||||||
|
case OpCode::Id::SUST: {
|
||||||
|
UNIMPLEMENTED_IF(instr.sust.mode != Tegra::Shader::SurfaceDataMode::P);
|
||||||
|
UNIMPLEMENTED_IF(instr.sust.image_type == Tegra::Shader::ImageType::TextureBuffer);
|
||||||
|
UNIMPLEMENTED_IF(instr.sust.out_of_bounds_store != Tegra::Shader::OutOfBoundsStore::Ignore);
|
||||||
|
UNIMPLEMENTED_IF(instr.sust.component_mask_selector != 0xf); // Ensure we have an RGBA store
|
||||||
|
|
||||||
|
std::vector<Node> values;
|
||||||
|
constexpr std::size_t hardcoded_size{4};
|
||||||
|
for (std::size_t i = 0; i < hardcoded_size; ++i) {
|
||||||
|
values.push_back(GetRegister(instr.gpr0.Value() + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Node> coords;
|
||||||
|
const std::size_t num_coords{GetImageTypeNumCoordinates(instr.sust.image_type)};
|
||||||
|
for (std::size_t i = 0; i < num_coords; ++i) {
|
||||||
|
coords.push_back(GetRegister(instr.gpr8.Value() + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(instr.sust.is_immediate);
|
||||||
|
const auto& image{GetImage(instr.image, instr.sust.image_type)};
|
||||||
|
MetaImage meta{image, values};
|
||||||
|
const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))};
|
||||||
|
bb.push_back(store);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
|
||||||
|
const auto offset{static_cast<std::size_t>(image.index.Value())};
|
||||||
|
|
||||||
|
// If this image has already been used, return the existing mapping.
|
||||||
|
const auto itr{std::find_if(used_images.begin(), used_images.end(),
|
||||||
|
[=](const Image& entry) { return entry.GetOffset() == offset; })};
|
||||||
|
if (itr != used_images.end()) {
|
||||||
|
ASSERT(itr->GetType() == type);
|
||||||
|
return *itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise create a new mapping for this image.
|
||||||
|
const std::size_t next_index{used_images.size()};
|
||||||
|
const Image entry{offset, next_index, type};
|
||||||
|
return *used_images.emplace(entry).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace VideoCommon::Shader
|
|
@ -146,6 +146,8 @@ enum class OperationCode {
|
||||||
TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
|
TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
|
||||||
TexelFetch, /// (MetaTexture, int[N], int) -> float4
|
TexelFetch, /// (MetaTexture, int[N], int) -> float4
|
||||||
|
|
||||||
|
ImageStore, /// (MetaImage, float[N] coords) -> void
|
||||||
|
|
||||||
Branch, /// (uint branch_target) -> void
|
Branch, /// (uint branch_target) -> void
|
||||||
PushFlowStack, /// (uint branch_target) -> void
|
PushFlowStack, /// (uint branch_target) -> void
|
||||||
PopFlowStack, /// () -> void
|
PopFlowStack, /// () -> void
|
||||||
|
@ -263,6 +265,39 @@ private:
|
||||||
bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
|
bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Image {
|
||||||
|
public:
|
||||||
|
explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type)
|
||||||
|
: offset{offset}, index{index}, type{type}, is_bindless{false} {}
|
||||||
|
|
||||||
|
std::size_t GetOffset() const {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t GetIndex() const {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tegra::Shader::ImageType GetType() const {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBindless() const {
|
||||||
|
return is_bindless;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const Image& rhs) const {
|
||||||
|
return std::tie(offset, index, type, is_bindless) <
|
||||||
|
std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t offset{};
|
||||||
|
std::size_t index{};
|
||||||
|
Tegra::Shader::ImageType type{};
|
||||||
|
bool is_bindless{};
|
||||||
|
};
|
||||||
|
|
||||||
struct GlobalMemoryBase {
|
struct GlobalMemoryBase {
|
||||||
u32 cbuf_index{};
|
u32 cbuf_index{};
|
||||||
u32 cbuf_offset{};
|
u32 cbuf_offset{};
|
||||||
|
@ -289,8 +324,13 @@ struct MetaTexture {
|
||||||
u32 element{};
|
u32 element{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MetaImage {
|
||||||
|
const Image& image;
|
||||||
|
std::vector<Node> values;
|
||||||
|
};
|
||||||
|
|
||||||
/// Parameters that modify an operation but are not part of any particular operand
|
/// Parameters that modify an operation but are not part of any particular operand
|
||||||
using Meta = std::variant<MetaArithmetic, MetaTexture, MetaStackClass, Tegra::Shader::HalfType>;
|
using Meta = std::variant<MetaArithmetic, MetaTexture, MetaImage, MetaStackClass, Tegra::Shader::HalfType>;
|
||||||
|
|
||||||
/// Holds any kind of operation that can be done in the IR
|
/// Holds any kind of operation that can be done in the IR
|
||||||
class OperationNode final {
|
class OperationNode final {
|
||||||
|
|
|
@ -104,6 +104,10 @@ public:
|
||||||
return used_samplers;
|
return used_samplers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::set<Image>& GetImages() const {
|
||||||
|
return used_images;
|
||||||
|
}
|
||||||
|
|
||||||
const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& GetClipDistances()
|
const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& GetClipDistances()
|
||||||
const {
|
const {
|
||||||
return used_clip_distances;
|
return used_clip_distances;
|
||||||
|
@ -154,6 +158,7 @@ private:
|
||||||
u32 DecodeConversion(NodeBlock& bb, u32 pc);
|
u32 DecodeConversion(NodeBlock& bb, u32 pc);
|
||||||
u32 DecodeMemory(NodeBlock& bb, u32 pc);
|
u32 DecodeMemory(NodeBlock& bb, u32 pc);
|
||||||
u32 DecodeTexture(NodeBlock& bb, u32 pc);
|
u32 DecodeTexture(NodeBlock& bb, u32 pc);
|
||||||
|
u32 DecodeImage(NodeBlock& bb, u32 pc);
|
||||||
u32 DecodeFloatSetPredicate(NodeBlock& bb, u32 pc);
|
u32 DecodeFloatSetPredicate(NodeBlock& bb, u32 pc);
|
||||||
u32 DecodeIntegerSetPredicate(NodeBlock& bb, u32 pc);
|
u32 DecodeIntegerSetPredicate(NodeBlock& bb, u32 pc);
|
||||||
u32 DecodeHalfSetPredicate(NodeBlock& bb, u32 pc);
|
u32 DecodeHalfSetPredicate(NodeBlock& bb, u32 pc);
|
||||||
|
@ -254,6 +259,9 @@ private:
|
||||||
Tegra::Shader::TextureType type, bool is_array,
|
Tegra::Shader::TextureType type, bool is_array,
|
||||||
bool is_shadow);
|
bool is_shadow);
|
||||||
|
|
||||||
|
/// Accesses an image.
|
||||||
|
const Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
|
||||||
|
|
||||||
/// Extracts a sequence of bits from a node
|
/// Extracts a sequence of bits from a node
|
||||||
Node BitfieldExtract(Node value, u32 offset, u32 bits);
|
Node BitfieldExtract(Node value, u32 offset, u32 bits);
|
||||||
|
|
||||||
|
@ -329,6 +337,7 @@ private:
|
||||||
std::set<Tegra::Shader::Attribute::Index> used_output_attributes;
|
std::set<Tegra::Shader::Attribute::Index> used_output_attributes;
|
||||||
std::map<u32, ConstBuffer> used_cbufs;
|
std::map<u32, ConstBuffer> used_cbufs;
|
||||||
std::set<Sampler> used_samplers;
|
std::set<Sampler> used_samplers;
|
||||||
|
std::set<Image> used_images;
|
||||||
std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{};
|
std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{};
|
||||||
std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;
|
std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;
|
||||||
bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
|
bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
|
||||||
|
|
Loading…
Reference in a new issue