diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_buffer_cache.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_primitive_assembler.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 19 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 5 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 405 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 874 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 5 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 210 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.h | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 27 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 11 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/utils.cpp | 38 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/utils.h | 15 |
15 files changed, 551 insertions, 1081 deletions
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index c142095c5..41a54b3e7 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp @@ -17,7 +17,7 @@ OGLBufferCache::OGLBufferCache(std::size_t size) : stream_buffer(GL_ARRAY_BUFFER GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, std::size_t alignment, bool cache) { auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager(); - const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; + const std::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; // Cache management is a big overhead, so only cache entries with a given size. // TODO: Figure out which size is the best for given games. diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp index ee1d9601b..741f14bc3 100644 --- a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp +++ b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp @@ -45,7 +45,7 @@ GLintptr PrimitiveAssembler::MakeQuadIndexed(Tegra::GPUVAddr gpu_addr, std::size auto [dst_pointer, index_offset] = buffer_cache.ReserveMemory(map_size); auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager(); - const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; + const std::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; const u8* source{Memory::GetPointer(*cpu_addr)}; for (u32 primitive = 0; primitive < count / 4; ++primitive) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index cb180b93c..75e31c6de 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -30,8 +30,8 @@ namespace OpenGL { using Maxwell = Tegra::Engines::Maxwell3D::Regs; -using PixelFormat = SurfaceParams::PixelFormat; -using SurfaceType = SurfaceParams::SurfaceType; +using PixelFormat = VideoCore::Surface::PixelFormat; +using SurfaceType = VideoCore::Surface::SurfaceType; MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192)); @@ -401,7 +401,7 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, bool preserve_contents, - boost::optional<std::size_t> single_color_target) { + std::optional<std::size_t> single_color_target) { MICROPROFILE_SCOPE(OpenGL_Framebuffer); const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; @@ -703,7 +703,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, // Verify that the cached surface is the same size and format as the requested framebuffer const auto& params{surface->GetSurfaceParams()}; - const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)}; + const auto& pixel_format{ + VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)}; ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different"); @@ -731,11 +732,15 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr if (mag_filter != config.mag_filter) { mag_filter = config.mag_filter; - glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter)); + glSamplerParameteri( + s, GL_TEXTURE_MAG_FILTER, + MaxwellToGL::TextureFilterMode(mag_filter, Tegra::Texture::TextureMipmapFilter::None)); } - if (min_filter != config.min_filter) { + if (min_filter != config.min_filter || mip_filter != config.mip_filter) { min_filter = config.min_filter; - glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter)); + mip_filter = config.mip_filter; + glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, + MaxwellToGL::TextureFilterMode(min_filter, mip_filter)); } 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..47097c569 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -8,12 +8,12 @@ #include <cstddef> #include <map> #include <memory> +#include <optional> #include <tuple> #include <utility> #include <vector> #include <boost/icl/interval_map.hpp> -#include <boost/optional.hpp> #include <boost/range/iterator_range.hpp> #include <glad/glad.h> @@ -93,6 +93,7 @@ private: private: Tegra::Texture::TextureFilter mag_filter; Tegra::Texture::TextureFilter min_filter; + Tegra::Texture::TextureMipmapFilter mip_filter; Tegra::Texture::WrapMode wrap_u; Tegra::Texture::WrapMode wrap_v; Tegra::Texture::WrapMode wrap_p; @@ -110,7 +111,7 @@ private: */ void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, bool preserve_contents = true, - boost::optional<std::size_t> single_color_target = {}); + std::optional<std::size_t> single_color_target = {}); /* * Configures the current constbuffers to use for the draw command. diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index b057e2efa..f194a7687 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -16,15 +16,21 @@ #include "core/settings.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h" +#include "video_core/renderer_opengl/utils.h" +#include "video_core/surface.h" #include "video_core/textures/astc.h" #include "video_core/textures/decoders.h" #include "video_core/utils.h" namespace OpenGL { -using SurfaceType = SurfaceParams::SurfaceType; -using PixelFormat = SurfaceParams::PixelFormat; -using ComponentType = SurfaceParams::ComponentType; +using VideoCore::Surface::ComponentTypeFromDepthFormat; +using VideoCore::Surface::ComponentTypeFromRenderTarget; +using VideoCore::Surface::ComponentTypeFromTexture; +using VideoCore::Surface::PixelFormatFromDepthFormat; +using VideoCore::Surface::PixelFormatFromRenderTargetFormat; +using VideoCore::Surface::PixelFormatFromTextureFormat; +using VideoCore::Surface::SurfaceTargetFromTextureType; struct FormatTuple { GLint internal_format; @@ -34,46 +40,6 @@ struct FormatTuple { bool compressed; }; -static bool IsPixelFormatASTC(PixelFormat format) { - switch (format) { - case PixelFormat::ASTC_2D_4X4: - case PixelFormat::ASTC_2D_5X4: - case PixelFormat::ASTC_2D_8X8: - case PixelFormat::ASTC_2D_8X5: - case PixelFormat::ASTC_2D_4X4_SRGB: - case PixelFormat::ASTC_2D_5X4_SRGB: - case PixelFormat::ASTC_2D_8X8_SRGB: - case PixelFormat::ASTC_2D_8X5_SRGB: - return true; - default: - return false; - } -} - -static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) { - switch (format) { - case PixelFormat::ASTC_2D_4X4: - return {4, 4}; - case PixelFormat::ASTC_2D_5X4: - return {5, 4}; - case PixelFormat::ASTC_2D_8X8: - return {8, 8}; - case PixelFormat::ASTC_2D_8X5: - return {8, 5}; - case PixelFormat::ASTC_2D_4X4_SRGB: - return {4, 4}; - case PixelFormat::ASTC_2D_5X4_SRGB: - return {5, 4}; - case PixelFormat::ASTC_2D_8X8_SRGB: - return {8, 8}; - case PixelFormat::ASTC_2D_8X5_SRGB: - return {8, 5}; - default: - LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format)); - UNREACHABLE(); - } -} - void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) { auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()}; const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)}; @@ -90,27 +56,36 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) { } } -std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { +std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only, + bool uncompressed) const { const u32 compression_factor{GetCompressionFactor(pixel_format)}; const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; u32 m_depth = (layer_only ? 1U : depth); - u32 m_width = std::max(1U, width / compression_factor); - u32 m_height = std::max(1U, height / compression_factor); - std::size_t size = Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, - m_depth, block_height, block_depth); - u32 m_block_height = block_height; - u32 m_block_depth = block_depth; - std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size - for (u32 i = 1; i < max_mip_level; i++) { - m_width = std::max(1U, m_width / 2); - m_height = std::max(1U, m_height / 2); - m_depth = std::max(1U, m_depth / 2); - m_block_height = std::max(1U, m_block_height / 2); - m_block_depth = std::max(1U, m_block_depth / 2); - size += Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, m_depth, - m_block_height, m_block_depth); + u32 m_width = MipWidth(mip_level); + u32 m_height = MipHeight(mip_level); + m_width = uncompressed ? m_width + : std::max(1U, (m_width + compression_factor - 1) / compression_factor); + m_height = uncompressed + ? m_height + : std::max(1U, (m_height + compression_factor - 1) / compression_factor); + m_depth = std::max(1U, m_depth >> mip_level); + u32 m_block_height = MipBlockHeight(mip_level); + u32 m_block_depth = MipBlockDepth(mip_level); + return Tegra::Texture::CalculateSize(force_gl ? false : is_tiled, bytes_per_pixel, m_width, + m_height, m_depth, m_block_height, m_block_depth); +} + +std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, + bool uncompressed) const { + std::size_t block_size_bytes = Tegra::Texture::GetGOBSize() * block_height * block_depth; + std::size_t size = 0; + for (u32 i = 0; i < max_mip_level; i++) { + size += InnerMipmapMemorySize(i, force_gl, layer_only, uncompressed); + } + if (!force_gl && is_tiled) { + size = Common::AlignUp(size, block_size_bytes); } - return is_tiled ? Common::AlignUp(size, block_size_bytes) : size; + return size; } /*static*/ SurfaceParams SurfaceParams::CreateForTexture( @@ -188,7 +163,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { params.unaligned_height = config.height; params.target = SurfaceTarget::Texture2D; params.depth = 1; - params.max_mip_level = 0; + params.max_mip_level = 1; params.is_layered = false; // Render target specific parameters, not used for caching @@ -222,7 +197,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { params.unaligned_height = zeta_height; params.target = SurfaceTarget::Texture2D; params.depth = 1; - params.max_mip_level = 0; + params.max_mip_level = 1; params.is_layered = false; params.rt = {}; @@ -249,7 +224,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { params.unaligned_height = config.height; params.target = SurfaceTarget::Texture2D; params.depth = 1; - params.max_mip_level = 0; + params.max_mip_level = 1; params.rt = {}; params.InitCacheParameters(config.Address()); @@ -257,7 +232,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { return params; } -static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{ +static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{ {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI @@ -273,7 +248,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, false}, // R11FG11FB10F {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI - {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, + {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXT1 {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXT23 @@ -318,7 +293,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4 {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 // Compressed sRGB formats - {GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, + {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXT1_SRGB {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXT23_SRGB @@ -345,19 +320,19 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form ComponentType::Float, false}, // Z32FS8 }}; -static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) { +static GLenum SurfaceTargetToGL(SurfaceTarget target) { switch (target) { - case SurfaceParams::SurfaceTarget::Texture1D: + case SurfaceTarget::Texture1D: return GL_TEXTURE_1D; - case SurfaceParams::SurfaceTarget::Texture2D: + case SurfaceTarget::Texture2D: return GL_TEXTURE_2D; - case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceTarget::Texture3D: return GL_TEXTURE_3D; - case SurfaceParams::SurfaceTarget::Texture1DArray: + case SurfaceTarget::Texture1DArray: return GL_TEXTURE_1D_ARRAY; - case SurfaceParams::SurfaceTarget::Texture2DArray: + case SurfaceTarget::Texture2DArray: return GL_TEXTURE_2D_ARRAY; - case SurfaceParams::SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubemap: return GL_TEXTURE_CUBE_MAP; } LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); @@ -373,40 +348,19 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType return format; } -MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { - u32 actual_height{unaligned_height}; +MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const { + u32 actual_height{std::max(1U, unaligned_height >> mip_level)}; if (IsPixelFormatASTC(pixel_format)) { // ASTC formats must stop at the ATSC block size boundary actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second); } - return {0, actual_height, width, 0}; -} - -/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN -static bool IsFormatBCn(PixelFormat format) { - switch (format) { - case PixelFormat::DXT1: - case PixelFormat::DXT23: - case PixelFormat::DXT45: - case PixelFormat::DXN1: - case PixelFormat::DXN2SNORM: - case PixelFormat::DXN2UNORM: - case PixelFormat::BC7U: - case PixelFormat::BC6H_UF16: - case PixelFormat::BC6H_SF16: - case PixelFormat::DXT1_SRGB: - case PixelFormat::DXT23_SRGB: - case PixelFormat::DXT45_SRGB: - case PixelFormat::BC7U_SRGB: - return true; - } - return false; + return {0, actual_height, MipWidth(mip_level), 0}; } template <bool morton_to_gl, PixelFormat format> void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer, std::size_t gl_buffer_size, VAddr addr) { - constexpr u32 bytes_per_pixel = SurfaceParams::GetBytesPerPixel(format); + constexpr u32 bytes_per_pixel = GetBytesPerPixel(format); // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual // pixel values. @@ -425,7 +379,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d } using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr), - SurfaceParams::MaxPixelFormat>; + VideoCore::Surface::MaxPixelFormat>; static constexpr GLConversionArray morton_to_gl_fns = { // clang-format off @@ -563,28 +517,31 @@ static constexpr GLConversionArray gl_to_morton_fns = { }; void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, - std::vector<u8>& gl_buffer) { - u32 depth = params.depth; - if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { + std::vector<u8>& gl_buffer, u32 mip_level) { + u32 depth = params.MipDepth(mip_level); + if (params.target == SurfaceTarget::Texture2D) { // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented. depth = 1U; } if (params.is_layered) { - u64 offset = 0; + u64 offset = params.GetMipmapLevelOffset(mip_level); u64 offset_gl = 0; u64 layer_size = params.LayerMemorySize(); - u64 gl_size = params.LayerSizeGL(); - for (u32 i = 0; i < depth; i++) { + u64 gl_size = params.LayerSizeGL(mip_level); + for (u32 i = 0; i < params.depth; i++) { functions[static_cast<std::size_t>(params.pixel_format)]( - params.width, params.block_height, params.height, params.block_depth, 1, + params.MipWidth(mip_level), params.MipBlockHeight(mip_level), + params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1, gl_buffer.data() + offset_gl, gl_size, params.addr + offset); offset += layer_size; offset_gl += gl_size; } } else { + u64 offset = params.GetMipmapLevelOffset(mip_level); functions[static_cast<std::size_t>(params.pixel_format)]( - params.width, params.block_height, params.height, params.block_depth, depth, - gl_buffer.data(), gl_buffer.size(), params.addr); + params.MipWidth(mip_level), params.MipBlockHeight(mip_level), + params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(), + gl_buffer.size(), params.addr + offset); } } @@ -609,13 +566,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, if (src_params.type == SurfaceType::ColorTexture) { switch (src_params.target) { - case SurfaceParams::SurfaceTarget::Texture2D: + case SurfaceTarget::Texture2D: glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, GL_TEXTURE_2D, src_surface->Texture().handle, 0); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); break; - case SurfaceParams::SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubemap: glFramebufferTexture2D( GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), @@ -624,12 +581,12 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); break; - case SurfaceParams::SurfaceTarget::Texture2DArray: + case SurfaceTarget::Texture2DArray: glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, src_surface->Texture().handle, 0, 0); glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); break; - case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceTarget::Texture3D: glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, SurfaceTargetToGL(src_params.target), src_surface->Texture().handle, 0, 0); @@ -645,13 +602,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, } switch (dst_params.target) { - case SurfaceParams::SurfaceTarget::Texture2D: + case SurfaceTarget::Texture2D: glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, GL_TEXTURE_2D, dst_surface->Texture().handle, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); break; - case SurfaceParams::SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubemap: glFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), @@ -660,13 +617,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); break; - case SurfaceParams::SurfaceTarget::Texture2DArray: + case SurfaceTarget::Texture2DArray: glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, dst_surface->Texture().handle, 0, 0); glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); break; - case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceTarget::Texture3D: glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, SurfaceTargetToGL(dst_params.target), dst_surface->Texture().handle, 0, 0); @@ -787,21 +744,21 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface, UNREACHABLE(); } else { switch (dst_params.target) { - case SurfaceParams::SurfaceTarget::Texture1D: + case SurfaceTarget::Texture1D: glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format, dest_format.type, nullptr); break; - case SurfaceParams::SurfaceTarget::Texture2D: + case SurfaceTarget::Texture2D: glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height, dest_format.format, dest_format.type, nullptr); break; - case SurfaceParams::SurfaceTarget::Texture3D: - case SurfaceParams::SurfaceTarget::Texture2DArray: + case SurfaceTarget::Texture3D: + case SurfaceTarget::Texture2DArray: glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height, static_cast<GLsizei>(dst_params.depth), dest_format.format, dest_format.type, nullptr); break; - case SurfaceParams::SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubemap: glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, static_cast<GLint>(cubemap_face), width, height, 1, dest_format.format, dest_format.type, nullptr); @@ -838,35 +795,42 @@ CachedSurface::CachedSurface(const SurfaceParams& params) if (!format_tuple.compressed) { // Only pre-create the texture for non-compressed textures. switch (params.target) { - case SurfaceParams::SurfaceTarget::Texture1D: - glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, - rect.GetWidth()); + case SurfaceTarget::Texture1D: + glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level, + format_tuple.internal_format, rect.GetWidth()); break; - case SurfaceParams::SurfaceTarget::Texture2D: - case SurfaceParams::SurfaceTarget::TextureCubemap: - glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, - rect.GetWidth(), rect.GetHeight()); + case SurfaceTarget::Texture2D: + case SurfaceTarget::TextureCubemap: + glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level, + format_tuple.internal_format, rect.GetWidth(), rect.GetHeight()); break; - case SurfaceParams::SurfaceTarget::Texture3D: - case SurfaceParams::SurfaceTarget::Texture2DArray: - glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, - rect.GetWidth(), rect.GetHeight(), params.depth); + case SurfaceTarget::Texture3D: + case SurfaceTarget::Texture2DArray: + glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level, + format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(), + params.depth); break; default: LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", static_cast<u32>(params.target)); UNREACHABLE(); - glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(), - rect.GetHeight()); + glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format, + rect.GetWidth(), rect.GetHeight()); } } glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, + params.max_mip_level - 1); + if (params.max_mip_level == 1) { + glTexParameterf(SurfaceTargetToGL(params.target), GL_TEXTURE_LOD_BIAS, 1000.0); + } - VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr, - SurfaceParams::SurfaceTargetName(params.target)); + LabelGLObject(GL_TEXTURE, texture.handle, params.addr, + SurfaceParams::SurfaceTargetName(params.target)); // Clamp size to mapped GPU memory region // TODO(bunnei): Super Mario Odyssey maps a 0x40000 byte region and then uses it for a 0x80000 @@ -896,7 +860,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo S8Z24 s8z24_pixel{}; Z24S8 z24s8_pixel{}; - constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::S8Z24)}; + constexpr auto bpp{GetBytesPerPixel(PixelFormat::S8Z24)}; for (std::size_t y = 0; y < height; ++y) { for (std::size_t x = 0; x < width; ++x) { const std::size_t offset{bpp * (y * width + x)}; @@ -916,7 +880,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo } static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { - constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::G8R8U)}; + constexpr auto bpp{GetBytesPerPixel(PixelFormat::G8R8U)}; for (std::size_t y = 0; y < height; ++y) { for (std::size_t x = 0; x < width; ++x) { const std::size_t offset{bpp * (y * width + x)}; @@ -992,20 +956,22 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); void CachedSurface::LoadGLBuffer() { MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); - - gl_buffer.resize(params.size_in_bytes_gl); + gl_buffer.resize(params.max_mip_level); + for (u32 i = 0; i < params.max_mip_level; i++) + gl_buffer[i].resize(params.GetMipmapSizeGL(i)); if (params.is_tiled) { ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", params.block_width, static_cast<u32>(params.target)); - - SwizzleFunc(morton_to_gl_fns, params, gl_buffer); + for (u32 i = 0; i < params.max_mip_level; i++) + SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i); } else { const auto texture_src_data{Memory::GetPointer(params.addr)}; const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; - gl_buffer.assign(texture_src_data, texture_src_data_end); + gl_buffer[0].assign(texture_src_data, texture_src_data_end); } - - ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); + for (u32 i = 0; i < params.max_mip_level; i++) + ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), + params.MipHeight(i)); } MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); @@ -1015,18 +981,19 @@ void CachedSurface::FlushGLBuffer() { ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented"); // OpenGL temporary buffer needs to be big enough to store raw texture size - gl_buffer.resize(GetSizeInBytes()); + gl_buffer.resize(1); + gl_buffer[0].resize(GetSizeInBytes()); const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); // Ensure no bad interactions with GL_UNPACK_ALIGNMENT - ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); + ASSERT(params.width * GetBytesPerPixel(params.pixel_format) % 4 == 0); glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); ASSERT(!tuple.compressed); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, - static_cast<GLsizei>(gl_buffer.size()), gl_buffer.data()); + static_cast<GLsizei>(gl_buffer[0].size()), gl_buffer[0].data()); glPixelStorei(GL_PACK_ROW_LENGTH, 0); - ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, + ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer[0], params.pixel_format, params.width, params.height); ASSERT(params.type != SurfaceType::Fill); const u8* const texture_src_data = Memory::GetPointer(params.addr); @@ -1035,28 +1002,23 @@ void CachedSurface::FlushGLBuffer() { ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", params.block_width, static_cast<u32>(params.target)); - SwizzleFunc(gl_to_morton_fns, params, gl_buffer); + SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0); } else { - std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes()); + std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes()); } } -MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); -void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { - if (params.type == SurfaceType::Fill) - return; - - MICROPROFILE_SCOPE(OpenGL_TextureUL); - - const auto& rect{params.GetRect()}; +void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, + GLuint draw_fb_handle) { + const auto& rect{params.GetRect(mip_map)}; // Load data from memory to the surface const GLint x0 = static_cast<GLint>(rect.left); const GLint y0 = static_cast<GLint>(rect.bottom); std::size_t buffer_offset = - static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + + static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) + static_cast<std::size_t>(x0)) * - SurfaceParams::GetBytesPerPixel(params.pixel_format); + GetBytesPerPixel(params.pixel_format); const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); const GLuint target_tex = texture.handle; @@ -1072,88 +1034,116 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle cur_state.Apply(); // Ensure no bad interactions with GL_UNPACK_ALIGNMENT - ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width)); + ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map))); + GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false)); glActiveTexture(GL_TEXTURE0); if (tuple.compressed) { switch (params.target) { - case SurfaceParams::SurfaceTarget::Texture2D: - glCompressedTexImage2D( - SurfaceTargetToGL(params.target), 0, tuple.internal_format, - static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, - static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); + case SurfaceTarget::Texture2D: + glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, + static_cast<GLsizei>(params.MipWidth(mip_map)), + static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size, + &gl_buffer[mip_map][buffer_offset]); + break; + case SurfaceTarget::Texture3D: + glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, + static_cast<GLsizei>(params.MipWidth(mip_map)), + static_cast<GLsizei>(params.MipHeight(mip_map)), + static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size, + &gl_buffer[mip_map][buffer_offset]); break; - case SurfaceParams::SurfaceTarget::Texture3D: - case SurfaceParams::SurfaceTarget::Texture2DArray: - glCompressedTexImage3D( - SurfaceTargetToGL(params.target), 0, tuple.internal_format, - static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), - static_cast<GLsizei>(params.depth), 0, - static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); + case SurfaceTarget::Texture2DArray: + glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, + static_cast<GLsizei>(params.MipWidth(mip_map)), + static_cast<GLsizei>(params.MipHeight(mip_map)), + static_cast<GLsizei>(params.depth), 0, image_size, + &gl_buffer[mip_map][buffer_offset]); break; - case SurfaceParams::SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubemap: { + GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map)); for (std::size_t face = 0; face < params.depth; ++face) { glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), - 0, tuple.internal_format, static_cast<GLsizei>(params.width), - static_cast<GLsizei>(params.height), 0, - static_cast<GLsizei>(params.SizeInBytesCubeFaceGL()), - &gl_buffer[buffer_offset]); - buffer_offset += params.SizeInBytesCubeFace(); + mip_map, tuple.internal_format, + static_cast<GLsizei>(params.MipWidth(mip_map)), + static_cast<GLsizei>(params.MipHeight(mip_map)), 0, + layer_size, &gl_buffer[mip_map][buffer_offset]); + buffer_offset += layer_size; } break; + } default: LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", static_cast<u32>(params.target)); UNREACHABLE(); - glCompressedTexImage2D( - GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), - static_cast<GLsizei>(params.height), 0, - static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); + glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format, + static_cast<GLsizei>(params.MipWidth(mip_map)), + static_cast<GLsizei>(params.MipHeight(mip_map)), 0, + static_cast<GLsizei>(params.size_in_bytes_gl), + &gl_buffer[mip_map][buffer_offset]); } } else { switch (params.target) { - case SurfaceParams::SurfaceTarget::Texture1D: - glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, + case SurfaceTarget::Texture1D: + glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0, static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, - &gl_buffer[buffer_offset]); + &gl_buffer[mip_map][buffer_offset]); break; - case SurfaceParams::SurfaceTarget::Texture2D: - glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, + case SurfaceTarget::Texture2D: + glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[buffer_offset]); + &gl_buffer[mip_map][buffer_offset]); break; - case SurfaceParams::SurfaceTarget::Texture3D: - case SurfaceParams::SurfaceTarget::Texture2DArray: - glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, + case SurfaceTarget::Texture3D: + glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, + static_cast<GLsizei>(rect.GetWidth()), + static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map), + tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]); + break; + case SurfaceTarget::Texture2DArray: + glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, - tuple.type, &gl_buffer[buffer_offset]); + tuple.type, &gl_buffer[mip_map][buffer_offset]); break; - case SurfaceParams::SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubemap: { + std::size_t start = buffer_offset; for (std::size_t face = 0; face < params.depth; ++face) { - glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, x0, - y0, static_cast<GLsizei>(rect.GetWidth()), + glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map, + x0, y0, static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[buffer_offset]); - buffer_offset += params.SizeInBytesCubeFace(); + &gl_buffer[mip_map][buffer_offset]); + buffer_offset += params.LayerSizeGL(mip_map); } break; + } default: LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", static_cast<u32>(params.target)); UNREACHABLE(); - glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), + glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()), static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, - &gl_buffer[buffer_offset]); + &gl_buffer[mip_map][buffer_offset]); } } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } +MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); +void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { + if (params.type == SurfaceType::Fill) + return; + + MICROPROFILE_SCOPE(OpenGL_TextureUL); + + for (u32 i = 0; i < params.max_mip_level; i++) + UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle); +} + RasterizerCacheOpenGL::RasterizerCacheOpenGL() { read_framebuffer.Create(); draw_framebuffer.Create(); @@ -1294,8 +1284,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, // For compatible surfaces, we can just do fast glCopyImageSubData based copy if (old_params.target == new_params.target && old_params.type == new_params.type && old_params.depth == new_params.depth && old_params.depth == 1 && - SurfaceParams::GetFormatBpp(old_params.pixel_format) == - SurfaceParams::GetFormatBpp(new_params.pixel_format)) { + GetFormatBpp(old_params.pixel_format) == GetFormatBpp(new_params.pixel_format)) { FastCopySurface(old_surface, new_surface); return new_surface; } @@ -1308,15 +1297,15 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, const bool is_blit{old_params.pixel_format == new_params.pixel_format}; switch (new_params.target) { - case SurfaceParams::SurfaceTarget::Texture2D: + case SurfaceTarget::Texture2D: if (is_blit) { BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle); } else { CopySurface(old_surface, new_surface, copy_pbo.handle); } break; - case SurfaceParams::SurfaceTarget::TextureCubemap: - case SurfaceParams::SurfaceTarget::Texture3D: + case SurfaceTarget::TextureCubemap: + case SurfaceTarget::Texture3D: AccurateCopySurface(old_surface, new_surface); break; default: @@ -1326,7 +1315,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, } return new_surface; -} // namespace OpenGL +} Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const { return TryGet(addr); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index be8c00e99..f255f4419 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -7,6 +7,7 @@ #include <array> #include <map> #include <memory> +#include <string> #include <vector> #include "common/alignment.h" @@ -18,6 +19,7 @@ #include "video_core/rasterizer_cache.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_gen.h" +#include "video_core/surface.h" #include "video_core/textures/decoders.h" #include "video_core/textures/texture.h" @@ -27,135 +29,12 @@ class CachedSurface; using Surface = std::shared_ptr<CachedSurface>; using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; -struct SurfaceParams { - enum class PixelFormat { - ABGR8U = 0, - ABGR8S = 1, - ABGR8UI = 2, - B5G6R5U = 3, - A2B10G10R10U = 4, - A1B5G5R5U = 5, - R8U = 6, - R8UI = 7, - RGBA16F = 8, - RGBA16U = 9, - RGBA16UI = 10, - R11FG11FB10F = 11, - RGBA32UI = 12, - DXT1 = 13, - DXT23 = 14, - DXT45 = 15, - DXN1 = 16, // This is also known as BC4 - DXN2UNORM = 17, - DXN2SNORM = 18, - BC7U = 19, - BC6H_UF16 = 20, - BC6H_SF16 = 21, - ASTC_2D_4X4 = 22, - G8R8U = 23, - G8R8S = 24, - BGRA8 = 25, - RGBA32F = 26, - RG32F = 27, - R32F = 28, - R16F = 29, - R16U = 30, - R16S = 31, - R16UI = 32, - R16I = 33, - RG16 = 34, - RG16F = 35, - RG16UI = 36, - RG16I = 37, - RG16S = 38, - RGB32F = 39, - RGBA8_SRGB = 40, - RG8U = 41, - RG8S = 42, - RG32UI = 43, - R32UI = 44, - ASTC_2D_8X8 = 45, - ASTC_2D_8X5 = 46, - ASTC_2D_5X4 = 47, - BGRA8_SRGB = 48, - DXT1_SRGB = 49, - DXT23_SRGB = 50, - DXT45_SRGB = 51, - BC7U_SRGB = 52, - ASTC_2D_4X4_SRGB = 53, - ASTC_2D_8X8_SRGB = 54, - ASTC_2D_8X5_SRGB = 55, - ASTC_2D_5X4_SRGB = 56, - - MaxColorFormat, - - // Depth formats - Z32F = 57, - Z16 = 58, - - MaxDepthFormat, - - // DepthStencil formats - Z24S8 = 59, - S8Z24 = 60, - Z32FS8 = 61, - - MaxDepthStencilFormat, - - Max = MaxDepthStencilFormat, - Invalid = 255, - }; - - static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max); - - enum class ComponentType { - Invalid = 0, - SNorm = 1, - UNorm = 2, - SInt = 3, - UInt = 4, - Float = 5, - }; - - enum class SurfaceType { - ColorTexture = 0, - Depth = 1, - DepthStencil = 2, - Fill = 3, - Invalid = 4, - }; - - enum class SurfaceTarget { - Texture1D, - Texture2D, - Texture3D, - Texture1DArray, - Texture2DArray, - TextureCubemap, - }; - - static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) { - switch (texture_type) { - case Tegra::Texture::TextureType::Texture1D: - return SurfaceTarget::Texture1D; - case Tegra::Texture::TextureType::Texture2D: - case Tegra::Texture::TextureType::Texture2DNoMipmap: - return SurfaceTarget::Texture2D; - case Tegra::Texture::TextureType::Texture3D: - return SurfaceTarget::Texture3D; - case Tegra::Texture::TextureType::TextureCubemap: - return SurfaceTarget::TextureCubemap; - case Tegra::Texture::TextureType::Texture1DArray: - return SurfaceTarget::Texture1DArray; - case Tegra::Texture::TextureType::Texture2DArray: - return SurfaceTarget::Texture2DArray; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type)); - UNREACHABLE(); - return SurfaceTarget::Texture2D; - } - } +using SurfaceTarget = VideoCore::Surface::SurfaceTarget; +using SurfaceType = VideoCore::Surface::SurfaceType; +using PixelFormat = VideoCore::Surface::PixelFormat; +using ComponentType = VideoCore::Surface::ComponentType; +struct SurfaceParams { static std::string SurfaceTargetName(SurfaceTarget target) { switch (target) { case SurfaceTarget::Texture1D: @@ -177,664 +56,12 @@ struct SurfaceParams { } } - static bool SurfaceTargetIsLayered(SurfaceTarget target) { - switch (target) { - case SurfaceTarget::Texture1D: - case SurfaceTarget::Texture2D: - case SurfaceTarget::Texture3D: - return false; - case SurfaceTarget::Texture1DArray: - case SurfaceTarget::Texture2DArray: - case SurfaceTarget::TextureCubemap: - return true; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target)); - UNREACHABLE(); - return false; - } - } - - /** - * Gets the compression factor for the specified PixelFormat. This applies to just the - * "compressed width" and "compressed height", not the overall compression factor of a - * compressed image. This is used for maintaining proper surface sizes for compressed - * texture formats. - */ - static constexpr u32 GetCompressionFactor(PixelFormat format) { - if (format == PixelFormat::Invalid) - return 0; - - constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{ - 1, // ABGR8U - 1, // ABGR8S - 1, // ABGR8UI - 1, // B5G6R5U - 1, // A2B10G10R10U - 1, // A1B5G5R5U - 1, // R8U - 1, // R8UI - 1, // RGBA16F - 1, // RGBA16U - 1, // RGBA16UI - 1, // R11FG11FB10F - 1, // RGBA32UI - 4, // DXT1 - 4, // DXT23 - 4, // DXT45 - 4, // DXN1 - 4, // DXN2UNORM - 4, // DXN2SNORM - 4, // BC7U - 4, // BC6H_UF16 - 4, // BC6H_SF16 - 4, // ASTC_2D_4X4 - 1, // G8R8U - 1, // G8R8S - 1, // BGRA8 - 1, // RGBA32F - 1, // RG32F - 1, // R32F - 1, // R16F - 1, // R16U - 1, // R16S - 1, // R16UI - 1, // R16I - 1, // RG16 - 1, // RG16F - 1, // RG16UI - 1, // RG16I - 1, // RG16S - 1, // RGB32F - 1, // RGBA8_SRGB - 1, // RG8U - 1, // RG8S - 1, // RG32UI - 1, // R32UI - 4, // ASTC_2D_8X8 - 4, // ASTC_2D_8X5 - 4, // ASTC_2D_5X4 - 1, // BGRA8_SRGB - 4, // DXT1_SRGB - 4, // DXT23_SRGB - 4, // DXT45_SRGB - 4, // BC7U_SRGB - 4, // ASTC_2D_4X4_SRGB - 4, // ASTC_2D_8X8_SRGB - 4, // ASTC_2D_8X5_SRGB - 4, // ASTC_2D_5X4_SRGB - 1, // Z32F - 1, // Z16 - 1, // Z24S8 - 1, // S8Z24 - 1, // Z32FS8 - }}; - - ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size()); - return compression_factor_table[static_cast<std::size_t>(format)]; - } - - static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { - if (format == PixelFormat::Invalid) - return 0; - constexpr std::array<u32, MaxPixelFormat> block_height_table = {{ - 1, // ABGR8U - 1, // ABGR8S - 1, // ABGR8UI - 1, // B5G6R5U - 1, // A2B10G10R10U - 1, // A1B5G5R5U - 1, // R8U - 1, // R8UI - 1, // RGBA16F - 1, // RGBA16U - 1, // RGBA16UI - 1, // R11FG11FB10F - 1, // RGBA32UI - 4, // DXT1 - 4, // DXT23 - 4, // DXT45 - 4, // DXN1 - 4, // DXN2UNORM - 4, // DXN2SNORM - 4, // BC7U - 4, // BC6H_UF16 - 4, // BC6H_SF16 - 4, // ASTC_2D_4X4 - 1, // G8R8U - 1, // G8R8S - 1, // BGRA8 - 1, // RGBA32F - 1, // RG32F - 1, // R32F - 1, // R16F - 1, // R16U - 1, // R16S - 1, // R16UI - 1, // R16I - 1, // RG16 - 1, // RG16F - 1, // RG16UI - 1, // RG16I - 1, // RG16S - 1, // RGB32F - 1, // RGBA8_SRGB - 1, // RG8U - 1, // RG8S - 1, // RG32UI - 1, // R32UI - 8, // ASTC_2D_8X8 - 5, // ASTC_2D_8X5 - 4, // ASTC_2D_5X4 - 1, // BGRA8_SRGB - 4, // DXT1_SRGB - 4, // DXT23_SRGB - 4, // DXT45_SRGB - 4, // BC7U_SRGB - 4, // ASTC_2D_4X4_SRGB - 8, // ASTC_2D_8X8_SRGB - 5, // ASTC_2D_8X5_SRGB - 4, // ASTC_2D_5X4_SRGB - 1, // Z32F - 1, // Z16 - 1, // Z24S8 - 1, // S8Z24 - 1, // Z32FS8 - }}; - ASSERT(static_cast<std::size_t>(format) < block_height_table.size()); - return block_height_table[static_cast<std::size_t>(format)]; - } - - static constexpr u32 GetFormatBpp(PixelFormat format) { - if (format == PixelFormat::Invalid) - return 0; - - constexpr std::array<u32, MaxPixelFormat> bpp_table = {{ - 32, // ABGR8U - 32, // ABGR8S - 32, // ABGR8UI - 16, // B5G6R5U - 32, // A2B10G10R10U - 16, // A1B5G5R5U - 8, // R8U - 8, // R8UI - 64, // RGBA16F - 64, // RGBA16U - 64, // RGBA16UI - 32, // R11FG11FB10F - 128, // RGBA32UI - 64, // DXT1 - 128, // DXT23 - 128, // DXT45 - 64, // DXN1 - 128, // DXN2UNORM - 128, // DXN2SNORM - 128, // BC7U - 128, // BC6H_UF16 - 128, // BC6H_SF16 - 32, // ASTC_2D_4X4 - 16, // G8R8U - 16, // G8R8S - 32, // BGRA8 - 128, // RGBA32F - 64, // RG32F - 32, // R32F - 16, // R16F - 16, // R16U - 16, // R16S - 16, // R16UI - 16, // R16I - 32, // RG16 - 32, // RG16F - 32, // RG16UI - 32, // RG16I - 32, // RG16S - 96, // RGB32F - 32, // RGBA8_SRGB - 16, // RG8U - 16, // RG8S - 64, // RG32UI - 32, // R32UI - 16, // ASTC_2D_8X8 - 16, // ASTC_2D_8X5 - 32, // ASTC_2D_5X4 - 32, // BGRA8_SRGB - 64, // DXT1_SRGB - 128, // DXT23_SRGB - 128, // DXT45_SRGB - 128, // BC7U - 32, // ASTC_2D_4X4_SRGB - 16, // ASTC_2D_8X8_SRGB - 32, // ASTC_2D_8X5_SRGB - 32, // ASTC_2D_5X4_SRGB - 32, // Z32F - 16, // Z16 - 32, // Z24S8 - 32, // S8Z24 - 64, // Z32FS8 - }}; - - ASSERT(static_cast<std::size_t>(format) < bpp_table.size()); - return bpp_table[static_cast<std::size_t>(format)]; - } - u32 GetFormatBpp() const { - return GetFormatBpp(pixel_format); - } - - static PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) { - switch (format) { - case Tegra::DepthFormat::S8_Z24_UNORM: - return PixelFormat::S8Z24; - case Tegra::DepthFormat::Z24_S8_UNORM: - return PixelFormat::Z24S8; - case Tegra::DepthFormat::Z32_FLOAT: - return PixelFormat::Z32F; - case Tegra::DepthFormat::Z16_UNORM: - return PixelFormat::Z16; - case Tegra::DepthFormat::Z32_S8_X24_FLOAT: - return PixelFormat::Z32FS8; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); - UNREACHABLE(); - } - } - - static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) { - switch (format) { - // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the - // gamma. - case Tegra::RenderTargetFormat::RGBA8_SRGB: - return PixelFormat::RGBA8_SRGB; - case Tegra::RenderTargetFormat::RGBA8_UNORM: - return PixelFormat::ABGR8U; - case Tegra::RenderTargetFormat::RGBA8_SNORM: - return PixelFormat::ABGR8S; - case Tegra::RenderTargetFormat::RGBA8_UINT: - return PixelFormat::ABGR8UI; - case Tegra::RenderTargetFormat::BGRA8_SRGB: - return PixelFormat::BGRA8_SRGB; - case Tegra::RenderTargetFormat::BGRA8_UNORM: - return PixelFormat::BGRA8; - case Tegra::RenderTargetFormat::RGB10_A2_UNORM: - return PixelFormat::A2B10G10R10U; - case Tegra::RenderTargetFormat::RGBA16_FLOAT: - return PixelFormat::RGBA16F; - case Tegra::RenderTargetFormat::RGBA16_UNORM: - return PixelFormat::RGBA16U; - case Tegra::RenderTargetFormat::RGBA16_UINT: - return PixelFormat::RGBA16UI; - case Tegra::RenderTargetFormat::RGBA32_FLOAT: - return PixelFormat::RGBA32F; - case Tegra::RenderTargetFormat::RG32_FLOAT: - return PixelFormat::RG32F; - case Tegra::RenderTargetFormat::R11G11B10_FLOAT: - return PixelFormat::R11FG11FB10F; - case Tegra::RenderTargetFormat::B5G6R5_UNORM: - return PixelFormat::B5G6R5U; - case Tegra::RenderTargetFormat::BGR5A1_UNORM: - return PixelFormat::A1B5G5R5U; - case Tegra::RenderTargetFormat::RGBA32_UINT: - return PixelFormat::RGBA32UI; - case Tegra::RenderTargetFormat::R8_UNORM: - return PixelFormat::R8U; - case Tegra::RenderTargetFormat::R8_UINT: - return PixelFormat::R8UI; - case Tegra::RenderTargetFormat::RG16_FLOAT: - return PixelFormat::RG16F; - case Tegra::RenderTargetFormat::RG16_UINT: - return PixelFormat::RG16UI; - case Tegra::RenderTargetFormat::RG16_SINT: - return PixelFormat::RG16I; - case Tegra::RenderTargetFormat::RG16_UNORM: - return PixelFormat::RG16; - case Tegra::RenderTargetFormat::RG16_SNORM: - return PixelFormat::RG16S; - case Tegra::RenderTargetFormat::RG8_UNORM: - return PixelFormat::RG8U; - case Tegra::RenderTargetFormat::RG8_SNORM: - return PixelFormat::RG8S; - case Tegra::RenderTargetFormat::R16_FLOAT: - return PixelFormat::R16F; - case Tegra::RenderTargetFormat::R16_UNORM: - return PixelFormat::R16U; - case Tegra::RenderTargetFormat::R16_SNORM: - return PixelFormat::R16S; - case Tegra::RenderTargetFormat::R16_UINT: - return PixelFormat::R16UI; - case Tegra::RenderTargetFormat::R16_SINT: - return PixelFormat::R16I; - case Tegra::RenderTargetFormat::R32_FLOAT: - return PixelFormat::R32F; - case Tegra::RenderTargetFormat::R32_UINT: - return PixelFormat::R32UI; - case Tegra::RenderTargetFormat::RG32_UINT: - return PixelFormat::RG32UI; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); - UNREACHABLE(); - } - } - - static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, - Tegra::Texture::ComponentType component_type, - bool is_srgb) { - // TODO(Subv): Properly implement this - switch (format) { - case Tegra::Texture::TextureFormat::A8R8G8B8: - if (is_srgb) { - return PixelFormat::RGBA8_SRGB; - } - switch (component_type) { - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::ABGR8U; - case Tegra::Texture::ComponentType::SNORM: - return PixelFormat::ABGR8S; - case Tegra::Texture::ComponentType::UINT: - return PixelFormat::ABGR8UI; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::B5G6R5: - switch (component_type) { - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::B5G6R5U; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::A2B10G10R10: - switch (component_type) { - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::A2B10G10R10U; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::A1B5G5R5: - switch (component_type) { - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::A1B5G5R5U; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::R8: - switch (component_type) { - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::R8U; - case Tegra::Texture::ComponentType::UINT: - return PixelFormat::R8UI; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::G8R8: - switch (component_type) { - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::G8R8U; - case Tegra::Texture::ComponentType::SNORM: - return PixelFormat::G8R8S; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::R16_G16_B16_A16: - switch (component_type) { - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::RGBA16U; - case Tegra::Texture::ComponentType::FLOAT: - return PixelFormat::RGBA16F; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::BF10GF11RF11: - switch (component_type) { - case Tegra::Texture::ComponentType::FLOAT: - return PixelFormat::R11FG11FB10F; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::R32_G32_B32_A32: - switch (component_type) { - case Tegra::Texture::ComponentType::FLOAT: - return PixelFormat::RGBA32F; - case Tegra::Texture::ComponentType::UINT: - return PixelFormat::RGBA32UI; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::R32_G32: - switch (component_type) { - case Tegra::Texture::ComponentType::FLOAT: - return PixelFormat::RG32F; - case Tegra::Texture::ComponentType::UINT: - return PixelFormat::RG32UI; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::R32_G32_B32: - switch (component_type) { - case Tegra::Texture::ComponentType::FLOAT: - return PixelFormat::RGB32F; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::R16: - switch (component_type) { - case Tegra::Texture::ComponentType::FLOAT: - return PixelFormat::R16F; - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::R16U; - case Tegra::Texture::ComponentType::SNORM: - return PixelFormat::R16S; - case Tegra::Texture::ComponentType::UINT: - return PixelFormat::R16UI; - case Tegra::Texture::ComponentType::SINT: - return PixelFormat::R16I; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::R32: - switch (component_type) { - case Tegra::Texture::ComponentType::FLOAT: - return PixelFormat::R32F; - case Tegra::Texture::ComponentType::UINT: - return PixelFormat::R32UI; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::ZF32: - return PixelFormat::Z32F; - case Tegra::Texture::TextureFormat::Z16: - return PixelFormat::Z16; - case Tegra::Texture::TextureFormat::Z24S8: - return PixelFormat::Z24S8; - case Tegra::Texture::TextureFormat::DXT1: - return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1; - case Tegra::Texture::TextureFormat::DXT23: - return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23; - case Tegra::Texture::TextureFormat::DXT45: - return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45; - case Tegra::Texture::TextureFormat::DXN1: - return PixelFormat::DXN1; - case Tegra::Texture::TextureFormat::DXN2: - switch (component_type) { - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::DXN2UNORM; - case Tegra::Texture::ComponentType::SNORM: - return PixelFormat::DXN2SNORM; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - case Tegra::Texture::TextureFormat::BC7U: - return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U; - case Tegra::Texture::TextureFormat::BC6H_UF16: - return PixelFormat::BC6H_UF16; - case Tegra::Texture::TextureFormat::BC6H_SF16: - return PixelFormat::BC6H_SF16; - case Tegra::Texture::TextureFormat::ASTC_2D_4X4: - return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4; - case Tegra::Texture::TextureFormat::ASTC_2D_5X4: - return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4; - case Tegra::Texture::TextureFormat::ASTC_2D_8X8: - return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8; - case Tegra::Texture::TextureFormat::ASTC_2D_8X5: - return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5; - case Tegra::Texture::TextureFormat::R16_G16: - switch (component_type) { - case Tegra::Texture::ComponentType::FLOAT: - return PixelFormat::RG16F; - case Tegra::Texture::ComponentType::UNORM: - return PixelFormat::RG16; - case Tegra::Texture::ComponentType::SNORM: - return PixelFormat::RG16S; - case Tegra::Texture::ComponentType::UINT: - return PixelFormat::RG16UI; - case Tegra::Texture::ComponentType::SINT: - return PixelFormat::RG16I; - } - LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", - static_cast<u32>(component_type)); - UNREACHABLE(); - default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", - static_cast<u32>(format), static_cast<u32>(component_type)); - UNREACHABLE(); - } - } - - static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) { - // TODO(Subv): Implement more component types - switch (type) { - case Tegra::Texture::ComponentType::UNORM: - return ComponentType::UNorm; - case Tegra::Texture::ComponentType::FLOAT: - return ComponentType::Float; - case Tegra::Texture::ComponentType::SNORM: - return ComponentType::SNorm; - case Tegra::Texture::ComponentType::UINT: - return ComponentType::UInt; - case Tegra::Texture::ComponentType::SINT: - return ComponentType::SInt; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type)); - UNREACHABLE(); - } - } - - static ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) { - // TODO(Subv): Implement more render targets - switch (format) { - case Tegra::RenderTargetFormat::RGBA8_UNORM: - case Tegra::RenderTargetFormat::RGBA8_SRGB: - case Tegra::RenderTargetFormat::BGRA8_UNORM: - case Tegra::RenderTargetFormat::BGRA8_SRGB: - case Tegra::RenderTargetFormat::RGB10_A2_UNORM: - case Tegra::RenderTargetFormat::R8_UNORM: - case Tegra::RenderTargetFormat::RG16_UNORM: - case Tegra::RenderTargetFormat::R16_UNORM: - case Tegra::RenderTargetFormat::B5G6R5_UNORM: - case Tegra::RenderTargetFormat::BGR5A1_UNORM: - case Tegra::RenderTargetFormat::RG8_UNORM: - case Tegra::RenderTargetFormat::RGBA16_UNORM: - return ComponentType::UNorm; - case Tegra::RenderTargetFormat::RGBA8_SNORM: - case Tegra::RenderTargetFormat::RG16_SNORM: - case Tegra::RenderTargetFormat::R16_SNORM: - case Tegra::RenderTargetFormat::RG8_SNORM: - return ComponentType::SNorm; - case Tegra::RenderTargetFormat::RGBA16_FLOAT: - case Tegra::RenderTargetFormat::R11G11B10_FLOAT: - case Tegra::RenderTargetFormat::RGBA32_FLOAT: - case Tegra::RenderTargetFormat::RG32_FLOAT: - case Tegra::RenderTargetFormat::RG16_FLOAT: - case Tegra::RenderTargetFormat::R16_FLOAT: - case Tegra::RenderTargetFormat::R32_FLOAT: - return ComponentType::Float; - case Tegra::RenderTargetFormat::RGBA32_UINT: - case Tegra::RenderTargetFormat::RGBA16_UINT: - case Tegra::RenderTargetFormat::RG16_UINT: - case Tegra::RenderTargetFormat::R8_UINT: - case Tegra::RenderTargetFormat::R16_UINT: - case Tegra::RenderTargetFormat::RG32_UINT: - case Tegra::RenderTargetFormat::R32_UINT: - case Tegra::RenderTargetFormat::RGBA8_UINT: - return ComponentType::UInt; - case Tegra::RenderTargetFormat::RG16_SINT: - case Tegra::RenderTargetFormat::R16_SINT: - return ComponentType::SInt; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); - UNREACHABLE(); - } - } - - static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { - switch (format) { - case Tegra::FramebufferConfig::PixelFormat::ABGR8: - return PixelFormat::ABGR8U; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); - UNREACHABLE(); - } - } - - static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) { - switch (format) { - case Tegra::DepthFormat::Z16_UNORM: - case Tegra::DepthFormat::S8_Z24_UNORM: - case Tegra::DepthFormat::Z24_S8_UNORM: - return ComponentType::UNorm; - case Tegra::DepthFormat::Z32_FLOAT: - case Tegra::DepthFormat::Z32_S8_X24_FLOAT: - return ComponentType::Float; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); - UNREACHABLE(); - } - } - - static SurfaceType GetFormatType(PixelFormat pixel_format) { - if (static_cast<std::size_t>(pixel_format) < - static_cast<std::size_t>(PixelFormat::MaxColorFormat)) { - return SurfaceType::ColorTexture; - } - - if (static_cast<std::size_t>(pixel_format) < - static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) { - return SurfaceType::Depth; - } - - if (static_cast<std::size_t>(pixel_format) < - static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) { - return SurfaceType::DepthStencil; - } - - // TODO(Subv): Implement the other formats - ASSERT(false); - - return SurfaceType::Invalid; - } - - /// Returns the sizer in bytes of the specified pixel format - static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) { - if (pixel_format == SurfaceParams::PixelFormat::Invalid) { - return 0; - } - return GetFormatBpp(pixel_format) / CHAR_BIT; + return VideoCore::Surface::GetFormatBpp(pixel_format); } /// Returns the rectangle corresponding to this surface - MathUtil::Rectangle<u32> GetRect() const; + MathUtil::Rectangle<u32> GetRect(u32 mip_level = 0) const; /// Returns the total size of this surface in bytes, adjusted for compression std::size_t SizeInBytesRaw(bool ignore_tiled = false) const { @@ -865,7 +92,7 @@ struct SurfaceParams { /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps. std::size_t MemorySize() const { - std::size_t size = InnerMemorySize(is_layered); + std::size_t size = InnerMemorySize(false, is_layered); if (is_layered) return size * depth; return size; @@ -874,12 +101,78 @@ struct SurfaceParams { /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including /// mipmaps. std::size_t LayerMemorySize() const { - return InnerMemorySize(true); + return InnerMemorySize(false, true); } /// Returns the size of a layer of this surface in OpenGL. - std::size_t LayerSizeGL() const { - return SizeInBytesRaw(true) / depth; + std::size_t LayerSizeGL(u32 mip_level) const { + return InnerMipmapMemorySize(mip_level, true, is_layered, false); + } + + std::size_t GetMipmapSizeGL(u32 mip_level, bool ignore_compressed = true) const { + std::size_t size = InnerMipmapMemorySize(mip_level, true, is_layered, ignore_compressed); + if (is_layered) + return size * depth; + return size; + } + + std::size_t GetMipmapLevelOffset(u32 mip_level) const { + std::size_t offset = 0; + for (u32 i = 0; i < mip_level; i++) + offset += InnerMipmapMemorySize(i, false, is_layered); + return offset; + } + + std::size_t GetMipmapLevelOffsetGL(u32 mip_level) const { + std::size_t offset = 0; + for (u32 i = 0; i < mip_level; i++) + offset += InnerMipmapMemorySize(i, true, is_layered); + return offset; + } + + u32 MipWidth(u32 mip_level) const { + return std::max(1U, width >> mip_level); + } + + u32 MipHeight(u32 mip_level) const { + return std::max(1U, height >> mip_level); + } + + u32 MipDepth(u32 mip_level) const { + return std::max(1U, depth >> mip_level); + } + + // Auto block resizing algorithm from: + // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c + u32 MipBlockHeight(u32 mip_level) const { + if (mip_level == 0) + return block_height; + u32 alt_height = MipHeight(mip_level); + u32 h = GetDefaultBlockHeight(pixel_format); + u32 blocks_in_y = (alt_height + h - 1) / h; + u32 bh = 16; + while (bh > 1 && blocks_in_y <= bh * 4) { + bh >>= 1; + } + return bh; + } + + u32 MipBlockDepth(u32 mip_level) const { + if (mip_level == 0) + return block_depth; + if (is_layered) + return 1; + u32 depth = MipDepth(mip_level); + u32 bd = 32; + while (bd > 1 && depth * 2 <= bd) { + bd >>= 1; + } + if (bd == 32) { + u32 bh = MipBlockHeight(mip_level); + if (bh >= 4) + return 16; + } + return bd; } /// Creates SurfaceParams from a texture configuration @@ -940,7 +233,10 @@ struct SurfaceParams { } rt; private: - std::size_t InnerMemorySize(bool layer_only = false) const; + std::size_t InnerMipmapMemorySize(u32 mip_level, bool force_gl = false, bool layer_only = false, + bool uncompressed = false) const; + std::size_t InnerMemorySize(bool force_gl = false, bool layer_only = false, + bool uncompressed = false) const; }; }; // namespace OpenGL @@ -1002,8 +298,10 @@ public: void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); private: + void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); + OGLTexture texture; - std::vector<u8> gl_buffer; + std::vector<std::vector<u8>> gl_buffer; SurfaceParams params; GLenum gl_target; 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 @@ #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_opengl/gl_shader_cache.h" #include "video_core/renderer_opengl/gl_shader_manager.h" +#include "video_core/renderer_opengl/utils.h" #include "video_core/utils.h" namespace OpenGL { @@ -89,7 +90,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type) shader.Create(program_result.first.c_str(), gl_type); program.Create(true, shader.handle); SetShaderUniformBlockBindings(program.handle); - VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr); + LabelGLObject(GL_PROGRAM, program.handle, addr); } else { // Store shader's code to lazily build it on draw geometry_programs.code = program_result.first; @@ -130,7 +131,7 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, shader.Create(source.c_str(), GL_GEOMETRY_SHADER); target_program.Create(true, shader.handle); SetShaderUniformBlockBindings(target_program.handle); - VideoCore::LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name); + LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name); return target_program.handle; }; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 087baf9ed..09b003c59 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -3,12 +3,12 @@ // Refer to the license.txt file included. #include <map> +#include <optional> #include <set> #include <string> #include <string_view> #include <unordered_set> -#include <boost/optional.hpp> #include <fmt/format.h> #include "common/assert.h" @@ -144,7 +144,7 @@ private: for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { const Instruction instr = {program_code[offset]}; if (const auto opcode = OpCode::Decode(instr)) { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::EXIT: { // The EXIT instruction can be predicated, which means that the shader can // conditionally end on this instruction. We have to consider the case where the @@ -373,6 +373,7 @@ public: if (sets_cc) { const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); + LOG_WARNING(HW_GPU, "Control Codes Imcomplete."); } } @@ -430,7 +431,7 @@ public: */ void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute, const Tegra::Shader::IpaMode& input_mode, - boost::optional<Register> vertex = {}) { + std::optional<Register> vertex = {}) { const std::string dest = GetRegisterAsFloat(reg); const std::string src = GetInputAttribute(attribute, input_mode, vertex) + GetSwizzle(elem); shader.AddLine(dest + " = " + src + ';'); @@ -807,10 +808,10 @@ private: /// Generates code representing an input attribute register. std::string GetInputAttribute(Attribute::Index attribute, const Tegra::Shader::IpaMode& input_mode, - boost::optional<Register> vertex = {}) { + std::optional<Register> vertex = {}) { auto GeometryPass = [&](const std::string& name) { if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) { - return "gs_" + name + '[' + GetRegisterAsInteger(vertex.value(), 0, false) + ']'; + return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) + ']'; } return name; }; @@ -1465,7 +1466,7 @@ private: } shader.AddLine( - fmt::format("// {}: {} (0x{:016x})", offset, opcode->GetName(), instr.value)); + fmt::format("// {}: {} (0x{:016x})", offset, opcode->get().GetName(), instr.value)); using Tegra::Shader::Pred; ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute, @@ -1473,7 +1474,7 @@ private: // Some instructions (like SSY) don't have a predicate field, they are always // unconditionally executed. - bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->GetId()); + bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->get().GetId()); if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) { shader.AddLine("if (" + @@ -1483,7 +1484,7 @@ private: ++shader.scope; } - switch (opcode->GetType()) { + switch (opcode->get().GetType()) { case OpCode::Type::Arithmetic: { std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); @@ -1500,7 +1501,7 @@ private: } } - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::MOV_C: case OpCode::Id::MOV_R: { // MOV does not have neither 'abs' nor 'neg' bits. @@ -1525,6 +1526,10 @@ private: regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, instr.alu.saturate_d, 0, true); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "FMUL Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::FADD_C: @@ -1535,6 +1540,10 @@ private: regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, instr.alu.saturate_d, 0, true); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "FADD Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::MUFU: { @@ -1588,6 +1597,10 @@ private: '(' + condition + ") ? min(" + parameters + ") : max(" + parameters + ')', 1, 1, false, 0, true); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "FMNMX Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::RRO_C: @@ -1600,14 +1613,15 @@ private: break; } default: { - LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", + opcode->get().GetName()); UNREACHABLE(); } } break; } case OpCode::Type::ArithmeticImmediate: { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::MOV32_IMM: { regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1); break; @@ -1617,6 +1631,10 @@ private: regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1, instr.fmul32.saturate, 0, true); + if (instr.op_32.generates_cc) { + LOG_CRITICAL(HW_GPU, "FMUL32 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::FADD32I: { @@ -1640,6 +1658,10 @@ private: } regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true); + if (instr.op_32.generates_cc) { + LOG_CRITICAL(HW_GPU, "FADD32 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } } @@ -1651,7 +1673,7 @@ private: std::string op_a = instr.bfe.negate_a ? "-" : ""; op_a += regs.GetRegisterAsInteger(instr.gpr8); - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::BFE_IMM: { std::string inner_shift = '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')'; @@ -1660,10 +1682,14 @@ private: std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')'; regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "BFE Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } default: { - LOG_CRITICAL(HW_GPU, "Unhandled BFE instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled BFE instruction: {}", opcode->get().GetName()); UNREACHABLE(); } } @@ -1685,7 +1711,7 @@ private: } } - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::SHR_C: case OpCode::Id::SHR_R: case OpCode::Id::SHR_IMM: { @@ -1697,15 +1723,23 @@ private: // Cast to int is superfluous for arithmetic shift, it's only for a logical shift regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')', 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "SHR Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::SHL_C: case OpCode::Id::SHL_R: case OpCode::Id::SHL_IMM: regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "SHL Generates an unhandled Control Code"); + UNREACHABLE(); + } break; default: { - LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName()); UNREACHABLE(); } } @@ -1715,13 +1749,17 @@ private: std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); std::string op_b = std::to_string(instr.alu.imm20_32.Value()); - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::IADD32I: if (instr.iadd32i.negate_a) op_a = "-(" + op_a + ')'; regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, instr.iadd32i.saturate != 0); + if (instr.op_32.generates_cc) { + LOG_CRITICAL(HW_GPU, "IADD32 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; case OpCode::Id::LOP32I: { if (instr.alu.lop32i.invert_a) @@ -1733,11 +1771,15 @@ private: WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b, Tegra::Shader::PredicateResultMode::None, Tegra::Shader::Pred::UnusedIndex); + if (instr.op_32.generates_cc) { + LOG_CRITICAL(HW_GPU, "LOP32I Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } default: { LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticIntegerImmediate instruction: {}", - opcode->GetName()); + opcode->get().GetName()); UNREACHABLE(); } } @@ -1757,7 +1799,7 @@ private: } } - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::IADD_C: case OpCode::Id::IADD_R: case OpCode::Id::IADD_IMM: { @@ -1769,6 +1811,10 @@ private: regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, instr.alu.saturate_d); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "IADD Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::IADD3_C: @@ -1793,7 +1839,7 @@ private: } }; - if (opcode->GetId() == OpCode::Id::IADD3_R) { + if (opcode->get().GetId() == OpCode::Id::IADD3_R) { apply_height(instr.iadd3.height_a, op_a); apply_height(instr.iadd3.height_b, op_b); apply_height(instr.iadd3.height_c, op_c); @@ -1809,7 +1855,7 @@ private: op_c = "-(" + op_c + ')'; std::string result; - if (opcode->GetId() == OpCode::Id::IADD3_R) { + if (opcode->get().GetId() == OpCode::Id::IADD3_R) { switch (instr.iadd3.mode) { case Tegra::Shader::IAdd3Mode::RightShift: // TODO(tech4me): According to @@ -1830,6 +1876,11 @@ private: } regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1); + + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "IADD3 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::ISCADD_C: @@ -1845,6 +1896,10 @@ private: regs.SetRegisterToInteger(instr.gpr0, true, 0, "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "ISCADD Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::POPC_C: @@ -1876,6 +1931,10 @@ private: WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b, instr.alu.lop.pred_result_mode, instr.alu.lop.pred48); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "LOP Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::LOP3_C: @@ -1884,13 +1943,17 @@ private: const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); std::string lut; - if (opcode->GetId() == OpCode::Id::LOP3_R) { + if (opcode->get().GetId() == OpCode::Id::LOP3_R) { lut = '(' + std::to_string(instr.alu.lop3.GetImmLut28()) + ')'; } else { lut = '(' + std::to_string(instr.alu.lop3.GetImmLut48()) + ')'; } WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "LOP3 Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::IMNMX_C: @@ -1905,6 +1968,10 @@ private: '(' + condition + ") ? min(" + parameters + ") : max(" + parameters + ')', 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "IMNMX Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::LEA_R2: @@ -1914,7 +1981,7 @@ private: case OpCode::Id::LEA_HI: { std::string op_c; - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::LEA_R2: { op_a = regs.GetRegisterAsInteger(instr.gpr20); op_b = regs.GetRegisterAsInteger(instr.gpr39); @@ -1959,7 +2026,8 @@ private: op_b = regs.GetRegisterAsInteger(instr.gpr8); op_a = std::to_string(instr.lea.imm.entry_a); op_c = std::to_string(instr.lea.imm.entry_b); - LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}", + opcode->get().GetName()); UNREACHABLE(); } } @@ -1974,7 +2042,7 @@ private: } default: { LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", - opcode->GetName()); + opcode->get().GetName()); UNREACHABLE(); } } @@ -1982,20 +2050,21 @@ private: break; } case OpCode::Type::ArithmeticHalf: { - if (opcode->GetId() == OpCode::Id::HADD2_C || opcode->GetId() == OpCode::Id::HADD2_R) { + if (opcode->get().GetId() == OpCode::Id::HADD2_C || + opcode->get().GetId() == OpCode::Id::HADD2_R) { ASSERT_MSG(instr.alu_half.ftz == 0, "Unimplemented"); } const bool negate_a = - opcode->GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0; + opcode->get().GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0; const bool negate_b = - opcode->GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0; + opcode->get().GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0; const std::string op_a = GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.alu_half.type_a, instr.alu_half.abs_a != 0, negate_a); std::string op_b; - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::HADD2_C: case OpCode::Id::HMUL2_C: op_b = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, @@ -2013,7 +2082,7 @@ private: op_b = GetHalfFloat(op_b, instr.alu_half.type_b, instr.alu_half.abs_b != 0, negate_b); const std::string result = [&]() { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::HADD2_C: case OpCode::Id::HADD2_R: return '(' + op_a + " + " + op_b + ')'; @@ -2021,7 +2090,8 @@ private: case OpCode::Id::HMUL2_R: return '(' + op_a + " * " + op_b + ')'; default: - LOG_CRITICAL(HW_GPU, "Unhandled half float instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled half float instruction: {}", + opcode->get().GetName()); UNREACHABLE(); return std::string("0"); } @@ -2032,7 +2102,7 @@ private: break; } case OpCode::Type::ArithmeticHalfImmediate: { - if (opcode->GetId() == OpCode::Id::HADD2_IMM) { + if (opcode->get().GetId() == OpCode::Id::HADD2_IMM) { ASSERT_MSG(instr.alu_half_imm.ftz == 0, "Unimplemented"); } else { ASSERT_MSG(instr.alu_half_imm.precision == Tegra::Shader::HalfPrecision::None, @@ -2046,7 +2116,7 @@ private: const std::string op_b = UnpackHalfImmediate(instr, true); const std::string result = [&]() { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::HADD2_IMM: return op_a + " + " + op_b; case OpCode::Id::HMUL2_IMM: @@ -2072,7 +2142,7 @@ private: ASSERT_MSG(instr.ffma.tab5980_1 == 0, "FFMA tab5980_1({}) not implemented", instr.ffma.tab5980_1.Value()); - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::FFMA_CR: { op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, GLSLRegister::Type::Float); @@ -2096,25 +2166,29 @@ private: break; } default: { - LOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->get().GetName()); UNREACHABLE(); } } regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')', 1, 1, instr.alu.saturate_d, 0, true); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "FFMA Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Type::Hfma2: { - if (opcode->GetId() == OpCode::Id::HFMA2_RR) { + if (opcode->get().GetId() == OpCode::Id::HFMA2_RR) { ASSERT_MSG(instr.hfma2.rr.precision == Tegra::Shader::HalfPrecision::None, "Unimplemented"); } else { ASSERT_MSG(instr.hfma2.precision == Tegra::Shader::HalfPrecision::None, "Unimplemented"); } - const bool saturate = opcode->GetId() == OpCode::Id::HFMA2_RR + const bool saturate = opcode->get().GetId() == OpCode::Id::HFMA2_RR ? instr.hfma2.rr.saturate != 0 : instr.hfma2.saturate != 0; @@ -2122,7 +2196,7 @@ private: GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.hfma2.type_a); std::string op_b, op_c; - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::HFMA2_CR: op_b = GetHalfFloat(regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, GLSLRegister::Type::UnsignedInteger), @@ -2160,7 +2234,7 @@ private: break; } case OpCode::Type::Conversion: { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::I2I_R: { ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); @@ -2208,6 +2282,11 @@ private: } regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); + + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "I2F Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::F2F_R: { @@ -2246,6 +2325,11 @@ private: } regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d); + + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "F2F Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } case OpCode::Id::F2I_R: @@ -2295,17 +2379,22 @@ private: regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, 1, false, 0, instr.conversion.dest_size); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "F2I Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } default: { - LOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", + opcode->get().GetName()); UNREACHABLE(); } } break; } case OpCode::Type::Memory: { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::LD_A: { // Note: Shouldn't this be interp mode flat? As in no interpolation made. ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex, @@ -2949,7 +3038,7 @@ private: break; } default: { - LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->get().GetName()); UNREACHABLE(); } } @@ -3043,7 +3132,7 @@ private: instr.hsetp2.abs_a, instr.hsetp2.negate_a); const std::string op_b = [&]() { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::HSETP2_R: return GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr20, 0, false), instr.hsetp2.type_b, instr.hsetp2.abs_a, @@ -3102,10 +3191,15 @@ private: regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1); } + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "PSET Generates an unhandled Control Code"); + UNREACHABLE(); + } + break; } case OpCode::Type::PredicateSetPredicate: { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::PSETP: { const std::string op_a = GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); @@ -3151,7 +3245,8 @@ private: break; } default: { - LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", + opcode->get().GetName()); UNREACHABLE(); } } @@ -3239,7 +3334,7 @@ private: instr.hset2.abs_a != 0, instr.hset2.negate_a != 0); const std::string op_b = [&]() { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::HSET2_R: return GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr20, 0, false), instr.hset2.type_b, instr.hset2.abs_b != 0, @@ -3288,7 +3383,7 @@ private: const bool is_signed{instr.xmad.sign_a == 1}; bool is_merge{}; - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::XMAD_CR: { is_merge = instr.xmad.merge_56; op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, @@ -3317,7 +3412,7 @@ private: break; } default: { - LOG_CRITICAL(HW_GPU, "Unhandled XMAD instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled XMAD instruction: {}", opcode->get().GetName()); UNREACHABLE(); } } @@ -3366,10 +3461,14 @@ private: } regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "XMAD Generates an unhandled Control Code"); + UNREACHABLE(); + } break; } default: { - switch (opcode->GetId()) { + switch (opcode->get().GetId()) { case OpCode::Id::EXIT: { if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { EmitFragmentOutputsWrite(); @@ -3561,6 +3660,11 @@ private: regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, instr.vmad.saturate == 1, 0, Register::Size::Word, instr.vmad.cc); + if (instr.generates_cc) { + LOG_CRITICAL(HW_GPU, "VMAD Generates an unhandled Control Code"); + UNREACHABLE(); + } + break; } case OpCode::Id::VSETP: { @@ -3588,7 +3692,7 @@ private: break; } default: { - LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName()); + LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->get().GetName()); UNREACHABLE(); } } @@ -3729,9 +3833,9 @@ std::string GetCommonDeclarations() { RasterizerOpenGL::MaxConstbufferSize / sizeof(GLvec4)); } -boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, - Maxwell3D::Regs::ShaderStage stage, - const std::string& suffix) { +std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, + Maxwell3D::Regs::ShaderStage stage, + const std::string& suffix) { try { const auto subroutines = ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); @@ -3740,7 +3844,7 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, } catch (const DecompileFail& exception) { LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); } - return boost::none; + return {}; } } // namespace OpenGL::GLShader::Decompiler diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index b20cc4bfa..d01a4a7ee 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h @@ -6,8 +6,8 @@ #include <array> #include <functional> +#include <optional> #include <string> -#include <boost/optional.hpp> #include "common/common_types.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_opengl/gl_shader_gen.h" @@ -18,8 +18,8 @@ using Tegra::Engines::Maxwell3D; std::string GetCommonDeclarations(); -boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, - Maxwell3D::Regs::ShaderStage stage, - const std::string& suffix); +std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, + Maxwell3D::Regs::ShaderStage stage, + const std::string& suffix); } // namespace OpenGL::GLShader::Decompiler diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index dfb562706..9d17edd63 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -37,7 +37,7 @@ layout(std140) uniform vs_config { ProgramResult program = Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, Maxwell3D::Regs::ShaderStage::Vertex, "vertex") - .get_value_or({}); + .value_or(ProgramResult()); out += program.first; @@ -45,7 +45,7 @@ layout(std140) uniform vs_config { ProgramResult program_b = Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET, Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b") - .get_value_or({}); + .value_or(ProgramResult()); out += program_b.first; } @@ -90,7 +90,7 @@ ProgramResult GenerateGeometryShader(const ShaderSetup& setup) { ProgramResult program = Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, Maxwell3D::Regs::ShaderStage::Geometry, "geometry") - .get_value_or({}); + .value_or(ProgramResult()); out += R"( out gl_PerVertex { vec4 gl_Position; @@ -124,7 +124,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup) { ProgramResult program = Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, Maxwell3D::Regs::ShaderStage::Fragment, "fragment") - .get_value_or({}); + .value_or(ProgramResult()); out += R"( layout(location = 0) out vec4 FragColor0; layout(location = 1) out vec4 FragColor1; 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) { return {}; } -inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { +inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode, + Tegra::Texture::TextureMipmapFilter mip_filter_mode) { switch (filter_mode) { - case Tegra::Texture::TextureFilter::Linear: - return GL_LINEAR; - case Tegra::Texture::TextureFilter::Nearest: - return GL_NEAREST; + case Tegra::Texture::TextureFilter::Linear: { + switch (mip_filter_mode) { + case Tegra::Texture::TextureMipmapFilter::None: + return GL_LINEAR; + case Tegra::Texture::TextureMipmapFilter::Nearest: + return GL_NEAREST_MIPMAP_LINEAR; + case Tegra::Texture::TextureMipmapFilter::Linear: + return GL_LINEAR_MIPMAP_LINEAR; + } + } + case Tegra::Texture::TextureFilter::Nearest: { + switch (mip_filter_mode) { + case Tegra::Texture::TextureMipmapFilter::None: + return GL_NEAREST; + case Tegra::Texture::TextureMipmapFilter::Nearest: + return GL_NEAREST_MIPMAP_NEAREST; + case Tegra::Texture::TextureMipmapFilter::Linear: + return GL_LINEAR_MIPMAP_NEAREST; + } + } } LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", static_cast<u32>(filter_mode)); diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 90b68943d..ea38da932 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -115,7 +115,8 @@ RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& window) RendererOpenGL::~RendererOpenGL() = default; /// Swap buffers (render frame) -void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { +void RendererOpenGL::SwapBuffers( + std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) { ScopeAcquireGLContext acquire_context{render_window}; Core::System::GetInstance().GetPerfStats().EndSystemFrame(); @@ -124,11 +125,11 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig& OpenGLState prev_state = OpenGLState::GetCurState(); state.Apply(); - if (framebuffer != boost::none) { + if (framebuffer) { // If framebuffer is provided, reload it from memory to a texture - if (screen_info.texture.width != (GLsizei)framebuffer->width || - screen_info.texture.height != (GLsizei)framebuffer->height || - screen_info.texture.pixel_format != framebuffer->pixel_format) { + if (screen_info.texture.width != (GLsizei)framebuffer->get().width || + screen_info.texture.height != (GLsizei)framebuffer->get().height || + screen_info.texture.pixel_format != framebuffer->get().pixel_format) { // Reallocate texture if the framebuffer size has changed. // This is expected to not happen very often and hence should not be a // performance problem. diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 961467a62..c0868c0e4 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -51,7 +51,8 @@ public: ~RendererOpenGL() override; /// Swap buffers (render frame) - void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) override; + void SwapBuffers( + std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override; /// Initialize the renderer bool Init() override; 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 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <string> +#include <fmt/format.h> +#include <glad/glad.h> +#include "common/common_types.h" +#include "video_core/renderer_opengl/utils.h" + +namespace OpenGL { + +void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info) { + if (!GLAD_GL_KHR_debug) { + return; // We don't need to throw an error as this is just for debugging + } + const std::string nice_addr = fmt::format("0x{:016x}", addr); + std::string object_label; + + if (extra_info.empty()) { + switch (identifier) { + case GL_TEXTURE: + object_label = "Texture@" + nice_addr; + break; + case GL_PROGRAM: + object_label = "Shader@" + nice_addr; + break; + default: + object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr); + break; + } + } else { + object_label = extra_info + '@' + nice_addr; + } + glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str())); +} + +} // 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 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <glad/glad.h> +#include "common/common_types.h" + +namespace OpenGL { + +void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info = ""); + +} // namespace OpenGL
\ No newline at end of file |
