summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar FernandoS272018-10-24 18:30:27 -0400
committerGravatar FernandoS272018-10-28 18:59:59 -0400
commitbbf3b2da0cee61ee99cdc42d08543881640990e4 (patch)
treeb07bae4543cf2b03fa71239df7a68e41442064bd /src
parentMerge pull request #1607 from FearlessTobi/patch-3 (diff)
downloadyuzu-bbf3b2da0cee61ee99cdc42d08543881640990e4.tar.gz
yuzu-bbf3b2da0cee61ee99cdc42d08543881640990e4.tar.xz
yuzu-bbf3b2da0cee61ee99cdc42d08543881640990e4.zip
Implement Mipmaps
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp240
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h72
2 files changed, 211 insertions, 101 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b057e2efa..70d1ebda5 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -90,27 +90,33 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
90 } 90 }
91} 91}
92 92
93std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { 93std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only,
94 bool uncompressed) const {
94 const u32 compression_factor{GetCompressionFactor(pixel_format)}; 95 const u32 compression_factor{GetCompressionFactor(pixel_format)};
95 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; 96 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
96 u32 m_depth = (layer_only ? 1U : depth); 97 u32 m_depth = (layer_only ? 1U : depth);
97 u32 m_width = std::max(1U, width / compression_factor); 98 u32 m_width = uncompressed ? width : std::max(1U, width / compression_factor);
98 u32 m_height = std::max(1U, height / compression_factor); 99 u32 m_height = uncompressed ? height : std::max(1U, height / compression_factor);
99 std::size_t size = Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, 100 m_width = std::max(1U, m_width >> mip_level);
100 m_depth, block_height, block_depth); 101 m_height = std::max(1U, m_height >> mip_level);
101 u32 m_block_height = block_height; 102 m_depth = std::max(1U, m_depth >> mip_level);
102 u32 m_block_depth = block_depth; 103 u32 m_block_height = MipBlockHeight(mip_level);
104 u32 m_block_depth = MipBlockDepth(mip_level);
105 return Tegra::Texture::CalculateSize(force_gl ? false : is_tiled, bytes_per_pixel, m_width,
106 m_height, m_depth, m_block_height, m_block_depth);
107}
108
109std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
110 bool uncompressed) const {
103 std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size 111 std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size
104 for (u32 i = 1; i < max_mip_level; i++) { 112 std::size_t size = 0;
105 m_width = std::max(1U, m_width / 2); 113 for (u32 i = 0; i < max_mip_level; i++) {
106 m_height = std::max(1U, m_height / 2); 114 size += InnerMipmapMemorySize(i, force_gl, layer_only, uncompressed);
107 m_depth = std::max(1U, m_depth / 2); 115 }
108 m_block_height = std::max(1U, m_block_height / 2); 116 if (!force_gl && is_tiled) {
109 m_block_depth = std::max(1U, m_block_depth / 2); 117 size = Common::AlignUp(size, block_size_bytes);
110 size += Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, m_depth,
111 m_block_height, m_block_depth);
112 } 118 }
113 return is_tiled ? Common::AlignUp(size, block_size_bytes) : size; 119 return size;
114} 120}
115 121
116/*static*/ SurfaceParams SurfaceParams::CreateForTexture( 122/*static*/ SurfaceParams SurfaceParams::CreateForTexture(
@@ -188,7 +194,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
188 params.unaligned_height = config.height; 194 params.unaligned_height = config.height;
189 params.target = SurfaceTarget::Texture2D; 195 params.target = SurfaceTarget::Texture2D;
190 params.depth = 1; 196 params.depth = 1;
191 params.max_mip_level = 0; 197 params.max_mip_level = 1;
192 params.is_layered = false; 198 params.is_layered = false;
193 199
194 // Render target specific parameters, not used for caching 200 // Render target specific parameters, not used for caching
@@ -222,7 +228,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
222 params.unaligned_height = zeta_height; 228 params.unaligned_height = zeta_height;
223 params.target = SurfaceTarget::Texture2D; 229 params.target = SurfaceTarget::Texture2D;
224 params.depth = 1; 230 params.depth = 1;
225 params.max_mip_level = 0; 231 params.max_mip_level = 1;
226 params.is_layered = false; 232 params.is_layered = false;
227 params.rt = {}; 233 params.rt = {};
228 234
@@ -249,7 +255,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
249 params.unaligned_height = config.height; 255 params.unaligned_height = config.height;
250 params.target = SurfaceTarget::Texture2D; 256 params.target = SurfaceTarget::Texture2D;
251 params.depth = 1; 257 params.depth = 1;
252 params.max_mip_level = 0; 258 params.max_mip_level = 1;
253 params.rt = {}; 259 params.rt = {};
254 260
255 params.InitCacheParameters(config.Address()); 261 params.InitCacheParameters(config.Address());
@@ -373,13 +379,13 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType
373 return format; 379 return format;
374} 380}
375 381
376MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { 382MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
377 u32 actual_height{unaligned_height}; 383 u32 actual_height{std::max(1U, unaligned_height >> mip_level)};
378 if (IsPixelFormatASTC(pixel_format)) { 384 if (IsPixelFormatASTC(pixel_format)) {
379 // ASTC formats must stop at the ATSC block size boundary 385 // ASTC formats must stop at the ATSC block size boundary
380 actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second); 386 actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second);
381 } 387 }
382 return {0, actual_height, width, 0}; 388 return {0, actual_height, MipWidth(mip_level), 0};
383} 389}
384 390
385/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN 391/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
@@ -563,28 +569,31 @@ static constexpr GLConversionArray gl_to_morton_fns = {
563}; 569};
564 570
565void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, 571void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
566 std::vector<u8>& gl_buffer) { 572 std::vector<u8>& gl_buffer, u32 mip_level) {
567 u32 depth = params.depth; 573 u32 depth = params.MipDepth(mip_level);
568 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { 574 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
569 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented. 575 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
570 depth = 1U; 576 depth = 1U;
571 } 577 }
572 if (params.is_layered) { 578 if (params.is_layered) {
573 u64 offset = 0; 579 u64 offset = params.GetMipmapLevelOffset(mip_level);
574 u64 offset_gl = 0; 580 u64 offset_gl = 0;
575 u64 layer_size = params.LayerMemorySize(); 581 u64 layer_size = params.LayerMemorySize();
576 u64 gl_size = params.LayerSizeGL(); 582 u64 gl_size = params.LayerSizeGL(mip_level);
577 for (u32 i = 0; i < depth; i++) { 583 for (u32 i = 0; i < params.depth; i++) {
578 functions[static_cast<std::size_t>(params.pixel_format)]( 584 functions[static_cast<std::size_t>(params.pixel_format)](
579 params.width, params.block_height, params.height, params.block_depth, 1, 585 params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
586 params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1,
580 gl_buffer.data() + offset_gl, gl_size, params.addr + offset); 587 gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
581 offset += layer_size; 588 offset += layer_size;
582 offset_gl += gl_size; 589 offset_gl += gl_size;
583 } 590 }
584 } else { 591 } else {
592 u64 offset = params.GetMipmapLevelOffset(mip_level);
585 functions[static_cast<std::size_t>(params.pixel_format)]( 593 functions[static_cast<std::size_t>(params.pixel_format)](
586 params.width, params.block_height, params.height, params.block_depth, depth, 594 params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
587 gl_buffer.data(), gl_buffer.size(), params.addr); 595 params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(),
596 gl_buffer.size(), params.addr + offset);
588 } 597 }
589} 598}
590 599
@@ -839,29 +848,31 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
839 // Only pre-create the texture for non-compressed textures. 848 // Only pre-create the texture for non-compressed textures.
840 switch (params.target) { 849 switch (params.target) {
841 case SurfaceParams::SurfaceTarget::Texture1D: 850 case SurfaceParams::SurfaceTarget::Texture1D:
842 glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 851 glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
843 rect.GetWidth()); 852 format_tuple.internal_format, rect.GetWidth());
844 break; 853 break;
845 case SurfaceParams::SurfaceTarget::Texture2D: 854 case SurfaceParams::SurfaceTarget::Texture2D:
846 case SurfaceParams::SurfaceTarget::TextureCubemap: 855 case SurfaceParams::SurfaceTarget::TextureCubemap:
847 glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 856 glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
848 rect.GetWidth(), rect.GetHeight()); 857 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
849 break; 858 break;
850 case SurfaceParams::SurfaceTarget::Texture3D: 859 case SurfaceParams::SurfaceTarget::Texture3D:
851 case SurfaceParams::SurfaceTarget::Texture2DArray: 860 case SurfaceParams::SurfaceTarget::Texture2DArray:
852 glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 861 glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
853 rect.GetWidth(), rect.GetHeight(), params.depth); 862 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
863 params.depth);
854 break; 864 break;
855 default: 865 default:
856 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 866 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
857 static_cast<u32>(params.target)); 867 static_cast<u32>(params.target));
858 UNREACHABLE(); 868 UNREACHABLE();
859 glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(), 869 glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format,
860 rect.GetHeight()); 870 rect.GetWidth(), rect.GetHeight());
861 } 871 }
862 } 872 }
863 873
864 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); 874 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
875 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
865 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 876 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
866 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 877 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
867 878
@@ -992,20 +1003,22 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
992MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); 1003MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
993void CachedSurface::LoadGLBuffer() { 1004void CachedSurface::LoadGLBuffer() {
994 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 1005 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
995 1006 gl_buffer.resize(params.max_mip_level);
996 gl_buffer.resize(params.size_in_bytes_gl); 1007 for (u32 i = 0; i < params.max_mip_level; i++)
1008 gl_buffer[i].resize(params.GetMipmapSizeGL(i));
997 if (params.is_tiled) { 1009 if (params.is_tiled) {
998 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 1010 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
999 params.block_width, static_cast<u32>(params.target)); 1011 params.block_width, static_cast<u32>(params.target));
1000 1012 for (u32 i = 0; i < params.max_mip_level; i++)
1001 SwizzleFunc(morton_to_gl_fns, params, gl_buffer); 1013 SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i);
1002 } else { 1014 } else {
1003 const auto texture_src_data{Memory::GetPointer(params.addr)}; 1015 const auto texture_src_data{Memory::GetPointer(params.addr)};
1004 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; 1016 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
1005 gl_buffer.assign(texture_src_data, texture_src_data_end); 1017 gl_buffer[0].assign(texture_src_data, texture_src_data_end);
1006 } 1018 }
1007 1019 for (u32 i = 0; i < params.max_mip_level; i++)
1008 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); 1020 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
1021 params.MipHeight(i));
1009} 1022}
1010 1023
1011MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 1024MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1015,7 +1028,8 @@ void CachedSurface::FlushGLBuffer() {
1015 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented"); 1028 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented");
1016 1029
1017 // OpenGL temporary buffer needs to be big enough to store raw texture size 1030 // OpenGL temporary buffer needs to be big enough to store raw texture size
1018 gl_buffer.resize(GetSizeInBytes()); 1031 gl_buffer.resize(1);
1032 gl_buffer[0].resize(GetSizeInBytes());
1019 1033
1020 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 1034 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
1021 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 1035 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
@@ -1023,10 +1037,10 @@ void CachedSurface::FlushGLBuffer() {
1023 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); 1037 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
1024 ASSERT(!tuple.compressed); 1038 ASSERT(!tuple.compressed);
1025 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 1039 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
1026 glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, 1040 glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, static_cast<GLsizei>(gl_buffer[0].size()),
1027 static_cast<GLsizei>(gl_buffer.size()), gl_buffer.data()); 1041 gl_buffer[0].data());
1028 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 1042 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1029 ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, 1043 ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer[0], params.pixel_format, params.width,
1030 params.height); 1044 params.height);
1031 ASSERT(params.type != SurfaceType::Fill); 1045 ASSERT(params.type != SurfaceType::Fill);
1032 const u8* const texture_src_data = Memory::GetPointer(params.addr); 1046 const u8* const texture_src_data = Memory::GetPointer(params.addr);
@@ -1035,26 +1049,21 @@ void CachedSurface::FlushGLBuffer() {
1035 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 1049 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
1036 params.block_width, static_cast<u32>(params.target)); 1050 params.block_width, static_cast<u32>(params.target));
1037 1051
1038 SwizzleFunc(gl_to_morton_fns, params, gl_buffer); 1052 SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0);
1039 } else { 1053 } else {
1040 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes()); 1054 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes());
1041 } 1055 }
1042} 1056}
1043 1057
1044MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); 1058void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1045void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { 1059 GLuint draw_fb_handle) {
1046 if (params.type == SurfaceType::Fill) 1060 const auto& rect{params.GetRect(mip_map)};
1047 return;
1048
1049 MICROPROFILE_SCOPE(OpenGL_TextureUL);
1050
1051 const auto& rect{params.GetRect()};
1052 1061
1053 // Load data from memory to the surface 1062 // Load data from memory to the surface
1054 const GLint x0 = static_cast<GLint>(rect.left); 1063 const GLint x0 = static_cast<GLint>(rect.left);
1055 const GLint y0 = static_cast<GLint>(rect.bottom); 1064 const GLint y0 = static_cast<GLint>(rect.bottom);
1056 std::size_t buffer_offset = 1065 std::size_t buffer_offset =
1057 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + 1066 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
1058 static_cast<std::size_t>(x0)) * 1067 static_cast<std::size_t>(x0)) *
1059 SurfaceParams::GetBytesPerPixel(params.pixel_format); 1068 SurfaceParams::GetBytesPerPixel(params.pixel_format);
1060 1069
@@ -1072,88 +1081,131 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
1072 cur_state.Apply(); 1081 cur_state.Apply();
1073 1082
1074 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 1083 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
1075 ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); 1084 ASSERT(params.MipWidth(mip_map) * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 ==
1076 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width)); 1085 0);
1086 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
1077 1087
1088 GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
1078 glActiveTexture(GL_TEXTURE0); 1089 glActiveTexture(GL_TEXTURE0);
1079 if (tuple.compressed) { 1090 if (tuple.compressed) {
1080 switch (params.target) { 1091 switch (params.target) {
1081 case SurfaceParams::SurfaceTarget::Texture2D: 1092 case SurfaceParams::SurfaceTarget::Texture2D:
1082 glCompressedTexImage2D( 1093 glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1083 SurfaceTargetToGL(params.target), 0, tuple.internal_format, 1094 static_cast<GLsizei>(params.MipWidth(mip_map)),
1084 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, 1095 static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
1085 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); 1096 &gl_buffer[mip_map][buffer_offset]);
1086 break; 1097 break;
1087 case SurfaceParams::SurfaceTarget::Texture3D: 1098 case SurfaceParams::SurfaceTarget::Texture3D:
1099 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1100 static_cast<GLsizei>(params.MipWidth(mip_map)),
1101 static_cast<GLsizei>(params.MipHeight(mip_map)),
1102 static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
1103 &gl_buffer[mip_map][buffer_offset]);
1104 break;
1088 case SurfaceParams::SurfaceTarget::Texture2DArray: 1105 case SurfaceParams::SurfaceTarget::Texture2DArray:
1089 glCompressedTexImage3D( 1106 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1090 SurfaceTargetToGL(params.target), 0, tuple.internal_format, 1107 static_cast<GLsizei>(params.MipWidth(mip_map)),
1091 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 1108 static_cast<GLsizei>(params.MipHeight(mip_map)),
1092 static_cast<GLsizei>(params.depth), 0, 1109 static_cast<GLsizei>(params.depth), 0, image_size,
1093 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); 1110 &gl_buffer[mip_map][buffer_offset]);
1094 break; 1111 break;
1095 case SurfaceParams::SurfaceTarget::TextureCubemap: 1112 case SurfaceParams::SurfaceTarget::TextureCubemap: {
1113 GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
1096 for (std::size_t face = 0; face < params.depth; ++face) { 1114 for (std::size_t face = 0; face < params.depth; ++face) {
1097 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 1115 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
1098 0, tuple.internal_format, static_cast<GLsizei>(params.width), 1116 mip_map, tuple.internal_format,
1099 static_cast<GLsizei>(params.height), 0, 1117 static_cast<GLsizei>(params.MipWidth(mip_map)),
1100 static_cast<GLsizei>(params.SizeInBytesCubeFaceGL()), 1118 static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
1101 &gl_buffer[buffer_offset]); 1119 layer_size, &gl_buffer[mip_map][buffer_offset]);
1102 buffer_offset += params.SizeInBytesCubeFace(); 1120 buffer_offset += layer_size;
1103 } 1121 }
1104 break; 1122 break;
1123 }
1105 default: 1124 default:
1106 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 1125 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
1107 static_cast<u32>(params.target)); 1126 static_cast<u32>(params.target));
1108 UNREACHABLE(); 1127 UNREACHABLE();
1109 glCompressedTexImage2D( 1128 glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format,
1110 GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), 1129 static_cast<GLsizei>(params.MipWidth(mip_map)),
1111 static_cast<GLsizei>(params.height), 0, 1130 static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
1112 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); 1131 static_cast<GLsizei>(params.size_in_bytes_gl),
1132 &gl_buffer[mip_map][buffer_offset]);
1113 } 1133 }
1114 } else { 1134 } else {
1115 1135
1116 switch (params.target) { 1136 switch (params.target) {
1117 case SurfaceParams::SurfaceTarget::Texture1D: 1137 case SurfaceParams::SurfaceTarget::Texture1D:
1118 glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, 1138 glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
1119 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, 1139 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
1120 &gl_buffer[buffer_offset]); 1140 &gl_buffer[mip_map][buffer_offset]);
1121 break; 1141 break;
1122 case SurfaceParams::SurfaceTarget::Texture2D: 1142 case SurfaceParams::SurfaceTarget::Texture2D:
1123 glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, 1143 glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
1124 static_cast<GLsizei>(rect.GetWidth()), 1144 static_cast<GLsizei>(rect.GetWidth()),
1125 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1145 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1126 &gl_buffer[buffer_offset]); 1146 &gl_buffer[mip_map][buffer_offset]);
1127 break; 1147 break;
1128 case SurfaceParams::SurfaceTarget::Texture3D: 1148 case SurfaceParams::SurfaceTarget::Texture3D:
1149 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1150 static_cast<GLsizei>(rect.GetWidth()),
1151 static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
1152 tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
1153 break;
1129 case SurfaceParams::SurfaceTarget::Texture2DArray: 1154 case SurfaceParams::SurfaceTarget::Texture2DArray:
1130 glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, 1155 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1131 static_cast<GLsizei>(rect.GetWidth()), 1156 static_cast<GLsizei>(rect.GetWidth()),
1132 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, 1157 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
1133 tuple.type, &gl_buffer[buffer_offset]); 1158 tuple.type, &gl_buffer[mip_map][buffer_offset]);
1134 break; 1159 break;
1135 case SurfaceParams::SurfaceTarget::TextureCubemap: 1160 case SurfaceParams::SurfaceTarget::TextureCubemap: {
1161 std::size_t start = buffer_offset;
1136 for (std::size_t face = 0; face < params.depth; ++face) { 1162 for (std::size_t face = 0; face < params.depth; ++face) {
1137 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, x0, 1163 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
1138 y0, static_cast<GLsizei>(rect.GetWidth()), 1164 x0, y0, static_cast<GLsizei>(rect.GetWidth()),
1139 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1165 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1140 &gl_buffer[buffer_offset]); 1166 &gl_buffer[mip_map][buffer_offset]);
1141 buffer_offset += params.SizeInBytesCubeFace(); 1167 buffer_offset += params.LayerSizeGL(mip_map);
1142 } 1168 }
1143 break; 1169 break;
1170 }
1144 default: 1171 default:
1145 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 1172 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
1146 static_cast<u32>(params.target)); 1173 static_cast<u32>(params.target));
1147 UNREACHABLE(); 1174 UNREACHABLE();
1148 glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), 1175 glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
1149 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1176 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1150 &gl_buffer[buffer_offset]); 1177 &gl_buffer[mip_map][buffer_offset]);
1151 } 1178 }
1152 } 1179 }
1153 1180
1154 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 1181 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1155} 1182}
1156 1183
1184MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
1185void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
1186 if (params.type == SurfaceType::Fill)
1187 return;
1188
1189 MICROPROFILE_SCOPE(OpenGL_TextureUL);
1190
1191 for (u32 i = 0; i < params.max_mip_level; i++)
1192 UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
1193
1194 if (params.max_mip_level == 1) {
1195 const GLuint target_tex = texture.handle;
1196 OpenGLState cur_state = OpenGLState::GetCurState();
1197 const auto& old_tex = cur_state.texture_units[0];
1198 SCOPE_EXIT({
1199 cur_state.texture_units[0] = old_tex;
1200 cur_state.Apply();
1201 });
1202 cur_state.texture_units[0].texture = target_tex;
1203 cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
1204 cur_state.Apply();
1205 glGenerateMipmap(SurfaceTargetToGL(params.target));
1206 }
1207}
1208
1157RasterizerCacheOpenGL::RasterizerCacheOpenGL() { 1209RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
1158 read_framebuffer.Create(); 1210 read_framebuffer.Create();
1159 draw_framebuffer.Create(); 1211 draw_framebuffer.Create();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index be8c00e99..5bcd33156 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -834,7 +834,7 @@ struct SurfaceParams {
834 } 834 }
835 835
836 /// Returns the rectangle corresponding to this surface 836 /// Returns the rectangle corresponding to this surface
837 MathUtil::Rectangle<u32> GetRect() const; 837 MathUtil::Rectangle<u32> GetRect(u32 mip_level = 0) const;
838 838
839 /// Returns the total size of this surface in bytes, adjusted for compression 839 /// Returns the total size of this surface in bytes, adjusted for compression
840 std::size_t SizeInBytesRaw(bool ignore_tiled = false) const { 840 std::size_t SizeInBytesRaw(bool ignore_tiled = false) const {
@@ -865,7 +865,7 @@ struct SurfaceParams {
865 865
866 /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps. 866 /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps.
867 std::size_t MemorySize() const { 867 std::size_t MemorySize() const {
868 std::size_t size = InnerMemorySize(is_layered); 868 std::size_t size = InnerMemorySize(false, is_layered);
869 if (is_layered) 869 if (is_layered)
870 return size * depth; 870 return size * depth;
871 return size; 871 return size;
@@ -874,12 +874,65 @@ struct SurfaceParams {
874 /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including 874 /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including
875 /// mipmaps. 875 /// mipmaps.
876 std::size_t LayerMemorySize() const { 876 std::size_t LayerMemorySize() const {
877 return InnerMemorySize(true); 877 return InnerMemorySize(false, true);
878 } 878 }
879 879
880 /// Returns the size of a layer of this surface in OpenGL. 880 /// Returns the size of a layer of this surface in OpenGL.
881 std::size_t LayerSizeGL() const { 881 std::size_t LayerSizeGL(u32 mip_level) const {
882 return SizeInBytesRaw(true) / depth; 882 return InnerMipmapMemorySize(mip_level, true, is_layered, false);
883 }
884
885 std::size_t GetMipmapSizeGL(u32 mip_level, bool ignore_compressed = true) const {
886 std::size_t size = InnerMipmapMemorySize(mip_level, true, is_layered, ignore_compressed);
887 if (is_layered)
888 return size * depth;
889 return size;
890 }
891
892 std::size_t GetMipmapLevelOffset(u32 mip_level) const {
893 std::size_t offset = 0;
894 for (u32 i = 0; i < mip_level; i++)
895 offset += InnerMipmapMemorySize(i, false, is_layered);
896 return offset;
897 }
898
899 std::size_t GetMipmapLevelOffsetGL(u32 mip_level) const {
900 std::size_t offset = 0;
901 for (u32 i = 0; i < mip_level; i++)
902 offset += InnerMipmapMemorySize(i, true, is_layered);
903 return offset;
904 }
905
906 u32 MipWidth(u32 mip_level) const {
907 return std::max(1U, width >> mip_level);
908 }
909
910 u32 MipHeight(u32 mip_level) const {
911 return std::max(1U, height >> mip_level);
912 }
913
914 u32 MipDepth(u32 mip_level) const {
915 return std::max(1U, depth >> mip_level);
916 }
917
918 u32 MipBlockHeight(u32 mip_level) const {
919 u32 height = MipHeight(mip_level);
920 u32 bh = block_height;
921 // Magical block resizing algorithm, needs more testing.
922 while (bh != 1 && height / bh <= 16) {
923 bh = bh >> 1;
924 }
925 return bh;
926 }
927
928 u32 MipBlockDepth(u32 mip_level) const {
929 u32 depth = MipDepth(mip_level);
930 u32 bd = block_depth;
931 // Magical block resizing algorithm, needs more testing.
932 while (bd != 1 && depth / bd <= 16) {
933 bd = bd >> 1;
934 }
935 return bd;
883 } 936 }
884 937
885 /// Creates SurfaceParams from a texture configuration 938 /// Creates SurfaceParams from a texture configuration
@@ -940,7 +993,10 @@ struct SurfaceParams {
940 } rt; 993 } rt;
941 994
942private: 995private:
943 std::size_t InnerMemorySize(bool layer_only = false) const; 996 std::size_t InnerMipmapMemorySize(u32 mip_level, bool force_gl = false, bool layer_only = false,
997 bool uncompressed = false) const;
998 std::size_t InnerMemorySize(bool force_gl = false, bool layer_only = false,
999 bool uncompressed = false) const;
944}; 1000};
945 1001
946}; // namespace OpenGL 1002}; // namespace OpenGL
@@ -1002,8 +1058,10 @@ public:
1002 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); 1058 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
1003 1059
1004private: 1060private:
1061 void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle);
1062
1005 OGLTexture texture; 1063 OGLTexture texture;
1006 std::vector<u8> gl_buffer; 1064 std::vector<std::vector<u8>> gl_buffer;
1007 SurfaceParams params; 1065 SurfaceParams params;
1008 GLenum gl_target; 1066 GLenum gl_target;
1009 std::size_t cached_size_in_bytes; 1067 std::size_t cached_size_in_bytes;