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.cpp191
1 files changed, 100 insertions, 91 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 5cbafa2e7..ced2b8247 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -7,7 +7,6 @@
#include <cstring>
#include <iterator>
#include <memory>
-#include <unordered_set>
#include <utility>
#include <vector>
#include <boost/optional.hpp>
@@ -20,7 +19,6 @@
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
-#include "common/vector_math.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "core/hle/kernel/process.h"
@@ -36,6 +34,7 @@
using SurfaceType = SurfaceParams::SurfaceType;
using PixelFormat = SurfaceParams::PixelFormat;
+using ComponentType = SurfaceParams::ComponentType;
struct FormatTuple {
GLint internal_format;
@@ -47,26 +46,24 @@ struct FormatTuple {
u32 compression_factor;
};
-static constexpr std::array<FormatTuple, 1> fb_format_tuples = {{
- {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8
+static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
+ {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false, 1}, // ABGR8
+ {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false, 1}, // B5G6R5
+ {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
+ {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT23
+ {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT45
}};
-static constexpr std::array<FormatTuple, 2> tex_format_tuples = {{
- {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8
- {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
-}};
-
-static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
+static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
- if (type == SurfaceType::Color) {
- ASSERT(static_cast<size_t>(pixel_format) < fb_format_tuples.size());
- return fb_format_tuples[static_cast<unsigned int>(pixel_format)];
+ if (type == SurfaceType::ColorTexture) {
+ ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
+ // For now only UNORM components are supported
+ ASSERT(component_type == ComponentType::UNorm);
+ return tex_format_tuples[static_cast<unsigned int>(pixel_format)];
} else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) {
// TODO(Subv): Implement depth formats
ASSERT_MSG(false, "Unimplemented");
- } else if (type == SurfaceType::Texture) {
- ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
- return tex_format_tuples[static_cast<unsigned int>(pixel_format)];
}
UNREACHABLE();
@@ -85,56 +82,42 @@ static u16 GetResolutionScaleFactor() {
}
template <bool morton_to_gl, PixelFormat format>
-static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
- constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
- constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
- for (u32 y = 0; y < 8; ++y) {
- for (u32 x = 0; x < 8; ++x) {
- u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel;
- u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * gl_bytes_per_pixel;
- if (morton_to_gl) {
- std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel);
- } else {
- std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel);
- }
- }
- }
-}
-
-template <bool morton_to_gl, PixelFormat format>
-void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) {
+void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, VAddr base, VAddr start,
+ VAddr end) {
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
- // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
- // configuration for this and perform more generic un/swizzle
- LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
- VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
- Memory::GetPointer(base), gl_buffer, morton_to_gl);
-}
-
-template <>
-void MortonCopy<true, PixelFormat::DXT1>(u32 stride, u32 height, u8* gl_buffer, VAddr base,
- VAddr start, VAddr end) {
- constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::DXT1) / 8;
- constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::DXT1);
-
- // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
- // configuration for this and perform more generic un/swizzle
- LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
- auto data =
- Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::DXT1, stride, height);
- std::memcpy(gl_buffer, data.data(), data.size());
+ if (morton_to_gl) {
+ auto data = Tegra::Texture::UnswizzleTexture(
+ base, SurfaceParams::TextureFormatFromPixelFormat(format), stride, height,
+ block_height);
+ std::memcpy(gl_buffer, data.data(), data.size());
+ } else {
+ // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check
+ // the configuration for this and perform more generic un/swizzle
+ LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
+ VideoCore::MortonCopyPixels128(stride, height, bytes_per_pixel, gl_bytes_per_pixel,
+ Memory::GetPointer(base), gl_buffer, morton_to_gl);
+ }
}
-static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> morton_to_gl_fns = {
- MortonCopy<true, PixelFormat::RGBA8>,
- MortonCopy<true, PixelFormat::DXT1>,
+static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
+ SurfaceParams::MaxPixelFormat>
+ morton_to_gl_fns = {
+ MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
+ MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
+ MortonCopy<true, PixelFormat::DXT45>,
};
-static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> gl_to_morton_fns = {
- MortonCopy<false, PixelFormat::RGBA8>,
- MortonCopy<false, PixelFormat::DXT1>,
+static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr),
+ SurfaceParams::MaxPixelFormat>
+ gl_to_morton_fns = {
+ MortonCopy<false, PixelFormat::ABGR8>,
+ MortonCopy<false, PixelFormat::B5G6R5>,
+ // TODO(Subv): Swizzling the DXT1/DXT23/DXT45 formats is not yet supported
+ nullptr,
+ nullptr,
+ nullptr,
};
// Allocate an uninitialized texture of appropriate size and format for the surface
@@ -183,7 +166,7 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
u32 buffers = 0;
- if (type == SurfaceType::Color || type == SurfaceType::Texture) {
+ if (type == SurfaceType::ColorTexture) {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex,
0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
@@ -311,15 +294,18 @@ MathUtil::Rectangle<u32> SurfaceParams::GetScaledSubRect(const SurfaceParams& su
bool SurfaceParams::ExactMatch(const SurfaceParams& other_surface) const {
return std::tie(other_surface.addr, other_surface.width, other_surface.height,
- other_surface.stride, other_surface.pixel_format, other_surface.is_tiled) ==
- std::tie(addr, width, height, stride, pixel_format, is_tiled) &&
+ other_surface.stride, other_surface.block_height, other_surface.pixel_format,
+ other_surface.component_type,
+ other_surface.is_tiled) == std::tie(addr, width, height, stride, block_height,
+ pixel_format, component_type, is_tiled) &&
pixel_format != PixelFormat::Invalid;
}
bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const {
return sub_surface.addr >= addr && sub_surface.end <= end &&
sub_surface.pixel_format == pixel_format && pixel_format != PixelFormat::Invalid &&
- sub_surface.is_tiled == is_tiled &&
+ sub_surface.is_tiled == is_tiled && sub_surface.block_height == block_height &&
+ sub_surface.component_type == component_type &&
(sub_surface.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 &&
(sub_surface.stride == stride || sub_surface.height <= (is_tiled ? 8u : 1u)) &&
GetSubRect(sub_surface).left + sub_surface.width <= stride;
@@ -328,7 +314,8 @@ bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const {
bool SurfaceParams::CanExpand(const SurfaceParams& expanded_surface) const {
return pixel_format != PixelFormat::Invalid && pixel_format == expanded_surface.pixel_format &&
addr <= expanded_surface.end && expanded_surface.addr <= end &&
- is_tiled == expanded_surface.is_tiled && stride == expanded_surface.stride &&
+ is_tiled == expanded_surface.is_tiled && block_height == expanded_surface.block_height &&
+ component_type == expanded_surface.component_type && stride == expanded_surface.stride &&
(std::max(expanded_surface.addr, addr) - std::min(expanded_surface.addr, addr)) %
BytesInPixels(stride * (is_tiled ? 8 : 1)) ==
0;
@@ -339,6 +326,10 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const {
end < texcopy_params.end) {
return false;
}
+ if (texcopy_params.block_height != block_height ||
+ texcopy_params.component_type != component_type)
+ return false;
+
if (texcopy_params.width != texcopy_params.stride) {
const u32 tile_stride = static_cast<u32>(BytesInPixels(stride * (is_tiled ? 8 : 1)));
return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 &&
@@ -481,18 +472,13 @@ void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
const u64 start_offset = load_start - addr;
if (!is_tiled) {
- ASSERT(type == SurfaceType::Color);
const u32 bytes_per_pixel{GetFormatBpp() >> 3};
- // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check
- // the configuration for this and perform more generic un/swizzle
- LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
- VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4,
- texture_src_data + start_offset, &gl_buffer[start_offset],
- true);
+ std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset,
+ bytes_per_pixel * width * height);
} else {
- morton_to_gl_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
- load_start, load_end);
+ morton_to_gl_fns[static_cast<size_t>(pixel_format)](
+ stride, block_height, height, &gl_buffer[0], addr, load_start, load_end);
}
}
@@ -533,11 +519,10 @@ void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) {
if (backup_bytes)
std::memcpy(&dst_buffer[coarse_start_offset], &backup_data[0], backup_bytes);
} else if (!is_tiled) {
- ASSERT(type == SurfaceType::Color);
std::memcpy(dst_buffer + start_offset, &gl_buffer[start_offset], flush_end - flush_start);
} else {
- gl_to_morton_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
- flush_start, flush_end);
+ gl_to_morton_fns[static_cast<size_t>(pixel_format)](
+ stride, block_height, height, &gl_buffer[0], addr, flush_start, flush_end);
}
}
@@ -556,7 +541,7 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint
GLint y0 = static_cast<GLint>(rect.bottom);
size_t buffer_offset = (y0 * stride + x0) * GetGLBytesPerPixel(pixel_format);
- const FormatTuple& tuple = GetFormatTuple(pixel_format);
+ const FormatTuple& tuple = GetFormatTuple(pixel_format, component_type);
GLuint target_tex = texture.handle;
// If not 1x scale, create 1x texture that we will blit from to replace texture subrect in
@@ -629,7 +614,7 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
OpenGLState prev_state = state;
SCOPE_EXIT({ prev_state.Apply(); });
- const FormatTuple& tuple = GetFormatTuple(pixel_format);
+ const FormatTuple& tuple = GetFormatTuple(pixel_format, component_type);
// Ensure no bad interactions with GL_PACK_ALIGNMENT
ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0);
@@ -662,7 +647,7 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
state.draw.read_framebuffer = read_fb_handle;
state.Apply();
- if (type == SurfaceType::Color || type == SurfaceType::Texture) {
+ if (type == SurfaceType::ColorTexture) {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
texture.handle, 0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
@@ -685,7 +670,8 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
}
-enum MatchFlags {
+enum class MatchFlags {
+ None = 0,
Invalid = 1, // Flag that can be applied to other match types, invalid matches require
// validation before they can be used
Exact = 1 << 1, // Surfaces perfectly match
@@ -699,6 +685,10 @@ constexpr MatchFlags operator|(MatchFlags lhs, MatchFlags rhs) {
return static_cast<MatchFlags>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
+constexpr MatchFlags operator&(MatchFlags lhs, MatchFlags rhs) {
+ return static_cast<MatchFlags>(static_cast<int>(lhs) & static_cast<int>(rhs));
+}
+
/// Get the best surface match (and its match type) for the given flags
template <MatchFlags find_flags>
Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params,
@@ -716,15 +706,15 @@ Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params
: (params.res_scale <= surface->res_scale);
// validity will be checked in GetCopyableInterval
bool is_valid =
- find_flags & MatchFlags::Copy
+ (find_flags & MatchFlags::Copy) != MatchFlags::None
? true
: surface->IsRegionValid(validate_interval.value_or(params.GetInterval()));
- if (!(find_flags & MatchFlags::Invalid) && !is_valid)
+ if ((find_flags & MatchFlags::Invalid) == MatchFlags::None && !is_valid)
continue;
auto IsMatch_Helper = [&](auto check_type, auto match_fn) {
- if (!(find_flags & check_type))
+ if ((find_flags & check_type) == MatchFlags::None)
return;
bool matched;
@@ -818,7 +808,7 @@ void main() {
color = texelFetch(tbo, tbo_offset).rabg;
}
)";
- d24s8_abgr_shader.Create(vs_source, nullptr, fs_source);
+ d24s8_abgr_shader.CreateFromSource(vs_source, nullptr, fs_source);
OpenGLState state = OpenGLState::GetCurState();
GLuint old_program = state.draw.shader_program;
@@ -1041,9 +1031,25 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu
params.height = config.tic.Height();
params.is_tiled = config.tic.IsTiled();
params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format);
+
+ // TODO(Subv): Different types per component are not supported.
+ ASSERT(config.tic.r_type.Value() == config.tic.g_type.Value() &&
+ config.tic.r_type.Value() == config.tic.b_type.Value() &&
+ config.tic.r_type.Value() == config.tic.a_type.Value());
+
+ params.component_type = SurfaceParams::ComponentTypeFromTexture(config.tic.r_type.Value());
+
+ if (config.tic.IsTiled()) {
+ params.block_height = config.tic.BlockHeight();
+ } else {
+ // Use the texture-provided stride value if the texture isn't tiled.
+ params.stride = params.PixelsInBytes(config.tic.Pitch());
+ }
+
params.UpdateParams();
- if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0) {
+ if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0 ||
+ params.stride != params.width) {
Surface src_surface;
MathUtil::Rectangle<u32> rect;
std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true);
@@ -1083,10 +1089,10 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
}
MathUtil::Rectangle<u32> viewport_clamped{
- static_cast<u32>(MathUtil::Clamp(viewport.left, 0, static_cast<s32>(config.width))),
- static_cast<u32>(MathUtil::Clamp(viewport.top, 0, static_cast<s32>(config.height))),
- static_cast<u32>(MathUtil::Clamp(viewport.right, 0, static_cast<s32>(config.width))),
- static_cast<u32>(MathUtil::Clamp(viewport.bottom, 0, static_cast<s32>(config.height)))};
+ static_cast<u32>(std::clamp(viewport.left, 0, static_cast<s32>(config.width))),
+ static_cast<u32>(std::clamp(viewport.top, 0, static_cast<s32>(config.height))),
+ static_cast<u32>(std::clamp(viewport.right, 0, static_cast<s32>(config.width))),
+ static_cast<u32>(std::clamp(viewport.bottom, 0, static_cast<s32>(config.height)))};
// get color and depth surfaces
SurfaceParams color_params;
@@ -1094,10 +1100,13 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
color_params.res_scale = resolution_scale_factor;
color_params.width = config.width;
color_params.height = config.height;
+ // TODO(Subv): Can framebuffers use a different block height?
+ color_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight;
SurfaceParams depth_params = color_params;
color_params.addr = memory_manager->PhysicalToVirtualAddress(config.Address());
color_params.pixel_format = SurfaceParams::PixelFormatFromRenderTargetFormat(config.format);
+ color_params.component_type = SurfaceParams::ComponentTypeFromRenderTarget(config.format);
color_params.UpdateParams();
ASSERT_MSG(!using_depth_fb, "depth buffer is unimplemented");
@@ -1293,7 +1302,6 @@ void RasterizerCacheOpenGL::InvalidateRegion(VAddr addr, u64 size, const Surface
const SurfaceInterval invalid_interval(addr, addr + size);
if (region_owner != nullptr) {
- ASSERT(region_owner->type != SurfaceType::Texture);
ASSERT(addr >= region_owner->addr && addr + size <= region_owner->end);
// Surfaces can't have a gap
ASSERT(region_owner->width == region_owner->stride);
@@ -1355,7 +1363,8 @@ Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) {
surface->gl_buffer_size = 0;
surface->invalid_regions.insert(surface->GetInterval());
- AllocateSurfaceTexture(surface->texture.handle, GetFormatTuple(surface->pixel_format),
+ AllocateSurfaceTexture(surface->texture.handle,
+ GetFormatTuple(surface->pixel_format, surface->component_type),
surface->GetScaledWidth(), surface->GetScaledHeight());
return surface;