diff options
| author | 2018-10-24 18:30:27 -0400 | |
|---|---|---|
| committer | 2018-10-28 18:59:59 -0400 | |
| commit | bbf3b2da0cee61ee99cdc42d08543881640990e4 (patch) | |
| tree | b07bae4543cf2b03fa71239df7a68e41442064bd /src | |
| parent | Merge pull request #1607 from FearlessTobi/patch-3 (diff) | |
| download | yuzu-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.cpp | 240 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 72 |
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 | ||
| 93 | std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | 93 | std::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 | |||
| 109 | std::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 | ||
| 376 | MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { | 382 | MathUtil::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 | ||
| 565 | void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, | 571 | void 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 | |||
| 992 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); | 1003 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); |
| 993 | void CachedSurface::LoadGLBuffer() { | 1004 | void 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 | ||
| 1011 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); | 1024 | MICROPROFILE_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 | ||
| 1044 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | 1058 | void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, |
| 1045 | void 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 | ||
| 1184 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | ||
| 1185 | void 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 | |||
| 1157 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { | 1209 | RasterizerCacheOpenGL::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 | ||
| 942 | private: | 995 | private: |
| 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 | ||
| 1004 | private: | 1060 | private: |
| 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; |