summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp135
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h40
-rw-r--r--src/video_core/textures/decoders.cpp6
3 files changed, 109 insertions, 72 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 9c8925383..591ec7998 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -78,6 +78,29 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
78 } 78 }
79} 79}
80 80
81std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
82 const u32 compression_factor{GetCompressionFactor(pixel_format)};
83 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
84 u32 m_depth = (layer_only ? 1U : depth);
85 u32 m_width = std::max(1U, width / compression_factor);
86 u32 m_height = std::max(1U, height / compression_factor);
87 std::size_t size = Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height,
88 m_depth, block_height, block_depth);
89 u32 m_block_height = block_height;
90 u32 m_block_depth = block_depth;
91 std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size
92 for (u32 i = 1; i < max_mip_level; i++) {
93 m_width = std::max(1U, m_width / 2);
94 m_height = std::max(1U, m_height / 2);
95 m_depth = std::max(1U, m_depth / 2);
96 m_block_height = std::max(1U, m_block_height / 2);
97 m_block_depth = std::max(1U, m_block_depth / 2);
98 size += Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, m_depth,
99 m_block_height, m_block_depth);
100 }
101 return is_tiled ? Common::AlignUp(size, block_size_bytes) : size;
102}
103
81/*static*/ SurfaceParams SurfaceParams::CreateForTexture( 104/*static*/ SurfaceParams SurfaceParams::CreateForTexture(
82 const Tegra::Texture::FullTextureInfo& config, const GLShader::SamplerEntry& entry) { 105 const Tegra::Texture::FullTextureInfo& config, const GLShader::SamplerEntry& entry) {
83 SurfaceParams params{}; 106 SurfaceParams params{};
@@ -124,6 +147,7 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
124 break; 147 break;
125 } 148 }
126 149
150 params.is_layered = SurfaceTargetIsLayered(params.target);
127 params.max_mip_level = config.tic.max_mip_level + 1; 151 params.max_mip_level = config.tic.max_mip_level + 1;
128 params.rt = {}; 152 params.rt = {};
129 153
@@ -150,6 +174,7 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
150 params.target = SurfaceTarget::Texture2D; 174 params.target = SurfaceTarget::Texture2D;
151 params.depth = 1; 175 params.depth = 1;
152 params.max_mip_level = 0; 176 params.max_mip_level = 0;
177 params.is_layered = false;
153 178
154 // Render target specific parameters, not used for caching 179 // Render target specific parameters, not used for caching
155 params.rt.index = static_cast<u32>(index); 180 params.rt.index = static_cast<u32>(index);
@@ -182,6 +207,7 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
182 params.target = SurfaceTarget::Texture2D; 207 params.target = SurfaceTarget::Texture2D;
183 params.depth = 1; 208 params.depth = 1;
184 params.max_mip_level = 0; 209 params.max_mip_level = 0;
210 params.is_layered = false;
185 params.rt = {}; 211 params.rt = {};
186 212
187 params.InitCacheParameters(zeta_address); 213 params.InitCacheParameters(zeta_address);
@@ -361,10 +387,11 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
361 } 387 }
362} 388}
363 389
364static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr), 390using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
365 SurfaceParams::MaxPixelFormat> 391 SurfaceParams::MaxPixelFormat>;
366 morton_to_gl_fns = { 392
367 // clang-format off 393static constexpr GLConversionArray morton_to_gl_fns = {
394 // clang-format off
368 MortonCopy<true, PixelFormat::ABGR8U>, 395 MortonCopy<true, PixelFormat::ABGR8U>,
369 MortonCopy<true, PixelFormat::ABGR8S>, 396 MortonCopy<true, PixelFormat::ABGR8S>,
370 MortonCopy<true, PixelFormat::ABGR8UI>, 397 MortonCopy<true, PixelFormat::ABGR8UI>,
@@ -418,13 +445,11 @@ static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t,
418 MortonCopy<true, PixelFormat::Z24S8>, 445 MortonCopy<true, PixelFormat::Z24S8>,
419 MortonCopy<true, PixelFormat::S8Z24>, 446 MortonCopy<true, PixelFormat::S8Z24>,
420 MortonCopy<true, PixelFormat::Z32FS8>, 447 MortonCopy<true, PixelFormat::Z32FS8>,
421 // clang-format on 448 // clang-format on
422}; 449};
423 450
424static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr), 451static constexpr GLConversionArray gl_to_morton_fns = {
425 SurfaceParams::MaxPixelFormat> 452 // clang-format off
426 gl_to_morton_fns = {
427 // clang-format off
428 MortonCopy<false, PixelFormat::ABGR8U>, 453 MortonCopy<false, PixelFormat::ABGR8U>,
429 MortonCopy<false, PixelFormat::ABGR8S>, 454 MortonCopy<false, PixelFormat::ABGR8S>,
430 MortonCopy<false, PixelFormat::ABGR8UI>, 455 MortonCopy<false, PixelFormat::ABGR8UI>,
@@ -479,9 +504,35 @@ static constexpr std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t,
479 MortonCopy<false, PixelFormat::Z24S8>, 504 MortonCopy<false, PixelFormat::Z24S8>,
480 MortonCopy<false, PixelFormat::S8Z24>, 505 MortonCopy<false, PixelFormat::S8Z24>,
481 MortonCopy<false, PixelFormat::Z32FS8>, 506 MortonCopy<false, PixelFormat::Z32FS8>,
482 // clang-format on 507 // clang-format on
483}; 508};
484 509
510void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
511 std::vector<u8>& gl_buffer) {
512 u32 depth = params.depth;
513 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
514 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
515 depth = 1U;
516 }
517 if (params.is_layered) {
518 u64 offset = 0;
519 u64 offset_gl = 0;
520 u64 layer_size = params.LayerMemorySize();
521 u64 gl_size = params.LayerSizeGL();
522 for (u32 i = 0; i < depth; i++) {
523 functions[static_cast<std::size_t>(params.pixel_format)](
524 params.width, params.block_height, params.height, params.block_depth, 1,
525 gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
526 offset += layer_size;
527 offset_gl += gl_size;
528 }
529 } else {
530 functions[static_cast<std::size_t>(params.pixel_format)](
531 params.width, params.block_height, params.height, params.block_depth, depth,
532 gl_buffer.data(), gl_buffer.size(), params.addr);
533 }
534}
535
485static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, 536static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
486 GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0, 537 GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
487 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { 538 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
@@ -881,21 +932,10 @@ void CachedSurface::LoadGLBuffer() {
881 932
882 gl_buffer.resize(params.size_in_bytes_gl); 933 gl_buffer.resize(params.size_in_bytes_gl);
883 if (params.is_tiled) { 934 if (params.is_tiled) {
884 u32 depth = params.depth;
885 u32 block_depth = params.block_depth;
886
887 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 935 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
888 params.block_width, static_cast<u32>(params.target)); 936 params.block_width, static_cast<u32>(params.target));
889 937
890 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { 938 SwizzleFunc(morton_to_gl_fns, params, gl_buffer);
891 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
892 depth = 1U;
893 block_depth = 1U;
894 }
895
896 morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)](
897 params.width, params.block_height, params.height, block_depth, depth, gl_buffer.data(),
898 gl_buffer.size(), params.addr);
899 } else { 939 } else {
900 const auto texture_src_data{Memory::GetPointer(params.addr)}; 940 const auto texture_src_data{Memory::GetPointer(params.addr)};
901 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; 941 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
@@ -929,19 +969,10 @@ void CachedSurface::FlushGLBuffer() {
929 const u8* const texture_src_data = Memory::GetPointer(params.addr); 969 const u8* const texture_src_data = Memory::GetPointer(params.addr);
930 ASSERT(texture_src_data); 970 ASSERT(texture_src_data);
931 if (params.is_tiled) { 971 if (params.is_tiled) {
932 u32 depth = params.depth;
933 u32 block_depth = params.block_depth;
934
935 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 972 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
936 params.block_width, static_cast<u32>(params.target)); 973 params.block_width, static_cast<u32>(params.target));
937 974
938 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { 975 SwizzleFunc(gl_to_morton_fns, params, gl_buffer);
939 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
940 depth = 1U;
941 }
942 gl_to_morton_fns[static_cast<size_t>(params.pixel_format)](
943 params.width, params.block_height, params.height, block_depth, depth, gl_buffer.data(),
944 gl_buffer.size(), GetAddr());
945 } else { 976 } else {
946 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes()); 977 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes());
947 } 978 }
@@ -1179,7 +1210,7 @@ void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface,
1179 const Surface& dst_surface) { 1210 const Surface& dst_surface) {
1180 const auto& src_params{src_surface->GetSurfaceParams()}; 1211 const auto& src_params{src_surface->GetSurfaceParams()};
1181 const auto& dst_params{dst_surface->GetSurfaceParams()}; 1212 const auto& dst_params{dst_surface->GetSurfaceParams()};
1182 FlushRegion(src_params.addr, dst_params.size_in_bytes); 1213 FlushRegion(src_params.addr, dst_params.MemorySize());
1183 LoadSurface(dst_surface); 1214 LoadSurface(dst_surface);
1184} 1215}
1185 1216
@@ -1221,44 +1252,10 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1221 CopySurface(old_surface, new_surface, copy_pbo.handle); 1252 CopySurface(old_surface, new_surface, copy_pbo.handle);
1222 } 1253 }
1223 break; 1254 break;
1255 case SurfaceParams::SurfaceTarget::TextureCubemap:
1224 case SurfaceParams::SurfaceTarget::Texture3D: 1256 case SurfaceParams::SurfaceTarget::Texture3D:
1225 AccurateCopySurface(old_surface, new_surface); 1257 AccurateCopySurface(old_surface, new_surface);
1226 break; 1258 break;
1227 case SurfaceParams::SurfaceTarget::TextureCubemap: {
1228 if (old_params.rt.array_mode != 1) {
1229 // TODO(bunnei): This is used by Breath of the Wild, I'm not sure how to implement this
1230 // yet (array rendering used as a cubemap texture).
1231 LOG_CRITICAL(HW_GPU, "Unhandled rendertarget array_mode {}", old_params.rt.array_mode);
1232 UNREACHABLE();
1233 return new_surface;
1234 }
1235
1236 // This seems to be used for render-to-cubemap texture
1237 ASSERT_MSG(old_params.target == SurfaceParams::SurfaceTarget::Texture2D, "Unexpected");
1238 ASSERT_MSG(old_params.pixel_format == new_params.pixel_format, "Unexpected");
1239 ASSERT_MSG(old_params.rt.base_layer == 0, "Unimplemented");
1240
1241 // TODO(bunnei): Verify the below - this stride seems to be in 32-bit words, not pixels.
1242 // Tested with Splatoon 2, Super Mario Odyssey, and Breath of the Wild.
1243 const std::size_t byte_stride{old_params.rt.layer_stride * sizeof(u32)};
1244
1245 for (std::size_t index = 0; index < new_params.depth; ++index) {
1246 Surface face_surface{TryGetReservedSurface(old_params)};
1247 ASSERT_MSG(face_surface, "Unexpected");
1248
1249 if (is_blit) {
1250 BlitSurface(face_surface, new_surface, read_framebuffer.handle,
1251 draw_framebuffer.handle, face_surface->GetSurfaceParams().rt.index,
1252 new_params.rt.index, index);
1253 } else {
1254 CopySurface(face_surface, new_surface, copy_pbo.handle,
1255 face_surface->GetSurfaceParams().rt.index, new_params.rt.index, index);
1256 }
1257
1258 old_params.addr += byte_stride;
1259 }
1260 break;
1261 }
1262 default: 1259 default:
1263 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 1260 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
1264 static_cast<u32>(new_params.target)); 1261 static_cast<u32>(new_params.target));
@@ -1266,7 +1263,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1266 } 1263 }
1267 1264
1268 return new_surface; 1265 return new_surface;
1269} 1266} // namespace OpenGL
1270 1267
1271Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const { 1268Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const {
1272 return TryGet(addr); 1269 return TryGet(addr);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 0dd0d90a3..50a7ab47d 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -168,6 +168,23 @@ struct SurfaceParams {
168 } 168 }
169 } 169 }
170 170
171 static bool SurfaceTargetIsLayered(SurfaceTarget target) {
172 switch (target) {
173 case SurfaceTarget::Texture1D:
174 case SurfaceTarget::Texture2D:
175 case SurfaceTarget::Texture3D:
176 return false;
177 case SurfaceTarget::Texture1DArray:
178 case SurfaceTarget::Texture2DArray:
179 case SurfaceTarget::TextureCubemap:
180 return true;
181 default:
182 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
183 UNREACHABLE();
184 return false;
185 }
186 }
187
171 /** 188 /**
172 * Gets the compression factor for the specified PixelFormat. This applies to just the 189 * Gets the compression factor for the specified PixelFormat. This applies to just the
173 * "compressed width" and "compressed height", not the overall compression factor of a 190 * "compressed width" and "compressed height", not the overall compression factor of a
@@ -742,6 +759,25 @@ struct SurfaceParams {
742 return size_in_bytes_gl / 6; 759 return size_in_bytes_gl / 6;
743 } 760 }
744 761
762 /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps.
763 std::size_t MemorySize() const {
764 std::size_t size = InnerMemorySize(is_layered);
765 if (is_layered)
766 return size * depth;
767 return size;
768 }
769
770 /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including
771 /// mipmaps.
772 std::size_t LayerMemorySize() const {
773 return InnerMemorySize(true);
774 }
775
776 /// Returns the size of a layer of this surface in OpenGL.
777 std::size_t LayerSizeGL() const {
778 return SizeInBytesRaw(true) / depth;
779 }
780
745 /// Creates SurfaceParams from a texture configuration 781 /// Creates SurfaceParams from a texture configuration
746 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config, 782 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config,
747 const GLShader::SamplerEntry& entry); 783 const GLShader::SamplerEntry& entry);
@@ -782,6 +818,7 @@ struct SurfaceParams {
782 u32 unaligned_height; 818 u32 unaligned_height;
783 SurfaceTarget target; 819 SurfaceTarget target;
784 u32 max_mip_level; 820 u32 max_mip_level;
821 bool is_layered;
785 822
786 // Parameters used for caching 823 // Parameters used for caching
787 VAddr addr; 824 VAddr addr;
@@ -797,6 +834,9 @@ struct SurfaceParams {
797 u32 layer_stride; 834 u32 layer_stride;
798 u32 base_layer; 835 u32 base_layer;
799 } rt; 836 } rt;
837
838private:
839 std::size_t InnerMemorySize(bool layer_only = false) const;
800}; 840};
801 841
802}; // namespace OpenGL 842}; // namespace OpenGL
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index da7989db9..550ca856c 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -319,13 +319,13 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
319std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, 319std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
320 u32 block_height, u32 block_depth) { 320 u32 block_height, u32 block_depth) {
321 if (tiled) { 321 if (tiled) {
322 const u32 gobs_in_x = 64 / bytes_per_pixel; 322 const u32 gobs_in_x = 64;
323 const u32 gobs_in_y = 8; 323 const u32 gobs_in_y = 8;
324 const u32 gobs_in_z = 1; 324 const u32 gobs_in_z = 1;
325 const u32 aligned_width = Common::AlignUp(width, gobs_in_x); 325 const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gobs_in_x);
326 const u32 aligned_height = Common::AlignUp(height, gobs_in_y * block_height); 326 const u32 aligned_height = Common::AlignUp(height, gobs_in_y * block_height);
327 const u32 aligned_depth = Common::AlignUp(depth, gobs_in_z * block_depth); 327 const u32 aligned_depth = Common::AlignUp(depth, gobs_in_z * block_depth);
328 return aligned_width * aligned_height * aligned_depth * bytes_per_pixel; 328 return aligned_width * aligned_height * aligned_depth;
329 } else { 329 } else {
330 return width * height * depth * bytes_per_pixel; 330 return width * height * depth * bytes_per_pixel;
331 } 331 }