summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp18
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h22
-rw-r--r--src/video_core/shader/decode/image.cpp40
-rw-r--r--src/video_core/shader/node.h48
-rw-r--r--src/video_core/shader/shader_ir.h8
7 files changed, 92 insertions, 62 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 70eece9af..4e266cdad 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -1098,6 +1098,9 @@ void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& t
if (!tic.IsBuffer()) {
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();
}
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index a5cc1a86f..6edb2ca38 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -389,11 +389,10 @@ public:
for (const auto& sampler : ir.GetSamplers()) {
entries.samplers.emplace_back(sampler);
}
- for (const auto& image : ir.GetImages()) {
+ for (const auto& [offset, image] : ir.GetImages()) {
entries.images.emplace_back(image);
}
- for (const auto& gmem_pair : ir.GetGlobalMemory()) {
- const auto& [base, usage] = gmem_pair;
+ for (const auto& [base, usage] : ir.GetGlobalMemory()) {
entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset,
usage.is_read, usage.is_written);
}
@@ -706,7 +705,7 @@ private:
void DeclareImages() {
const auto& images{ir.GetImages()};
- for (const auto& image : images) {
+ for (const auto& [offset, image] : images) {
const std::string image_type = [&]() {
switch (image.GetType()) {
case Tegra::Shader::ImageType::Texture1D:
@@ -726,9 +725,16 @@ private:
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()) {
code.AddNewLine();
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 969fe9ced..5450feedf 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -341,13 +341,16 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
u64 index{};
u32 type{};
u8 is_bindless{};
+ u8 is_read{};
+ u8 is_written{};
if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) ||
- !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless)) {
+ !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) ||
+ !LoadObjectFromPrecompiled(is_read) || !LoadObjectFromPrecompiled(is_written)) {
return {};
}
- entry.entries.images.emplace_back(
- static_cast<std::size_t>(offset), static_cast<std::size_t>(index),
- static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0);
+ entry.entries.images.emplace_back(static_cast<u64>(offset), static_cast<std::size_t>(index),
+ static_cast<Tegra::Shader::ImageType>(type),
+ is_bindless != 0, is_written != 0, is_read != 0);
}
u32 global_memory_count{};
@@ -429,7 +432,9 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) ||
!SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) ||
!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;
}
}
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 21324488a..8e13ab38b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -78,6 +78,17 @@ public:
/// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER
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 {
if (is_proxy) {
return surface.GetTexture();
@@ -89,13 +100,6 @@ public:
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:
u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source,
Tegra::Texture::SwizzleSource y_source,
@@ -111,8 +115,8 @@ private:
GLenum target{};
OGLTextureView texture_view;
- u32 swizzle;
- bool is_proxy;
+ u32 swizzle{};
+ bool is_proxy{};
};
class TextureCacheOpenGL final : public TextureCacheBase {
diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp
index 77151a24b..008109a99 100644
--- a/src/video_core/shader/decode/image.cpp
+++ b/src/video_core/shader/decode/image.cpp
@@ -61,56 +61,54 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
}
const auto type{instr.sust.image_type};
- const auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
- : GetBindlessImage(instr.gpr39, type)};
+ auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
+ : GetBindlessImage(instr.gpr39, type)};
+ image.MarkWrite();
+
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());
+ UNIMPLEMENTED_MSG("Unhandled image 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())};
+Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
+ const auto offset{static_cast<u64>(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;
+ const auto it = used_images.find(offset);
+ if (it != used_images.end()) {
+ ASSERT(it->second.GetType() == type);
+ return it->second;
}
// 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;
+ return used_images.emplace(offset, Image{offset, next_index, type}).first->second;
}
-const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg,
- Tegra::Shader::ImageType type) {
+Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) {
const Node image_register{GetRegister(reg)};
const auto [base_image, cbuf_index, cbuf_offset]{
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)};
// 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() == cbuf_key; })};
- if (itr != used_images.end()) {
- ASSERT(itr->GetType() == type);
- return *itr;
+ const auto it = used_images.find(cbuf_key);
+ if (it != used_images.end()) {
+ ASSERT(it->second.GetType() == type);
+ return it->second;
}
// Otherwise create a new mapping for this image.
const std::size_t next_index{used_images.size()};
- const Image entry{cbuf_index, cbuf_offset, next_index, type};
- return *used_images.emplace(entry).first;
+ return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type})
+ .first->second;
}
} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 0397f4c6e..b29aedce8 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -273,50 +273,64 @@ private:
bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
};
-class Image {
+class Image final {
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} {}
- explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
- Tegra::Shader::ImageType type)
+ constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
+ Tegra::Shader::ImageType type)
: offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
is_bindless{true} {}
- explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
- bool is_bindless)
- : offset{offset}, index{index}, type{type}, is_bindless{is_bindless} {}
+ constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
+ bool is_bindless, bool is_written, bool is_read)
+ : 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;
}
- std::size_t GetIndex() const {
+ constexpr std::size_t GetIndex() const {
return index;
}
- Tegra::Shader::ImageType GetType() const {
+ constexpr Tegra::Shader::ImageType GetType() const {
return type;
}
- bool IsBindless() const {
+ constexpr bool IsBindless() const {
return is_bindless;
}
- std::pair<u32, u32> GetBindlessCBuf() const {
- return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
+ constexpr bool IsRead() const {
+ return is_read;
+ }
+
+ constexpr bool IsWritten() const {
+ return is_written;
}
- 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);
+ constexpr std::pair<u32, u32> GetBindlessCBuf() const {
+ return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
}
private:
- std::size_t offset{};
+ u64 offset{};
std::size_t index{};
Tegra::Shader::ImageType type{};
bool is_bindless{};
+ bool is_read{};
+ bool is_written{};
};
struct GlobalMemoryBase {
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index bcc9b79b6..0f891eace 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -95,7 +95,7 @@ public:
return used_samplers;
}
- const std::set<Image>& GetImages() const {
+ const std::map<u64, Image>& GetImages() const {
return used_images;
}
@@ -272,10 +272,10 @@ private:
bool is_shadow);
/// 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.
- 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
Node BitfieldExtract(Node value, u32 offset, u32 bits);
@@ -356,7 +356,7 @@ private:
std::set<Tegra::Shader::Attribute::Index> used_output_attributes;
std::map<u32, ConstBuffer> used_cbufs;
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::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;
bool uses_layer{};