summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
authorGravatar spholz2021-08-12 22:27:17 +0200
committerGravatar GitHub2021-08-12 22:27:17 +0200
commit78a82495931e8c6b2161f79d2ac00ea88baea4f2 (patch)
tree94480efdcd09a71e676782434a44d124002f835a /src/video_core
parentnetwork: correct formatting in network.cpp and network_interface.cpp (diff)
parentMerge pull request #6838 from ameerj/sws-align (diff)
downloadyuzu-78a82495931e8c6b2161f79d2ac00ea88baea4f2.tar.gz
yuzu-78a82495931e8c6b2161f79d2ac00ea88baea4f2.tar.xz
yuzu-78a82495931e8c6b2161f79d2ac00ea88baea4f2.zip
Merge branch 'yuzu-emu:master' into fix-lan-play
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/CMakeLists.txt3
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp4
-rw-r--r--src/video_core/command_classes/codecs/vp9_types.h2
-rw-r--r--src/video_core/command_classes/nvdec.cpp2
-rw-r--r--src/video_core/command_classes/vic.cpp5
-rw-r--r--src/video_core/host_shaders/astc_decoder.comp271
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache_base.cpp10
-rw-r--r--src/video_core/renderer_opengl/util_shaders.cpp31
-rw-r--r--src/video_core/renderer_opengl/util_shaders.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp97
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache_base.cpp10
-rw-r--r--src/video_core/texture_cache/image_view_info.cpp4
-rw-r--r--src/video_core/texture_cache/texture_cache.h419
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h385
-rw-r--r--src/video_core/textures/astc.cpp156
-rw-r--r--src/video_core/textures/astc.h111
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp8
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h2
26 files changed, 685 insertions, 857 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 1eb67c051..2f6cdd216 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -97,6 +97,7 @@ add_library(video_core STATIC
97 renderer_opengl/gl_stream_buffer.h 97 renderer_opengl/gl_stream_buffer.h
98 renderer_opengl/gl_texture_cache.cpp 98 renderer_opengl/gl_texture_cache.cpp
99 renderer_opengl/gl_texture_cache.h 99 renderer_opengl/gl_texture_cache.h
100 renderer_opengl/gl_texture_cache_base.cpp
100 renderer_opengl/gl_query_cache.cpp 101 renderer_opengl/gl_query_cache.cpp
101 renderer_opengl/gl_query_cache.h 102 renderer_opengl/gl_query_cache.h
102 renderer_opengl/maxwell_to_gl.h 103 renderer_opengl/maxwell_to_gl.h
@@ -155,6 +156,7 @@ add_library(video_core STATIC
155 renderer_vulkan/vk_swapchain.h 156 renderer_vulkan/vk_swapchain.h
156 renderer_vulkan/vk_texture_cache.cpp 157 renderer_vulkan/vk_texture_cache.cpp
157 renderer_vulkan/vk_texture_cache.h 158 renderer_vulkan/vk_texture_cache.h
159 renderer_vulkan/vk_texture_cache_base.cpp
158 renderer_vulkan/vk_update_descriptor.cpp 160 renderer_vulkan/vk_update_descriptor.cpp
159 renderer_vulkan/vk_update_descriptor.h 161 renderer_vulkan/vk_update_descriptor.h
160 shader_cache.cpp 162 shader_cache.cpp
@@ -186,6 +188,7 @@ add_library(video_core STATIC
186 texture_cache/samples_helper.h 188 texture_cache/samples_helper.h
187 texture_cache/slot_vector.h 189 texture_cache/slot_vector.h
188 texture_cache/texture_cache.h 190 texture_cache/texture_cache.h
191 texture_cache/texture_cache_base.h
189 texture_cache/types.h 192 texture_cache/types.h
190 texture_cache/util.cpp 193 texture_cache/util.cpp
191 texture_cache/util.h 194 texture_cache/util.h
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index 7eecb3991..70030066a 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -397,14 +397,14 @@ Vp9FrameContainer VP9::GetCurrentFrame(const NvdecCommon::NvdecRegisters& state)
397 next_frame = std::move(temp); 397 next_frame = std::move(temp);
398 } else { 398 } else {
399 next_frame.info = current_frame.info; 399 next_frame.info = current_frame.info;
400 next_frame.bit_stream = std::move(current_frame.bit_stream); 400 next_frame.bit_stream = current_frame.bit_stream;
401 } 401 }
402 return current_frame; 402 return current_frame;
403} 403}
404 404
405std::vector<u8> VP9::ComposeCompressedHeader() { 405std::vector<u8> VP9::ComposeCompressedHeader() {
406 VpxRangeEncoder writer{}; 406 VpxRangeEncoder writer{};
407 const bool update_probs = current_frame_info.show_frame && !current_frame_info.is_key_frame; 407 const bool update_probs = !current_frame_info.is_key_frame && current_frame_info.show_frame;
408 if (!current_frame_info.lossless) { 408 if (!current_frame_info.lossless) {
409 if (static_cast<u32>(current_frame_info.transform_mode) >= 3) { 409 if (static_cast<u32>(current_frame_info.transform_mode) >= 3) {
410 writer.Write(3, 2); 410 writer.Write(3, 2);
diff --git a/src/video_core/command_classes/codecs/vp9_types.h b/src/video_core/command_classes/codecs/vp9_types.h
index 6820afa26..87eafdb03 100644
--- a/src/video_core/command_classes/codecs/vp9_types.h
+++ b/src/video_core/command_classes/codecs/vp9_types.h
@@ -176,7 +176,7 @@ struct PictureInfo {
176 .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0, 176 .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0,
177 .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0, 177 .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0,
178 .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0, 178 .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0,
179 .show_frame = false, 179 .show_frame = true,
180 .ref_frame_sign_bias = ref_frame_sign_bias, 180 .ref_frame_sign_bias = ref_frame_sign_bias,
181 .base_q_index = base_q_index, 181 .base_q_index = base_q_index,
182 .y_dc_delta_q = y_dc_delta_q, 182 .y_dc_delta_q = y_dc_delta_q,
diff --git a/src/video_core/command_classes/nvdec.cpp b/src/video_core/command_classes/nvdec.cpp
index b5e3b70fc..b5c55f14a 100644
--- a/src/video_core/command_classes/nvdec.cpp
+++ b/src/video_core/command_classes/nvdec.cpp
@@ -39,7 +39,7 @@ void Nvdec::Execute() {
39 codec->Decode(); 39 codec->Decode();
40 break; 40 break;
41 default: 41 default:
42 UNIMPLEMENTED_MSG("Unknown codec {}", static_cast<u32>(codec->GetCurrentCodec())); 42 UNIMPLEMENTED_MSG("Codec {}", codec->GetCurrentCodecName());
43 break; 43 break;
44 } 44 }
45} 45}
diff --git a/src/video_core/command_classes/vic.cpp b/src/video_core/command_classes/vic.cpp
index d5e77941c..0ee07f398 100644
--- a/src/video_core/command_classes/vic.cpp
+++ b/src/video_core/command_classes/vic.cpp
@@ -96,12 +96,11 @@ void Vic::Execute() {
96 if (!converted_frame_buffer) { 96 if (!converted_frame_buffer) {
97 converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(linear_size)), av_free}; 97 converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(linear_size)), av_free};
98 } 98 }
99 99 const std::array<int, 4> converted_stride{frame->width * 4, frame->height * 4, 0, 0};
100 const int converted_stride{frame->width * 4};
101 u8* const converted_frame_buf_addr{converted_frame_buffer.get()}; 100 u8* const converted_frame_buf_addr{converted_frame_buffer.get()};
102 101
103 sws_scale(scaler_ctx, frame->data, frame->linesize, 0, frame->height, 102 sws_scale(scaler_ctx, frame->data, frame->linesize, 0, frame->height,
104 &converted_frame_buf_addr, &converted_stride); 103 &converted_frame_buf_addr, converted_stride.data());
105 104
106 const u32 blk_kind = static_cast<u32>(config.block_linear_kind); 105 const u32 blk_kind = static_cast<u32>(config.block_linear_kind);
107 if (blk_kind != 0) { 106 if (blk_kind != 0) {
diff --git a/src/video_core/host_shaders/astc_decoder.comp b/src/video_core/host_shaders/astc_decoder.comp
index c37f15bfd..f34c5f5d9 100644
--- a/src/video_core/host_shaders/astc_decoder.comp
+++ b/src/video_core/host_shaders/astc_decoder.comp
@@ -10,33 +10,27 @@
10#define END_PUSH_CONSTANTS }; 10#define END_PUSH_CONSTANTS };
11#define UNIFORM(n) 11#define UNIFORM(n)
12#define BINDING_INPUT_BUFFER 0 12#define BINDING_INPUT_BUFFER 0
13#define BINDING_ENC_BUFFER 1 13#define BINDING_OUTPUT_IMAGE 1
14#define BINDING_SWIZZLE_BUFFER 2
15#define BINDING_OUTPUT_IMAGE 3
16 14
17#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv 15#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
18 16
19#define BEGIN_PUSH_CONSTANTS 17#define BEGIN_PUSH_CONSTANTS
20#define END_PUSH_CONSTANTS 18#define END_PUSH_CONSTANTS
21#define UNIFORM(n) layout(location = n) uniform 19#define UNIFORM(n) layout(location = n) uniform
22#define BINDING_SWIZZLE_BUFFER 0 20#define BINDING_INPUT_BUFFER 0
23#define BINDING_INPUT_BUFFER 1
24#define BINDING_ENC_BUFFER 2
25#define BINDING_OUTPUT_IMAGE 0 21#define BINDING_OUTPUT_IMAGE 0
26 22
27#endif 23#endif
28 24
29layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in; 25layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
30 26
31BEGIN_PUSH_CONSTANTS 27BEGIN_PUSH_CONSTANTS
32UNIFORM(1) uvec2 block_dims; 28UNIFORM(1) uvec2 block_dims;
33 29UNIFORM(2) uint layer_stride;
34UNIFORM(2) uint bytes_per_block_log2; 30UNIFORM(3) uint block_size;
35UNIFORM(3) uint layer_stride; 31UNIFORM(4) uint x_shift;
36UNIFORM(4) uint block_size; 32UNIFORM(5) uint block_height;
37UNIFORM(5) uint x_shift; 33UNIFORM(6) uint block_height_mask;
38UNIFORM(6) uint block_height;
39UNIFORM(7) uint block_height_mask;
40END_PUSH_CONSTANTS 34END_PUSH_CONSTANTS
41 35
42struct EncodingData { 36struct EncodingData {
@@ -55,45 +49,35 @@ struct TexelWeightParams {
55 bool void_extent_hdr; 49 bool void_extent_hdr;
56}; 50};
57 51
58// Swizzle data
59layout(binding = BINDING_SWIZZLE_BUFFER, std430) readonly buffer SwizzleTable {
60 uint swizzle_table[];
61};
62
63layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 { 52layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 {
64 uint astc_data[]; 53 uvec4 astc_data[];
65};
66
67// ASTC Encodings data
68layout(binding = BINDING_ENC_BUFFER, std430) readonly buffer EncodingsValues {
69 EncodingData encoding_values[];
70}; 54};
71 55
72layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image; 56layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image;
73 57
74const uint GOB_SIZE_X = 64;
75const uint GOB_SIZE_Y = 8;
76const uint GOB_SIZE_Z = 1;
77const uint GOB_SIZE = GOB_SIZE_X * GOB_SIZE_Y * GOB_SIZE_Z;
78
79const uint GOB_SIZE_X_SHIFT = 6; 58const uint GOB_SIZE_X_SHIFT = 6;
80const uint GOB_SIZE_Y_SHIFT = 3; 59const uint GOB_SIZE_Y_SHIFT = 3;
81const uint GOB_SIZE_Z_SHIFT = 0; 60const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT;
82const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT;
83
84const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1, GOB_SIZE_Y - 1);
85 61
86const int BLOCK_SIZE_IN_BYTES = 16; 62const uint BYTES_PER_BLOCK_LOG2 = 4;
87
88const int BLOCK_INFO_ERROR = 0;
89const int BLOCK_INFO_VOID_EXTENT_HDR = 1;
90const int BLOCK_INFO_VOID_EXTENT_LDR = 2;
91const int BLOCK_INFO_NORMAL = 3;
92 63
93const int JUST_BITS = 0; 64const int JUST_BITS = 0;
94const int QUINT = 1; 65const int QUINT = 1;
95const int TRIT = 2; 66const int TRIT = 2;
96 67
68// ASTC Encodings data, sorted in ascending order based on their BitLength value
69// (see GetBitLength() function)
70EncodingData encoding_values[22] = EncodingData[](
71 EncodingData(JUST_BITS, 0, 0, 0), EncodingData(JUST_BITS, 1, 0, 0), EncodingData(TRIT, 0, 0, 0),
72 EncodingData(JUST_BITS, 2, 0, 0), EncodingData(QUINT, 0, 0, 0), EncodingData(TRIT, 1, 0, 0),
73 EncodingData(JUST_BITS, 3, 0, 0), EncodingData(QUINT, 1, 0, 0), EncodingData(TRIT, 2, 0, 0),
74 EncodingData(JUST_BITS, 4, 0, 0), EncodingData(QUINT, 2, 0, 0), EncodingData(TRIT, 3, 0, 0),
75 EncodingData(JUST_BITS, 5, 0, 0), EncodingData(QUINT, 3, 0, 0), EncodingData(TRIT, 4, 0, 0),
76 EncodingData(JUST_BITS, 6, 0, 0), EncodingData(QUINT, 4, 0, 0), EncodingData(TRIT, 5, 0, 0),
77 EncodingData(JUST_BITS, 7, 0, 0), EncodingData(QUINT, 5, 0, 0), EncodingData(TRIT, 6, 0, 0),
78 EncodingData(JUST_BITS, 8, 0, 0)
79);
80
97// The following constants are expanded variants of the Replicate() 81// The following constants are expanded variants of the Replicate()
98// function calls corresponding to the following arguments: 82// function calls corresponding to the following arguments:
99// value: index into the generated table 83// value: index into the generated table
@@ -135,44 +119,37 @@ const uint REPLICATE_7_BIT_TO_8_TABLE[128] =
135// Input ASTC texture globals 119// Input ASTC texture globals
136uint current_index = 0; 120uint current_index = 0;
137int bitsread = 0; 121int bitsread = 0;
138uint total_bitsread = 0; 122int total_bitsread = 0;
139uint local_buff[16]; 123uvec4 local_buff;
140 124
141// Color data globals 125// Color data globals
142uint color_endpoint_data[16]; 126uvec4 color_endpoint_data;
143int color_bitsread = 0; 127int color_bitsread = 0;
144uint total_color_bitsread = 0;
145int color_index = 0;
146 128
147// Four values, two endpoints, four maximum paritions 129// Four values, two endpoints, four maximum paritions
148uint color_values[32]; 130uint color_values[32];
149int colvals_index = 0; 131int colvals_index = 0;
150 132
151// Weight data globals 133// Weight data globals
152uint texel_weight_data[16]; 134uvec4 texel_weight_data;
153int texel_bitsread = 0; 135int texel_bitsread = 0;
154uint total_texel_bitsread = 0;
155int texel_index = 0;
156 136
157bool texel_flag = false; 137bool texel_flag = false;
158 138
159// Global "vectors" to be pushed into when decoding 139// Global "vectors" to be pushed into when decoding
160EncodingData result_vector[100]; 140EncodingData result_vector[144];
161int result_index = 0; 141int result_index = 0;
162 142
163EncodingData texel_vector[100]; 143EncodingData texel_vector[144];
164int texel_vector_index = 0; 144int texel_vector_index = 0;
165 145
166uint unquantized_texel_weights[2][144]; 146uint unquantized_texel_weights[2][144];
167 147
168uint SwizzleOffset(uvec2 pos) { 148uint SwizzleOffset(uvec2 pos) {
169 pos = pos & SWIZZLE_MASK; 149 uint x = pos.x;
170 return swizzle_table[pos.y * 64 + pos.x]; 150 uint y = pos.y;
171} 151 return ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
172 152 (y % 2) * 16 + (x % 16);
173uint ReadTexel(uint offset) {
174 // extract the 8-bit value from the 32-bit packed data.
175 return bitfieldExtract(astc_data[offset / 4], int((offset * 8) & 24), 8);
176} 153}
177 154
178// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)] 155// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
@@ -278,14 +255,10 @@ uint Hash52(uint p) {
278 return p; 255 return p;
279} 256}
280 257
281uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bool small_block) { 258uint Select2DPartition(uint seed, uint x, uint y, uint partition_count, bool small_block) {
282 if (partition_count == 1) {
283 return 0;
284 }
285 if (small_block) { 259 if (small_block) {
286 x <<= 1; 260 x <<= 1;
287 y <<= 1; 261 y <<= 1;
288 z <<= 1;
289 } 262 }
290 263
291 seed += (partition_count - 1) * 1024; 264 seed += (partition_count - 1) * 1024;
@@ -299,10 +272,6 @@ uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bo
299 uint seed6 = uint((rnum >> 20) & 0xF); 272 uint seed6 = uint((rnum >> 20) & 0xF);
300 uint seed7 = uint((rnum >> 24) & 0xF); 273 uint seed7 = uint((rnum >> 24) & 0xF);
301 uint seed8 = uint((rnum >> 28) & 0xF); 274 uint seed8 = uint((rnum >> 28) & 0xF);
302 uint seed9 = uint((rnum >> 18) & 0xF);
303 uint seed10 = uint((rnum >> 22) & 0xF);
304 uint seed11 = uint((rnum >> 26) & 0xF);
305 uint seed12 = uint(((rnum >> 30) | (rnum << 2)) & 0xF);
306 275
307 seed1 = (seed1 * seed1); 276 seed1 = (seed1 * seed1);
308 seed2 = (seed2 * seed2); 277 seed2 = (seed2 * seed2);
@@ -312,12 +281,8 @@ uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bo
312 seed6 = (seed6 * seed6); 281 seed6 = (seed6 * seed6);
313 seed7 = (seed7 * seed7); 282 seed7 = (seed7 * seed7);
314 seed8 = (seed8 * seed8); 283 seed8 = (seed8 * seed8);
315 seed9 = (seed9 * seed9);
316 seed10 = (seed10 * seed10);
317 seed11 = (seed11 * seed11);
318 seed12 = (seed12 * seed12);
319 284
320 int sh1, sh2, sh3; 285 uint sh1, sh2;
321 if ((seed & 1) > 0) { 286 if ((seed & 1) > 0) {
322 sh1 = (seed & 2) > 0 ? 4 : 5; 287 sh1 = (seed & 2) > 0 ? 4 : 5;
323 sh2 = (partition_count == 3) ? 6 : 5; 288 sh2 = (partition_count == 3) ? 6 : 5;
@@ -325,25 +290,19 @@ uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bo
325 sh1 = (partition_count == 3) ? 6 : 5; 290 sh1 = (partition_count == 3) ? 6 : 5;
326 sh2 = (seed & 2) > 0 ? 4 : 5; 291 sh2 = (seed & 2) > 0 ? 4 : 5;
327 } 292 }
328 sh3 = (seed & 0x10) > 0 ? sh1 : sh2; 293 seed1 >>= sh1;
329 294 seed2 >>= sh2;
330 seed1 = (seed1 >> sh1); 295 seed3 >>= sh1;
331 seed2 = (seed2 >> sh2); 296 seed4 >>= sh2;
332 seed3 = (seed3 >> sh1); 297 seed5 >>= sh1;
333 seed4 = (seed4 >> sh2); 298 seed6 >>= sh2;
334 seed5 = (seed5 >> sh1); 299 seed7 >>= sh1;
335 seed6 = (seed6 >> sh2); 300 seed8 >>= sh2;
336 seed7 = (seed7 >> sh1); 301
337 seed8 = (seed8 >> sh2); 302 uint a = seed1 * x + seed2 * y + (rnum >> 14);
338 seed9 = (seed9 >> sh3); 303 uint b = seed3 * x + seed4 * y + (rnum >> 10);
339 seed10 = (seed10 >> sh3); 304 uint c = seed5 * x + seed6 * y + (rnum >> 6);
340 seed11 = (seed11 >> sh3); 305 uint d = seed7 * x + seed8 * y + (rnum >> 2);
341 seed12 = (seed12 >> sh3);
342
343 uint a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
344 uint b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
345 uint c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
346 uint d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
347 306
348 a &= 0x3F; 307 a &= 0x3F;
349 b &= 0x3F; 308 b &= 0x3F;
@@ -368,58 +327,37 @@ uint SelectPartition(uint seed, uint x, uint y, uint z, uint partition_count, bo
368 } 327 }
369} 328}
370 329
371uint Select2DPartition(uint seed, uint x, uint y, uint partition_count, bool small_block) { 330uint ExtractBits(uvec4 payload, int offset, int bits) {
372 return SelectPartition(seed, x, y, 0, partition_count, small_block); 331 if (bits <= 0) {
373}
374
375uint ReadBit() {
376 if (current_index >= local_buff.length()) {
377 return 0; 332 return 0;
378 } 333 }
379 uint bit = bitfieldExtract(local_buff[current_index], bitsread, 1); 334 int last_offset = offset + bits - 1;
380 ++bitsread; 335 int shifted_offset = offset >> 5;
381 ++total_bitsread; 336 if ((last_offset >> 5) == shifted_offset) {
382 if (bitsread == 8) { 337 return bitfieldExtract(payload[shifted_offset], offset & 31, bits);
383 ++current_index;
384 bitsread = 0;
385 } 338 }
386 return bit; 339 int first_bits = 32 - (offset & 31);
340 int result_first = int(bitfieldExtract(payload[shifted_offset], offset & 31, first_bits));
341 int result_second = int(bitfieldExtract(payload[shifted_offset + 1], 0, bits - first_bits));
342 return result_first | (result_second << first_bits);
387} 343}
388 344
389uint StreamBits(uint num_bits) { 345uint StreamBits(uint num_bits) {
390 uint ret = 0; 346 int int_bits = int(num_bits);
391 for (uint i = 0; i < num_bits; i++) { 347 uint ret = ExtractBits(local_buff, total_bitsread, int_bits);
392 ret |= ((ReadBit() & 1) << i); 348 total_bitsread += int_bits;
393 }
394 return ret; 349 return ret;
395} 350}
396 351
397uint ReadColorBit() {
398 uint bit = 0;
399 if (texel_flag) {
400 bit = bitfieldExtract(texel_weight_data[texel_index], texel_bitsread, 1);
401 ++texel_bitsread;
402 ++total_texel_bitsread;
403 if (texel_bitsread == 8) {
404 ++texel_index;
405 texel_bitsread = 0;
406 }
407 } else {
408 bit = bitfieldExtract(color_endpoint_data[color_index], color_bitsread, 1);
409 ++color_bitsread;
410 ++total_color_bitsread;
411 if (color_bitsread == 8) {
412 ++color_index;
413 color_bitsread = 0;
414 }
415 }
416 return bit;
417}
418
419uint StreamColorBits(uint num_bits) { 352uint StreamColorBits(uint num_bits) {
420 uint ret = 0; 353 uint ret = 0;
421 for (uint i = 0; i < num_bits; i++) { 354 int int_bits = int(num_bits);
422 ret |= ((ReadColorBit() & 1) << i); 355 if (texel_flag) {
356 ret = ExtractBits(texel_weight_data, texel_bitsread, int_bits);
357 texel_bitsread += int_bits;
358 } else {
359 ret = ExtractBits(color_endpoint_data, color_bitsread, int_bits);
360 color_bitsread += int_bits;
423 } 361 }
424 return ret; 362 return ret;
425} 363}
@@ -596,22 +534,16 @@ void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits) {
596 for (uint i = 0; i < num_partitions; i++) { 534 for (uint i = 0; i < num_partitions; i++) {
597 num_values += ((modes[i] >> 2) + 1) << 1; 535 num_values += ((modes[i] >> 2) + 1) << 1;
598 } 536 }
599 int range = 256; 537 // Find the largest encoding that's within color_data_bits
600 while (--range > 0) { 538 // TODO(ameerj): profile with binary search
601 EncodingData val = encoding_values[range]; 539 int range = 0;
540 while (++range < encoding_values.length()) {
602 uint bit_length = GetBitLength(num_values, range); 541 uint bit_length = GetBitLength(num_values, range);
603 if (bit_length <= color_data_bits) { 542 if (bit_length > color_data_bits) {
604 while (--range > 0) {
605 EncodingData newval = encoding_values[range];
606 if (newval.encoding != val.encoding && newval.num_bits != val.num_bits) {
607 break;
608 }
609 }
610 ++range;
611 break; 543 break;
612 } 544 }
613 } 545 }
614 DecodeIntegerSequence(range, num_values); 546 DecodeIntegerSequence(range - 1, num_values);
615 uint out_index = 0; 547 uint out_index = 0;
616 for (int itr = 0; itr < result_index; ++itr) { 548 for (int itr = 0; itr < result_index; ++itr) {
617 if (out_index >= num_values) { 549 if (out_index >= num_values) {
@@ -1028,7 +960,7 @@ int FindLayout(uint mode) {
1028 return 5; 960 return 5;
1029} 961}
1030 962
1031TexelWeightParams DecodeBlockInfo(uint block_index) { 963TexelWeightParams DecodeBlockInfo() {
1032 TexelWeightParams params = TexelWeightParams(uvec2(0), 0, false, false, false, false); 964 TexelWeightParams params = TexelWeightParams(uvec2(0), 0, false, false, false, false);
1033 uint mode = StreamBits(11); 965 uint mode = StreamBits(11);
1034 if ((mode & 0x1ff) == 0x1fc) { 966 if ((mode & 0x1ff) == 0x1fc) {
@@ -1110,10 +1042,10 @@ TexelWeightParams DecodeBlockInfo(uint block_index) {
1110 } 1042 }
1111 weight_index -= 2; 1043 weight_index -= 2;
1112 if ((mode_layout != 9) && ((mode & 0x200) != 0)) { 1044 if ((mode_layout != 9) && ((mode & 0x200) != 0)) {
1113 const int max_weights[6] = int[6](9, 11, 15, 19, 23, 31); 1045 const int max_weights[6] = int[6](7, 8, 9, 10, 11, 12);
1114 params.max_weight = max_weights[weight_index]; 1046 params.max_weight = max_weights[weight_index];
1115 } else { 1047 } else {
1116 const int max_weights[6] = int[6](1, 2, 3, 4, 5, 7); 1048 const int max_weights[6] = int[6](1, 2, 3, 4, 5, 6);
1117 params.max_weight = max_weights[weight_index]; 1049 params.max_weight = max_weights[weight_index];
1118 } 1050 }
1119 return params; 1051 return params;
@@ -1144,8 +1076,8 @@ void FillVoidExtentLDR(ivec3 coord) {
1144 } 1076 }
1145} 1077}
1146 1078
1147void DecompressBlock(ivec3 coord, uint block_index) { 1079void DecompressBlock(ivec3 coord) {
1148 TexelWeightParams params = DecodeBlockInfo(block_index); 1080 TexelWeightParams params = DecodeBlockInfo();
1149 if (params.error_state) { 1081 if (params.error_state) {
1150 FillError(coord); 1082 FillError(coord);
1151 return; 1083 return;
@@ -1212,7 +1144,7 @@ void DecompressBlock(ivec3 coord, uint block_index) {
1212 // Read color data... 1144 // Read color data...
1213 uint color_data_bits = remaining_bits; 1145 uint color_data_bits = remaining_bits;
1214 while (remaining_bits > 0) { 1146 while (remaining_bits > 0) {
1215 int nb = int(min(remaining_bits, 8U)); 1147 int nb = int(min(remaining_bits, 32U));
1216 uint b = StreamBits(nb); 1148 uint b = StreamBits(nb);
1217 color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb)); 1149 color_endpoint_data[ced_pointer] = uint(bitfieldExtract(b, 0, nb));
1218 ++ced_pointer; 1150 ++ced_pointer;
@@ -1254,25 +1186,20 @@ void DecompressBlock(ivec3 coord, uint block_index) {
1254 ComputeEndpoints(endpoints[i][0], endpoints[i][1], color_endpoint_mode[i]); 1186 ComputeEndpoints(endpoints[i][0], endpoints[i][1], color_endpoint_mode[i]);
1255 } 1187 }
1256 1188
1257 for (uint i = 0; i < 16; i++) { 1189 texel_weight_data = local_buff;
1258 texel_weight_data[i] = local_buff[i]; 1190 texel_weight_data = bitfieldReverse(texel_weight_data).wzyx;
1259 }
1260 for (uint i = 0; i < 8; i++) {
1261#define REVERSE_BYTE(b) ((b * 0x0802U & 0x22110U) | (b * 0x8020U & 0x88440U)) * 0x10101U >> 16
1262 uint a = REVERSE_BYTE(texel_weight_data[i]);
1263 uint b = REVERSE_BYTE(texel_weight_data[15 - i]);
1264#undef REVERSE_BYTE
1265 texel_weight_data[i] = uint(bitfieldExtract(b, 0, 8));
1266 texel_weight_data[15 - i] = uint(bitfieldExtract(a, 0, 8));
1267 }
1268 uint clear_byte_start = 1191 uint clear_byte_start =
1269 (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) >> 3) + 1; 1192 (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) >> 3) + 1;
1270 texel_weight_data[clear_byte_start - 1] = 1193
1271 texel_weight_data[clear_byte_start - 1] & 1194 uint byte_insert = ExtractBits(texel_weight_data, int(clear_byte_start - 1) * 8, 8) &
1272 uint( 1195 uint(
1273 ((1 << (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) % 8)) - 1)); 1196 ((1 << (GetPackedBitSize(params.size, params.dual_plane, params.max_weight) % 8)) - 1));
1274 for (uint i = 0; i < 16 - clear_byte_start; i++) { 1197 uint vec_index = (clear_byte_start - 1) >> 2;
1275 texel_weight_data[clear_byte_start + i] = 0U; 1198 texel_weight_data[vec_index] =
1199 bitfieldInsert(texel_weight_data[vec_index], byte_insert, int((clear_byte_start - 1) % 4) * 8, 8);
1200 for (uint i = clear_byte_start; i < 16; ++i) {
1201 uint idx = i >> 2;
1202 texel_weight_data[idx] = bitfieldInsert(texel_weight_data[idx], 0, int(i % 4) * 8, 8);
1276 } 1203 }
1277 texel_flag = true; // use texel "vector" and bit stream in integer decoding 1204 texel_flag = true; // use texel "vector" and bit stream in integer decoding
1278 DecodeIntegerSequence(params.max_weight, GetNumWeightValues(params.size, params.dual_plane)); 1205 DecodeIntegerSequence(params.max_weight, GetNumWeightValues(params.size, params.dual_plane));
@@ -1281,8 +1208,11 @@ void DecompressBlock(ivec3 coord, uint block_index) {
1281 1208
1282 for (uint j = 0; j < block_dims.y; j++) { 1209 for (uint j = 0; j < block_dims.y; j++) {
1283 for (uint i = 0; i < block_dims.x; i++) { 1210 for (uint i = 0; i < block_dims.x; i++) {
1284 uint local_partition = Select2DPartition(partition_index, i, j, num_partitions, 1211 uint local_partition = 0;
1212 if (num_partitions > 1) {
1213 local_partition = Select2DPartition(partition_index, i, j, num_partitions,
1285 (block_dims.y * block_dims.x) < 32); 1214 (block_dims.y * block_dims.x) < 32);
1215 }
1286 vec4 p; 1216 vec4 p;
1287 uvec4 C0 = ReplicateByteTo16(endpoints[local_partition][0]); 1217 uvec4 C0 = ReplicateByteTo16(endpoints[local_partition][0]);
1288 uvec4 C1 = ReplicateByteTo16(endpoints[local_partition][1]); 1218 uvec4 C1 = ReplicateByteTo16(endpoints[local_partition][1]);
@@ -1303,7 +1233,7 @@ void DecompressBlock(ivec3 coord, uint block_index) {
1303 1233
1304void main() { 1234void main() {
1305 uvec3 pos = gl_GlobalInvocationID; 1235 uvec3 pos = gl_GlobalInvocationID;
1306 pos.x <<= bytes_per_block_log2; 1236 pos.x <<= BYTES_PER_BLOCK_LOG2;
1307 1237
1308 // Read as soon as possible due to its latency 1238 // Read as soon as possible due to its latency
1309 const uint swizzle = SwizzleOffset(pos.xy); 1239 const uint swizzle = SwizzleOffset(pos.xy);
@@ -1321,13 +1251,8 @@ void main() {
1321 if (any(greaterThanEqual(coord, imageSize(dest_image)))) { 1251 if (any(greaterThanEqual(coord, imageSize(dest_image)))) {
1322 return; 1252 return;
1323 } 1253 }
1324 uint block_index =
1325 pos.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + pos.y * gl_WorkGroupSize.x + pos.x;
1326
1327 current_index = 0; 1254 current_index = 0;
1328 bitsread = 0; 1255 bitsread = 0;
1329 for (int i = 0; i < 16; i++) { 1256 local_buff = astc_data[offset / 16];
1330 local_buff[i] = ReadTexel(offset + i); 1257 DecompressBlock(coord);
1331 }
1332 DecompressBlock(coord, block_index);
1333} 1258}
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
index fac0034fb..bccb37a58 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
@@ -15,7 +15,7 @@
15#include "video_core/renderer_opengl/gl_shader_util.h" 15#include "video_core/renderer_opengl/gl_shader_util.h"
16#include "video_core/renderer_opengl/gl_state_tracker.h" 16#include "video_core/renderer_opengl/gl_state_tracker.h"
17#include "video_core/shader_notify.h" 17#include "video_core/shader_notify.h"
18#include "video_core/texture_cache/texture_cache.h" 18#include "video_core/texture_cache/texture_cache_base.h"
19 19
20#if defined(_MSC_VER) && defined(NDEBUG) 20#if defined(_MSC_VER) && defined(NDEBUG)
21#define LAMBDA_FORCEINLINE [[msvc::forceinline]] 21#define LAMBDA_FORCEINLINE [[msvc::forceinline]]
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 41d2b73f4..b909c387e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -32,7 +32,7 @@
32#include "video_core/renderer_opengl/maxwell_to_gl.h" 32#include "video_core/renderer_opengl/maxwell_to_gl.h"
33#include "video_core/renderer_opengl/renderer_opengl.h" 33#include "video_core/renderer_opengl/renderer_opengl.h"
34#include "video_core/shader_cache.h" 34#include "video_core/shader_cache.h"
35#include "video_core/texture_cache/texture_cache.h" 35#include "video_core/texture_cache/texture_cache_base.h"
36 36
37namespace OpenGL { 37namespace OpenGL {
38 38
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index c373c9cb4..b0aee6cc1 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -18,10 +18,8 @@
18#include "video_core/renderer_opengl/maxwell_to_gl.h" 18#include "video_core/renderer_opengl/maxwell_to_gl.h"
19#include "video_core/renderer_opengl/util_shaders.h" 19#include "video_core/renderer_opengl/util_shaders.h"
20#include "video_core/surface.h" 20#include "video_core/surface.h"
21#include "video_core/texture_cache/format_lookup_table.h" 21#include "video_core/texture_cache/formatter.h"
22#include "video_core/texture_cache/samples_helper.h" 22#include "video_core/texture_cache/samples_helper.h"
23#include "video_core/texture_cache/texture_cache.h"
24#include "video_core/textures/decoders.h"
25 23
26namespace OpenGL { 24namespace OpenGL {
27namespace { 25namespace {
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 921072ebe..4a4f6301c 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -12,7 +12,7 @@
12#include "shader_recompiler/shader_info.h" 12#include "shader_recompiler/shader_info.h"
13#include "video_core/renderer_opengl/gl_resource_manager.h" 13#include "video_core/renderer_opengl/gl_resource_manager.h"
14#include "video_core/renderer_opengl/util_shaders.h" 14#include "video_core/renderer_opengl/util_shaders.h"
15#include "video_core/texture_cache/texture_cache.h" 15#include "video_core/texture_cache/texture_cache_base.h"
16 16
17namespace OpenGL { 17namespace OpenGL {
18 18
diff --git a/src/video_core/renderer_opengl/gl_texture_cache_base.cpp b/src/video_core/renderer_opengl/gl_texture_cache_base.cpp
new file mode 100644
index 000000000..385358fea
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_texture_cache_base.cpp
@@ -0,0 +1,10 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "video_core/renderer_opengl/gl_texture_cache.h"
6#include "video_core/texture_cache/texture_cache.h"
7
8namespace VideoCommon {
9template class VideoCommon::TextureCache<OpenGL::TextureCacheParams>;
10}
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp
index 37a4d1d9d..333f35a1c 100644
--- a/src/video_core/renderer_opengl/util_shaders.cpp
+++ b/src/video_core/renderer_opengl/util_shaders.cpp
@@ -60,19 +60,14 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
60 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { 60 copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) {
61 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); 61 const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
62 swizzle_table_buffer.Create(); 62 swizzle_table_buffer.Create();
63 astc_buffer.Create();
64 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0); 63 glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
65 glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_ENCODINGS_VALUES), &ASTC_ENCODINGS_VALUES,
66 0);
67} 64}
68 65
69UtilShaders::~UtilShaders() = default; 66UtilShaders::~UtilShaders() = default;
70 67
71void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map, 68void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
72 std::span<const VideoCommon::SwizzleParameters> swizzles) { 69 std::span<const VideoCommon::SwizzleParameters> swizzles) {
73 static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0; 70 static constexpr GLuint BINDING_INPUT_BUFFER = 0;
74 static constexpr GLuint BINDING_INPUT_BUFFER = 1;
75 static constexpr GLuint BINDING_ENC_BUFFER = 2;
76 static constexpr GLuint BINDING_OUTPUT_IMAGE = 0; 71 static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
77 72
78 const Extent2D tile_size{ 73 const Extent2D tile_size{
@@ -80,34 +75,32 @@ void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
80 .height = VideoCore::Surface::DefaultBlockHeight(image.info.format), 75 .height = VideoCore::Surface::DefaultBlockHeight(image.info.format),
81 }; 76 };
82 program_manager.BindComputeProgram(astc_decoder_program.handle); 77 program_manager.BindComputeProgram(astc_decoder_program.handle);
83 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
84 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle);
85
86 glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes); 78 glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
87 glUniform2ui(1, tile_size.width, tile_size.height); 79 glUniform2ui(1, tile_size.width, tile_size.height);
80
88 // Ensure buffer data is valid before dispatching 81 // Ensure buffer data is valid before dispatching
89 glFlush(); 82 glFlush();
90 for (const SwizzleParameters& swizzle : swizzles) { 83 for (const SwizzleParameters& swizzle : swizzles) {
91 const size_t input_offset = swizzle.buffer_offset + map.offset; 84 const size_t input_offset = swizzle.buffer_offset + map.offset;
92 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U); 85 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U);
93 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U); 86 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
94 87
95 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info); 88 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
96 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0})); 89 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
97 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0})); 90 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
91 ASSERT(params.bytes_per_block_log2 == 4);
98 92
99 glUniform1ui(2, params.bytes_per_block_log2); 93 glUniform1ui(2, params.layer_stride);
100 glUniform1ui(3, params.layer_stride); 94 glUniform1ui(3, params.block_size);
101 glUniform1ui(4, params.block_size); 95 glUniform1ui(4, params.x_shift);
102 glUniform1ui(5, params.x_shift); 96 glUniform1ui(5, params.block_height);
103 glUniform1ui(6, params.block_height); 97 glUniform1ui(6, params.block_height_mask);
104 glUniform1ui(7, params.block_height_mask);
105 98
106 glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
107 GL_WRITE_ONLY, GL_RGBA8);
108 // ASTC texture data 99 // ASTC texture data
109 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset, 100 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset,
110 image.guest_size_bytes - swizzle.buffer_offset); 101 image.guest_size_bytes - swizzle.buffer_offset);
102 glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
103 GL_WRITE_ONLY, GL_RGBA8);
111 104
112 glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers); 105 glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
113 } 106 }
diff --git a/src/video_core/renderer_opengl/util_shaders.h b/src/video_core/renderer_opengl/util_shaders.h
index 53d65f368..ef881e35f 100644
--- a/src/video_core/renderer_opengl/util_shaders.h
+++ b/src/video_core/renderer_opengl/util_shaders.h
@@ -62,7 +62,6 @@ private:
62 ProgramManager& program_manager; 62 ProgramManager& program_manager;
63 63
64 OGLBuffer swizzle_table_buffer; 64 OGLBuffer swizzle_table_buffer;
65 OGLBuffer astc_buffer;
66 65
67 OGLProgram astc_decoder_program; 66 OGLProgram astc_decoder_program;
68 OGLProgram block_linear_unswizzle_2d_program; 67 OGLProgram block_linear_unswizzle_2d_program;
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 561cf5e11..3e96c0f60 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -30,16 +30,12 @@
30namespace Vulkan { 30namespace Vulkan {
31 31
32using Tegra::Texture::SWIZZLE_TABLE; 32using Tegra::Texture::SWIZZLE_TABLE;
33using Tegra::Texture::ASTC::ASTC_ENCODINGS_VALUES;
34using namespace Tegra::Texture::ASTC;
35 33
36namespace { 34namespace {
37 35
38constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0; 36constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
39constexpr u32 ASTC_BINDING_ENC_BUFFER = 1; 37constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 1;
40constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 2; 38constexpr size_t ASTC_NUM_BINDINGS = 2;
41constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 3;
42constexpr size_t ASTC_NUM_BINDINGS = 4;
43 39
44template <size_t size> 40template <size_t size>
45inline constexpr VkPushConstantRange COMPUTE_PUSH_CONSTANT_RANGE{ 41inline constexpr VkPushConstantRange COMPUTE_PUSH_CONSTANT_RANGE{
@@ -75,7 +71,7 @@ constexpr DescriptorBankInfo INPUT_OUTPUT_BANK_INFO{
75 .score = 2, 71 .score = 2,
76}; 72};
77 73
78constexpr std::array<VkDescriptorSetLayoutBinding, 4> ASTC_DESCRIPTOR_SET_BINDINGS{{ 74constexpr std::array<VkDescriptorSetLayoutBinding, ASTC_NUM_BINDINGS> ASTC_DESCRIPTOR_SET_BINDINGS{{
79 { 75 {
80 .binding = ASTC_BINDING_INPUT_BUFFER, 76 .binding = ASTC_BINDING_INPUT_BUFFER,
81 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 77 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
@@ -84,20 +80,6 @@ constexpr std::array<VkDescriptorSetLayoutBinding, 4> ASTC_DESCRIPTOR_SET_BINDIN
84 .pImmutableSamplers = nullptr, 80 .pImmutableSamplers = nullptr,
85 }, 81 },
86 { 82 {
87 .binding = ASTC_BINDING_ENC_BUFFER,
88 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
89 .descriptorCount = 1,
90 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
91 .pImmutableSamplers = nullptr,
92 },
93 {
94 .binding = ASTC_BINDING_SWIZZLE_BUFFER,
95 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
96 .descriptorCount = 1,
97 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
98 .pImmutableSamplers = nullptr,
99 },
100 {
101 .binding = ASTC_BINDING_OUTPUT_IMAGE, 83 .binding = ASTC_BINDING_OUTPUT_IMAGE,
102 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 84 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
103 .descriptorCount = 1, 85 .descriptorCount = 1,
@@ -108,12 +90,12 @@ constexpr std::array<VkDescriptorSetLayoutBinding, 4> ASTC_DESCRIPTOR_SET_BINDIN
108 90
109constexpr DescriptorBankInfo ASTC_BANK_INFO{ 91constexpr DescriptorBankInfo ASTC_BANK_INFO{
110 .uniform_buffers = 0, 92 .uniform_buffers = 0,
111 .storage_buffers = 3, 93 .storage_buffers = 1,
112 .texture_buffers = 0, 94 .texture_buffers = 0,
113 .image_buffers = 0, 95 .image_buffers = 0,
114 .textures = 0, 96 .textures = 0,
115 .images = 1, 97 .images = 1,
116 .score = 4, 98 .score = 2,
117}; 99};
118 100
119constexpr VkDescriptorUpdateTemplateEntryKHR INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{ 101constexpr VkDescriptorUpdateTemplateEntryKHR INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{
@@ -136,22 +118,6 @@ constexpr std::array<VkDescriptorUpdateTemplateEntryKHR, ASTC_NUM_BINDINGS>
136 .stride = sizeof(DescriptorUpdateEntry), 118 .stride = sizeof(DescriptorUpdateEntry),
137 }, 119 },
138 { 120 {
139 .dstBinding = ASTC_BINDING_ENC_BUFFER,
140 .dstArrayElement = 0,
141 .descriptorCount = 1,
142 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
143 .offset = ASTC_BINDING_ENC_BUFFER * sizeof(DescriptorUpdateEntry),
144 .stride = sizeof(DescriptorUpdateEntry),
145 },
146 {
147 .dstBinding = ASTC_BINDING_SWIZZLE_BUFFER,
148 .dstArrayElement = 0,
149 .descriptorCount = 1,
150 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
151 .offset = ASTC_BINDING_SWIZZLE_BUFFER * sizeof(DescriptorUpdateEntry),
152 .stride = sizeof(DescriptorUpdateEntry),
153 },
154 {
155 .dstBinding = ASTC_BINDING_OUTPUT_IMAGE, 121 .dstBinding = ASTC_BINDING_OUTPUT_IMAGE,
156 .dstArrayElement = 0, 122 .dstArrayElement = 0,
157 .descriptorCount = 1, 123 .descriptorCount = 1,
@@ -163,7 +129,6 @@ constexpr std::array<VkDescriptorUpdateTemplateEntryKHR, ASTC_NUM_BINDINGS>
163 129
164struct AstcPushConstants { 130struct AstcPushConstants {
165 std::array<u32, 2> blocks_dims; 131 std::array<u32, 2> blocks_dims;
166 u32 bytes_per_block_log2;
167 u32 layer_stride; 132 u32 layer_stride;
168 u32 block_size; 133 u32 block_size;
169 u32 x_shift; 134 u32 x_shift;
@@ -354,46 +319,6 @@ ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
354 319
355ASTCDecoderPass::~ASTCDecoderPass() = default; 320ASTCDecoderPass::~ASTCDecoderPass() = default;
356 321
357void ASTCDecoderPass::MakeDataBuffer() {
358 constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_ENCODINGS_VALUES) + sizeof(SWIZZLE_TABLE);
359 data_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
360 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
361 .pNext = nullptr,
362 .flags = 0,
363 .size = TOTAL_BUFFER_SIZE,
364 .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
365 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
366 .queueFamilyIndexCount = 0,
367 .pQueueFamilyIndices = nullptr,
368 });
369 data_buffer_commit = memory_allocator.Commit(data_buffer, MemoryUsage::Upload);
370
371 const auto staging_ref = staging_buffer_pool.Request(TOTAL_BUFFER_SIZE, MemoryUsage::Upload);
372 std::memcpy(staging_ref.mapped_span.data(), &ASTC_ENCODINGS_VALUES,
373 sizeof(ASTC_ENCODINGS_VALUES));
374 // Tack on the swizzle table at the end of the buffer
375 std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_ENCODINGS_VALUES), &SWIZZLE_TABLE,
376 sizeof(SWIZZLE_TABLE));
377
378 scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
379 TOTAL_BUFFER_SIZE](vk::CommandBuffer cmdbuf) {
380 static constexpr VkMemoryBarrier write_barrier{
381 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
382 .pNext = nullptr,
383 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
384 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
385 };
386 const VkBufferCopy copy{
387 .srcOffset = offset,
388 .dstOffset = 0,
389 .size = TOTAL_BUFFER_SIZE,
390 };
391 cmdbuf.CopyBuffer(src, dst, copy);
392 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
393 0, write_barrier);
394 });
395}
396
397void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, 322void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
398 std::span<const VideoCommon::SwizzleParameters> swizzles) { 323 std::span<const VideoCommon::SwizzleParameters> swizzles) {
399 using namespace VideoCommon::Accelerated; 324 using namespace VideoCommon::Accelerated;
@@ -402,9 +327,6 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
402 VideoCore::Surface::DefaultBlockHeight(image.info.format), 327 VideoCore::Surface::DefaultBlockHeight(image.info.format),
403 }; 328 };
404 scheduler.RequestOutsideRenderPassOperationContext(); 329 scheduler.RequestOutsideRenderPassOperationContext();
405 if (!data_buffer) {
406 MakeDataBuffer();
407 }
408 const VkPipeline vk_pipeline = *pipeline; 330 const VkPipeline vk_pipeline = *pipeline;
409 const VkImageAspectFlags aspect_mask = image.AspectMask(); 331 const VkImageAspectFlags aspect_mask = image.AspectMask();
410 const VkImage vk_image = image.Handle(); 332 const VkImage vk_image = image.Handle();
@@ -436,16 +358,13 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
436 }); 358 });
437 for (const VideoCommon::SwizzleParameters& swizzle : swizzles) { 359 for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
438 const size_t input_offset = swizzle.buffer_offset + map.offset; 360 const size_t input_offset = swizzle.buffer_offset + map.offset;
439 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U); 361 const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U);
440 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U); 362 const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
441 const u32 num_dispatches_z = image.info.resources.layers; 363 const u32 num_dispatches_z = image.info.resources.layers;
442 364
443 update_descriptor_queue.Acquire(); 365 update_descriptor_queue.Acquire();
444 update_descriptor_queue.AddBuffer(map.buffer, input_offset, 366 update_descriptor_queue.AddBuffer(map.buffer, input_offset,
445 image.guest_size_bytes - swizzle.buffer_offset); 367 image.guest_size_bytes - swizzle.buffer_offset);
446 update_descriptor_queue.AddBuffer(*data_buffer, 0, sizeof(ASTC_ENCODINGS_VALUES));
447 update_descriptor_queue.AddBuffer(*data_buffer, sizeof(ASTC_ENCODINGS_VALUES),
448 sizeof(SWIZZLE_TABLE));
449 update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level)); 368 update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
450 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 369 const void* const descriptor_data{update_descriptor_queue.UpdateData()};
451 370
@@ -453,11 +372,11 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
453 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info); 372 const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
454 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0})); 373 ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
455 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0})); 374 ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
375 ASSERT(params.bytes_per_block_log2 == 4);
456 scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims, 376 scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims,
457 params, descriptor_data](vk::CommandBuffer cmdbuf) { 377 params, descriptor_data](vk::CommandBuffer cmdbuf) {
458 const AstcPushConstants uniforms{ 378 const AstcPushConstants uniforms{
459 .blocks_dims = block_dims, 379 .blocks_dims = block_dims,
460 .bytes_per_block_log2 = params.bytes_per_block_log2,
461 .layer_stride = params.layer_stride, 380 .layer_stride = params.layer_stride,
462 .block_size = params.block_size, 381 .block_size = params.block_size,
463 .x_shift = params.x_shift, 382 .x_shift = params.x_shift,
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index 114aef2bd..c7b92cce0 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -96,15 +96,10 @@ public:
96 std::span<const VideoCommon::SwizzleParameters> swizzles); 96 std::span<const VideoCommon::SwizzleParameters> swizzles);
97 97
98private: 98private:
99 void MakeDataBuffer();
100
101 VKScheduler& scheduler; 99 VKScheduler& scheduler;
102 StagingBufferPool& staging_buffer_pool; 100 StagingBufferPool& staging_buffer_pool;
103 VKUpdateDescriptorQueue& update_descriptor_queue; 101 VKUpdateDescriptorQueue& update_descriptor_queue;
104 MemoryAllocator& memory_allocator; 102 MemoryAllocator& memory_allocator;
105
106 vk::Buffer data_buffer;
107 MemoryCommit data_buffer_commit;
108}; 103};
109 104
110} // namespace Vulkan 105} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 23cef2996..3ac18ea54 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -32,7 +32,7 @@
32#include "video_core/renderer_vulkan/vk_texture_cache.h" 32#include "video_core/renderer_vulkan/vk_texture_cache.h"
33#include "video_core/renderer_vulkan/vk_update_descriptor.h" 33#include "video_core/renderer_vulkan/vk_update_descriptor.h"
34#include "video_core/shader_cache.h" 34#include "video_core/shader_cache.h"
35#include "video_core/texture_cache/texture_cache.h" 35#include "video_core/texture_cache/texture_cache_base.h"
36#include "video_core/vulkan_common/vulkan_device.h" 36#include "video_core/vulkan_common/vulkan_device.h"
37#include "video_core/vulkan_common/vulkan_wrapper.h" 37#include "video_core/vulkan_common/vulkan_wrapper.h"
38 38
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 8e029bcb3..8f4df7122 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -19,6 +19,8 @@
19#include "video_core/renderer_vulkan/vk_scheduler.h" 19#include "video_core/renderer_vulkan/vk_scheduler.h"
20#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 20#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
21#include "video_core/renderer_vulkan/vk_texture_cache.h" 21#include "video_core/renderer_vulkan/vk_texture_cache.h"
22#include "video_core/texture_cache/formatter.h"
23#include "video_core/texture_cache/samples_helper.h"
22#include "video_core/vulkan_common/vulkan_device.h" 24#include "video_core/vulkan_common/vulkan_device.h"
23#include "video_core/vulkan_common/vulkan_memory_allocator.h" 25#include "video_core/vulkan_common/vulkan_memory_allocator.h"
24#include "video_core/vulkan_common/vulkan_wrapper.h" 26#include "video_core/vulkan_common/vulkan_wrapper.h"
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 0b73d55f8..5fe6b7ba3 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -9,7 +9,7 @@
9 9
10#include "shader_recompiler/shader_info.h" 10#include "shader_recompiler/shader_info.h"
11#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 11#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
12#include "video_core/texture_cache/texture_cache.h" 12#include "video_core/texture_cache/texture_cache_base.h"
13#include "video_core/vulkan_common/vulkan_memory_allocator.h" 13#include "video_core/vulkan_common/vulkan_memory_allocator.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache_base.cpp b/src/video_core/renderer_vulkan/vk_texture_cache_base.cpp
new file mode 100644
index 000000000..44e688342
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_texture_cache_base.cpp
@@ -0,0 +1,10 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "video_core/renderer_vulkan/vk_texture_cache.h"
6#include "video_core/texture_cache/texture_cache.h"
7
8namespace VideoCommon {
9template class VideoCommon::TextureCache<Vulkan::TextureCacheParams>;
10}
diff --git a/src/video_core/texture_cache/image_view_info.cpp b/src/video_core/texture_cache/image_view_info.cpp
index faf5b151f..6527e14c8 100644
--- a/src/video_core/texture_cache/image_view_info.cpp
+++ b/src/video_core/texture_cache/image_view_info.cpp
@@ -6,7 +6,7 @@
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "video_core/texture_cache/image_view_info.h" 8#include "video_core/texture_cache/image_view_info.h"
9#include "video_core/texture_cache/texture_cache.h" 9#include "video_core/texture_cache/texture_cache_base.h"
10#include "video_core/texture_cache/types.h" 10#include "video_core/texture_cache/types.h"
11#include "video_core/textures/texture.h" 11#include "video_core/textures/texture.h"
12 12
@@ -14,6 +14,8 @@ namespace VideoCommon {
14 14
15namespace { 15namespace {
16 16
17using Tegra::Texture::TextureType;
18
17constexpr u8 RENDER_TARGET_SWIZZLE = std::numeric_limits<u8>::max(); 19constexpr u8 RENDER_TARGET_SWIZZLE = std::numeric_limits<u8>::max();
18 20
19[[nodiscard]] u8 CastSwizzle(SwizzleSource source) { 21[[nodiscard]] u8 CastSwizzle(SwizzleSource source) {
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index f34c9d9ca..a087498ff 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -4,48 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
8#include <array>
9#include <bit>
10#include <memory>
11#include <mutex>
12#include <optional>
13#include <span>
14#include <type_traits>
15#include <unordered_map>
16#include <unordered_set>
17#include <utility>
18#include <vector>
19
20#include <boost/container/small_vector.hpp>
21
22#include "common/alignment.h" 7#include "common/alignment.h"
23#include "common/common_types.h"
24#include "common/literals.h"
25#include "common/logging/log.h"
26#include "common/settings.h" 8#include "common/settings.h"
27#include "video_core/compatible_formats.h"
28#include "video_core/delayed_destruction_ring.h"
29#include "video_core/dirty_flags.h" 9#include "video_core/dirty_flags.h"
30#include "video_core/engines/fermi_2d.h"
31#include "video_core/engines/kepler_compute.h"
32#include "video_core/engines/maxwell_3d.h"
33#include "video_core/memory_manager.h"
34#include "video_core/rasterizer_interface.h"
35#include "video_core/surface.h"
36#include "video_core/texture_cache/descriptor_table.h"
37#include "video_core/texture_cache/format_lookup_table.h"
38#include "video_core/texture_cache/formatter.h"
39#include "video_core/texture_cache/image_base.h"
40#include "video_core/texture_cache/image_info.h"
41#include "video_core/texture_cache/image_view_base.h"
42#include "video_core/texture_cache/image_view_info.h"
43#include "video_core/texture_cache/render_targets.h"
44#include "video_core/texture_cache/samples_helper.h" 10#include "video_core/texture_cache/samples_helper.h"
45#include "video_core/texture_cache/slot_vector.h" 11#include "video_core/texture_cache/texture_cache_base.h"
46#include "video_core/texture_cache/types.h"
47#include "video_core/texture_cache/util.h"
48#include "video_core/textures/texture.h"
49 12
50namespace VideoCommon { 13namespace VideoCommon {
51 14
@@ -62,352 +25,6 @@ using VideoCore::Surface::SurfaceType;
62using namespace Common::Literals; 25using namespace Common::Literals;
63 26
64template <class P> 27template <class P>
65class TextureCache {
66 /// Address shift for caching images into a hash table
67 static constexpr u64 PAGE_BITS = 20;
68
69 /// Enables debugging features to the texture cache
70 static constexpr bool ENABLE_VALIDATION = P::ENABLE_VALIDATION;
71 /// Implement blits as copies between framebuffers
72 static constexpr bool FRAMEBUFFER_BLITS = P::FRAMEBUFFER_BLITS;
73 /// True when some copies have to be emulated
74 static constexpr bool HAS_EMULATED_COPIES = P::HAS_EMULATED_COPIES;
75 /// True when the API can provide info about the memory of the device.
76 static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
77
78 /// Image view ID for null descriptors
79 static constexpr ImageViewId NULL_IMAGE_VIEW_ID{0};
80 /// Sampler ID for bugged sampler ids
81 static constexpr SamplerId NULL_SAMPLER_ID{0};
82
83 static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
84 static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
85
86 using Runtime = typename P::Runtime;
87 using Image = typename P::Image;
88 using ImageAlloc = typename P::ImageAlloc;
89 using ImageView = typename P::ImageView;
90 using Sampler = typename P::Sampler;
91 using Framebuffer = typename P::Framebuffer;
92
93 struct BlitImages {
94 ImageId dst_id;
95 ImageId src_id;
96 PixelFormat dst_format;
97 PixelFormat src_format;
98 };
99
100 template <typename T>
101 struct IdentityHash {
102 [[nodiscard]] size_t operator()(T value) const noexcept {
103 return static_cast<size_t>(value);
104 }
105 };
106
107public:
108 explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&, Tegra::Engines::Maxwell3D&,
109 Tegra::Engines::KeplerCompute&, Tegra::MemoryManager&);
110
111 /// Notify the cache that a new frame has been queued
112 void TickFrame();
113
114 /// Return a constant reference to the given image view id
115 [[nodiscard]] const ImageView& GetImageView(ImageViewId id) const noexcept;
116
117 /// Return a reference to the given image view id
118 [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept;
119
120 /// Mark an image as modified from the GPU
121 void MarkModification(ImageId id) noexcept;
122
123 /// Fill image_view_ids with the graphics images in indices
124 void FillGraphicsImageViews(std::span<const u32> indices,
125 std::span<ImageViewId> image_view_ids);
126
127 /// Fill image_view_ids with the compute images in indices
128 void FillComputeImageViews(std::span<const u32> indices, std::span<ImageViewId> image_view_ids);
129
130 /// Get the sampler from the graphics descriptor table in the specified index
131 Sampler* GetGraphicsSampler(u32 index);
132
133 /// Get the sampler from the compute descriptor table in the specified index
134 Sampler* GetComputeSampler(u32 index);
135
136 /// Refresh the state for graphics image view and sampler descriptors
137 void SynchronizeGraphicsDescriptors();
138
139 /// Refresh the state for compute image view and sampler descriptors
140 void SynchronizeComputeDescriptors();
141
142 /// Update bound render targets and upload memory if necessary
143 /// @param is_clear True when the render targets are being used for clears
144 void UpdateRenderTargets(bool is_clear);
145
146 /// Find a framebuffer with the currently bound render targets
147 /// UpdateRenderTargets should be called before this
148 Framebuffer* GetFramebuffer();
149
150 /// Mark images in a range as modified from the CPU
151 void WriteMemory(VAddr cpu_addr, size_t size);
152
153 /// Download contents of host images to guest memory in a region
154 void DownloadMemory(VAddr cpu_addr, size_t size);
155
156 /// Remove images in a region
157 void UnmapMemory(VAddr cpu_addr, size_t size);
158
159 /// Remove images in a region
160 void UnmapGPUMemory(GPUVAddr gpu_addr, size_t size);
161
162 /// Blit an image with the given parameters
163 void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
164 const Tegra::Engines::Fermi2D::Surface& src,
165 const Tegra::Engines::Fermi2D::Config& copy);
166
167 /// Invalidate the contents of the color buffer index
168 /// These contents become unspecified, the cache can assume aggressive optimizations.
169 void InvalidateColorBuffer(size_t index);
170
171 /// Invalidate the contents of the depth buffer
172 /// These contents become unspecified, the cache can assume aggressive optimizations.
173 void InvalidateDepthBuffer();
174
175 /// Try to find a cached image view in the given CPU address
176 [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr);
177
178 /// Return true when there are uncommitted images to be downloaded
179 [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
180
181 /// Return true when the caller should wait for async downloads
182 [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
183
184 /// Commit asynchronous downloads
185 void CommitAsyncFlushes();
186
187 /// Pop asynchronous downloads
188 void PopAsyncFlushes();
189
190 /// Return true when a CPU region is modified from the GPU
191 [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
192
193 std::mutex mutex;
194
195private:
196 /// Iterate over all page indices in a range
197 template <typename Func>
198 static void ForEachCPUPage(VAddr addr, size_t size, Func&& func) {
199 static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
200 const u64 page_end = (addr + size - 1) >> PAGE_BITS;
201 for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
202 if constexpr (RETURNS_BOOL) {
203 if (func(page)) {
204 break;
205 }
206 } else {
207 func(page);
208 }
209 }
210 }
211
212 template <typename Func>
213 static void ForEachGPUPage(GPUVAddr addr, size_t size, Func&& func) {
214 static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
215 const u64 page_end = (addr + size - 1) >> PAGE_BITS;
216 for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
217 if constexpr (RETURNS_BOOL) {
218 if (func(page)) {
219 break;
220 }
221 } else {
222 func(page);
223 }
224 }
225 }
226
227 /// Runs the Garbage Collector.
228 void RunGarbageCollector();
229
230 /// Fills image_view_ids in the image views in indices
231 void FillImageViews(DescriptorTable<TICEntry>& table,
232 std::span<ImageViewId> cached_image_view_ids, std::span<const u32> indices,
233 std::span<ImageViewId> image_view_ids);
234
235 /// Find or create an image view in the guest descriptor table
236 ImageViewId VisitImageView(DescriptorTable<TICEntry>& table,
237 std::span<ImageViewId> cached_image_view_ids, u32 index);
238
239 /// Find or create a framebuffer with the given render target parameters
240 FramebufferId GetFramebufferId(const RenderTargets& key);
241
242 /// Refresh the contents (pixel data) of an image
243 void RefreshContents(Image& image, ImageId image_id);
244
245 /// Upload data from guest to an image
246 template <typename StagingBuffer>
247 void UploadImageContents(Image& image, StagingBuffer& staging_buffer);
248
249 /// Find or create an image view from a guest descriptor
250 [[nodiscard]] ImageViewId FindImageView(const TICEntry& config);
251
252 /// Create a new image view from a guest descriptor
253 [[nodiscard]] ImageViewId CreateImageView(const TICEntry& config);
254
255 /// Find or create an image from the given parameters
256 [[nodiscard]] ImageId FindOrInsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
257 RelaxedOptions options = RelaxedOptions{});
258
259 /// Find an image from the given parameters
260 [[nodiscard]] ImageId FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
261 RelaxedOptions options);
262
263 /// Create an image from the given parameters
264 [[nodiscard]] ImageId InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
265 RelaxedOptions options);
266
267 /// Create a new image and join perfectly matching existing images
268 /// Remove joined images from the cache
269 [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr);
270
271 /// Return a blit image pair from the given guest blit parameters
272 [[nodiscard]] BlitImages GetBlitImages(const Tegra::Engines::Fermi2D::Surface& dst,
273 const Tegra::Engines::Fermi2D::Surface& src);
274
275 /// Find or create a sampler from a guest descriptor sampler
276 [[nodiscard]] SamplerId FindSampler(const TSCEntry& config);
277
278 /// Find or create an image view for the given color buffer index
279 [[nodiscard]] ImageViewId FindColorBuffer(size_t index, bool is_clear);
280
281 /// Find or create an image view for the depth buffer
282 [[nodiscard]] ImageViewId FindDepthBuffer(bool is_clear);
283
284 /// Find or create a view for a render target with the given image parameters
285 [[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr,
286 bool is_clear);
287
288 /// Iterates over all the images in a region calling func
289 template <typename Func>
290 void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func);
291
292 template <typename Func>
293 void ForEachImageInRegionGPU(GPUVAddr gpu_addr, size_t size, Func&& func);
294
295 template <typename Func>
296 void ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func);
297
298 /// Iterates over all the images in a region calling func
299 template <typename Func>
300 void ForEachSparseSegment(ImageBase& image, Func&& func);
301
302 /// Find or create an image view in the given image with the passed parameters
303 [[nodiscard]] ImageViewId FindOrEmplaceImageView(ImageId image_id, const ImageViewInfo& info);
304
305 /// Register image in the page table
306 void RegisterImage(ImageId image);
307
308 /// Unregister image from the page table
309 void UnregisterImage(ImageId image);
310
311 /// Track CPU reads and writes for image
312 void TrackImage(ImageBase& image, ImageId image_id);
313
314 /// Stop tracking CPU reads and writes for image
315 void UntrackImage(ImageBase& image, ImageId image_id);
316
317 /// Delete image from the cache
318 void DeleteImage(ImageId image);
319
320 /// Remove image views references from the cache
321 void RemoveImageViewReferences(std::span<const ImageViewId> removed_views);
322
323 /// Remove framebuffers using the given image views from the cache
324 void RemoveFramebuffers(std::span<const ImageViewId> removed_views);
325
326 /// Mark an image as modified from the GPU
327 void MarkModification(ImageBase& image) noexcept;
328
329 /// Synchronize image aliases, copying data if needed
330 void SynchronizeAliases(ImageId image_id);
331
332 /// Prepare an image to be used
333 void PrepareImage(ImageId image_id, bool is_modification, bool invalidate);
334
335 /// Prepare an image view to be used
336 void PrepareImageView(ImageViewId image_view_id, bool is_modification, bool invalidate);
337
338 /// Execute copies from one image to the other, even if they are incompatible
339 void CopyImage(ImageId dst_id, ImageId src_id, std::span<const ImageCopy> copies);
340
341 /// Bind an image view as render target, downloading resources preemtively if needed
342 void BindRenderTarget(ImageViewId* old_id, ImageViewId new_id);
343
344 /// Create a render target from a given image and image view parameters
345 [[nodiscard]] std::pair<FramebufferId, ImageViewId> RenderTargetFromImage(
346 ImageId, const ImageViewInfo& view_info);
347
348 /// Returns true if the current clear parameters clear the whole image of a given image view
349 [[nodiscard]] bool IsFullClear(ImageViewId id);
350
351 Runtime& runtime;
352 VideoCore::RasterizerInterface& rasterizer;
353 Tegra::Engines::Maxwell3D& maxwell3d;
354 Tegra::Engines::KeplerCompute& kepler_compute;
355 Tegra::MemoryManager& gpu_memory;
356
357 DescriptorTable<TICEntry> graphics_image_table{gpu_memory};
358 DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory};
359 std::vector<SamplerId> graphics_sampler_ids;
360 std::vector<ImageViewId> graphics_image_view_ids;
361
362 DescriptorTable<TICEntry> compute_image_table{gpu_memory};
363 DescriptorTable<TSCEntry> compute_sampler_table{gpu_memory};
364 std::vector<SamplerId> compute_sampler_ids;
365 std::vector<ImageViewId> compute_image_view_ids;
366
367 RenderTargets render_targets;
368
369 std::unordered_map<TICEntry, ImageViewId> image_views;
370 std::unordered_map<TSCEntry, SamplerId> samplers;
371 std::unordered_map<RenderTargets, FramebufferId> framebuffers;
372
373 std::unordered_map<u64, std::vector<ImageMapId>, IdentityHash<u64>> page_table;
374 std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> gpu_page_table;
375 std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> sparse_page_table;
376
377 std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views;
378
379 VAddr virtual_invalid_space{};
380
381 bool has_deleted_images = false;
382 u64 total_used_memory = 0;
383 u64 minimum_memory;
384 u64 expected_memory;
385 u64 critical_memory;
386
387 SlotVector<Image> slot_images;
388 SlotVector<ImageMapView> slot_map_views;
389 SlotVector<ImageView> slot_image_views;
390 SlotVector<ImageAlloc> slot_image_allocs;
391 SlotVector<Sampler> slot_samplers;
392 SlotVector<Framebuffer> slot_framebuffers;
393
394 // TODO: This data structure is not optimal and it should be reworked
395 std::vector<ImageId> uncommitted_downloads;
396 std::queue<std::vector<ImageId>> committed_downloads;
397
398 static constexpr size_t TICKS_TO_DESTROY = 6;
399 DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images;
400 DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view;
401 DelayedDestructionRing<Framebuffer, TICKS_TO_DESTROY> sentenced_framebuffers;
402
403 std::unordered_map<GPUVAddr, ImageAllocId> image_allocs_table;
404
405 u64 modification_tick = 0;
406 u64 frame_tick = 0;
407 typename SlotVector<Image>::Iterator deletion_iterator;
408};
409
410template <class P>
411TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface& rasterizer_, 28TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface& rasterizer_,
412 Tegra::Engines::Maxwell3D& maxwell3d_, 29 Tegra::Engines::Maxwell3D& maxwell3d_,
413 Tegra::Engines::KeplerCompute& kepler_compute_, 30 Tegra::Engines::KeplerCompute& kepler_compute_,
@@ -821,40 +438,6 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
821} 438}
822 439
823template <class P> 440template <class P>
824void TextureCache<P>::InvalidateColorBuffer(size_t index) {
825 ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index];
826 color_buffer_id = FindColorBuffer(index, false);
827 if (!color_buffer_id) {
828 LOG_ERROR(HW_GPU, "Invalidating invalid color buffer in index={}", index);
829 return;
830 }
831 // When invalidating a color buffer, the old contents are no longer relevant
832 ImageView& color_buffer = slot_image_views[color_buffer_id];
833 Image& image = slot_images[color_buffer.image_id];
834 image.flags &= ~ImageFlagBits::CpuModified;
835 image.flags &= ~ImageFlagBits::GpuModified;
836
837 runtime.InvalidateColorBuffer(color_buffer, index);
838}
839
840template <class P>
841void TextureCache<P>::InvalidateDepthBuffer() {
842 ImageViewId& depth_buffer_id = render_targets.depth_buffer_id;
843 depth_buffer_id = FindDepthBuffer(false);
844 if (!depth_buffer_id) {
845 LOG_ERROR(HW_GPU, "Invalidating invalid depth buffer");
846 return;
847 }
848 // When invalidating the depth buffer, the old contents are no longer relevant
849 ImageBase& image = slot_images[slot_image_views[depth_buffer_id].image_id];
850 image.flags &= ~ImageFlagBits::CpuModified;
851 image.flags &= ~ImageFlagBits::GpuModified;
852
853 ImageView& depth_buffer = slot_image_views[depth_buffer_id];
854 runtime.InvalidateDepthBuffer(depth_buffer);
855}
856
857template <class P>
858typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_addr) { 441typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_addr) {
859 // TODO: Properly implement this 442 // TODO: Properly implement this
860 const auto it = page_table.find(cpu_addr >> PAGE_BITS); 443 const auto it = page_table.find(cpu_addr >> PAGE_BITS);
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
new file mode 100644
index 000000000..e4ae351cb
--- /dev/null
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -0,0 +1,385 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <mutex>
9#include <span>
10#include <type_traits>
11#include <unordered_map>
12#include <unordered_set>
13#include <vector>
14
15#include "common/common_types.h"
16#include "common/literals.h"
17#include "video_core/compatible_formats.h"
18#include "video_core/delayed_destruction_ring.h"
19#include "video_core/engines/fermi_2d.h"
20#include "video_core/engines/kepler_compute.h"
21#include "video_core/engines/maxwell_3d.h"
22#include "video_core/memory_manager.h"
23#include "video_core/rasterizer_interface.h"
24#include "video_core/surface.h"
25#include "video_core/texture_cache/descriptor_table.h"
26#include "video_core/texture_cache/image_base.h"
27#include "video_core/texture_cache/image_info.h"
28#include "video_core/texture_cache/image_view_info.h"
29#include "video_core/texture_cache/render_targets.h"
30#include "video_core/texture_cache/slot_vector.h"
31#include "video_core/texture_cache/types.h"
32#include "video_core/texture_cache/util.h"
33#include "video_core/textures/texture.h"
34
35namespace VideoCommon {
36
37using Tegra::Texture::SwizzleSource;
38using Tegra::Texture::TICEntry;
39using Tegra::Texture::TSCEntry;
40using VideoCore::Surface::GetFormatType;
41using VideoCore::Surface::IsCopyCompatible;
42using VideoCore::Surface::PixelFormat;
43using VideoCore::Surface::PixelFormatFromDepthFormat;
44using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
45using namespace Common::Literals;
46
47template <class P>
48class TextureCache {
49 /// Address shift for caching images into a hash table
50 static constexpr u64 PAGE_BITS = 20;
51
52 /// Enables debugging features to the texture cache
53 static constexpr bool ENABLE_VALIDATION = P::ENABLE_VALIDATION;
54 /// Implement blits as copies between framebuffers
55 static constexpr bool FRAMEBUFFER_BLITS = P::FRAMEBUFFER_BLITS;
56 /// True when some copies have to be emulated
57 static constexpr bool HAS_EMULATED_COPIES = P::HAS_EMULATED_COPIES;
58 /// True when the API can provide info about the memory of the device.
59 static constexpr bool HAS_DEVICE_MEMORY_INFO = P::HAS_DEVICE_MEMORY_INFO;
60
61 /// Image view ID for null descriptors
62 static constexpr ImageViewId NULL_IMAGE_VIEW_ID{0};
63 /// Sampler ID for bugged sampler ids
64 static constexpr SamplerId NULL_SAMPLER_ID{0};
65
66 static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
67 static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
68
69 using Runtime = typename P::Runtime;
70 using Image = typename P::Image;
71 using ImageAlloc = typename P::ImageAlloc;
72 using ImageView = typename P::ImageView;
73 using Sampler = typename P::Sampler;
74 using Framebuffer = typename P::Framebuffer;
75
76 struct BlitImages {
77 ImageId dst_id;
78 ImageId src_id;
79 PixelFormat dst_format;
80 PixelFormat src_format;
81 };
82
83 template <typename T>
84 struct IdentityHash {
85 [[nodiscard]] size_t operator()(T value) const noexcept {
86 return static_cast<size_t>(value);
87 }
88 };
89
90public:
91 explicit TextureCache(Runtime&, VideoCore::RasterizerInterface&, Tegra::Engines::Maxwell3D&,
92 Tegra::Engines::KeplerCompute&, Tegra::MemoryManager&);
93
94 /// Notify the cache that a new frame has been queued
95 void TickFrame();
96
97 /// Return a constant reference to the given image view id
98 [[nodiscard]] const ImageView& GetImageView(ImageViewId id) const noexcept;
99
100 /// Return a reference to the given image view id
101 [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept;
102
103 /// Mark an image as modified from the GPU
104 void MarkModification(ImageId id) noexcept;
105
106 /// Fill image_view_ids with the graphics images in indices
107 void FillGraphicsImageViews(std::span<const u32> indices,
108 std::span<ImageViewId> image_view_ids);
109
110 /// Fill image_view_ids with the compute images in indices
111 void FillComputeImageViews(std::span<const u32> indices, std::span<ImageViewId> image_view_ids);
112
113 /// Get the sampler from the graphics descriptor table in the specified index
114 Sampler* GetGraphicsSampler(u32 index);
115
116 /// Get the sampler from the compute descriptor table in the specified index
117 Sampler* GetComputeSampler(u32 index);
118
119 /// Refresh the state for graphics image view and sampler descriptors
120 void SynchronizeGraphicsDescriptors();
121
122 /// Refresh the state for compute image view and sampler descriptors
123 void SynchronizeComputeDescriptors();
124
125 /// Update bound render targets and upload memory if necessary
126 /// @param is_clear True when the render targets are being used for clears
127 void UpdateRenderTargets(bool is_clear);
128
129 /// Find a framebuffer with the currently bound render targets
130 /// UpdateRenderTargets should be called before this
131 Framebuffer* GetFramebuffer();
132
133 /// Mark images in a range as modified from the CPU
134 void WriteMemory(VAddr cpu_addr, size_t size);
135
136 /// Download contents of host images to guest memory in a region
137 void DownloadMemory(VAddr cpu_addr, size_t size);
138
139 /// Remove images in a region
140 void UnmapMemory(VAddr cpu_addr, size_t size);
141
142 /// Remove images in a region
143 void UnmapGPUMemory(GPUVAddr gpu_addr, size_t size);
144
145 /// Blit an image with the given parameters
146 void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
147 const Tegra::Engines::Fermi2D::Surface& src,
148 const Tegra::Engines::Fermi2D::Config& copy);
149
150 /// Try to find a cached image view in the given CPU address
151 [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr);
152
153 /// Return true when there are uncommitted images to be downloaded
154 [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
155
156 /// Return true when the caller should wait for async downloads
157 [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
158
159 /// Commit asynchronous downloads
160 void CommitAsyncFlushes();
161
162 /// Pop asynchronous downloads
163 void PopAsyncFlushes();
164
165 /// Return true when a CPU region is modified from the GPU
166 [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size);
167
168 std::mutex mutex;
169
170private:
171 /// Iterate over all page indices in a range
172 template <typename Func>
173 static void ForEachCPUPage(VAddr addr, size_t size, Func&& func) {
174 static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
175 const u64 page_end = (addr + size - 1) >> PAGE_BITS;
176 for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
177 if constexpr (RETURNS_BOOL) {
178 if (func(page)) {
179 break;
180 }
181 } else {
182 func(page);
183 }
184 }
185 }
186
187 template <typename Func>
188 static void ForEachGPUPage(GPUVAddr addr, size_t size, Func&& func) {
189 static constexpr bool RETURNS_BOOL = std::is_same_v<std::invoke_result<Func, u64>, bool>;
190 const u64 page_end = (addr + size - 1) >> PAGE_BITS;
191 for (u64 page = addr >> PAGE_BITS; page <= page_end; ++page) {
192 if constexpr (RETURNS_BOOL) {
193 if (func(page)) {
194 break;
195 }
196 } else {
197 func(page);
198 }
199 }
200 }
201
202 /// Runs the Garbage Collector.
203 void RunGarbageCollector();
204
205 /// Fills image_view_ids in the image views in indices
206 void FillImageViews(DescriptorTable<TICEntry>& table,
207 std::span<ImageViewId> cached_image_view_ids, std::span<const u32> indices,
208 std::span<ImageViewId> image_view_ids);
209
210 /// Find or create an image view in the guest descriptor table
211 ImageViewId VisitImageView(DescriptorTable<TICEntry>& table,
212 std::span<ImageViewId> cached_image_view_ids, u32 index);
213
214 /// Find or create a framebuffer with the given render target parameters
215 FramebufferId GetFramebufferId(const RenderTargets& key);
216
217 /// Refresh the contents (pixel data) of an image
218 void RefreshContents(Image& image, ImageId image_id);
219
220 /// Upload data from guest to an image
221 template <typename StagingBuffer>
222 void UploadImageContents(Image& image, StagingBuffer& staging_buffer);
223
224 /// Find or create an image view from a guest descriptor
225 [[nodiscard]] ImageViewId FindImageView(const TICEntry& config);
226
227 /// Create a new image view from a guest descriptor
228 [[nodiscard]] ImageViewId CreateImageView(const TICEntry& config);
229
230 /// Find or create an image from the given parameters
231 [[nodiscard]] ImageId FindOrInsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
232 RelaxedOptions options = RelaxedOptions{});
233
234 /// Find an image from the given parameters
235 [[nodiscard]] ImageId FindImage(const ImageInfo& info, GPUVAddr gpu_addr,
236 RelaxedOptions options);
237
238 /// Create an image from the given parameters
239 [[nodiscard]] ImageId InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
240 RelaxedOptions options);
241
242 /// Create a new image and join perfectly matching existing images
243 /// Remove joined images from the cache
244 [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr);
245
246 /// Return a blit image pair from the given guest blit parameters
247 [[nodiscard]] BlitImages GetBlitImages(const Tegra::Engines::Fermi2D::Surface& dst,
248 const Tegra::Engines::Fermi2D::Surface& src);
249
250 /// Find or create a sampler from a guest descriptor sampler
251 [[nodiscard]] SamplerId FindSampler(const TSCEntry& config);
252
253 /// Find or create an image view for the given color buffer index
254 [[nodiscard]] ImageViewId FindColorBuffer(size_t index, bool is_clear);
255
256 /// Find or create an image view for the depth buffer
257 [[nodiscard]] ImageViewId FindDepthBuffer(bool is_clear);
258
259 /// Find or create a view for a render target with the given image parameters
260 [[nodiscard]] ImageViewId FindRenderTargetView(const ImageInfo& info, GPUVAddr gpu_addr,
261 bool is_clear);
262
263 /// Iterates over all the images in a region calling func
264 template <typename Func>
265 void ForEachImageInRegion(VAddr cpu_addr, size_t size, Func&& func);
266
267 template <typename Func>
268 void ForEachImageInRegionGPU(GPUVAddr gpu_addr, size_t size, Func&& func);
269
270 template <typename Func>
271 void ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func);
272
273 /// Iterates over all the images in a region calling func
274 template <typename Func>
275 void ForEachSparseSegment(ImageBase& image, Func&& func);
276
277 /// Find or create an image view in the given image with the passed parameters
278 [[nodiscard]] ImageViewId FindOrEmplaceImageView(ImageId image_id, const ImageViewInfo& info);
279
280 /// Register image in the page table
281 void RegisterImage(ImageId image);
282
283 /// Unregister image from the page table
284 void UnregisterImage(ImageId image);
285
286 /// Track CPU reads and writes for image
287 void TrackImage(ImageBase& image, ImageId image_id);
288
289 /// Stop tracking CPU reads and writes for image
290 void UntrackImage(ImageBase& image, ImageId image_id);
291
292 /// Delete image from the cache
293 void DeleteImage(ImageId image);
294
295 /// Remove image views references from the cache
296 void RemoveImageViewReferences(std::span<const ImageViewId> removed_views);
297
298 /// Remove framebuffers using the given image views from the cache
299 void RemoveFramebuffers(std::span<const ImageViewId> removed_views);
300
301 /// Mark an image as modified from the GPU
302 void MarkModification(ImageBase& image) noexcept;
303
304 /// Synchronize image aliases, copying data if needed
305 void SynchronizeAliases(ImageId image_id);
306
307 /// Prepare an image to be used
308 void PrepareImage(ImageId image_id, bool is_modification, bool invalidate);
309
310 /// Prepare an image view to be used
311 void PrepareImageView(ImageViewId image_view_id, bool is_modification, bool invalidate);
312
313 /// Execute copies from one image to the other, even if they are incompatible
314 void CopyImage(ImageId dst_id, ImageId src_id, std::span<const ImageCopy> copies);
315
316 /// Bind an image view as render target, downloading resources preemtively if needed
317 void BindRenderTarget(ImageViewId* old_id, ImageViewId new_id);
318
319 /// Create a render target from a given image and image view parameters
320 [[nodiscard]] std::pair<FramebufferId, ImageViewId> RenderTargetFromImage(
321 ImageId, const ImageViewInfo& view_info);
322
323 /// Returns true if the current clear parameters clear the whole image of a given image view
324 [[nodiscard]] bool IsFullClear(ImageViewId id);
325
326 Runtime& runtime;
327 VideoCore::RasterizerInterface& rasterizer;
328 Tegra::Engines::Maxwell3D& maxwell3d;
329 Tegra::Engines::KeplerCompute& kepler_compute;
330 Tegra::MemoryManager& gpu_memory;
331
332 DescriptorTable<TICEntry> graphics_image_table{gpu_memory};
333 DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory};
334 std::vector<SamplerId> graphics_sampler_ids;
335 std::vector<ImageViewId> graphics_image_view_ids;
336
337 DescriptorTable<TICEntry> compute_image_table{gpu_memory};
338 DescriptorTable<TSCEntry> compute_sampler_table{gpu_memory};
339 std::vector<SamplerId> compute_sampler_ids;
340 std::vector<ImageViewId> compute_image_view_ids;
341
342 RenderTargets render_targets;
343
344 std::unordered_map<TICEntry, ImageViewId> image_views;
345 std::unordered_map<TSCEntry, SamplerId> samplers;
346 std::unordered_map<RenderTargets, FramebufferId> framebuffers;
347
348 std::unordered_map<u64, std::vector<ImageMapId>, IdentityHash<u64>> page_table;
349 std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> gpu_page_table;
350 std::unordered_map<u64, std::vector<ImageId>, IdentityHash<u64>> sparse_page_table;
351
352 std::unordered_map<ImageId, std::vector<ImageViewId>> sparse_views;
353
354 VAddr virtual_invalid_space{};
355
356 bool has_deleted_images = false;
357 u64 total_used_memory = 0;
358 u64 minimum_memory;
359 u64 expected_memory;
360 u64 critical_memory;
361
362 SlotVector<Image> slot_images;
363 SlotVector<ImageMapView> slot_map_views;
364 SlotVector<ImageView> slot_image_views;
365 SlotVector<ImageAlloc> slot_image_allocs;
366 SlotVector<Sampler> slot_samplers;
367 SlotVector<Framebuffer> slot_framebuffers;
368
369 // TODO: This data structure is not optimal and it should be reworked
370 std::vector<ImageId> uncommitted_downloads;
371 std::queue<std::vector<ImageId>> committed_downloads;
372
373 static constexpr size_t TICKS_TO_DESTROY = 6;
374 DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images;
375 DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view;
376 DelayedDestructionRing<Framebuffer, TICKS_TO_DESTROY> sentenced_framebuffers;
377
378 std::unordered_map<GPUVAddr, ImageAllocId> image_allocs_table;
379
380 u64 modification_tick = 0;
381 u64 frame_tick = 0;
382 typename SlotVector<Image>::Iterator deletion_iterator;
383};
384
385} // namespace VideoCommon
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
index 3ab500760..25161df1f 100644
--- a/src/video_core/textures/astc.cpp
+++ b/src/video_core/textures/astc.cpp
@@ -151,6 +151,76 @@ private:
151 const IntType& m_Bits; 151 const IntType& m_Bits;
152}; 152};
153 153
154enum class IntegerEncoding { JustBits, Quint, Trit };
155
156struct IntegerEncodedValue {
157 constexpr IntegerEncodedValue() = default;
158
159 constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
160 : encoding{encoding_}, num_bits{num_bits_} {}
161
162 constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
163 return encoding == other.encoding && num_bits == other.num_bits;
164 }
165
166 // Returns the number of bits required to encode num_vals values.
167 u32 GetBitLength(u32 num_vals) const {
168 u32 total_bits = num_bits * num_vals;
169 if (encoding == IntegerEncoding::Trit) {
170 total_bits += (num_vals * 8 + 4) / 5;
171 } else if (encoding == IntegerEncoding::Quint) {
172 total_bits += (num_vals * 7 + 2) / 3;
173 }
174 return total_bits;
175 }
176
177 IntegerEncoding encoding{};
178 u32 num_bits = 0;
179 u32 bit_value = 0;
180 union {
181 u32 quint_value = 0;
182 u32 trit_value;
183 };
184};
185
186// Returns a new instance of this struct that corresponds to the
187// can take no more than mav_value values
188static constexpr IntegerEncodedValue CreateEncoding(u32 mav_value) {
189 while (mav_value > 0) {
190 u32 check = mav_value + 1;
191
192 // Is mav_value a power of two?
193 if (!(check & (check - 1))) {
194 return IntegerEncodedValue(IntegerEncoding::JustBits, std::popcount(mav_value));
195 }
196
197 // Is mav_value of the type 3*2^n - 1?
198 if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
199 return IntegerEncodedValue(IntegerEncoding::Trit, std::popcount(check / 3 - 1));
200 }
201
202 // Is mav_value of the type 5*2^n - 1?
203 if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
204 return IntegerEncodedValue(IntegerEncoding::Quint, std::popcount(check / 5 - 1));
205 }
206
207 // Apparently it can't be represented with a bounded integer sequence...
208 // just iterate.
209 mav_value--;
210 }
211 return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
212}
213
214static constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
215 std::array<IntegerEncodedValue, 256> encodings{};
216 for (std::size_t i = 0; i < encodings.size(); ++i) {
217 encodings[i] = CreateEncoding(static_cast<u32>(i));
218 }
219 return encodings;
220}
221
222static constexpr std::array<IntegerEncodedValue, 256> ASTC_ENCODINGS_VALUES = MakeEncodedValues();
223
154namespace Tegra::Texture::ASTC { 224namespace Tegra::Texture::ASTC {
155using IntegerEncodedVector = boost::container::static_vector< 225using IntegerEncodedVector = boost::container::static_vector<
156 IntegerEncodedValue, 256, 226 IntegerEncodedValue, 256,
@@ -521,35 +591,41 @@ static TexelWeightParams DecodeBlockInfo(InputBitStream& strm) {
521 return params; 591 return params;
522} 592}
523 593
524static void FillVoidExtentLDR(InputBitStream& strm, std::span<u32> outBuf, u32 blockWidth, 594// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
525 u32 blockHeight) { 595// is the same as [(num_bits - 1):0] and repeats all the way down.
526 // Don't actually care about the void extent, just read the bits... 596template <typename IntType>
527 for (s32 i = 0; i < 4; ++i) { 597static constexpr IntType Replicate(IntType val, u32 num_bits, u32 to_bit) {
528 strm.ReadBits<13>(); 598 if (num_bits == 0 || to_bit == 0) {
599 return 0;
529 } 600 }
530 601 const IntType v = val & static_cast<IntType>((1 << num_bits) - 1);
531 // Decode the RGBA components and renormalize them to the range [0, 255] 602 IntType res = v;
532 u16 r = static_cast<u16>(strm.ReadBits<16>()); 603 u32 reslen = num_bits;
533 u16 g = static_cast<u16>(strm.ReadBits<16>()); 604 while (reslen < to_bit) {
534 u16 b = static_cast<u16>(strm.ReadBits<16>()); 605 u32 comp = 0;
535 u16 a = static_cast<u16>(strm.ReadBits<16>()); 606 if (num_bits > to_bit - reslen) {
536 607 u32 newshift = to_bit - reslen;
537 u32 rgba = (r >> 8) | (g & 0xFF00) | (static_cast<u32>(b) & 0xFF00) << 8 | 608 comp = num_bits - newshift;
538 (static_cast<u32>(a) & 0xFF00) << 16; 609 num_bits = newshift;
539
540 for (u32 j = 0; j < blockHeight; j++) {
541 for (u32 i = 0; i < blockWidth; i++) {
542 outBuf[j * blockWidth + i] = rgba;
543 } 610 }
611 res = static_cast<IntType>(res << num_bits);
612 res = static_cast<IntType>(res | (v >> comp));
613 reslen += num_bits;
544 } 614 }
615 return res;
545} 616}
546 617
547static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) { 618static constexpr std::size_t NumReplicateEntries(u32 num_bits) {
548 for (u32 j = 0; j < blockHeight; j++) { 619 return std::size_t(1) << num_bits;
549 for (u32 i = 0; i < blockWidth; i++) { 620}
550 outBuf[j * blockWidth + i] = 0xFFFF00FF; 621
551 } 622template <typename IntType, u32 num_bits, u32 to_bit>
623static constexpr auto MakeReplicateTable() {
624 std::array<IntType, NumReplicateEntries(num_bits)> table{};
625 for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
626 table[value] = Replicate(value, num_bits, to_bit);
552 } 627 }
628 return table;
553} 629}
554 630
555static constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>(); 631static constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
@@ -572,6 +648,9 @@ static constexpr auto REPLICATE_2_BIT_TO_8_TABLE = MakeReplicateTable<u32, 2, 8>
572static constexpr auto REPLICATE_3_BIT_TO_8_TABLE = MakeReplicateTable<u32, 3, 8>(); 648static constexpr auto REPLICATE_3_BIT_TO_8_TABLE = MakeReplicateTable<u32, 3, 8>();
573static constexpr auto REPLICATE_4_BIT_TO_8_TABLE = MakeReplicateTable<u32, 4, 8>(); 649static constexpr auto REPLICATE_4_BIT_TO_8_TABLE = MakeReplicateTable<u32, 4, 8>();
574static constexpr auto REPLICATE_5_BIT_TO_8_TABLE = MakeReplicateTable<u32, 5, 8>(); 650static constexpr auto REPLICATE_5_BIT_TO_8_TABLE = MakeReplicateTable<u32, 5, 8>();
651static constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
652static constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
653static constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
575/// Use a precompiled table with the most common usages, if it's not in the expected range, fallback 654/// Use a precompiled table with the most common usages, if it's not in the expected range, fallback
576/// to the runtime implementation 655/// to the runtime implementation
577static constexpr u32 FastReplicateTo8(u32 value, u32 num_bits) { 656static constexpr u32 FastReplicateTo8(u32 value, u32 num_bits) {
@@ -1316,6 +1395,37 @@ static void ComputeEndpoints(Pixel& ep1, Pixel& ep2, const u32*& colorValues,
1316#undef READ_INT_VALUES 1395#undef READ_INT_VALUES
1317} 1396}
1318 1397
1398static void FillVoidExtentLDR(InputBitStream& strm, std::span<u32> outBuf, u32 blockWidth,
1399 u32 blockHeight) {
1400 // Don't actually care about the void extent, just read the bits...
1401 for (s32 i = 0; i < 4; ++i) {
1402 strm.ReadBits<13>();
1403 }
1404
1405 // Decode the RGBA components and renormalize them to the range [0, 255]
1406 u16 r = static_cast<u16>(strm.ReadBits<16>());
1407 u16 g = static_cast<u16>(strm.ReadBits<16>());
1408 u16 b = static_cast<u16>(strm.ReadBits<16>());
1409 u16 a = static_cast<u16>(strm.ReadBits<16>());
1410
1411 u32 rgba = (r >> 8) | (g & 0xFF00) | (static_cast<u32>(b) & 0xFF00) << 8 |
1412 (static_cast<u32>(a) & 0xFF00) << 16;
1413
1414 for (u32 j = 0; j < blockHeight; j++) {
1415 for (u32 i = 0; i < blockWidth; i++) {
1416 outBuf[j * blockWidth + i] = rgba;
1417 }
1418 }
1419}
1420
1421static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) {
1422 for (u32 j = 0; j < blockHeight; j++) {
1423 for (u32 i = 0; i < blockWidth; i++) {
1424 outBuf[j * blockWidth + i] = 0xFFFF00FF;
1425 }
1426 }
1427}
1428
1319static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth, 1429static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
1320 const u32 blockHeight, std::span<u32, 12 * 12> outBuf) { 1430 const u32 blockHeight, std::span<u32, 12 * 12> outBuf) {
1321 InputBitStream strm(inBuf); 1431 InputBitStream strm(inBuf);
diff --git a/src/video_core/textures/astc.h b/src/video_core/textures/astc.h
index 0229ae122..14d2beec0 100644
--- a/src/video_core/textures/astc.h
+++ b/src/video_core/textures/astc.h
@@ -9,117 +9,6 @@
9 9
10namespace Tegra::Texture::ASTC { 10namespace Tegra::Texture::ASTC {
11 11
12enum class IntegerEncoding { JustBits, Quint, Trit };
13
14struct IntegerEncodedValue {
15 constexpr IntegerEncodedValue() = default;
16
17 constexpr IntegerEncodedValue(IntegerEncoding encoding_, u32 num_bits_)
18 : encoding{encoding_}, num_bits{num_bits_} {}
19
20 constexpr bool MatchesEncoding(const IntegerEncodedValue& other) const {
21 return encoding == other.encoding && num_bits == other.num_bits;
22 }
23
24 // Returns the number of bits required to encode num_vals values.
25 u32 GetBitLength(u32 num_vals) const {
26 u32 total_bits = num_bits * num_vals;
27 if (encoding == IntegerEncoding::Trit) {
28 total_bits += (num_vals * 8 + 4) / 5;
29 } else if (encoding == IntegerEncoding::Quint) {
30 total_bits += (num_vals * 7 + 2) / 3;
31 }
32 return total_bits;
33 }
34
35 IntegerEncoding encoding{};
36 u32 num_bits = 0;
37 u32 bit_value = 0;
38 union {
39 u32 quint_value = 0;
40 u32 trit_value;
41 };
42};
43
44// Returns a new instance of this struct that corresponds to the
45// can take no more than mav_value values
46constexpr IntegerEncodedValue CreateEncoding(u32 mav_value) {
47 while (mav_value > 0) {
48 u32 check = mav_value + 1;
49
50 // Is mav_value a power of two?
51 if (!(check & (check - 1))) {
52 return IntegerEncodedValue(IntegerEncoding::JustBits, std::popcount(mav_value));
53 }
54
55 // Is mav_value of the type 3*2^n - 1?
56 if ((check % 3 == 0) && !((check / 3) & ((check / 3) - 1))) {
57 return IntegerEncodedValue(IntegerEncoding::Trit, std::popcount(check / 3 - 1));
58 }
59
60 // Is mav_value of the type 5*2^n - 1?
61 if ((check % 5 == 0) && !((check / 5) & ((check / 5) - 1))) {
62 return IntegerEncodedValue(IntegerEncoding::Quint, std::popcount(check / 5 - 1));
63 }
64
65 // Apparently it can't be represented with a bounded integer sequence...
66 // just iterate.
67 mav_value--;
68 }
69 return IntegerEncodedValue(IntegerEncoding::JustBits, 0);
70}
71
72constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
73 std::array<IntegerEncodedValue, 256> encodings{};
74 for (std::size_t i = 0; i < encodings.size(); ++i) {
75 encodings[i] = CreateEncoding(static_cast<u32>(i));
76 }
77 return encodings;
78}
79
80constexpr std::array<IntegerEncodedValue, 256> ASTC_ENCODINGS_VALUES = MakeEncodedValues();
81
82// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
83// is the same as [(num_bits - 1):0] and repeats all the way down.
84template <typename IntType>
85constexpr IntType Replicate(IntType val, u32 num_bits, u32 to_bit) {
86 if (num_bits == 0 || to_bit == 0) {
87 return 0;
88 }
89 const IntType v = val & static_cast<IntType>((1 << num_bits) - 1);
90 IntType res = v;
91 u32 reslen = num_bits;
92 while (reslen < to_bit) {
93 u32 comp = 0;
94 if (num_bits > to_bit - reslen) {
95 u32 newshift = to_bit - reslen;
96 comp = num_bits - newshift;
97 num_bits = newshift;
98 }
99 res = static_cast<IntType>(res << num_bits);
100 res = static_cast<IntType>(res | (v >> comp));
101 reslen += num_bits;
102 }
103 return res;
104}
105
106constexpr std::size_t NumReplicateEntries(u32 num_bits) {
107 return std::size_t(1) << num_bits;
108}
109
110template <typename IntType, u32 num_bits, u32 to_bit>
111constexpr auto MakeReplicateTable() {
112 std::array<IntType, NumReplicateEntries(num_bits)> table{};
113 for (IntType value = 0; value < static_cast<IntType>(std::size(table)); ++value) {
114 table[value] = Replicate(value, num_bits, to_bit);
115 }
116 return table;
117}
118
119constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
120constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
121constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
122
123void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 12void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
124 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output); 13 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output);
125 14
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index aa173d19e..300a61205 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -228,7 +228,9 @@ void MemoryCommit::Release() {
228 228
229MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_) 229MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_)
230 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()}, 230 : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()},
231 export_allocations{export_allocations_} {} 231 export_allocations{export_allocations_},
232 buffer_image_granularity{
233 device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
232 234
233MemoryAllocator::~MemoryAllocator() = default; 235MemoryAllocator::~MemoryAllocator() = default;
234 236
@@ -258,7 +260,9 @@ MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage
258} 260}
259 261
260MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { 262MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) {
261 auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), usage); 263 VkMemoryRequirements requirements = device.GetLogical().GetImageMemoryRequirements(*image);
264 requirements.size = Common::AlignUp(requirements.size, buffer_image_granularity);
265 auto commit = Commit(requirements, usage);
262 image.BindMemory(commit.Memory(), commit.Offset()); 266 image.BindMemory(commit.Memory(), commit.Offset());
263 return commit; 267 return commit;
264} 268}
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h
index b61e931e0..86e8ed119 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.h
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h
@@ -123,6 +123,8 @@ private:
123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. 123 const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties.
124 const bool export_allocations; ///< True when memory allocations have to be exported. 124 const bool export_allocations; ///< True when memory allocations have to be exported.
125 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. 125 std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
126 VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
127 // and optimal images
126}; 128};
127 129
128/// Returns true when a memory usage is guaranteed to be host visible. 130/// Returns true when a memory usage is guaranteed to be host visible.