summaryrefslogtreecommitdiff
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
1098 if (!tic.IsBuffer()) { 1098 if (!tic.IsBuffer()) {
1099 view->ApplySwizzle(tic.x_source, tic.y_source, tic.z_source, tic.w_source); 1099 view->ApplySwizzle(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
1100 } 1100 }
1101 if (entry.IsWritten()) {
1102 view->MarkAsModified(texture_cache.Tick());
1103 }
1101 state.images[binding] = view->GetTexture(); 1104 state.images[binding] = view->GetTexture();
1102} 1105}
1103 1106
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:
389 for (const auto& sampler : ir.GetSamplers()) { 389 for (const auto& sampler : ir.GetSamplers()) {
390 entries.samplers.emplace_back(sampler); 390 entries.samplers.emplace_back(sampler);
391 } 391 }
392 for (const auto& image : ir.GetImages()) { 392 for (const auto& [offset, image] : ir.GetImages()) {
393 entries.images.emplace_back(image); 393 entries.images.emplace_back(image);
394 } 394 }
395 for (const auto& gmem_pair : ir.GetGlobalMemory()) { 395 for (const auto& [base, usage] : ir.GetGlobalMemory()) {
396 const auto& [base, usage] = gmem_pair;
397 entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset, 396 entries.global_memory_entries.emplace_back(base.cbuf_index, base.cbuf_offset,
398 usage.is_read, usage.is_written); 397 usage.is_read, usage.is_written);
399 } 398 }
@@ -706,7 +705,7 @@ private:
706 705
707 void DeclareImages() { 706 void DeclareImages() {
708 const auto& images{ir.GetImages()}; 707 const auto& images{ir.GetImages()};
709 for (const auto& image : images) { 708 for (const auto& [offset, image] : images) {
710 const std::string image_type = [&]() { 709 const std::string image_type = [&]() {
711 switch (image.GetType()) { 710 switch (image.GetType()) {
712 case Tegra::Shader::ImageType::Texture1D: 711 case Tegra::Shader::ImageType::Texture1D:
@@ -726,9 +725,16 @@ private:
726 return "image1D"; 725 return "image1D";
727 } 726 }
728 }(); 727 }();
729 code.AddLine("layout (binding = IMAGE_BINDING_{}) coherent volatile writeonly uniform " 728 std::string qualifier = "coherent volatile";
729 if (image.IsRead() && !image.IsWritten()) {
730 qualifier += " readonly";
731 } else if (image.IsWritten() && !image.IsRead()) {
732 qualifier += " writeonly";
733 }
734
735 code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform "
730 "{} {};", 736 "{} {};",
731 image.GetIndex(), image_type, GetImage(image)); 737 image.GetIndex(), qualifier, image_type, GetImage(image));
732 } 738 }
733 if (!images.empty()) { 739 if (!images.empty()) {
734 code.AddNewLine(); 740 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
341 u64 index{}; 341 u64 index{};
342 u32 type{}; 342 u32 type{};
343 u8 is_bindless{}; 343 u8 is_bindless{};
344 u8 is_read{};
345 u8 is_written{};
344 if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || 346 if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) ||
345 !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless)) { 347 !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) ||
348 !LoadObjectFromPrecompiled(is_read) || !LoadObjectFromPrecompiled(is_written)) {
346 return {}; 349 return {};
347 } 350 }
348 entry.entries.images.emplace_back( 351 entry.entries.images.emplace_back(static_cast<u64>(offset), static_cast<std::size_t>(index),
349 static_cast<std::size_t>(offset), static_cast<std::size_t>(index), 352 static_cast<Tegra::Shader::ImageType>(type),
350 static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0); 353 is_bindless != 0, is_written != 0, is_read != 0);
351 } 354 }
352 355
353 u32 global_memory_count{}; 356 u32 global_memory_count{};
@@ -429,7 +432,9 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
429 if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) || 432 if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) ||
430 !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) || 433 !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) ||
431 !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) || 434 !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) ||
432 !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0))) { 435 !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) ||
436 !SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) ||
437 !SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0))) {
433 return false; 438 return false;
434 } 439 }
435 } 440 }
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:
78 /// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER 78 /// Attaches this texture view to the current bound GL_DRAW_FRAMEBUFFER
79 void Attach(GLenum attachment, GLenum target) const; 79 void Attach(GLenum attachment, GLenum target) const;
80 80
81 void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
82 Tegra::Texture::SwizzleSource y_source,
83 Tegra::Texture::SwizzleSource z_source,
84 Tegra::Texture::SwizzleSource w_source);
85
86 void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
87
88 void MarkAsModified(u64 tick) {
89 surface.MarkAsModified(true, tick);
90 }
91
81 GLuint GetTexture() const { 92 GLuint GetTexture() const {
82 if (is_proxy) { 93 if (is_proxy) {
83 return surface.GetTexture(); 94 return surface.GetTexture();
@@ -89,13 +100,6 @@ public:
89 return surface.GetSurfaceParams(); 100 return surface.GetSurfaceParams();
90 } 101 }
91 102
92 void ApplySwizzle(Tegra::Texture::SwizzleSource x_source,
93 Tegra::Texture::SwizzleSource y_source,
94 Tegra::Texture::SwizzleSource z_source,
95 Tegra::Texture::SwizzleSource w_source);
96
97 void DecorateViewName(GPUVAddr gpu_addr, std::string prefix);
98
99private: 103private:
100 u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source, 104 u32 EncodeSwizzle(Tegra::Texture::SwizzleSource x_source,
101 Tegra::Texture::SwizzleSource y_source, 105 Tegra::Texture::SwizzleSource y_source,
@@ -111,8 +115,8 @@ private:
111 GLenum target{}; 115 GLenum target{};
112 116
113 OGLTextureView texture_view; 117 OGLTextureView texture_view;
114 u32 swizzle; 118 u32 swizzle{};
115 bool is_proxy; 119 bool is_proxy{};
116}; 120};
117 121
118class TextureCacheOpenGL final : public TextureCacheBase { 122class 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) {
61 } 61 }
62 62
63 const auto type{instr.sust.image_type}; 63 const auto type{instr.sust.image_type};
64 const auto& image{instr.sust.is_immediate ? GetImage(instr.image, type) 64 auto& image{instr.sust.is_immediate ? GetImage(instr.image, type)
65 : GetBindlessImage(instr.gpr39, type)}; 65 : GetBindlessImage(instr.gpr39, type)};
66 image.MarkWrite();
67
66 MetaImage meta{image, values}; 68 MetaImage meta{image, values};
67 const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))}; 69 const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))};
68 bb.push_back(store); 70 bb.push_back(store);
69 break; 71 break;
70 } 72 }
71 default: 73 default:
72 UNIMPLEMENTED_MSG("Unhandled conversion instruction: {}", opcode->get().GetName()); 74 UNIMPLEMENTED_MSG("Unhandled image instruction: {}", opcode->get().GetName());
73 } 75 }
74 76
75 return pc; 77 return pc;
76} 78}
77 79
78const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) { 80Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) {
79 const auto offset{static_cast<std::size_t>(image.index.Value())}; 81 const auto offset{static_cast<u64>(image.index.Value())};
80 82
81 // If this image has already been used, return the existing mapping. 83 // If this image has already been used, return the existing mapping.
82 const auto itr{std::find_if(used_images.begin(), used_images.end(), 84 const auto it = used_images.find(offset);
83 [=](const Image& entry) { return entry.GetOffset() == offset; })}; 85 if (it != used_images.end()) {
84 if (itr != used_images.end()) { 86 ASSERT(it->second.GetType() == type);
85 ASSERT(itr->GetType() == type); 87 return it->second;
86 return *itr;
87 } 88 }
88 89
89 // Otherwise create a new mapping for this image. 90 // Otherwise create a new mapping for this image.
90 const std::size_t next_index{used_images.size()}; 91 const std::size_t next_index{used_images.size()};
91 const Image entry{offset, next_index, type}; 92 return used_images.emplace(offset, Image{offset, next_index, type}).first->second;
92 return *used_images.emplace(entry).first;
93} 93}
94 94
95const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, 95Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type) {
96 Tegra::Shader::ImageType type) {
97 const Node image_register{GetRegister(reg)}; 96 const Node image_register{GetRegister(reg)};
98 const auto [base_image, cbuf_index, cbuf_offset]{ 97 const auto [base_image, cbuf_index, cbuf_offset]{
99 TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))}; 98 TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
100 const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)}; 99 const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
101 100
102 // If this image has already been used, return the existing mapping. 101 // If this image has already been used, return the existing mapping.
103 const auto itr{std::find_if(used_images.begin(), used_images.end(), 102 const auto it = used_images.find(cbuf_key);
104 [=](const Image& entry) { return entry.GetOffset() == cbuf_key; })}; 103 if (it != used_images.end()) {
105 if (itr != used_images.end()) { 104 ASSERT(it->second.GetType() == type);
106 ASSERT(itr->GetType() == type); 105 return it->second;
107 return *itr;
108 } 106 }
109 107
110 // Otherwise create a new mapping for this image. 108 // Otherwise create a new mapping for this image.
111 const std::size_t next_index{used_images.size()}; 109 const std::size_t next_index{used_images.size()};
112 const Image entry{cbuf_index, cbuf_offset, next_index, type}; 110 return used_images.emplace(cbuf_key, Image{cbuf_index, cbuf_offset, next_index, type})
113 return *used_images.emplace(entry).first; 111 .first->second;
114} 112}
115 113
116} // namespace VideoCommon::Shader 114} // 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:
273 bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not. 273 bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
274}; 274};
275 275
276class Image { 276class Image final {
277public: 277public:
278 explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type) 278 constexpr explicit Image(u64 offset, std::size_t index, Tegra::Shader::ImageType type)
279 : offset{offset}, index{index}, type{type}, is_bindless{false} {} 279 : offset{offset}, index{index}, type{type}, is_bindless{false} {}
280 280
281 explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, 281 constexpr explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index,
282 Tegra::Shader::ImageType type) 282 Tegra::Shader::ImageType type)
283 : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, 283 : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type},
284 is_bindless{true} {} 284 is_bindless{true} {}
285 285
286 explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, 286 constexpr explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type,
287 bool is_bindless) 287 bool is_bindless, bool is_written, bool is_read)
288 : offset{offset}, index{index}, type{type}, is_bindless{is_bindless} {} 288 : offset{offset}, index{index}, type{type}, is_bindless{is_bindless},
289 is_written{is_written}, is_read{is_read} {}
289 290
290 std::size_t GetOffset() const { 291 void MarkRead() {
292 is_read = true;
293 }
294
295 void MarkWrite() {
296 is_written = true;
297 }
298
299 constexpr std::size_t GetOffset() const {
291 return offset; 300 return offset;
292 } 301 }
293 302
294 std::size_t GetIndex() const { 303 constexpr std::size_t GetIndex() const {
295 return index; 304 return index;
296 } 305 }
297 306
298 Tegra::Shader::ImageType GetType() const { 307 constexpr Tegra::Shader::ImageType GetType() const {
299 return type; 308 return type;
300 } 309 }
301 310
302 bool IsBindless() const { 311 constexpr bool IsBindless() const {
303 return is_bindless; 312 return is_bindless;
304 } 313 }
305 314
306 std::pair<u32, u32> GetBindlessCBuf() const { 315 constexpr bool IsRead() const {
307 return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; 316 return is_read;
317 }
318
319 constexpr bool IsWritten() const {
320 return is_written;
308 } 321 }
309 322
310 bool operator<(const Image& rhs) const { 323 constexpr std::pair<u32, u32> GetBindlessCBuf() const {
311 return std::tie(offset, index, type, is_bindless) < 324 return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
312 std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless);
313 } 325 }
314 326
315private: 327private:
316 std::size_t offset{}; 328 u64 offset{};
317 std::size_t index{}; 329 std::size_t index{};
318 Tegra::Shader::ImageType type{}; 330 Tegra::Shader::ImageType type{};
319 bool is_bindless{}; 331 bool is_bindless{};
332 bool is_read{};
333 bool is_written{};
320}; 334};
321 335
322struct GlobalMemoryBase { 336struct 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:
95 return used_samplers; 95 return used_samplers;
96 } 96 }
97 97
98 const std::set<Image>& GetImages() const { 98 const std::map<u64, Image>& GetImages() const {
99 return used_images; 99 return used_images;
100 } 100 }
101 101
@@ -272,10 +272,10 @@ private:
272 bool is_shadow); 272 bool is_shadow);
273 273
274 /// Accesses an image. 274 /// Accesses an image.
275 const Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); 275 Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type);
276 276
277 /// Access a bindless image sampler. 277 /// Access a bindless image sampler.
278 const Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type); 278 Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type);
279 279
280 /// Extracts a sequence of bits from a node 280 /// Extracts a sequence of bits from a node
281 Node BitfieldExtract(Node value, u32 offset, u32 bits); 281 Node BitfieldExtract(Node value, u32 offset, u32 bits);
@@ -356,7 +356,7 @@ private:
356 std::set<Tegra::Shader::Attribute::Index> used_output_attributes; 356 std::set<Tegra::Shader::Attribute::Index> used_output_attributes;
357 std::map<u32, ConstBuffer> used_cbufs; 357 std::map<u32, ConstBuffer> used_cbufs;
358 std::set<Sampler> used_samplers; 358 std::set<Sampler> used_samplers;
359 std::set<Image> used_images; 359 std::map<u64, Image> used_images;
360 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; 360 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{};
361 std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; 361 std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory;
362 bool uses_layer{}; 362 bool uses_layer{};