gl_shader_decompiler: Keep track of written images and mark them as modified
This commit is contained in:
parent
7228e22098
commit
1f43e5296f
|
@ -1098,6 +1098,9 @@ void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& t
|
||||||
if (!tic.IsBuffer()) {
|
if (!tic.IsBuffer()) {
|
||||||
view->ApplySwizzle(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
|
view->ApplySwizzle(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
|
||||||
}
|
}
|
||||||
|
if (entry.IsWritten()) {
|
||||||
|
view->MarkAsModified(texture_cache.Tick());
|
||||||
|
}
|
||||||
state.images[binding] = view->GetTexture();
|
state.images[binding] = view->GetTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -389,11 +389,10 @@ public:
|
||||||
for (const auto& sampler : ir.GetSamplers()) {
|
for (const auto& sampler : ir.GetSamplers()) {
|
||||||
entries.samplers.emplace_back(sampler);
|
entries.samplers.emplace_back(sampler);
|
||||||
}
|
}
|
||||||
for (const auto& image : ir.GetImages()) {
|
for (const auto& [offset, image] : ir.GetImages()) {
|
||||||
entries.images.emplace_back(image);
|
entries.images.emplace_back(image);
|
||||||
}
|
}
|
||||||
for (const auto& gmem_pair : ir.GetGlobalMemory()) {
|
for (const auto& [base, usage] : ir.GetGlobalMemory()) {
|
||||||
const auto& [base, usage] = gmem_pair;
|
|
||||||
entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset,
|
entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset,
|
||||||
usage.is_read, usage.is_written);
|
usage.is_read, usage.is_written);
|
||||||
}
|
}
|
||||||
|
@ -706,7 +705,7 @@ private:
|
||||||
|
|
||||||
void DeclareImages() {
|
void DeclareImages() {
|
||||||
const auto& images{ir.GetImages()};
|
const auto& images{ir.GetImages()};
|
||||||
for (const auto& image : images) {
|
for (const auto& [offset, image] : images) {
|
||||||
const std::string image_type = [&]() {
|
const std::string image_type = [&]() {
|
||||||
switch (image.GetType()) {
|
switch (image.GetType()) {
|
||||||
case Tegra::Shader::ImageType::Texture1D:
|
case Tegra::Shader::ImageType::Texture1D:
|
||||||
|
@ -726,9 +725,16 @@ private:
|
||||||
return "image1D";
|
return "image1D";
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
code.AddLine("layout (binding = IMAGE_BINDING_{}) coherent volatile writeonly uniform "
|
std::string qualifier = "coherent volatile";
|
||||||
|
if (image.IsRead() && !image.IsWritten()) {
|
||||||
|
qualifier += " readonly";
|
||||||
|
} else if (image.IsWritten() && !image.IsRead()) {
|
||||||
|
qualifier += " writeonly";
|
||||||
|
}
|
||||||
|
|
||||||
|
code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform "
|
||||||
"{} {};",
|
"{} {};",
|
||||||
image.GetIndex(), image_type, GetImage(image));
|
image.GetIndex(), qualifier, image_type, GetImage(image));
|
||||||
}
|
}
|
||||||
if (!images.empty()) {
|
if (!images.empty()) {
|
||||||
code.AddNewLine();
|
code.AddNewLine();
|
||||||
|
|
|
@ -341,13 +341,16 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
|
||||||
u64 index{};
|
u64 index{};
|
||||||
u32 type{};
|
u32 type{};
|
||||||
u8 is_bindless{};
|
u8 is_bindless{};
|
||||||
|
u8 is_read{};
|
||||||
|
u8 is_written{};
|
||||||
if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) ||
|
if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) ||
|
||||||
!LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless)) {
|
!LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) ||
|
||||||
|
!LoadObjectFromPrecompiled(is_read) || !LoadObjectFromPrecompiled(is_written)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
entry.entries.images.emplace_back(
|
entry.entries.images.emplace_back(static_cast<u64>(offset), static_cast<std::size_t>(index),
|
||||||
static_cast<std::size_t>(offset), static_cast<std::size_t>(index),
|
static_cast<Tegra::Shader::ImageType>(type),
|
||||||
static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0);
|
is_bindless != 0, is_written != 0, is_read != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 global_memory_count{};
|
u32 global_memory_count{};
|
||||||
|
@ -429,7 +432,9 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
|
||||||
if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) ||
|
if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) ||
|
||||||
!SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) ||
|
!SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) ||
|
||||||
!SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) ||
|
!SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) ||
|
||||||
!SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0))) {
|
!SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) ||
|
||||||
|
!SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) ||
|
||||||
|
!SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,17 @@ public:
|
||||||
/// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER
|
/// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER
|
||||||
void Attach(GLenum attachment, GLenum target) const;
|
void Attach(GLenum attachment, GLenum target) const;
|
||||||
|
|
||||||
|
void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
|
||||||
|
Tegra::Texture::SwizzleSource y_source,
|
||||||
|
Tegra::Texture::SwizzleSource z_source,
|
||||||
|
Tegra::Texture::SwizzleSource w_source);
|
||||||
|
|
||||||
|
void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
|
||||||
|
|
||||||
|
void MarkAsModified(u64 tick) {
|
||||||
|
surface.MarkAsModified(true, tick);
|
||||||
|
}
|
||||||
|
|
||||||
GLuint GetTexture() const {
|
GLuint GetTexture() const {
|
||||||
if (is_proxy) {
|
if (is_proxy) {
|
||||||
return surface.GetTexture();
|
return surface.GetTexture();
|
||||||
|
@ -89,13 +100,6 @@ public:
|
||||||
return surface.GetSurfaceParams();
|
return surface.GetSurfaceParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
|
|
||||||
Tegra::Texture::SwizzleSource y_source,
|
|
||||||
Tegra::Texture::SwizzleSource z_source,
|
|
||||||
Tegra::Texture::SwizzleSource w_source);
|
|
||||||
|
|
||||||
void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source,
|
u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source,
|
||||||
Tegra::Texture::SwizzleSource y_source,
|
Tegra::Texture::SwizzleSource y_source,
|
||||||
|
@ -111,8 +115,8 @@ private:
|
||||||
GLenum target{};
|
GLenum target{};
|
||||||
|
|
||||||
OGLTextureView texture_view;
|
OGLTextureView texture_view;
|
||||||
u32 swizzle;
|
u32 swizzle{};
|
||||||
bool is_proxy;
|
bool is_proxy{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextureCacheOpenGL final : public TextureCacheBase {
|
class TextureCacheOpenGL final : public TextureCacheBase {
|
||||||
|
|
|
@ -61,56 +61,54 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto type{instr.sust.image_type};
|
const auto type{instr.sust.image_type};
|
||||||
const auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
|
auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
|
||||||
: GetBindlessImage(instr.gpr39, type)};
|
: GetBindlessImage(instr.gpr39, type)};
|
||||||
|
image.MarkWrite();
|
||||||
|
|
||||||
MetaImage meta{image, values};
|
MetaImage meta{image, values};
|
||||||
const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))};
|
const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))};
|
||||||
bb.push_back(store);
|
bb.push_back(store);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName());
|
UNIMPLEMENTED_MSG("Unhandled image instruction: {}", opcode->get().GetName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
|
Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
|
||||||
const auto offset{static_cast<std::size_t>(image.index.Value())};
|
const auto offset{static_cast<u64>(image.index.Value())};
|
||||||
|
|
||||||
// If this image has already been used, return the existing mapping.
|
// If this image has already been used, return the existing mapping.
|
||||||
const auto itr{std::find_if(used_images.begin(), used_images.end(),
|
const auto it = used_images.find(offset);
|
||||||
[=](const Image& entry) { return entry.GetOffset() == offset; })};
|
if (it != used_images.end()) {
|
||||||
if (itr != used_images.end()) {
|
ASSERT(it->second.GetType() == type);
|
||||||
ASSERT(itr->GetType() == type);
|
return it->second;
|
||||||
return *itr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise create a new mapping for this image.
|
// Otherwise create a new mapping for this image.
|
||||||
const std::size_t next_index{used_images.size()};
|
const std::size_t next_index{used_images.size()};
|
||||||
const Image entry{offset, next_index, type};
|
return used_images.emplace(offset, Image{offset, next_index, type}).first->second;
|
||||||
return *used_images.emplace(entry).first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg,
|
Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) {
|
||||||
Tegra::Shader::ImageType type) {
|
|
||||||
const Node image_register{GetRegister(reg)};
|
const Node image_register{GetRegister(reg)};
|
||||||
const auto [base_image, cbuf_index, cbuf_offset]{
|
const auto [base_image, cbuf_index, cbuf_offset]{
|
||||||
TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
|
TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
|
||||||
const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
|
const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
|
||||||
|
|
||||||
// If this image has already been used, return the existing mapping.
|
// If this image has already been used, return the existing mapping.
|
||||||
const auto itr{std::find_if(used_images.begin(), used_images.end(),
|
const auto it = used_images.find(cbuf_key);
|
||||||
[=](const Image& entry) { return entry.GetOffset() == cbuf_key; })};
|
if (it != used_images.end()) {
|
||||||
if (itr != used_images.end()) {
|
ASSERT(it->second.GetType() == type);
|
||||||
ASSERT(itr->GetType() == type);
|
return it->second;
|
||||||
return *itr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise create a new mapping for this image.
|
// Otherwise create a new mapping for this image.
|
||||||
const std::size_t next_index{used_images.size()};
|
const std::size_t next_index{used_images.size()};
|
||||||
const Image entry{cbuf_index, cbuf_offset, next_index, type};
|
return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type})
|
||||||
return *used_images.emplace(entry).first;
|
.first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VideoCommon::Shader
|
} // namespace VideoCommon::Shader
|
||||||
|
|
|
@ -273,50 +273,64 @@ 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 {
|
class Image final {
|
||||||
public:
|
public:
|
||||||
explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type)
|
constexpr explicit Image(u64 offset, std::size_t index, Tegra::Shader::ImageType type)
|
||||||
: offset{offset}, index{index}, type{type}, is_bindless{false} {}
|
: offset{offset}, index{index}, type{type}, is_bindless{false} {}
|
||||||
|
|
||||||
explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
|
constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
|
||||||
Tegra::Shader::ImageType type)
|
Tegra::Shader::ImageType type)
|
||||||
: offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
|
: offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
|
||||||
is_bindless{true} {}
|
is_bindless{true} {}
|
||||||
|
|
||||||
explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
|
constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
|
||||||
bool is_bindless)
|
bool is_bindless, bool is_written, bool is_read)
|
||||||
: offset{offset}, index{index}, type{type}, is_bindless{is_bindless} {}
|
: offset{offset}, index{index}, type{type}, is_bindless{is_bindless},
|
||||||
|
is_written{is_written}, is_read{is_read} {}
|
||||||
|
|
||||||
std::size_t GetOffset() const {
|
void MarkRead() {
|
||||||
|
is_read = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkWrite() {
|
||||||
|
is_written = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::size_t GetOffset() const {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t GetIndex() const {
|
constexpr std::size_t GetIndex() const {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tegra::Shader::ImageType GetType() const {
|
constexpr Tegra::Shader::ImageType GetType() const {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsBindless() const {
|
constexpr bool IsBindless() const {
|
||||||
return is_bindless;
|
return is_bindless;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<u32, u32> GetBindlessCBuf() const {
|
constexpr bool IsRead() const {
|
||||||
|
return is_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsWritten() const {
|
||||||
|
return is_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::pair<u32, u32> GetBindlessCBuf() const {
|
||||||
return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
|
return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
private:
|
||||||
std::size_t offset{};
|
u64 offset{};
|
||||||
std::size_t index{};
|
std::size_t index{};
|
||||||
Tegra::Shader::ImageType type{};
|
Tegra::Shader::ImageType type{};
|
||||||
bool is_bindless{};
|
bool is_bindless{};
|
||||||
|
bool is_read{};
|
||||||
|
bool is_written{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GlobalMemoryBase {
|
struct GlobalMemoryBase {
|
||||||
|
|
|
@ -95,7 +95,7 @@ public:
|
||||||
return used_samplers;
|
return used_samplers;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::set<Image>& GetImages() const {
|
const std::map<u64, Image>& GetImages() const {
|
||||||
return used_images;
|
return used_images;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,10 +272,10 @@ private:
|
||||||
bool is_shadow);
|
bool is_shadow);
|
||||||
|
|
||||||
/// Accesses an image.
|
/// Accesses an image.
|
||||||
const Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
|
Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
|
||||||
|
|
||||||
/// Access a bindless image sampler.
|
/// Access a bindless image sampler.
|
||||||
const Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type);
|
Image& GetBindlessImage(Tegra::Shader::Register reg, 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);
|
||||||
|
@ -356,7 +356,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::map<u64, 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_layer{};
|
bool uses_layer{};
|
||||||
|
|
Reference in New Issue