yuzu-emu
/
yuzu-mainline
Archived
1
0
Fork 0

gl_shader_decompiler: Keep track of written images and mark them as modified

This commit is contained in:
ReinUsesLisp 2019-09-05 23:26:05 -03:00
parent 7228e22098
commit 1f43e5296f
7 changed files with 93 additions and 63 deletions

View File

@ -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();
} }

View File

@ -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();

View File

@ -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;
} }
} }

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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{};