summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl/gl_rasterizer_cache.cpp')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp405
1 files changed, 197 insertions, 208 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b057e2efa..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);