summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/engines/kepler_compute.cpp53
-rw-r--r--src/video_core/engines/kepler_compute.h23
-rw-r--r--src/video_core/engines/maxwell_3d.h1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp132
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h19
-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_state.cpp86
-rw-r--r--src/video_core/renderer_opengl/gl_state.h19
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h22
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp4
-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
-rw-r--r--src/video_core/texture_cache/surface_base.h12
-rw-r--r--src/video_core/texture_cache/surface_params.cpp134
-rw-r--r--src/video_core/texture_cache/surface_params.h9
-rw-r--r--src/video_core/texture_cache/surface_view.cpp2
-rw-r--r--src/video_core/texture_cache/surface_view.h20
-rw-r--r--src/video_core/texture_cache/texture_cache.h21
20 files changed, 457 insertions, 229 deletions
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp
index 08586d33c..63d449135 100644
--- a/src/video_core/engines/kepler_compute.cpp
+++ b/src/video_core/engines/kepler_compute.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <bitset>
5#include "common/assert.h" 6#include "common/assert.h"
6#include "common/logging/log.h" 7#include "common/logging/log.h"
7#include "core/core.h" 8#include "core/core.h"
@@ -49,6 +50,33 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) {
49 } 50 }
50} 51}
51 52
53Tegra::Texture::FullTextureInfo KeplerCompute::GetTexture(std::size_t offset) const {
54 const std::bitset<8> cbuf_mask = launch_description.const_buffer_enable_mask.Value();
55 ASSERT(cbuf_mask[regs.tex_cb_index]);
56
57 const auto& texinfo = launch_description.const_buffer_config[regs.tex_cb_index];
58 ASSERT(texinfo.Address() != 0);
59
60 const GPUVAddr address = texinfo.Address() + offset * sizeof(Texture::TextureHandle);
61 ASSERT(address < texinfo.Address() + texinfo.size);
62
63 const Texture::TextureHandle tex_handle{memory_manager.Read<u32>(address)};
64 return GetTextureInfo(tex_handle, offset);
65}
66
67Texture::FullTextureInfo KeplerCompute::GetTextureInfo(const Texture::TextureHandle tex_handle,
68 std::size_t offset) const {
69 return Texture::FullTextureInfo{static_cast<u32>(offset), GetTICEntry(tex_handle.tic_id),
70 GetTSCEntry(tex_handle.tsc_id)};
71}
72
73u32 KeplerCompute::AccessConstBuffer32(u64 const_buffer, u64 offset) const {
74 const auto& buffer = launch_description.const_buffer_config[const_buffer];
75 u32 result;
76 std::memcpy(&result, memory_manager.GetPointer(buffer.Address() + offset), sizeof(u32));
77 return result;
78}
79
52void KeplerCompute::ProcessLaunch() { 80void KeplerCompute::ProcessLaunch() {
53 const GPUVAddr launch_desc_loc = regs.launch_desc_loc.Address(); 81 const GPUVAddr launch_desc_loc = regs.launch_desc_loc.Address();
54 memory_manager.ReadBlockUnsafe(launch_desc_loc, &launch_description, 82 memory_manager.ReadBlockUnsafe(launch_desc_loc, &launch_description,
@@ -60,4 +88,29 @@ void KeplerCompute::ProcessLaunch() {
60 rasterizer.DispatchCompute(code_addr); 88 rasterizer.DispatchCompute(code_addr);
61} 89}
62 90
91Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const {
92 const GPUVAddr tic_address_gpu{regs.tic.Address() + tic_index * sizeof(Texture::TICEntry)};
93
94 Texture::TICEntry tic_entry;
95 memory_manager.ReadBlockUnsafe(tic_address_gpu, &tic_entry, sizeof(Texture::TICEntry));
96
97 const auto r_type{tic_entry.r_type.Value()};
98 const auto g_type{tic_entry.g_type.Value()};
99 const auto b_type{tic_entry.b_type.Value()};
100 const auto a_type{tic_entry.a_type.Value()};
101
102 // TODO(Subv): Different data types for separate components are not supported
103 DEBUG_ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
104
105 return tic_entry;
106}
107
108Texture::TSCEntry KeplerCompute::GetTSCEntry(u32 tsc_index) const {
109 const GPUVAddr tsc_address_gpu{regs.tsc.Address() + tsc_index * sizeof(Texture::TSCEntry)};
110
111 Texture::TSCEntry tsc_entry;
112 memory_manager.ReadBlockUnsafe(tsc_address_gpu, &tsc_entry, sizeof(Texture::TSCEntry));
113 return tsc_entry;
114}
115
63} // namespace Tegra::Engines 116} // namespace Tegra::Engines
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h
index 6a3309a2c..90cf650d2 100644
--- a/src/video_core/engines/kepler_compute.h
+++ b/src/video_core/engines/kepler_compute.h
@@ -12,6 +12,7 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/engines/engine_upload.h" 13#include "video_core/engines/engine_upload.h"
14#include "video_core/gpu.h" 14#include "video_core/gpu.h"
15#include "video_core/textures/texture.h"
15 16
16namespace Core { 17namespace Core {
17class System; 18class System;
@@ -111,7 +112,7 @@ public:
111 112
112 INSERT_PADDING_WORDS(0x3FE); 113 INSERT_PADDING_WORDS(0x3FE);
113 114
114 u32 texture_const_buffer_index; 115 u32 tex_cb_index;
115 116
116 INSERT_PADDING_WORDS(0x374); 117 INSERT_PADDING_WORDS(0x374);
117 }; 118 };
@@ -149,7 +150,7 @@ public:
149 union { 150 union {
150 BitField<0, 8, u32> const_buffer_enable_mask; 151 BitField<0, 8, u32> const_buffer_enable_mask;
151 BitField<29, 2, u32> cache_layout; 152 BitField<29, 2, u32> cache_layout;
152 } memory_config; 153 };
153 154
154 INSERT_PADDING_WORDS(0x8); 155 INSERT_PADDING_WORDS(0x8);
155 156
@@ -194,6 +195,14 @@ public:
194 /// Write the value to the register identified by method. 195 /// Write the value to the register identified by method.
195 void CallMethod(const GPU::MethodCall& method_call); 196 void CallMethod(const GPU::MethodCall& method_call);
196 197
198 Tegra::Texture::FullTextureInfo GetTexture(std::size_t offset) const;
199
200 /// Given a Texture Handle, returns the TSC and TIC entries.
201 Texture::FullTextureInfo GetTextureInfo(const Texture::TextureHandle tex_handle,
202 std::size_t offset) const;
203
204 u32 AccessConstBuffer32(u64 const_buffer, u64 offset) const;
205
197private: 206private:
198 Core::System& system; 207 Core::System& system;
199 VideoCore::RasterizerInterface& rasterizer; 208 VideoCore::RasterizerInterface& rasterizer;
@@ -201,6 +210,12 @@ private:
201 Upload::State upload_state; 210 Upload::State upload_state;
202 211
203 void ProcessLaunch(); 212 void ProcessLaunch();
213
214 /// Retrieves information about a specific TIC entry from the TIC buffer.
215 Texture::TICEntry GetTICEntry(u32 tic_index) const;
216
217 /// Retrieves information about a specific TSC entry from the TSC buffer.
218 Texture::TSCEntry GetTSCEntry(u32 tsc_index) const;
204}; 219};
205 220
206#define ASSERT_REG_POSITION(field_name, position) \ 221#define ASSERT_REG_POSITION(field_name, position) \
@@ -218,12 +233,12 @@ ASSERT_REG_POSITION(launch, 0xAF);
218ASSERT_REG_POSITION(tsc, 0x557); 233ASSERT_REG_POSITION(tsc, 0x557);
219ASSERT_REG_POSITION(tic, 0x55D); 234ASSERT_REG_POSITION(tic, 0x55D);
220ASSERT_REG_POSITION(code_loc, 0x582); 235ASSERT_REG_POSITION(code_loc, 0x582);
221ASSERT_REG_POSITION(texture_const_buffer_index, 0x982); 236ASSERT_REG_POSITION(tex_cb_index, 0x982);
222ASSERT_LAUNCH_PARAM_POSITION(program_start, 0x8); 237ASSERT_LAUNCH_PARAM_POSITION(program_start, 0x8);
223ASSERT_LAUNCH_PARAM_POSITION(grid_dim_x, 0xC); 238ASSERT_LAUNCH_PARAM_POSITION(grid_dim_x, 0xC);
224ASSERT_LAUNCH_PARAM_POSITION(shared_alloc, 0x11); 239ASSERT_LAUNCH_PARAM_POSITION(shared_alloc, 0x11);
225ASSERT_LAUNCH_PARAM_POSITION(block_dim_x, 0x12); 240ASSERT_LAUNCH_PARAM_POSITION(block_dim_x, 0x12);
226ASSERT_LAUNCH_PARAM_POSITION(memory_config, 0x14); 241ASSERT_LAUNCH_PARAM_POSITION(const_buffer_enable_mask, 0x14);
227ASSERT_LAUNCH_PARAM_POSITION(const_buffer_config, 0x1D); 242ASSERT_LAUNCH_PARAM_POSITION(const_buffer_config, 0x1D);
228 243
229#undef ASSERT_REG_POSITION 244#undef ASSERT_REG_POSITION
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 0184342a0..3b3c82f41 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -62,6 +62,7 @@ public:
62 static constexpr std::size_t NumVertexAttributes = 32; 62 static constexpr std::size_t NumVertexAttributes = 32;
63 static constexpr std::size_t NumVaryings = 31; 63 static constexpr std::size_t NumVaryings = 31;
64 static constexpr std::size_t NumTextureSamplers = 32; 64 static constexpr std::size_t NumTextureSamplers = 32;
65 static constexpr std::size_t NumImages = 8; // TODO(Rodrigo): Investigate this number
65 static constexpr std::size_t NumClipDistances = 8; 66 static constexpr std::size_t NumClipDistances = 8;
66 static constexpr std::size_t MaxShaderProgram = 6; 67 static constexpr std::size_t MaxShaderProgram = 6;
67 static constexpr std::size_t MaxShaderStage = 5; 68 static constexpr std::size_t MaxShaderStage = 5;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 01d89f47d..4e266cdad 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -331,7 +331,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
331 const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage); 331 const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage);
332 SetupDrawConstBuffers(stage_enum, shader); 332 SetupDrawConstBuffers(stage_enum, shader);
333 SetupDrawGlobalMemory(stage_enum, shader); 333 SetupDrawGlobalMemory(stage_enum, shader);
334 const auto texture_buffer_usage{SetupTextures(stage_enum, shader, base_bindings)}; 334 const auto texture_buffer_usage{SetupDrawTextures(stage_enum, shader, base_bindings)};
335 335
336 const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage}; 336 const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage};
337 const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant); 337 const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant);
@@ -801,7 +801,11 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
801 } 801 }
802 802
803 auto kernel = shader_cache.GetComputeKernel(code_addr); 803 auto kernel = shader_cache.GetComputeKernel(code_addr);
804 const auto [program, next_bindings] = kernel->GetProgramHandle({}); 804 ProgramVariant variant;
805 variant.texture_buffer_usage = SetupComputeTextures(kernel);
806 SetupComputeImages(kernel);
807
808 const auto [program, next_bindings] = kernel->GetProgramHandle(variant);
805 state.draw.shader_program = program; 809 state.draw.shader_program = program;
806 state.draw.program_pipeline = 0; 810 state.draw.program_pipeline = 0;
807 811
@@ -816,13 +820,13 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) {
816 SetupComputeConstBuffers(kernel); 820 SetupComputeConstBuffers(kernel);
817 SetupComputeGlobalMemory(kernel); 821 SetupComputeGlobalMemory(kernel);
818 822
819 // TODO(Rodrigo): Bind images and samplers
820
821 buffer_cache.Unmap(); 823 buffer_cache.Unmap();
822 824
823 bind_ubo_pushbuffer.Bind(); 825 bind_ubo_pushbuffer.Bind();
824 bind_ssbo_pushbuffer.Bind(); 826 bind_ssbo_pushbuffer.Bind();
825 827
828 state.ApplyTextures();
829 state.ApplyImages();
826 state.ApplyShaderProgram(); 830 state.ApplyShaderProgram();
827 state.ApplyProgramPipeline(); 831 state.ApplyProgramPipeline();
828 832
@@ -922,7 +926,7 @@ void RasterizerOpenGL::SetupComputeConstBuffers(const Shader& kernel) {
922 const auto& launch_desc = system.GPU().KeplerCompute().launch_description; 926 const auto& launch_desc = system.GPU().KeplerCompute().launch_description;
923 for (const auto& entry : kernel->GetShaderEntries().const_buffers) { 927 for (const auto& entry : kernel->GetShaderEntries().const_buffers) {
924 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()]; 928 const auto& config = launch_desc.const_buffer_config[entry.GetIndex()];
925 const std::bitset<8> mask = launch_desc.memory_config.const_buffer_enable_mask.Value(); 929 const std::bitset<8> mask = launch_desc.const_buffer_enable_mask.Value();
926 Tegra::Engines::ConstBufferInfo buffer; 930 Tegra::Engines::ConstBufferInfo buffer;
927 buffer.address = config.Address(); 931 buffer.address = config.Address();
928 buffer.size = config.size; 932 buffer.size = config.size;
@@ -981,53 +985,125 @@ void RasterizerOpenGL::SetupGlobalMemory(const GLShader::GlobalMemoryEntry& entr
981 bind_ssbo_pushbuffer.Push(ssbo, buffer_offset, static_cast<GLsizeiptr>(size)); 985 bind_ssbo_pushbuffer.Push(ssbo, buffer_offset, static_cast<GLsizeiptr>(size));
982} 986}
983 987
984TextureBufferUsage RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader, 988TextureBufferUsage RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage,
985 BaseBindings base_bindings) { 989 const Shader& shader,
990 BaseBindings base_bindings) {
986 MICROPROFILE_SCOPE(OpenGL_Texture); 991 MICROPROFILE_SCOPE(OpenGL_Texture);
987 const auto& gpu = system.GPU(); 992 const auto& gpu = system.GPU();
988 const auto& maxwell3d = gpu.Maxwell3D(); 993 const auto& maxwell3d = gpu.Maxwell3D();
989 const auto& entries = shader->GetShaderEntries().samplers; 994 const auto& entries = shader->GetShaderEntries().samplers;
990 995
991 ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units), 996 ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.textures),
992 "Exceeded the number of active textures."); 997 "Exceeded the number of active textures.");
993 998
994 TextureBufferUsage texture_buffer_usage{0}; 999 TextureBufferUsage texture_buffer_usage{0};
995 1000
996 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) { 1001 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
997 const auto& entry = entries[bindpoint]; 1002 const auto& entry = entries[bindpoint];
998 Tegra::Texture::FullTextureInfo texture; 1003 const auto texture = [&]() {
999 if (entry.IsBindless()) { 1004 if (!entry.IsBindless()) {
1005 return maxwell3d.GetStageTexture(stage, entry.GetOffset());
1006 }
1000 const auto cbuf = entry.GetBindlessCBuf(); 1007 const auto cbuf = entry.GetBindlessCBuf();
1001 Tegra::Texture::TextureHandle tex_handle; 1008 Tegra::Texture::TextureHandle tex_handle;
1002 tex_handle.raw = maxwell3d.AccessConstBuffer32(stage, cbuf.first, cbuf.second); 1009 tex_handle.raw = maxwell3d.AccessConstBuffer32(stage, cbuf.first, cbuf.second);
1003 texture = maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset()); 1010 return maxwell3d.GetTextureInfo(tex_handle, entry.GetOffset());
1004 } else { 1011 }();
1005 texture = maxwell3d.GetStageTexture(stage, entry.GetOffset()); 1012
1013 if (SetupTexture(base_bindings.sampler + bindpoint, texture, entry)) {
1014 texture_buffer_usage.set(bindpoint);
1006 } 1015 }
1007 const u32 current_bindpoint = base_bindings.sampler + bindpoint; 1016 }
1008 1017
1009 auto& unit{state.texture_units[current_bindpoint]}; 1018 return texture_buffer_usage;
1010 unit.sampler = sampler_cache.GetSampler(texture.tsc); 1019}
1011 1020
1012 if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) { 1021TextureBufferUsage RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) {
1013 if (view->GetSurfaceParams().IsBuffer()) { 1022 MICROPROFILE_SCOPE(OpenGL_Texture);
1014 // Record that this texture is a texture buffer. 1023 const auto& compute = system.GPU().KeplerCompute();
1015 texture_buffer_usage.set(bindpoint); 1024 const auto& entries = kernel->GetShaderEntries().samplers;
1016 } else { 1025
1017 // Apply swizzle to textures that are not buffers. 1026 ASSERT_MSG(entries.size() <= std::size(state.textures),
1018 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source, 1027 "Exceeded the number of active textures.");
1019 texture.tic.w_source); 1028
1029 TextureBufferUsage texture_buffer_usage{0};
1030
1031 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
1032 const auto& entry = entries[bindpoint];
1033 const auto texture = [&]() {
1034 if (!entry.IsBindless()) {
1035 return compute.GetTexture(entry.GetOffset());
1020 } 1036 }
1021 state.texture_units[current_bindpoint].texture = view->GetTexture(); 1037 const auto cbuf = entry.GetBindlessCBuf();
1022 } else { 1038 Tegra::Texture::TextureHandle tex_handle;
1023 // Can occur when texture addr is null or its memory is unmapped/invalid 1039 tex_handle.raw = compute.AccessConstBuffer32(cbuf.first, cbuf.second);
1024 unit.texture = 0; 1040 return compute.GetTextureInfo(tex_handle, entry.GetOffset());
1041 }();
1042
1043 if (SetupTexture(bindpoint, texture, entry)) {
1044 texture_buffer_usage.set(bindpoint);
1025 } 1045 }
1026 } 1046 }
1027 1047
1028 return texture_buffer_usage; 1048 return texture_buffer_usage;
1029} 1049}
1030 1050
1051bool RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
1052 const GLShader::SamplerEntry& entry) {
1053 state.samplers[binding] = sampler_cache.GetSampler(texture.tsc);
1054
1055 const auto view = texture_cache.GetTextureSurface(texture.tic, entry);
1056 if (!view) {
1057 // Can occur when texture addr is null or its memory is unmapped/invalid
1058 state.textures[binding] = 0;
1059 return false;
1060 }
1061 state.textures[binding] = view->GetTexture();
1062
1063 if (view->GetSurfaceParams().IsBuffer()) {
1064 return true;
1065 }
1066
1067 // Apply swizzle to textures that are not buffers.
1068 view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
1069 texture.tic.w_source);
1070 return false;
1071}
1072
1073void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
1074 const auto& compute = system.GPU().KeplerCompute();
1075 const auto& entries = shader->GetShaderEntries().images;
1076 for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
1077 const auto& entry = entries[bindpoint];
1078 const auto tic = [&]() {
1079 if (!entry.IsBindless()) {
1080 return compute.GetTexture(entry.GetOffset()).tic;
1081 }
1082 const auto cbuf = entry.GetBindlessCBuf();
1083 Tegra::Texture::TextureHandle tex_handle;
1084 tex_handle.raw = compute.AccessConstBuffer32(cbuf.first, cbuf.second);
1085 return compute.GetTextureInfo(tex_handle, entry.GetOffset()).tic;
1086 }();
1087 SetupImage(bindpoint, tic, entry);
1088 }
1089}
1090
1091void RasterizerOpenGL::SetupImage(u32 binding, const Tegra::Texture::TICEntry& tic,
1092 const GLShader::ImageEntry& entry) {
1093 const auto view = texture_cache.GetImageSurface(tic, entry);
1094 if (!view) {
1095 state.images[binding] = 0;
1096 return;
1097 }
1098 if (!tic.IsBuffer()) {
1099 view->ApplySwizzle(tic.x_source, tic.y_source, tic.z_source, tic.w_source);
1100 }
1101 if (entry.IsWritten()) {
1102 view->MarkAsModified(texture_cache.Tick());
1103 }
1104 state.images[binding] = view->GetTexture();
1105}
1106
1031void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { 1107void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
1032 const auto& regs = system.GPU().Maxwell3D().regs; 1108 const auto& regs = system.GPU().Maxwell3D().regs;
1033 const bool geometry_shaders_enabled = 1109 const bool geometry_shaders_enabled =
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9d20a4fbf..eada752e0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -32,6 +32,7 @@
32#include "video_core/renderer_opengl/gl_state.h" 32#include "video_core/renderer_opengl/gl_state.h"
33#include "video_core/renderer_opengl/gl_texture_cache.h" 33#include "video_core/renderer_opengl/gl_texture_cache.h"
34#include "video_core/renderer_opengl/utils.h" 34#include "video_core/renderer_opengl/utils.h"
35#include "video_core/textures/texture.h"
35 36
36namespace Core { 37namespace Core {
37class System; 38class System;
@@ -137,8 +138,22 @@ private:
137 138
138 /// Configures the current textures to use for the draw command. Returns shaders texture buffer 139 /// Configures the current textures to use for the draw command. Returns shaders texture buffer
139 /// usage. 140 /// usage.
140 TextureBufferUsage SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, 141 TextureBufferUsage SetupDrawTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
141 const Shader& shader, BaseBindings base_bindings); 142 const Shader& shader, BaseBindings base_bindings);
143
144 /// Configures the textures used in a compute shader. Returns texture buffer usage.
145 TextureBufferUsage SetupComputeTextures(const Shader& kernel);
146
147 /// Configures a texture. Returns true when the texture is a texture buffer.
148 bool SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
149 const GLShader::SamplerEntry& entry);
150
151 /// Configures images in a compute shader.
152 void SetupComputeImages(const Shader& shader);
153
154 /// Configures an image.
155 void SetupImage(u32 binding, const Tegra::Texture::TICEntry& tic,
156 const GLShader::ImageEntry& entry);
142 157
143 /// Syncs the viewport and depth range to match the guest state 158 /// Syncs the viewport and depth range to match the guest state
144 void SyncViewport(OpenGLState& current_state); 159 void SyncViewport(OpenGLState& current_state);
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_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index f4777d0b0..6eabf4fac 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -34,6 +34,25 @@ bool UpdateTie(T1 current_value, const T2 new_value) {
34 return changed; 34 return changed;
35} 35}
36 36
37template <typename T>
38std::optional<std::pair<GLuint, GLsizei>> UpdateArray(T& current_values, const T& new_values) {
39 std::optional<std::size_t> first;
40 std::size_t last;
41 for (std::size_t i = 0; i < std::size(current_values); ++i) {
42 if (!UpdateValue(current_values[i], new_values[i])) {
43 continue;
44 }
45 if (!first) {
46 first = i;
47 }
48 last = i;
49 }
50 if (!first) {
51 return std::nullopt;
52 }
53 return std::make_pair(static_cast<GLuint>(*first), static_cast<GLsizei>(last - *first + 1));
54}
55
37void Enable(GLenum cap, bool enable) { 56void Enable(GLenum cap, bool enable) {
38 if (enable) { 57 if (enable) {
39 glEnable(cap); 58 glEnable(cap);
@@ -134,10 +153,6 @@ OpenGLState::OpenGLState() {
134 logic_op.enabled = false; 153 logic_op.enabled = false;
135 logic_op.operation = GL_COPY; 154 logic_op.operation = GL_COPY;
136 155
137 for (auto& texture_unit : texture_units) {
138 texture_unit.Reset();
139 }
140
141 draw.read_framebuffer = 0; 156 draw.read_framebuffer = 0;
142 draw.draw_framebuffer = 0; 157 draw.draw_framebuffer = 0;
143 draw.vertex_array = 0; 158 draw.vertex_array = 0;
@@ -496,52 +511,20 @@ void OpenGLState::ApplyAlphaTest() const {
496} 511}
497 512
498void OpenGLState::ApplyTextures() const { 513void OpenGLState::ApplyTextures() const {
499 bool has_delta{}; 514 if (const auto update = UpdateArray(cur_state.textures, textures)) {
500 std::size_t first{}; 515 glBindTextures(update->first, update->second, textures.data() + update->first);
501 std::size_t last{};
502 std::array<GLuint, Maxwell::NumTextureSamplers> textures;
503
504 for (std::size_t i = 0; i < std::size(texture_units); ++i) {
505 const auto& texture_unit = texture_units[i];
506 auto& cur_state_texture_unit = cur_state.texture_units[i];
507 textures[i] = texture_unit.texture;
508 if (cur_state_texture_unit.texture == textures[i]) {
509 continue;
510 }
511 cur_state_texture_unit.texture = textures[i];
512 if (!has_delta) {
513 first = i;
514 has_delta = true;
515 }
516 last = i;
517 }
518 if (has_delta) {
519 glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
520 textures.data() + first);
521 } 516 }
522} 517}
523 518
524void OpenGLState::ApplySamplers() const { 519void OpenGLState::ApplySamplers() const {
525 bool has_delta{}; 520 if (const auto update = UpdateArray(cur_state.samplers, samplers)) {
526 std::size_t first{}; 521 glBindSamplers(update->first, update->second, samplers.data() + update->first);
527 std::size_t last{};
528 std::array<GLuint, Maxwell::NumTextureSamplers> samplers;
529
530 for (std::size_t i = 0; i < std::size(samplers); ++i) {
531 samplers[i] = texture_units[i].sampler;
532 if (cur_state.texture_units[i].sampler == texture_units[i].sampler) {
533 continue;
534 }
535 cur_state.texture_units[i].sampler = texture_units[i].sampler;
536 if (!has_delta) {
537 first = i;
538 has_delta = true;
539 }
540 last = i;
541 } 522 }
542 if (has_delta) { 523}
543 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), 524
544 samplers.data() + first); 525void OpenGLState::ApplyImages() const {
526 if (const auto update = UpdateArray(cur_state.images, images)) {
527 glBindImageTextures(update->first, update->second, images.data() + update->first);
545 } 528 }
546} 529}
547 530
@@ -576,6 +559,7 @@ void OpenGLState::Apply() {
576 ApplyLogicOp(); 559 ApplyLogicOp();
577 ApplyTextures(); 560 ApplyTextures();
578 ApplySamplers(); 561 ApplySamplers();
562 ApplyImages();
579 if (dirty.polygon_offset) { 563 if (dirty.polygon_offset) {
580 ApplyPolygonOffset(); 564 ApplyPolygonOffset();
581 dirty.polygon_offset = false; 565 dirty.polygon_offset = false;
@@ -606,18 +590,18 @@ void OpenGLState::EmulateViewportWithScissor() {
606} 590}
607 591
608OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { 592OpenGLState& OpenGLState::UnbindTexture(GLuint handle) {
609 for (auto& unit : texture_units) { 593 for (auto& texture : textures) {
610 if (unit.texture == handle) { 594 if (texture == handle) {
611 unit.Unbind(); 595 texture = 0;
612 } 596 }
613 } 597 }
614 return *this; 598 return *this;
615} 599}
616 600
617OpenGLState& OpenGLState::ResetSampler(GLuint handle) { 601OpenGLState& OpenGLState::ResetSampler(GLuint handle) {
618 for (auto& unit : texture_units) { 602 for (auto& sampler : samplers) {
619 if (unit.sampler == handle) { 603 if (sampler == handle) {
620 unit.sampler = 0; 604 sampler = 0;
621 } 605 }
622 } 606 }
623 return *this; 607 return *this;
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index fdf9a8a12..949b13051 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -118,21 +118,9 @@ public:
118 GLenum operation; 118 GLenum operation;
119 } logic_op; 119 } logic_op;
120 120
121 // 3 texture units - one for each that is used in PICA fragment shader emulation 121 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures{};
122 struct TextureUnit { 122 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers{};
123 GLuint texture; // GL_TEXTURE_BINDING_2D 123 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumImages> images{};
124 GLuint sampler; // GL_SAMPLER_BINDING
125
126 void Unbind() {
127 texture = 0;
128 }
129
130 void Reset() {
131 Unbind();
132 sampler = 0;
133 }
134 };
135 std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
136 124
137 struct { 125 struct {
138 GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING 126 GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
@@ -220,6 +208,7 @@ public:
220 void ApplyLogicOp() const; 208 void ApplyLogicOp() const;
221 void ApplyTextures() const; 209 void ApplyTextures() const;
222 void ApplySamplers() const; 210 void ApplySamplers() const;
211 void ApplyImages() const;
223 void ApplyDepthClamp() const; 212 void ApplyDepthClamp() const;
224 void ApplyPolygonOffset() const; 213 void ApplyPolygonOffset() const;
225 void ApplyAlphaTest() const; 214 void ApplyAlphaTest() const;
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/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index af9684839..839178152 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -342,7 +342,7 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
342 ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v), 342 ScreenRectVertex(x + w, y + h, texcoords.bottom * scale_u, right * scale_v),
343 }}; 343 }};
344 344
345 state.texture_units[0].texture = screen_info.display_texture; 345 state.textures[0] = screen_info.display_texture;
346 // Workaround brigthness problems in SMO by enabling sRGB in the final output 346 // Workaround brigthness problems in SMO by enabling sRGB in the final output
347 // if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987 347 // if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987
348 state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed(); 348 state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed();
@@ -352,7 +352,7 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
352 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 352 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
353 // Restore default state 353 // Restore default state
354 state.framebuffer_srgb.enabled = false; 354 state.framebuffer_srgb.enabled = false;
355 state.texture_units[0].texture = 0; 355 state.textures[0] = 0;
356 state.AllDirty(); 356 state.AllDirty();
357 state.Apply(); 357 state.Apply();
358 // Clear sRGB state for the next frame 358 // Clear sRGB state for the next frame
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 5db9313c4..b29aedce8 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -273,46 +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 bool operator<(const Image& rhs) const { 315 constexpr bool IsRead() const {
307 return std::tie(offset, index, type, is_bindless) < 316 return is_read;
308 std::tie(rhs.offset, rhs.index, rhs.type, rhs.is_bindless); 317 }
318
319 constexpr bool IsWritten() const {
320 return is_written;
321 }
322
323 constexpr std::pair<u32, u32> GetBindlessCBuf() const {
324 return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)};
309 } 325 }
310 326
311private: 327private:
312 std::size_t offset{}; 328 u64 offset{};
313 std::size_t index{}; 329 std::size_t index{};
314 Tegra::Shader::ImageType type{}; 330 Tegra::Shader::ImageType type{};
315 bool is_bindless{}; 331 bool is_bindless{};
332 bool is_read{};
333 bool is_written{};
316}; 334};
317 335
318struct 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{};
diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h
index bcce8d863..5e497e49f 100644
--- a/src/video_core/texture_cache/surface_base.h
+++ b/src/video_core/texture_cache/surface_base.h
@@ -195,18 +195,18 @@ public:
195 195
196 virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0; 196 virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;
197 197
198 void MarkAsModified(const bool is_modified_, const u64 tick) { 198 void MarkAsModified(bool is_modified_, u64 tick) {
199 is_modified = is_modified_ || is_target; 199 is_modified = is_modified_ || is_target;
200 modification_tick = tick; 200 modification_tick = tick;
201 } 201 }
202 202
203 void MarkAsRenderTarget(const bool is_target, const u32 index) { 203 void MarkAsRenderTarget(bool is_target_, u32 index_) {
204 this->is_target = is_target; 204 is_target = is_target_;
205 this->index = index; 205 index = index_;
206 } 206 }
207 207
208 void MarkAsPicked(const bool is_picked) { 208 void MarkAsPicked(bool is_picked_) {
209 this->is_picked = is_picked; 209 is_picked = is_picked_;
210 } 210 }
211 211
212 bool IsModified() const { 212 bool IsModified() const {
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index fd5472451..1e4d3fb79 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -24,55 +24,62 @@ using VideoCore::Surface::SurfaceTarget;
24using VideoCore::Surface::SurfaceTargetFromTextureType; 24using VideoCore::Surface::SurfaceTargetFromTextureType;
25using VideoCore::Surface::SurfaceType; 25using VideoCore::Surface::SurfaceType;
26 26
27SurfaceTarget TextureType2SurfaceTarget(Tegra::Shader::TextureType type, bool is_array) { 27namespace {
28
29SurfaceTarget TextureTypeToSurfaceTarget(Tegra::Shader::TextureType type, bool is_array) {
28 switch (type) { 30 switch (type) {
29 case Tegra::Shader::TextureType::Texture1D: { 31 case Tegra::Shader::TextureType::Texture1D:
30 if (is_array) 32 return is_array ? SurfaceTarget::Texture1DArray : SurfaceTarget::Texture1D;
31 return SurfaceTarget::Texture1DArray; 33 case Tegra::Shader::TextureType::Texture2D:
32 else 34 return is_array ? SurfaceTarget::Texture2DArray : SurfaceTarget::Texture2D;
33 return SurfaceTarget::Texture1D; 35 case Tegra::Shader::TextureType::Texture3D:
34 }
35 case Tegra::Shader::TextureType::Texture2D: {
36 if (is_array)
37 return SurfaceTarget::Texture2DArray;
38 else
39 return SurfaceTarget::Texture2D;
40 }
41 case Tegra::Shader::TextureType::Texture3D: {
42 ASSERT(!is_array); 36 ASSERT(!is_array);
43 return SurfaceTarget::Texture3D; 37 return SurfaceTarget::Texture3D;
44 } 38 case Tegra::Shader::TextureType::TextureCube:
45 case Tegra::Shader::TextureType::TextureCube: { 39 return is_array ? SurfaceTarget::TextureCubeArray : SurfaceTarget::TextureCubemap;
46 if (is_array) 40 default:
47 return SurfaceTarget::TextureCubeArray;
48 else
49 return SurfaceTarget::TextureCubemap;
50 }
51 default: {
52 UNREACHABLE(); 41 UNREACHABLE();
53 return SurfaceTarget::Texture2D; 42 return SurfaceTarget::Texture2D;
54 } 43 }
44}
45
46SurfaceTarget ImageTypeToSurfaceTarget(Tegra::Shader::ImageType type) {
47 switch (type) {
48 case Tegra::Shader::ImageType::Texture1D:
49 return SurfaceTarget::Texture1D;
50 case Tegra::Shader::ImageType::TextureBuffer:
51 return SurfaceTarget::TextureBuffer;
52 case Tegra::Shader::ImageType::Texture1DArray:
53 return SurfaceTarget::Texture1DArray;
54 case Tegra::Shader::ImageType::Texture2D:
55 return SurfaceTarget::Texture2D;
56 case Tegra::Shader::ImageType::Texture2DArray:
57 return SurfaceTarget::Texture2DArray;
58 case Tegra::Shader::ImageType::Texture3D:
59 return SurfaceTarget::Texture3D;
60 default:
61 UNREACHABLE();
62 return SurfaceTarget::Texture2D;
55 } 63 }
56} 64}
57 65
58namespace {
59constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { 66constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
60 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile); 67 return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
61} 68}
69
62} // Anonymous namespace 70} // Anonymous namespace
63 71
64SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, 72SurfaceParams SurfaceParams::CreateForTexture(const Tegra::Texture::TICEntry& tic,
65 const Tegra::Texture::FullTextureInfo& config,
66 const VideoCommon::Shader::Sampler& entry) { 73 const VideoCommon::Shader::Sampler& entry) {
67 SurfaceParams params; 74 SurfaceParams params;
68 params.is_tiled = config.tic.IsTiled(); 75 params.is_tiled = tic.IsTiled();
69 params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); 76 params.srgb_conversion = tic.IsSrgbConversionEnabled();
70 params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, 77 params.block_width = params.is_tiled ? tic.BlockWidth() : 0,
71 params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, 78 params.block_height = params.is_tiled ? tic.BlockHeight() : 0,
72 params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, 79 params.block_depth = params.is_tiled ? tic.BlockDepth() : 0,
73 params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1; 80 params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
74 params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), 81 params.pixel_format =
75 params.srgb_conversion); 82 PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion);
76 params.type = GetFormatType(params.pixel_format); 83 params.type = GetFormatType(params.pixel_format);
77 if (entry.IsShadow() && params.type == SurfaceType::ColorTexture) { 84 if (entry.IsShadow() && params.type == SurfaceType::ColorTexture) {
78 switch (params.pixel_format) { 85 switch (params.pixel_format) {
@@ -92,31 +99,72 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
92 } 99 }
93 params.type = GetFormatType(params.pixel_format); 100 params.type = GetFormatType(params.pixel_format);
94 } 101 }
95 params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); 102 params.component_type = ComponentTypeFromTexture(tic.r_type.Value());
96 params.type = GetFormatType(params.pixel_format); 103 params.type = GetFormatType(params.pixel_format);
97 // TODO: on 1DBuffer we should use the tic info. 104 // TODO: on 1DBuffer we should use the tic info.
98 if (!config.tic.IsBuffer()) { 105 if (tic.IsBuffer()) {
99 params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray()); 106 params.target = SurfaceTarget::TextureBuffer;
100 params.width = config.tic.Width(); 107 params.width = tic.Width();
101 params.height = config.tic.Height(); 108 params.pitch = params.width * params.GetBytesPerPixel();
102 params.depth = config.tic.Depth(); 109 params.height = 1;
103 params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); 110 params.depth = 1;
111 params.num_levels = 1;
112 params.emulated_levels = 1;
113 params.is_layered = false;
114 } else {
115 params.target = TextureTypeToSurfaceTarget(entry.GetType(), entry.IsArray());
116 params.width = tic.Width();
117 params.height = tic.Height();
118 params.depth = tic.Depth();
119 params.pitch = params.is_tiled ? 0 : tic.Pitch();
104 if (params.target == SurfaceTarget::TextureCubemap || 120 if (params.target == SurfaceTarget::TextureCubemap ||
105 params.target == SurfaceTarget::TextureCubeArray) { 121 params.target == SurfaceTarget::TextureCubeArray) {
106 params.depth *= 6; 122 params.depth *= 6;
107 } 123 }
108 params.num_levels = config.tic.max_mip_level + 1; 124 params.num_levels = tic.max_mip_level + 1;
109 params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap()); 125 params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
110 params.is_layered = params.IsLayered(); 126 params.is_layered = params.IsLayered();
111 } else { 127 }
128 return params;
129}
130
131SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic,
132 const VideoCommon::Shader::Image& entry) {
133 SurfaceParams params;
134 params.is_tiled = tic.IsTiled();
135 params.srgb_conversion = tic.IsSrgbConversionEnabled();
136 params.block_width = params.is_tiled ? tic.BlockWidth() : 0,
137 params.block_height = params.is_tiled ? tic.BlockHeight() : 0,
138 params.block_depth = params.is_tiled ? tic.BlockDepth() : 0,
139 params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
140 params.pixel_format =
141 PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion);
142 params.type = GetFormatType(params.pixel_format);
143 params.component_type = ComponentTypeFromTexture(tic.r_type.Value());
144 params.type = GetFormatType(params.pixel_format);
145 params.target = ImageTypeToSurfaceTarget(entry.GetType());
146 // TODO: on 1DBuffer we should use the tic info.
147 if (tic.IsBuffer()) {
112 params.target = SurfaceTarget::TextureBuffer; 148 params.target = SurfaceTarget::TextureBuffer;
113 params.width = config.tic.Width(); 149 params.width = tic.Width();
114 params.pitch = params.width * params.GetBytesPerPixel(); 150 params.pitch = params.width * params.GetBytesPerPixel();
115 params.height = 1; 151 params.height = 1;
116 params.depth = 1; 152 params.depth = 1;
117 params.num_levels = 1; 153 params.num_levels = 1;
118 params.emulated_levels = 1; 154 params.emulated_levels = 1;
119 params.is_layered = false; 155 params.is_layered = false;
156 } else {
157 params.width = tic.Width();
158 params.height = tic.Height();
159 params.depth = tic.Depth();
160 params.pitch = params.is_tiled ? 0 : tic.Pitch();
161 if (params.target == SurfaceTarget::TextureCubemap ||
162 params.target == SurfaceTarget::TextureCubeArray) {
163 params.depth *= 6;
164 }
165 params.num_levels = tic.max_mip_level + 1;
166 params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
167 params.is_layered = params.IsLayered();
120 } 168 }
121 return params; 169 return params;
122} 170}
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h
index e7ef66ee2..c58e7f8a4 100644
--- a/src/video_core/texture_cache/surface_params.h
+++ b/src/video_core/texture_cache/surface_params.h
@@ -4,8 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <map>
8
9#include "common/alignment.h" 7#include "common/alignment.h"
10#include "common/bit_util.h" 8#include "common/bit_util.h"
11#include "common/cityhash.h" 9#include "common/cityhash.h"
@@ -23,10 +21,13 @@ using VideoCore::Surface::SurfaceCompression;
23class SurfaceParams { 21class SurfaceParams {
24public: 22public:
25 /// Creates SurfaceCachedParams from a texture configuration. 23 /// Creates SurfaceCachedParams from a texture configuration.
26 static SurfaceParams CreateForTexture(Core::System& system, 24 static SurfaceParams CreateForTexture(const Tegra::Texture::TICEntry& tic,
27 const Tegra::Texture::FullTextureInfo& config,
28 const VideoCommon::Shader::Sampler& entry); 25 const VideoCommon::Shader::Sampler& entry);
29 26
27 /// Creates SurfaceCachedParams from an image configuration.
28 static SurfaceParams CreateForImage(const Tegra::Texture::TICEntry& tic,
29 const VideoCommon::Shader::Image& entry);
30
30 /// Creates SurfaceCachedParams for a depth buffer configuration. 31 /// Creates SurfaceCachedParams for a depth buffer configuration.
31 static SurfaceParams CreateForDepthBuffer( 32 static SurfaceParams CreateForDepthBuffer(
32 Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format, 33 Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format,
diff --git a/src/video_core/texture_cache/surface_view.cpp b/src/video_core/texture_cache/surface_view.cpp
index 467696a4c..57a1f5803 100644
--- a/src/video_core/texture_cache/surface_view.cpp
+++ b/src/video_core/texture_cache/surface_view.cpp
@@ -10,7 +10,7 @@
10namespace VideoCommon { 10namespace VideoCommon {
11 11
12std::size_t ViewParams::Hash() const { 12std::size_t ViewParams::Hash() const {
13 return static_cast<std::size_t>(base_layer) ^ static_cast<std::size_t>(num_layers << 16) ^ 13 return static_cast<std::size_t>(base_layer) ^ (static_cast<std::size_t>(num_layers) << 16) ^
14 (static_cast<std::size_t>(base_level) << 24) ^ 14 (static_cast<std::size_t>(base_level) << 24) ^
15 (static_cast<std::size_t>(num_levels) << 32) ^ (static_cast<std::size_t>(target) << 36); 15 (static_cast<std::size_t>(num_levels) << 32) ^ (static_cast<std::size_t>(target) << 36);
16} 16}
diff --git a/src/video_core/texture_cache/surface_view.h b/src/video_core/texture_cache/surface_view.h
index 04ca5639b..b17fd11a9 100644
--- a/src/video_core/texture_cache/surface_view.h
+++ b/src/video_core/texture_cache/surface_view.h
@@ -13,8 +13,8 @@
13namespace VideoCommon { 13namespace VideoCommon {
14 14
15struct ViewParams { 15struct ViewParams {
16 ViewParams(VideoCore::Surface::SurfaceTarget target, u32 base_layer, u32 num_layers, 16 constexpr explicit ViewParams(VideoCore::Surface::SurfaceTarget target, u32 base_layer,
17 u32 base_level, u32 num_levels) 17 u32 num_layers, u32 base_level, u32 num_levels)
18 : target{target}, base_layer{base_layer}, num_layers{num_layers}, base_level{base_level}, 18 : target{target}, base_layer{base_layer}, num_layers{num_layers}, base_level{base_level},
19 num_levels{num_levels} {} 19 num_levels{num_levels} {}
20 20
@@ -22,12 +22,6 @@ struct ViewParams {
22 22
23 bool operator==(const ViewParams& rhs) const; 23 bool operator==(const ViewParams& rhs) const;
24 24
25 VideoCore::Surface::SurfaceTarget target{};
26 u32 base_layer{};
27 u32 num_layers{};
28 u32 base_level{};
29 u32 num_levels{};
30
31 bool IsLayered() const { 25 bool IsLayered() const {
32 switch (target) { 26 switch (target) {
33 case VideoCore::Surface::SurfaceTarget::Texture1DArray: 27 case VideoCore::Surface::SurfaceTarget::Texture1DArray:
@@ -39,13 +33,19 @@ struct ViewParams {
39 return false; 33 return false;
40 } 34 }
41 } 35 }
36
37 VideoCore::Surface::SurfaceTarget target{};
38 u32 base_layer{};
39 u32 num_layers{};
40 u32 base_level{};
41 u32 num_levels{};
42}; 42};
43 43
44class ViewBase { 44class ViewBase {
45public: 45public:
46 ViewBase(const ViewParams& params) : params{params} {} 46 constexpr explicit ViewBase(const ViewParams& params) : params{params} {}
47 47
48 const ViewParams& GetViewParams() const { 48 constexpr const ViewParams& GetViewParams() const {
49 return params; 49 return params;
50 } 50 }
51 51
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 2ec0203d1..877c6635d 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -89,14 +89,29 @@ public:
89 } 89 }
90 } 90 }
91 91
92 TView GetTextureSurface(const Tegra::Texture::FullTextureInfo& config, 92 TView GetTextureSurface(const Tegra::Texture::TICEntry& tic,
93 const VideoCommon::Shader::Sampler& entry) { 93 const VideoCommon::Shader::Sampler& entry) {
94 std::lock_guard lock{mutex}; 94 std::lock_guard lock{mutex};
95 const auto gpu_addr{config.tic.Address()}; 95 const auto gpu_addr{tic.Address()};
96 if (!gpu_addr) { 96 if (!gpu_addr) {
97 return {}; 97 return {};
98 } 98 }
99 const auto params{SurfaceParams::CreateForTexture(system, config, entry)}; 99 const auto params{SurfaceParams::CreateForTexture(tic, entry)};
100 const auto [surface, view] = GetSurface(gpu_addr, params, true, false);
101 if (guard_samplers) {
102 sampled_textures.push_back(surface);
103 }
104 return view;
105 }
106
107 TView GetImageSurface(const Tegra::Texture::TICEntry& tic,
108 const VideoCommon::Shader::Image& entry) {
109 std::lock_guard lock{mutex};
110 const auto gpu_addr{tic.Address()};
111 if (!gpu_addr) {
112 return {};
113 }
114 const auto params{SurfaceParams::CreateForImage(tic, entry)};
100 const auto [surface, view] = GetSurface(gpu_addr, params, true, false); 115 const auto [surface, view] = GetSurface(gpu_addr, params, true, false);
101 if (guard_samplers) { 116 if (guard_samplers) {
102 sampled_textures.push_back(surface); 117 sampled_textures.push_back(surface);