diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio_core/time_stretch.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 243 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 87 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 5 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 27 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/utils.cpp | 38 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/utils.h | 15 | ||||
| -rw-r--r-- | src/video_core/textures/decoders.h | 6 | ||||
| -rw-r--r-- | src/video_core/utils.h | 26 |
12 files changed, 321 insertions, 145 deletions
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp index cee8b12dd..2fe0b3aef 100644 --- a/src/audio_core/time_stretch.cpp +++ b/src/audio_core/time_stretch.cpp | |||
| @@ -32,10 +32,10 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out, | |||
| 32 | // We were given actual_samples number of samples, and num_samples were requested from us. | 32 | // We were given actual_samples number of samples, and num_samples were requested from us. |
| 33 | double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out); | 33 | double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out); |
| 34 | 34 | ||
| 35 | const double max_latency = 1.0; // seconds | 35 | const double max_latency = 0.25; // seconds |
| 36 | const double max_backlog = m_sample_rate * max_latency; | 36 | const double max_backlog = m_sample_rate * max_latency; |
| 37 | const double backlog_fullness = m_sound_touch.numSamples() / max_backlog; | 37 | const double backlog_fullness = m_sound_touch.numSamples() / max_backlog; |
| 38 | if (backlog_fullness > 5.0) { | 38 | if (backlog_fullness > 4.0) { |
| 39 | // Too many samples in backlog: Don't push anymore on | 39 | // Too many samples in backlog: Don't push anymore on |
| 40 | num_in = 0; | 40 | num_in = 0; |
| 41 | } | 41 | } |
| @@ -49,7 +49,7 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out, | |||
| 49 | 49 | ||
| 50 | // This low-pass filter smoothes out variance in the calculated stretch ratio. | 50 | // This low-pass filter smoothes out variance in the calculated stretch ratio. |
| 51 | // The time-scale determines how responsive this filter is. | 51 | // The time-scale determines how responsive this filter is. |
| 52 | constexpr double lpf_time_scale = 2.0; // seconds | 52 | constexpr double lpf_time_scale = 0.712; // seconds |
| 53 | const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale); | 53 | const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale); |
| 54 | m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio); | 54 | m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio); |
| 55 | 55 | ||
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 09ecc5bad..c5f7128ec 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -51,6 +51,8 @@ add_library(video_core STATIC | |||
| 51 | renderer_opengl/maxwell_to_gl.h | 51 | renderer_opengl/maxwell_to_gl.h |
| 52 | renderer_opengl/renderer_opengl.cpp | 52 | renderer_opengl/renderer_opengl.cpp |
| 53 | renderer_opengl/renderer_opengl.h | 53 | renderer_opengl/renderer_opengl.h |
| 54 | renderer_opengl/utils.cpp | ||
| 55 | renderer_opengl/utils.h | ||
| 54 | textures/astc.cpp | 56 | textures/astc.cpp |
| 55 | textures/astc.h | 57 | textures/astc.h |
| 56 | textures/decoders.cpp | 58 | textures/decoders.cpp |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index cb180b93c..7bb5544fc 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -731,11 +731,15 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr | |||
| 731 | 731 | ||
| 732 | if (mag_filter != config.mag_filter) { | 732 | if (mag_filter != config.mag_filter) { |
| 733 | mag_filter = config.mag_filter; | 733 | mag_filter = config.mag_filter; |
| 734 | glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter)); | 734 | glSamplerParameteri( |
| 735 | s, GL_TEXTURE_MAG_FILTER, | ||
| 736 | MaxwellToGL::TextureFilterMode(mag_filter, Tegra::Texture::TextureMipmapFilter::None)); | ||
| 735 | } | 737 | } |
| 736 | if (min_filter != config.min_filter) { | 738 | if (min_filter != config.min_filter || mip_filter != config.mip_filter) { |
| 737 | min_filter = config.min_filter; | 739 | min_filter = config.min_filter; |
| 738 | glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter)); | 740 | mip_filter = config.mip_filter; |
| 741 | glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, | ||
| 742 | MaxwellToGL::TextureFilterMode(min_filter, mip_filter)); | ||
| 739 | } | 743 | } |
| 740 | 744 | ||
| 741 | if (wrap_u != config.wrap_u) { | 745 | if (wrap_u != config.wrap_u) { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 5020a5392..7b0615125 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -93,6 +93,7 @@ private: | |||
| 93 | private: | 93 | private: |
| 94 | Tegra::Texture::TextureFilter mag_filter; | 94 | Tegra::Texture::TextureFilter mag_filter; |
| 95 | Tegra::Texture::TextureFilter min_filter; | 95 | Tegra::Texture::TextureFilter min_filter; |
| 96 | Tegra::Texture::TextureMipmapFilter mip_filter; | ||
| 96 | Tegra::Texture::WrapMode wrap_u; | 97 | Tegra::Texture::WrapMode wrap_u; |
| 97 | Tegra::Texture::WrapMode wrap_v; | 98 | Tegra::Texture::WrapMode wrap_v; |
| 98 | Tegra::Texture::WrapMode wrap_p; | 99 | Tegra::Texture::WrapMode wrap_p; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index b057e2efa..1d43a419d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "core/settings.h" | 16 | #include "core/settings.h" |
| 17 | #include "video_core/engines/maxwell_3d.h" | 17 | #include "video_core/engines/maxwell_3d.h" |
| 18 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 18 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 19 | #include "video_core/renderer_opengl/utils.h" | ||
| 19 | #include "video_core/textures/astc.h" | 20 | #include "video_core/textures/astc.h" |
| 20 | #include "video_core/textures/decoders.h" | 21 | #include "video_core/textures/decoders.h" |
| 21 | #include "video_core/utils.h" | 22 | #include "video_core/utils.h" |
| @@ -90,27 +91,36 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) { | |||
| 90 | } | 91 | } |
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | 94 | std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only, |
| 95 | bool uncompressed) const { | ||
| 94 | const u32 compression_factor{GetCompressionFactor(pixel_format)}; | 96 | const u32 compression_factor{GetCompressionFactor(pixel_format)}; |
| 95 | const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; | 97 | const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; |
| 96 | u32 m_depth = (layer_only ? 1U : depth); | 98 | u32 m_depth = (layer_only ? 1U : depth); |
| 97 | u32 m_width = std::max(1U, width / compression_factor); | 99 | u32 m_width = MipWidth(mip_level); |
| 98 | u32 m_height = std::max(1U, height / compression_factor); | 100 | u32 m_height = MipHeight(mip_level); |
| 99 | std::size_t size = Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, | 101 | m_width = uncompressed ? m_width |
| 100 | m_depth, block_height, block_depth); | 102 | : std::max(1U, (m_width + compression_factor - 1) / compression_factor); |
| 101 | u32 m_block_height = block_height; | 103 | m_height = uncompressed |
| 102 | u32 m_block_depth = block_depth; | 104 | ? m_height |
| 103 | std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size | 105 | : std::max(1U, (m_height + compression_factor - 1) / compression_factor); |
| 104 | for (u32 i = 1; i < max_mip_level; i++) { | 106 | m_depth = std::max(1U, m_depth >> mip_level); |
| 105 | m_width = std::max(1U, m_width / 2); | 107 | u32 m_block_height = MipBlockHeight(mip_level); |
| 106 | m_height = std::max(1U, m_height / 2); | 108 | u32 m_block_depth = MipBlockDepth(mip_level); |
| 107 | m_depth = std::max(1U, m_depth / 2); | 109 | return Tegra::Texture::CalculateSize(force_gl ? false : is_tiled, bytes_per_pixel, m_width, |
| 108 | m_block_height = std::max(1U, m_block_height / 2); | 110 | m_height, m_depth, m_block_height, m_block_depth); |
| 109 | m_block_depth = std::max(1U, m_block_depth / 2); | 111 | } |
| 110 | size += Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, m_depth, | 112 | |
| 111 | m_block_height, m_block_depth); | 113 | std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, |
| 114 | bool uncompressed) const { | ||
| 115 | std::size_t block_size_bytes = Tegra::Texture::GetGOBSize() * block_height * block_depth; | ||
| 116 | std::size_t size = 0; | ||
| 117 | for (u32 i = 0; i < max_mip_level; i++) { | ||
| 118 | size += InnerMipmapMemorySize(i, force_gl, layer_only, uncompressed); | ||
| 119 | } | ||
| 120 | if (!force_gl && is_tiled) { | ||
| 121 | size = Common::AlignUp(size, block_size_bytes); | ||
| 112 | } | 122 | } |
| 113 | return is_tiled ? Common::AlignUp(size, block_size_bytes) : size; | 123 | return size; |
| 114 | } | 124 | } |
| 115 | 125 | ||
| 116 | /*static*/ SurfaceParams SurfaceParams::CreateForTexture( | 126 | /*static*/ SurfaceParams SurfaceParams::CreateForTexture( |
| @@ -188,7 +198,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | |||
| 188 | params.unaligned_height = config.height; | 198 | params.unaligned_height = config.height; |
| 189 | params.target = SurfaceTarget::Texture2D; | 199 | params.target = SurfaceTarget::Texture2D; |
| 190 | params.depth = 1; | 200 | params.depth = 1; |
| 191 | params.max_mip_level = 0; | 201 | params.max_mip_level = 1; |
| 192 | params.is_layered = false; | 202 | params.is_layered = false; |
| 193 | 203 | ||
| 194 | // Render target specific parameters, not used for caching | 204 | // Render target specific parameters, not used for caching |
| @@ -222,7 +232,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | |||
| 222 | params.unaligned_height = zeta_height; | 232 | params.unaligned_height = zeta_height; |
| 223 | params.target = SurfaceTarget::Texture2D; | 233 | params.target = SurfaceTarget::Texture2D; |
| 224 | params.depth = 1; | 234 | params.depth = 1; |
| 225 | params.max_mip_level = 0; | 235 | params.max_mip_level = 1; |
| 226 | params.is_layered = false; | 236 | params.is_layered = false; |
| 227 | params.rt = {}; | 237 | params.rt = {}; |
| 228 | 238 | ||
| @@ -249,7 +259,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | |||
| 249 | params.unaligned_height = config.height; | 259 | params.unaligned_height = config.height; |
| 250 | params.target = SurfaceTarget::Texture2D; | 260 | params.target = SurfaceTarget::Texture2D; |
| 251 | params.depth = 1; | 261 | params.depth = 1; |
| 252 | params.max_mip_level = 0; | 262 | params.max_mip_level = 1; |
| 253 | params.rt = {}; | 263 | params.rt = {}; |
| 254 | 264 | ||
| 255 | params.InitCacheParameters(config.Address()); | 265 | params.InitCacheParameters(config.Address()); |
| @@ -273,7 +283,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form | |||
| 273 | {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, | 283 | {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, |
| 274 | false}, // R11FG11FB10F | 284 | false}, // R11FG11FB10F |
| 275 | {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI | 285 | {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI |
| 276 | {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 286 | {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 277 | true}, // DXT1 | 287 | true}, // DXT1 |
| 278 | {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 288 | {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 279 | true}, // DXT23 | 289 | true}, // DXT23 |
| @@ -318,7 +328,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form | |||
| 318 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4 | 328 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4 |
| 319 | {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 | 329 | {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 |
| 320 | // Compressed sRGB formats | 330 | // Compressed sRGB formats |
| 321 | {GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 331 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 322 | true}, // DXT1_SRGB | 332 | true}, // DXT1_SRGB |
| 323 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 333 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 324 | true}, // DXT23_SRGB | 334 | true}, // DXT23_SRGB |
| @@ -373,13 +383,13 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType | |||
| 373 | return format; | 383 | return format; |
| 374 | } | 384 | } |
| 375 | 385 | ||
| 376 | MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { | 386 | MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const { |
| 377 | u32 actual_height{unaligned_height}; | 387 | u32 actual_height{std::max(1U, unaligned_height >> mip_level)}; |
| 378 | if (IsPixelFormatASTC(pixel_format)) { | 388 | if (IsPixelFormatASTC(pixel_format)) { |
| 379 | // ASTC formats must stop at the ATSC block size boundary | 389 | // ASTC formats must stop at the ATSC block size boundary |
| 380 | actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second); | 390 | actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second); |
| 381 | } | 391 | } |
| 382 | return {0, actual_height, width, 0}; | 392 | return {0, actual_height, MipWidth(mip_level), 0}; |
| 383 | } | 393 | } |
| 384 | 394 | ||
| 385 | /// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN | 395 | /// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN |
| @@ -563,28 +573,31 @@ static constexpr GLConversionArray gl_to_morton_fns = { | |||
| 563 | }; | 573 | }; |
| 564 | 574 | ||
| 565 | void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, | 575 | void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, |
| 566 | std::vector<u8>& gl_buffer) { | 576 | std::vector<u8>& gl_buffer, u32 mip_level) { |
| 567 | u32 depth = params.depth; | 577 | u32 depth = params.MipDepth(mip_level); |
| 568 | if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { | 578 | if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { |
| 569 | // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented. | 579 | // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented. |
| 570 | depth = 1U; | 580 | depth = 1U; |
| 571 | } | 581 | } |
| 572 | if (params.is_layered) { | 582 | if (params.is_layered) { |
| 573 | u64 offset = 0; | 583 | u64 offset = params.GetMipmapLevelOffset(mip_level); |
| 574 | u64 offset_gl = 0; | 584 | u64 offset_gl = 0; |
| 575 | u64 layer_size = params.LayerMemorySize(); | 585 | u64 layer_size = params.LayerMemorySize(); |
| 576 | u64 gl_size = params.LayerSizeGL(); | 586 | u64 gl_size = params.LayerSizeGL(mip_level); |
| 577 | for (u32 i = 0; i < depth; i++) { | 587 | for (u32 i = 0; i < params.depth; i++) { |
| 578 | functions[static_cast<std::size_t>(params.pixel_format)]( | 588 | functions[static_cast<std::size_t>(params.pixel_format)]( |
| 579 | params.width, params.block_height, params.height, params.block_depth, 1, | 589 | params.MipWidth(mip_level), params.MipBlockHeight(mip_level), |
| 590 | params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1, | ||
| 580 | gl_buffer.data() + offset_gl, gl_size, params.addr + offset); | 591 | gl_buffer.data() + offset_gl, gl_size, params.addr + offset); |
| 581 | offset += layer_size; | 592 | offset += layer_size; |
| 582 | offset_gl += gl_size; | 593 | offset_gl += gl_size; |
| 583 | } | 594 | } |
| 584 | } else { | 595 | } else { |
| 596 | u64 offset = params.GetMipmapLevelOffset(mip_level); | ||
| 585 | functions[static_cast<std::size_t>(params.pixel_format)]( | 597 | functions[static_cast<std::size_t>(params.pixel_format)]( |
| 586 | params.width, params.block_height, params.height, params.block_depth, depth, | 598 | params.MipWidth(mip_level), params.MipBlockHeight(mip_level), |
| 587 | gl_buffer.data(), gl_buffer.size(), params.addr); | 599 | params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(), |
| 600 | gl_buffer.size(), params.addr + offset); | ||
| 588 | } | 601 | } |
| 589 | } | 602 | } |
| 590 | 603 | ||
| @@ -839,34 +852,41 @@ CachedSurface::CachedSurface(const SurfaceParams& params) | |||
| 839 | // Only pre-create the texture for non-compressed textures. | 852 | // Only pre-create the texture for non-compressed textures. |
| 840 | switch (params.target) { | 853 | switch (params.target) { |
| 841 | case SurfaceParams::SurfaceTarget::Texture1D: | 854 | case SurfaceParams::SurfaceTarget::Texture1D: |
| 842 | glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, | 855 | glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level, |
| 843 | rect.GetWidth()); | 856 | format_tuple.internal_format, rect.GetWidth()); |
| 844 | break; | 857 | break; |
| 845 | case SurfaceParams::SurfaceTarget::Texture2D: | 858 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 846 | case SurfaceParams::SurfaceTarget::TextureCubemap: | 859 | case SurfaceParams::SurfaceTarget::TextureCubemap: |
| 847 | glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, | 860 | glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level, |
| 848 | rect.GetWidth(), rect.GetHeight()); | 861 | format_tuple.internal_format, rect.GetWidth(), rect.GetHeight()); |
| 849 | break; | 862 | break; |
| 850 | case SurfaceParams::SurfaceTarget::Texture3D: | 863 | case SurfaceParams::SurfaceTarget::Texture3D: |
| 851 | case SurfaceParams::SurfaceTarget::Texture2DArray: | 864 | case SurfaceParams::SurfaceTarget::Texture2DArray: |
| 852 | glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, | 865 | glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level, |
| 853 | rect.GetWidth(), rect.GetHeight(), params.depth); | 866 | format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(), |
| 867 | params.depth); | ||
| 854 | break; | 868 | break; |
| 855 | default: | 869 | default: |
| 856 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | 870 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", |
| 857 | static_cast<u32>(params.target)); | 871 | static_cast<u32>(params.target)); |
| 858 | UNREACHABLE(); | 872 | UNREACHABLE(); |
| 859 | glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(), | 873 | glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format, |
| 860 | rect.GetHeight()); | 874 | rect.GetWidth(), rect.GetHeight()); |
| 861 | } | 875 | } |
| 862 | } | 876 | } |
| 863 | 877 | ||
| 864 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 878 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 879 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
| 865 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 880 | 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); | 881 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 882 | glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, | ||
| 883 | params.max_mip_level - 1); | ||
| 884 | if (params.max_mip_level == 1) { | ||
| 885 | glTexParameterf(SurfaceTargetToGL(params.target), GL_TEXTURE_LOD_BIAS, 1000.0); | ||
| 886 | } | ||
| 867 | 887 | ||
| 868 | VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr, | 888 | LabelGLObject(GL_TEXTURE, texture.handle, params.addr, |
| 869 | SurfaceParams::SurfaceTargetName(params.target)); | 889 | SurfaceParams::SurfaceTargetName(params.target)); |
| 870 | 890 | ||
| 871 | // Clamp size to mapped GPU memory region | 891 | // Clamp size to mapped GPU memory region |
| 872 | // TODO(bunnei): Super Mario Odyssey maps a 0x40000 byte region and then uses it for a 0x80000 | 892 | // TODO(bunnei): Super Mario Odyssey maps a 0x40000 byte region and then uses it for a 0x80000 |
| @@ -992,20 +1012,22 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm | |||
| 992 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); | 1012 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); |
| 993 | void CachedSurface::LoadGLBuffer() { | 1013 | void CachedSurface::LoadGLBuffer() { |
| 994 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); | 1014 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); |
| 995 | 1015 | gl_buffer.resize(params.max_mip_level); | |
| 996 | gl_buffer.resize(params.size_in_bytes_gl); | 1016 | for (u32 i = 0; i < params.max_mip_level; i++) |
| 1017 | gl_buffer[i].resize(params.GetMipmapSizeGL(i)); | ||
| 997 | if (params.is_tiled) { | 1018 | if (params.is_tiled) { |
| 998 | ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", | 1019 | ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", |
| 999 | params.block_width, static_cast<u32>(params.target)); | 1020 | params.block_width, static_cast<u32>(params.target)); |
| 1000 | 1021 | for (u32 i = 0; i < params.max_mip_level; i++) | |
| 1001 | SwizzleFunc(morton_to_gl_fns, params, gl_buffer); | 1022 | SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i); |
| 1002 | } else { | 1023 | } else { |
| 1003 | const auto texture_src_data{Memory::GetPointer(params.addr)}; | 1024 | const auto texture_src_data{Memory::GetPointer(params.addr)}; |
| 1004 | const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; | 1025 | 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); | 1026 | gl_buffer[0].assign(texture_src_data, texture_src_data_end); |
| 1006 | } | 1027 | } |
| 1007 | 1028 | for (u32 i = 0; i < params.max_mip_level; i++) | |
| 1008 | ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); | 1029 | ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), |
| 1030 | params.MipHeight(i)); | ||
| 1009 | } | 1031 | } |
| 1010 | 1032 | ||
| 1011 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); | 1033 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); |
| @@ -1015,7 +1037,8 @@ void CachedSurface::FlushGLBuffer() { | |||
| 1015 | ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented"); | 1037 | ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented"); |
| 1016 | 1038 | ||
| 1017 | // OpenGL temporary buffer needs to be big enough to store raw texture size | 1039 | // OpenGL temporary buffer needs to be big enough to store raw texture size |
| 1018 | gl_buffer.resize(GetSizeInBytes()); | 1040 | gl_buffer.resize(1); |
| 1041 | gl_buffer[0].resize(GetSizeInBytes()); | ||
| 1019 | 1042 | ||
| 1020 | const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); | 1043 | const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); |
| 1021 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT | 1044 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT |
| @@ -1024,9 +1047,9 @@ void CachedSurface::FlushGLBuffer() { | |||
| 1024 | ASSERT(!tuple.compressed); | 1047 | ASSERT(!tuple.compressed); |
| 1025 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | 1048 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); |
| 1026 | glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, | 1049 | glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, |
| 1027 | static_cast<GLsizei>(gl_buffer.size()), gl_buffer.data()); | 1050 | static_cast<GLsizei>(gl_buffer[0].size()), gl_buffer[0].data()); |
| 1028 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); | 1051 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); |
| 1029 | ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, | 1052 | ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer[0], params.pixel_format, params.width, |
| 1030 | params.height); | 1053 | params.height); |
| 1031 | ASSERT(params.type != SurfaceType::Fill); | 1054 | ASSERT(params.type != SurfaceType::Fill); |
| 1032 | const u8* const texture_src_data = Memory::GetPointer(params.addr); | 1055 | const u8* const texture_src_data = Memory::GetPointer(params.addr); |
| @@ -1035,26 +1058,21 @@ void CachedSurface::FlushGLBuffer() { | |||
| 1035 | ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", | 1058 | ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", |
| 1036 | params.block_width, static_cast<u32>(params.target)); | 1059 | params.block_width, static_cast<u32>(params.target)); |
| 1037 | 1060 | ||
| 1038 | SwizzleFunc(gl_to_morton_fns, params, gl_buffer); | 1061 | SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0); |
| 1039 | } else { | 1062 | } else { |
| 1040 | std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes()); | 1063 | std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes()); |
| 1041 | } | 1064 | } |
| 1042 | } | 1065 | } |
| 1043 | 1066 | ||
| 1044 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | 1067 | void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, |
| 1045 | void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { | 1068 | GLuint draw_fb_handle) { |
| 1046 | if (params.type == SurfaceType::Fill) | 1069 | const auto& rect{params.GetRect(mip_map)}; |
| 1047 | return; | ||
| 1048 | |||
| 1049 | MICROPROFILE_SCOPE(OpenGL_TextureUL); | ||
| 1050 | |||
| 1051 | const auto& rect{params.GetRect()}; | ||
| 1052 | 1070 | ||
| 1053 | // Load data from memory to the surface | 1071 | // Load data from memory to the surface |
| 1054 | const GLint x0 = static_cast<GLint>(rect.left); | 1072 | const GLint x0 = static_cast<GLint>(rect.left); |
| 1055 | const GLint y0 = static_cast<GLint>(rect.bottom); | 1073 | const GLint y0 = static_cast<GLint>(rect.bottom); |
| 1056 | std::size_t buffer_offset = | 1074 | std::size_t buffer_offset = |
| 1057 | static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + | 1075 | static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) + |
| 1058 | static_cast<std::size_t>(x0)) * | 1076 | static_cast<std::size_t>(x0)) * |
| 1059 | SurfaceParams::GetBytesPerPixel(params.pixel_format); | 1077 | SurfaceParams::GetBytesPerPixel(params.pixel_format); |
| 1060 | 1078 | ||
| @@ -1072,88 +1090,117 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle | |||
| 1072 | cur_state.Apply(); | 1090 | cur_state.Apply(); |
| 1073 | 1091 | ||
| 1074 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT | 1092 | // Ensure no bad interactions with GL_UNPACK_ALIGNMENT |
| 1075 | ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); | 1093 | ASSERT(params.MipWidth(mip_map) * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == |
| 1076 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width)); | 1094 | 0); |
| 1095 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map))); | ||
| 1077 | 1096 | ||
| 1097 | GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false)); | ||
| 1078 | glActiveTexture(GL_TEXTURE0); | 1098 | glActiveTexture(GL_TEXTURE0); |
| 1079 | if (tuple.compressed) { | 1099 | if (tuple.compressed) { |
| 1080 | switch (params.target) { | 1100 | switch (params.target) { |
| 1081 | case SurfaceParams::SurfaceTarget::Texture2D: | 1101 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 1082 | glCompressedTexImage2D( | 1102 | glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, |
| 1083 | SurfaceTargetToGL(params.target), 0, tuple.internal_format, | 1103 | static_cast<GLsizei>(params.MipWidth(mip_map)), |
| 1084 | static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, | 1104 | static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size, |
| 1085 | static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); | 1105 | &gl_buffer[mip_map][buffer_offset]); |
| 1086 | break; | 1106 | break; |
| 1087 | case SurfaceParams::SurfaceTarget::Texture3D: | 1107 | case SurfaceParams::SurfaceTarget::Texture3D: |
| 1108 | glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, | ||
| 1109 | static_cast<GLsizei>(params.MipWidth(mip_map)), | ||
| 1110 | static_cast<GLsizei>(params.MipHeight(mip_map)), | ||
| 1111 | static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size, | ||
| 1112 | &gl_buffer[mip_map][buffer_offset]); | ||
| 1113 | break; | ||
| 1088 | case SurfaceParams::SurfaceTarget::Texture2DArray: | 1114 | case SurfaceParams::SurfaceTarget::Texture2DArray: |
| 1089 | glCompressedTexImage3D( | 1115 | glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, |
| 1090 | SurfaceTargetToGL(params.target), 0, tuple.internal_format, | 1116 | static_cast<GLsizei>(params.MipWidth(mip_map)), |
| 1091 | static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), | 1117 | static_cast<GLsizei>(params.MipHeight(mip_map)), |
| 1092 | static_cast<GLsizei>(params.depth), 0, | 1118 | static_cast<GLsizei>(params.depth), 0, image_size, |
| 1093 | static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); | 1119 | &gl_buffer[mip_map][buffer_offset]); |
| 1094 | break; | 1120 | break; |
| 1095 | case SurfaceParams::SurfaceTarget::TextureCubemap: | 1121 | case SurfaceParams::SurfaceTarget::TextureCubemap: { |
| 1122 | GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map)); | ||
| 1096 | for (std::size_t face = 0; face < params.depth; ++face) { | 1123 | for (std::size_t face = 0; face < params.depth; ++face) { |
| 1097 | glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), | 1124 | glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), |
| 1098 | 0, tuple.internal_format, static_cast<GLsizei>(params.width), | 1125 | mip_map, tuple.internal_format, |
| 1099 | static_cast<GLsizei>(params.height), 0, | 1126 | static_cast<GLsizei>(params.MipWidth(mip_map)), |
| 1100 | static_cast<GLsizei>(params.SizeInBytesCubeFaceGL()), | 1127 | static_cast<GLsizei>(params.MipHeight(mip_map)), 0, |
| 1101 | &gl_buffer[buffer_offset]); | 1128 | layer_size, &gl_buffer[mip_map][buffer_offset]); |
| 1102 | buffer_offset += params.SizeInBytesCubeFace(); | 1129 | buffer_offset += layer_size; |
| 1103 | } | 1130 | } |
| 1104 | break; | 1131 | break; |
| 1132 | } | ||
| 1105 | default: | 1133 | default: |
| 1106 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | 1134 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", |
| 1107 | static_cast<u32>(params.target)); | 1135 | static_cast<u32>(params.target)); |
| 1108 | UNREACHABLE(); | 1136 | UNREACHABLE(); |
| 1109 | glCompressedTexImage2D( | 1137 | glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format, |
| 1110 | GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), | 1138 | static_cast<GLsizei>(params.MipWidth(mip_map)), |
| 1111 | static_cast<GLsizei>(params.height), 0, | 1139 | static_cast<GLsizei>(params.MipHeight(mip_map)), 0, |
| 1112 | static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); | 1140 | static_cast<GLsizei>(params.size_in_bytes_gl), |
| 1141 | &gl_buffer[mip_map][buffer_offset]); | ||
| 1113 | } | 1142 | } |
| 1114 | } else { | 1143 | } else { |
| 1115 | 1144 | ||
| 1116 | switch (params.target) { | 1145 | switch (params.target) { |
| 1117 | case SurfaceParams::SurfaceTarget::Texture1D: | 1146 | case SurfaceParams::SurfaceTarget::Texture1D: |
| 1118 | glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, | 1147 | glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0, |
| 1119 | static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, | 1148 | static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, |
| 1120 | &gl_buffer[buffer_offset]); | 1149 | &gl_buffer[mip_map][buffer_offset]); |
| 1121 | break; | 1150 | break; |
| 1122 | case SurfaceParams::SurfaceTarget::Texture2D: | 1151 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 1123 | glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, | 1152 | glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0, |
| 1124 | static_cast<GLsizei>(rect.GetWidth()), | 1153 | static_cast<GLsizei>(rect.GetWidth()), |
| 1125 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | 1154 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, |
| 1126 | &gl_buffer[buffer_offset]); | 1155 | &gl_buffer[mip_map][buffer_offset]); |
| 1127 | break; | 1156 | break; |
| 1128 | case SurfaceParams::SurfaceTarget::Texture3D: | 1157 | case SurfaceParams::SurfaceTarget::Texture3D: |
| 1158 | glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, | ||
| 1159 | static_cast<GLsizei>(rect.GetWidth()), | ||
| 1160 | static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map), | ||
| 1161 | tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]); | ||
| 1162 | break; | ||
| 1129 | case SurfaceParams::SurfaceTarget::Texture2DArray: | 1163 | case SurfaceParams::SurfaceTarget::Texture2DArray: |
| 1130 | glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, | 1164 | glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, |
| 1131 | static_cast<GLsizei>(rect.GetWidth()), | 1165 | static_cast<GLsizei>(rect.GetWidth()), |
| 1132 | static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, | 1166 | static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, |
| 1133 | tuple.type, &gl_buffer[buffer_offset]); | 1167 | tuple.type, &gl_buffer[mip_map][buffer_offset]); |
| 1134 | break; | 1168 | break; |
| 1135 | case SurfaceParams::SurfaceTarget::TextureCubemap: | 1169 | case SurfaceParams::SurfaceTarget::TextureCubemap: { |
| 1170 | std::size_t start = buffer_offset; | ||
| 1136 | for (std::size_t face = 0; face < params.depth; ++face) { | 1171 | for (std::size_t face = 0; face < params.depth; ++face) { |
| 1137 | glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, x0, | 1172 | glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map, |
| 1138 | y0, static_cast<GLsizei>(rect.GetWidth()), | 1173 | x0, y0, static_cast<GLsizei>(rect.GetWidth()), |
| 1139 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | 1174 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, |
| 1140 | &gl_buffer[buffer_offset]); | 1175 | &gl_buffer[mip_map][buffer_offset]); |
| 1141 | buffer_offset += params.SizeInBytesCubeFace(); | 1176 | buffer_offset += params.LayerSizeGL(mip_map); |
| 1142 | } | 1177 | } |
| 1143 | break; | 1178 | break; |
| 1179 | } | ||
| 1144 | default: | 1180 | default: |
| 1145 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | 1181 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", |
| 1146 | static_cast<u32>(params.target)); | 1182 | static_cast<u32>(params.target)); |
| 1147 | UNREACHABLE(); | 1183 | UNREACHABLE(); |
| 1148 | glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), | 1184 | glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()), |
| 1149 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | 1185 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, |
| 1150 | &gl_buffer[buffer_offset]); | 1186 | &gl_buffer[mip_map][buffer_offset]); |
| 1151 | } | 1187 | } |
| 1152 | } | 1188 | } |
| 1153 | 1189 | ||
| 1154 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | 1190 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
| 1155 | } | 1191 | } |
| 1156 | 1192 | ||
| 1193 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | ||
| 1194 | void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { | ||
| 1195 | if (params.type == SurfaceType::Fill) | ||
| 1196 | return; | ||
| 1197 | |||
| 1198 | MICROPROFILE_SCOPE(OpenGL_TextureUL); | ||
| 1199 | |||
| 1200 | for (u32 i = 0; i < params.max_mip_level; i++) | ||
| 1201 | UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle); | ||
| 1202 | } | ||
| 1203 | |||
| 1157 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { | 1204 | RasterizerCacheOpenGL::RasterizerCacheOpenGL() { |
| 1158 | read_framebuffer.Create(); | 1205 | read_framebuffer.Create(); |
| 1159 | draw_framebuffer.Create(); | 1206 | 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..e72f4f2d2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -404,7 +404,7 @@ struct SurfaceParams { | |||
| 404 | 128, // BC7U | 404 | 128, // BC7U |
| 405 | 32, // ASTC_2D_4X4_SRGB | 405 | 32, // ASTC_2D_4X4_SRGB |
| 406 | 16, // ASTC_2D_8X8_SRGB | 406 | 16, // ASTC_2D_8X8_SRGB |
| 407 | 32, // ASTC_2D_8X5_SRGB | 407 | 16, // ASTC_2D_8X5_SRGB |
| 408 | 32, // ASTC_2D_5X4_SRGB | 408 | 32, // ASTC_2D_5X4_SRGB |
| 409 | 32, // Z32F | 409 | 32, // Z32F |
| 410 | 16, // Z16 | 410 | 16, // Z16 |
| @@ -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,78 @@ 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 | // Auto block resizing algorithm from: | ||
| 919 | // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c | ||
| 920 | u32 MipBlockHeight(u32 mip_level) const { | ||
| 921 | if (mip_level == 0) | ||
| 922 | return block_height; | ||
| 923 | u32 alt_height = MipHeight(mip_level); | ||
| 924 | u32 h = GetDefaultBlockHeight(pixel_format); | ||
| 925 | u32 blocks_in_y = (alt_height + h - 1) / h; | ||
| 926 | u32 bh = 16; | ||
| 927 | while (bh > 1 && blocks_in_y <= bh * 4) { | ||
| 928 | bh >>= 1; | ||
| 929 | } | ||
| 930 | return bh; | ||
| 931 | } | ||
| 932 | |||
| 933 | u32 MipBlockDepth(u32 mip_level) const { | ||
| 934 | if (mip_level == 0) | ||
| 935 | return block_depth; | ||
| 936 | if (is_layered) | ||
| 937 | return 1; | ||
| 938 | u32 depth = MipDepth(mip_level); | ||
| 939 | u32 bd = 32; | ||
| 940 | while (bd > 1 && depth * 2 <= bd) { | ||
| 941 | bd >>= 1; | ||
| 942 | } | ||
| 943 | if (bd == 32) { | ||
| 944 | u32 bh = MipBlockHeight(mip_level); | ||
| 945 | if (bh >= 4) | ||
| 946 | return 16; | ||
| 947 | } | ||
| 948 | return bd; | ||
| 883 | } | 949 | } |
| 884 | 950 | ||
| 885 | /// Creates SurfaceParams from a texture configuration | 951 | /// Creates SurfaceParams from a texture configuration |
| @@ -940,7 +1006,10 @@ struct SurfaceParams { | |||
| 940 | } rt; | 1006 | } rt; |
| 941 | 1007 | ||
| 942 | private: | 1008 | private: |
| 943 | std::size_t InnerMemorySize(bool layer_only = false) const; | 1009 | std::size_t InnerMipmapMemorySize(u32 mip_level, bool force_gl = false, bool layer_only = false, |
| 1010 | bool uncompressed = false) const; | ||
| 1011 | std::size_t InnerMemorySize(bool force_gl = false, bool layer_only = false, | ||
| 1012 | bool uncompressed = false) const; | ||
| 944 | }; | 1013 | }; |
| 945 | 1014 | ||
| 946 | }; // namespace OpenGL | 1015 | }; // namespace OpenGL |
| @@ -1002,8 +1071,10 @@ public: | |||
| 1002 | void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); | 1071 | void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); |
| 1003 | 1072 | ||
| 1004 | private: | 1073 | private: |
| 1074 | void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); | ||
| 1075 | |||
| 1005 | OGLTexture texture; | 1076 | OGLTexture texture; |
| 1006 | std::vector<u8> gl_buffer; | 1077 | std::vector<std::vector<u8>> gl_buffer; |
| 1007 | SurfaceParams params; | 1078 | SurfaceParams params; |
| 1008 | GLenum gl_target; | 1079 | GLenum gl_target; |
| 1009 | std::size_t cached_size_in_bytes; | 1080 | std::size_t cached_size_in_bytes; |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 1a03a677f..9522fd344 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "video_core/engines/maxwell_3d.h" | 8 | #include "video_core/engines/maxwell_3d.h" |
| 9 | #include "video_core/renderer_opengl/gl_shader_cache.h" | 9 | #include "video_core/renderer_opengl/gl_shader_cache.h" |
| 10 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 10 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| 11 | #include "video_core/renderer_opengl/utils.h" | ||
| 11 | #include "video_core/utils.h" | 12 | #include "video_core/utils.h" |
| 12 | 13 | ||
| 13 | namespace OpenGL { | 14 | namespace OpenGL { |
| @@ -89,7 +90,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type) | |||
| 89 | shader.Create(program_result.first.c_str(), gl_type); | 90 | shader.Create(program_result.first.c_str(), gl_type); |
| 90 | program.Create(true, shader.handle); | 91 | program.Create(true, shader.handle); |
| 91 | SetShaderUniformBlockBindings(program.handle); | 92 | SetShaderUniformBlockBindings(program.handle); |
| 92 | VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr); | 93 | LabelGLObject(GL_PROGRAM, program.handle, addr); |
| 93 | } else { | 94 | } else { |
| 94 | // Store shader's code to lazily build it on draw | 95 | // Store shader's code to lazily build it on draw |
| 95 | geometry_programs.code = program_result.first; | 96 | geometry_programs.code = program_result.first; |
| @@ -130,7 +131,7 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, | |||
| 130 | shader.Create(source.c_str(), GL_GEOMETRY_SHADER); | 131 | shader.Create(source.c_str(), GL_GEOMETRY_SHADER); |
| 131 | target_program.Create(true, shader.handle); | 132 | target_program.Create(true, shader.handle); |
| 132 | SetShaderUniformBlockBindings(target_program.handle); | 133 | SetShaderUniformBlockBindings(target_program.handle); |
| 133 | VideoCore::LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name); | 134 | LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name); |
| 134 | return target_program.handle; | 135 | return target_program.handle; |
| 135 | }; | 136 | }; |
| 136 | 137 | ||
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 0f6dcab2b..87d511c38 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -135,12 +135,29 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { | |||
| 135 | return {}; | 135 | return {}; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { | 138 | inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode, |
| 139 | Tegra::Texture::TextureMipmapFilter mip_filter_mode) { | ||
| 139 | switch (filter_mode) { | 140 | switch (filter_mode) { |
| 140 | case Tegra::Texture::TextureFilter::Linear: | 141 | case Tegra::Texture::TextureFilter::Linear: { |
| 141 | return GL_LINEAR; | 142 | switch (mip_filter_mode) { |
| 142 | case Tegra::Texture::TextureFilter::Nearest: | 143 | case Tegra::Texture::TextureMipmapFilter::None: |
| 143 | return GL_NEAREST; | 144 | return GL_LINEAR; |
| 145 | case Tegra::Texture::TextureMipmapFilter::Nearest: | ||
| 146 | return GL_NEAREST_MIPMAP_LINEAR; | ||
| 147 | case Tegra::Texture::TextureMipmapFilter::Linear: | ||
| 148 | return GL_LINEAR_MIPMAP_LINEAR; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | case Tegra::Texture::TextureFilter::Nearest: { | ||
| 152 | switch (mip_filter_mode) { | ||
| 153 | case Tegra::Texture::TextureMipmapFilter::None: | ||
| 154 | return GL_NEAREST; | ||
| 155 | case Tegra::Texture::TextureMipmapFilter::Nearest: | ||
| 156 | return GL_NEAREST_MIPMAP_NEAREST; | ||
| 157 | case Tegra::Texture::TextureMipmapFilter::Linear: | ||
| 158 | return GL_LINEAR_MIPMAP_NEAREST; | ||
| 159 | } | ||
| 160 | } | ||
| 144 | } | 161 | } |
| 145 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", | 162 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", |
| 146 | static_cast<u32>(filter_mode)); | 163 | static_cast<u32>(filter_mode)); |
diff --git a/src/video_core/renderer_opengl/utils.cpp b/src/video_core/renderer_opengl/utils.cpp new file mode 100644 index 000000000..d84634cb3 --- /dev/null +++ b/src/video_core/renderer_opengl/utils.cpp | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <string> | ||
| 6 | #include <fmt/format.h> | ||
| 7 | #include <glad/glad.h> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "video_core/renderer_opengl/utils.h" | ||
| 10 | |||
| 11 | namespace OpenGL { | ||
| 12 | |||
| 13 | void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info) { | ||
| 14 | if (!GLAD_GL_KHR_debug) { | ||
| 15 | return; // We don't need to throw an error as this is just for debugging | ||
| 16 | } | ||
| 17 | const std::string nice_addr = fmt::format("0x{:016x}", addr); | ||
| 18 | std::string object_label; | ||
| 19 | |||
| 20 | if (extra_info.empty()) { | ||
| 21 | switch (identifier) { | ||
| 22 | case GL_TEXTURE: | ||
| 23 | object_label = "Texture@" + nice_addr; | ||
| 24 | break; | ||
| 25 | case GL_PROGRAM: | ||
| 26 | object_label = "Shader@" + nice_addr; | ||
| 27 | break; | ||
| 28 | default: | ||
| 29 | object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr); | ||
| 30 | break; | ||
| 31 | } | ||
| 32 | } else { | ||
| 33 | object_label = extra_info + '@' + nice_addr; | ||
| 34 | } | ||
| 35 | glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str())); | ||
| 36 | } | ||
| 37 | |||
| 38 | } // namespace OpenGL \ No newline at end of file | ||
diff --git a/src/video_core/renderer_opengl/utils.h b/src/video_core/renderer_opengl/utils.h new file mode 100644 index 000000000..1fcb6fc11 --- /dev/null +++ b/src/video_core/renderer_opengl/utils.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | // Copyright 2014 Citra 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 <string> | ||
| 8 | #include <glad/glad.h> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace OpenGL { | ||
| 12 | |||
| 13 | void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info = ""); | ||
| 14 | |||
| 15 | } // namespace OpenGL \ No newline at end of file | ||
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index 4726f54a5..b390219e4 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h | |||
| @@ -10,6 +10,12 @@ | |||
| 10 | 10 | ||
| 11 | namespace Tegra::Texture { | 11 | namespace Tegra::Texture { |
| 12 | 12 | ||
| 13 | // GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents | ||
| 14 | // an small rect of (64/bytes_per_pixel)X8. | ||
| 15 | inline std::size_t GetGOBSize() { | ||
| 16 | return 512; | ||
| 17 | } | ||
| 18 | |||
| 13 | /** | 19 | /** |
| 14 | * Unswizzles a swizzled texture without changing its format. | 20 | * Unswizzles a swizzled texture without changing its format. |
| 15 | */ | 21 | */ |
diff --git a/src/video_core/utils.h b/src/video_core/utils.h index 237cc1307..e0a14d48f 100644 --- a/src/video_core/utils.h +++ b/src/video_core/utils.h | |||
| @@ -161,30 +161,4 @@ static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixe | |||
| 161 | } | 161 | } |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, | ||
| 165 | std::string extra_info = "") { | ||
| 166 | if (!GLAD_GL_KHR_debug) { | ||
| 167 | return; // We don't need to throw an error as this is just for debugging | ||
| 168 | } | ||
| 169 | const std::string nice_addr = fmt::format("0x{:016x}", addr); | ||
| 170 | std::string object_label; | ||
| 171 | |||
| 172 | if (extra_info.empty()) { | ||
| 173 | switch (identifier) { | ||
| 174 | case GL_TEXTURE: | ||
| 175 | object_label = "Texture@" + nice_addr; | ||
| 176 | break; | ||
| 177 | case GL_PROGRAM: | ||
| 178 | object_label = "Shader@" + nice_addr; | ||
| 179 | break; | ||
| 180 | default: | ||
| 181 | object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr); | ||
| 182 | break; | ||
| 183 | } | ||
| 184 | } else { | ||
| 185 | object_label = extra_info + '@' + nice_addr; | ||
| 186 | } | ||
| 187 | glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str())); | ||
| 188 | } | ||
| 189 | |||
| 190 | } // namespace VideoCore | 164 | } // namespace VideoCore |