mirror of
https://github.com/Lime3DS/Lime3DS
synced 2024-12-27 01:22:37 -06:00
rasterizer_cache: Factor morton swizzle and pixel format to dedicate headers
* Makes the code cleaner in general by not having to alias PixelFormat and SurfaceType everywhere
This commit is contained in:
parent
efc2db4088
commit
6a7d601e42
13 changed files with 427 additions and 409 deletions
|
@ -23,6 +23,8 @@ add_library(video_core STATIC
|
|||
regs_texturing.h
|
||||
renderer_base.cpp
|
||||
renderer_base.h
|
||||
rasterizer_cache/morton_swizzle.h
|
||||
rasterizer_cache/pixel_format.h
|
||||
rasterizer_cache/rasterizer_cache.cpp
|
||||
rasterizer_cache/rasterizer_cache.h
|
||||
rasterizer_cache/surface_params.cpp
|
||||
|
|
171
src/video_core/rasterizer_cache/morton_swizzle.h
Normal file
171
src/video_core/rasterizer_cache/morton_swizzle.h
Normal file
|
@ -0,0 +1,171 @@
|
|||
// Copyright 2022 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include "common/alignment.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
#include "video_core/utils.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
template <bool morton_to_gl, PixelFormat format>
|
||||
static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
|
||||
constexpr u32 bytes_per_pixel = GetFormatBpp(format) / 8;
|
||||
constexpr u32 aligned_bytes_per_pixel = GetBytesPerPixel(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) * aligned_bytes_per_pixel;
|
||||
if constexpr (morton_to_gl) {
|
||||
if constexpr (format == PixelFormat::D24S8) {
|
||||
gl_ptr[0] = tile_ptr[3];
|
||||
std::memcpy(gl_ptr + 1, tile_ptr, 3);
|
||||
} else if (format == PixelFormat::RGBA8 && GLES) {
|
||||
// because GLES does not have ABGR format
|
||||
// so we will do byteswapping here
|
||||
gl_ptr[0] = tile_ptr[3];
|
||||
gl_ptr[1] = tile_ptr[2];
|
||||
gl_ptr[2] = tile_ptr[1];
|
||||
gl_ptr[3] = tile_ptr[0];
|
||||
} else if (format == PixelFormat::RGB8 && GLES) {
|
||||
gl_ptr[0] = tile_ptr[2];
|
||||
gl_ptr[1] = tile_ptr[1];
|
||||
gl_ptr[2] = tile_ptr[0];
|
||||
} else {
|
||||
std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel);
|
||||
}
|
||||
} else {
|
||||
if constexpr (format == PixelFormat::D24S8) {
|
||||
std::memcpy(tile_ptr, gl_ptr + 1, 3);
|
||||
tile_ptr[3] = gl_ptr[0];
|
||||
} else if (format == PixelFormat::RGBA8 && GLES) {
|
||||
// because GLES does not have ABGR format
|
||||
// so we will do byteswapping here
|
||||
tile_ptr[0] = gl_ptr[3];
|
||||
tile_ptr[1] = gl_ptr[2];
|
||||
tile_ptr[2] = gl_ptr[1];
|
||||
tile_ptr[3] = gl_ptr[0];
|
||||
} else if (format == PixelFormat::RGB8 && GLES) {
|
||||
tile_ptr[0] = gl_ptr[2];
|
||||
tile_ptr[1] = gl_ptr[1];
|
||||
tile_ptr[2] = gl_ptr[0];
|
||||
} else {
|
||||
std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool morton_to_gl, PixelFormat format>
|
||||
static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr start, PAddr end) {
|
||||
constexpr u32 bytes_per_pixel = GetFormatBpp(format) / 8;
|
||||
constexpr u32 tile_size = bytes_per_pixel * 64;
|
||||
|
||||
constexpr u32 aligned_bytes_per_pixel = GetBytesPerPixel(format);
|
||||
static_assert(aligned_bytes_per_pixel >= bytes_per_pixel, "");
|
||||
gl_buffer += aligned_bytes_per_pixel - bytes_per_pixel;
|
||||
|
||||
const PAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size);
|
||||
const PAddr aligned_start = base + Common::AlignUp(start - base, tile_size);
|
||||
const PAddr aligned_end = base + Common::AlignDown(end - base, tile_size);
|
||||
|
||||
ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end));
|
||||
|
||||
const u32 begin_pixel_index = (aligned_down_start - base) / bytes_per_pixel;
|
||||
u32 x = (begin_pixel_index % (stride * 8)) / 8;
|
||||
u32 y = (begin_pixel_index / (stride * 8)) * 8;
|
||||
|
||||
gl_buffer += ((height - 8 - y) * stride + x) * aligned_bytes_per_pixel;
|
||||
|
||||
auto glbuf_next_tile = [&] {
|
||||
x = (x + 8) % stride;
|
||||
gl_buffer += 8 * aligned_bytes_per_pixel;
|
||||
if (!x) {
|
||||
y += 8;
|
||||
gl_buffer -= stride * 9 * aligned_bytes_per_pixel;
|
||||
}
|
||||
};
|
||||
|
||||
u8* tile_buffer = VideoCore::g_memory->GetPhysicalPointer(start);
|
||||
|
||||
if (start < aligned_start && !morton_to_gl) {
|
||||
std::array<u8, tile_size> tmp_buf;
|
||||
MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer);
|
||||
std::memcpy(tile_buffer, &tmp_buf[start - aligned_down_start],
|
||||
std::min(aligned_start, end) - start);
|
||||
|
||||
tile_buffer += aligned_start - start;
|
||||
glbuf_next_tile();
|
||||
}
|
||||
|
||||
const u8* const buffer_end = tile_buffer + aligned_end - aligned_start;
|
||||
PAddr current_paddr = aligned_start;
|
||||
while (tile_buffer < buffer_end) {
|
||||
// Pokemon Super Mystery Dungeon will try to use textures that go beyond
|
||||
// the end address of VRAM. Stop reading if reaches invalid address
|
||||
if (!VideoCore::g_memory->IsValidPhysicalAddress(current_paddr) ||
|
||||
!VideoCore::g_memory->IsValidPhysicalAddress(current_paddr + tile_size)) {
|
||||
LOG_ERROR(Render_OpenGL, "Out of bound texture");
|
||||
break;
|
||||
}
|
||||
MortonCopyTile<morton_to_gl, format>(stride, tile_buffer, gl_buffer);
|
||||
tile_buffer += tile_size;
|
||||
current_paddr += tile_size;
|
||||
glbuf_next_tile();
|
||||
}
|
||||
|
||||
if (end > std::max(aligned_start, aligned_end) && !morton_to_gl) {
|
||||
std::array<u8, tile_size> tmp_buf;
|
||||
MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer);
|
||||
std::memcpy(tile_buffer, &tmp_buf[0], end - aligned_end);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> morton_to_gl_fns = {
|
||||
MortonCopy<true, PixelFormat::RGBA8>, // 0
|
||||
MortonCopy<true, PixelFormat::RGB8>, // 1
|
||||
MortonCopy<true, PixelFormat::RGB5A1>, // 2
|
||||
MortonCopy<true, PixelFormat::RGB565>, // 3
|
||||
MortonCopy<true, PixelFormat::RGBA4>, // 4
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // 5 - 13
|
||||
MortonCopy<true, PixelFormat::D16>, // 14
|
||||
nullptr, // 15
|
||||
MortonCopy<true, PixelFormat::D24>, // 16
|
||||
MortonCopy<true, PixelFormat::D24S8> // 17
|
||||
};
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl_to_morton_fns = {
|
||||
MortonCopy<false, PixelFormat::RGBA8>, // 0
|
||||
MortonCopy<false, PixelFormat::RGB8>, // 1
|
||||
MortonCopy<false, PixelFormat::RGB5A1>, // 2
|
||||
MortonCopy<false, PixelFormat::RGB565>, // 3
|
||||
MortonCopy<false, PixelFormat::RGBA4>, // 4
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // 5 - 13
|
||||
MortonCopy<false, PixelFormat::D16>, // 14
|
||||
nullptr, // 15
|
||||
MortonCopy<false, PixelFormat::D24>, // 16
|
||||
MortonCopy<false, PixelFormat::D24S8> // 17
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
194
src/video_core/rasterizer_cache/pixel_format.h
Normal file
194
src/video_core/rasterizer_cache/pixel_format.h
Normal file
|
@ -0,0 +1,194 @@
|
|||
// Copyright 2022 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#include <string_view>
|
||||
#include "core/hw/gpu.h"
|
||||
#include "video_core/regs_texturing.h"
|
||||
#include "video_core/regs_framebuffer.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
enum class PixelFormat : u8 {
|
||||
// First 5 formats are shared between textures and color buffers
|
||||
RGBA8 = 0,
|
||||
RGB8 = 1,
|
||||
RGB5A1 = 2,
|
||||
RGB565 = 3,
|
||||
RGBA4 = 4,
|
||||
// Texture-only formats
|
||||
IA8 = 5,
|
||||
RG8 = 6,
|
||||
I8 = 7,
|
||||
A8 = 8,
|
||||
IA4 = 9,
|
||||
I4 = 10,
|
||||
A4 = 11,
|
||||
ETC1 = 12,
|
||||
ETC1A4 = 13,
|
||||
// Depth buffer-only formats
|
||||
D16 = 14,
|
||||
D24 = 16,
|
||||
D24S8 = 17,
|
||||
Invalid = 255,
|
||||
};
|
||||
|
||||
enum class SurfaceType {
|
||||
Color = 0,
|
||||
Texture = 1,
|
||||
Depth = 2,
|
||||
DepthStencil = 3,
|
||||
Fill = 4,
|
||||
Invalid = 5
|
||||
};
|
||||
|
||||
static constexpr std::string_view PixelFormatAsString(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::RGBA8:
|
||||
return "RGBA8";
|
||||
case PixelFormat::RGB8:
|
||||
return "RGB8";
|
||||
case PixelFormat::RGB5A1:
|
||||
return "RGB5A1";
|
||||
case PixelFormat::RGB565:
|
||||
return "RGB565";
|
||||
case PixelFormat::RGBA4:
|
||||
return "RGBA4";
|
||||
case PixelFormat::IA8:
|
||||
return "IA8";
|
||||
case PixelFormat::RG8:
|
||||
return "RG8";
|
||||
case PixelFormat::I8:
|
||||
return "I8";
|
||||
case PixelFormat::A8:
|
||||
return "A8";
|
||||
case PixelFormat::IA4:
|
||||
return "IA4";
|
||||
case PixelFormat::I4:
|
||||
return "I4";
|
||||
case PixelFormat::A4:
|
||||
return "A4";
|
||||
case PixelFormat::ETC1:
|
||||
return "ETC1";
|
||||
case PixelFormat::ETC1A4:
|
||||
return "ETC1A4";
|
||||
case PixelFormat::D16:
|
||||
return "D16";
|
||||
case PixelFormat::D24:
|
||||
return "D24";
|
||||
case PixelFormat::D24S8:
|
||||
return "D24S8";
|
||||
default:
|
||||
return "NotReal";
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) {
|
||||
const u32 format_index = static_cast<u32>(format);
|
||||
return (format_index < 14) ? static_cast<PixelFormat>(format) : PixelFormat::Invalid;
|
||||
}
|
||||
|
||||
static constexpr PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) {
|
||||
const u32 format_index = static_cast<u32>(format);
|
||||
return (format_index < 5) ? static_cast<PixelFormat>(format) : PixelFormat::Invalid;
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) {
|
||||
const u32 format_index = static_cast<u32>(format);
|
||||
return (format_index < 4) ? static_cast<PixelFormat>(format_index + 14)
|
||||
: PixelFormat::Invalid;
|
||||
}
|
||||
|
||||
static constexpr PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) {
|
||||
switch (format) {
|
||||
// RGB565 and RGB5A1 are switched in PixelFormat compared to ColorFormat
|
||||
case GPU::Regs::PixelFormat::RGB565:
|
||||
return PixelFormat::RGB565;
|
||||
case GPU::Regs::PixelFormat::RGB5A1:
|
||||
return PixelFormat::RGB5A1;
|
||||
default:
|
||||
return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) {
|
||||
const u32 format_index = static_cast<u32>(pixel_format);
|
||||
if (format_index < 5) {
|
||||
return SurfaceType::Color;
|
||||
}
|
||||
|
||||
if (format_index < 14) {
|
||||
return SurfaceType::Texture;
|
||||
}
|
||||
|
||||
if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) {
|
||||
return SurfaceType::Depth;
|
||||
}
|
||||
|
||||
if (pixel_format == PixelFormat::D24S8) {
|
||||
return SurfaceType::DepthStencil;
|
||||
}
|
||||
|
||||
return SurfaceType::Invalid;
|
||||
}
|
||||
|
||||
static constexpr bool CheckFormatsBlittable(PixelFormat source_format, PixelFormat dest_format) {
|
||||
SurfaceType source_type = GetFormatType(source_format);
|
||||
SurfaceType dest_type = GetFormatType(dest_format);
|
||||
|
||||
if ((source_type == SurfaceType::Color || source_type == SurfaceType::Texture) &&
|
||||
(dest_type == SurfaceType::Color || dest_type == SurfaceType::Texture)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (source_type == SurfaceType::Depth && dest_type == SurfaceType::Depth) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (source_type == SurfaceType::DepthStencil && dest_type == SurfaceType::DepthStencil) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr u32 GetFormatBpp(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::RGBA8:
|
||||
case PixelFormat::D24S8:
|
||||
return 32;
|
||||
case PixelFormat::RGB8:
|
||||
case PixelFormat::D24:
|
||||
return 24;
|
||||
case PixelFormat::RGB5A1:
|
||||
case PixelFormat::RGB565:
|
||||
case PixelFormat::RGBA4:
|
||||
case PixelFormat::IA8:
|
||||
case PixelFormat::RG8:
|
||||
case PixelFormat::D16:
|
||||
return 16;
|
||||
case PixelFormat::I8:
|
||||
case PixelFormat::A8:
|
||||
case PixelFormat::IA4:
|
||||
case PixelFormat::ETC1A4:
|
||||
return 8;
|
||||
case PixelFormat::I4:
|
||||
case PixelFormat::A4:
|
||||
case PixelFormat::ETC1:
|
||||
return 4;
|
||||
case PixelFormat::Invalid:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr u32 GetBytesPerPixel(PixelFormat format) {
|
||||
// OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type
|
||||
if (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
return GetFormatBpp(format) / 8;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
|
@ -29,24 +29,17 @@
|
|||
#include "core/custom_tex_cache.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/pica_state.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/gl_format_reinterpreter.h"
|
||||
#include "video_core/rasterizer_cache/morton_swizzle.h"
|
||||
#include "video_core/rasterizer_cache/rasterizer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
#include "video_core/renderer_opengl/texture_downloader_es.h"
|
||||
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
|
||||
#include "video_core/utils.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
using SurfaceType = SurfaceParams::SurfaceType;
|
||||
using PixelFormat = SurfaceParams::PixelFormat;
|
||||
|
||||
static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}, // RGBA8
|
||||
{GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE}, // RGB8
|
||||
|
@ -67,7 +60,7 @@ static constexpr std::array<FormatTuple, 5> fb_format_tuples_oes = {{
|
|||
}};
|
||||
|
||||
const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
|
||||
const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
|
||||
const SurfaceType type = GetFormatType(pixel_format);
|
||||
if (type == SurfaceType::Color) {
|
||||
ASSERT(static_cast<std::size_t>(pixel_format) < fb_format_tuples.size());
|
||||
if (GLES) {
|
||||
|
@ -87,162 +80,6 @@ static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
|||
return boost::make_iterator_range(map.equal_range(interval));
|
||||
}
|
||||
|
||||
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 constexpr (morton_to_gl) {
|
||||
if constexpr (format == PixelFormat::D24S8) {
|
||||
gl_ptr[0] = tile_ptr[3];
|
||||
std::memcpy(gl_ptr + 1, tile_ptr, 3);
|
||||
} else if (format == PixelFormat::RGBA8 && GLES) {
|
||||
// because GLES does not have ABGR format
|
||||
// so we will do byteswapping here
|
||||
gl_ptr[0] = tile_ptr[3];
|
||||
gl_ptr[1] = tile_ptr[2];
|
||||
gl_ptr[2] = tile_ptr[1];
|
||||
gl_ptr[3] = tile_ptr[0];
|
||||
} else if (format == PixelFormat::RGB8 && GLES) {
|
||||
gl_ptr[0] = tile_ptr[2];
|
||||
gl_ptr[1] = tile_ptr[1];
|
||||
gl_ptr[2] = tile_ptr[0];
|
||||
} else {
|
||||
std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel);
|
||||
}
|
||||
} else {
|
||||
if constexpr (format == PixelFormat::D24S8) {
|
||||
std::memcpy(tile_ptr, gl_ptr + 1, 3);
|
||||
tile_ptr[3] = gl_ptr[0];
|
||||
} else if (format == PixelFormat::RGBA8 && GLES) {
|
||||
// because GLES does not have ABGR format
|
||||
// so we will do byteswapping here
|
||||
tile_ptr[0] = gl_ptr[3];
|
||||
tile_ptr[1] = gl_ptr[2];
|
||||
tile_ptr[2] = gl_ptr[1];
|
||||
tile_ptr[3] = gl_ptr[0];
|
||||
} else if (format == PixelFormat::RGB8 && GLES) {
|
||||
tile_ptr[0] = gl_ptr[2];
|
||||
tile_ptr[1] = gl_ptr[1];
|
||||
tile_ptr[2] = gl_ptr[0];
|
||||
} else {
|
||||
std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool morton_to_gl, PixelFormat format>
|
||||
static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr start, PAddr end) {
|
||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
|
||||
constexpr u32 tile_size = bytes_per_pixel * 64;
|
||||
|
||||
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
|
||||
static_assert(gl_bytes_per_pixel >= bytes_per_pixel, "");
|
||||
gl_buffer += gl_bytes_per_pixel - bytes_per_pixel;
|
||||
|
||||
const PAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size);
|
||||
const PAddr aligned_start = base + Common::AlignUp(start - base, tile_size);
|
||||
const PAddr aligned_end = base + Common::AlignDown(end - base, tile_size);
|
||||
|
||||
ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end));
|
||||
|
||||
const u32 begin_pixel_index = (aligned_down_start - base) / bytes_per_pixel;
|
||||
u32 x = (begin_pixel_index % (stride * 8)) / 8;
|
||||
u32 y = (begin_pixel_index / (stride * 8)) * 8;
|
||||
|
||||
gl_buffer += ((height - 8 - y) * stride + x) * gl_bytes_per_pixel;
|
||||
|
||||
auto glbuf_next_tile = [&] {
|
||||
x = (x + 8) % stride;
|
||||
gl_buffer += 8 * gl_bytes_per_pixel;
|
||||
if (!x) {
|
||||
y += 8;
|
||||
gl_buffer -= stride * 9 * gl_bytes_per_pixel;
|
||||
}
|
||||
};
|
||||
|
||||
u8* tile_buffer = VideoCore::g_memory->GetPhysicalPointer(start);
|
||||
|
||||
if (start < aligned_start && !morton_to_gl) {
|
||||
std::array<u8, tile_size> tmp_buf;
|
||||
MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer);
|
||||
std::memcpy(tile_buffer, &tmp_buf[start - aligned_down_start],
|
||||
std::min(aligned_start, end) - start);
|
||||
|
||||
tile_buffer += aligned_start - start;
|
||||
glbuf_next_tile();
|
||||
}
|
||||
|
||||
const u8* const buffer_end = tile_buffer + aligned_end - aligned_start;
|
||||
PAddr current_paddr = aligned_start;
|
||||
while (tile_buffer < buffer_end) {
|
||||
// Pokemon Super Mystery Dungeon will try to use textures that go beyond
|
||||
// the end address of VRAM. Stop reading if reaches invalid address
|
||||
if (!VideoCore::g_memory->IsValidPhysicalAddress(current_paddr) ||
|
||||
!VideoCore::g_memory->IsValidPhysicalAddress(current_paddr + tile_size)) {
|
||||
LOG_ERROR(Render_OpenGL, "Out of bound texture");
|
||||
break;
|
||||
}
|
||||
MortonCopyTile<morton_to_gl, format>(stride, tile_buffer, gl_buffer);
|
||||
tile_buffer += tile_size;
|
||||
current_paddr += tile_size;
|
||||
glbuf_next_tile();
|
||||
}
|
||||
|
||||
if (end > std::max(aligned_start, aligned_end) && !morton_to_gl) {
|
||||
std::array<u8, tile_size> tmp_buf;
|
||||
MortonCopyTile<morton_to_gl, format>(stride, &tmp_buf[0], gl_buffer);
|
||||
std::memcpy(tile_buffer, &tmp_buf[0], end - aligned_end);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> morton_to_gl_fns = {
|
||||
MortonCopy<true, PixelFormat::RGBA8>, // 0
|
||||
MortonCopy<true, PixelFormat::RGB8>, // 1
|
||||
MortonCopy<true, PixelFormat::RGB5A1>, // 2
|
||||
MortonCopy<true, PixelFormat::RGB565>, // 3
|
||||
MortonCopy<true, PixelFormat::RGBA4>, // 4
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // 5 - 13
|
||||
MortonCopy<true, PixelFormat::D16>, // 14
|
||||
nullptr, // 15
|
||||
MortonCopy<true, PixelFormat::D24>, // 16
|
||||
MortonCopy<true, PixelFormat::D24S8> // 17
|
||||
};
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl_to_morton_fns = {
|
||||
MortonCopy<false, PixelFormat::RGBA8>, // 0
|
||||
MortonCopy<false, PixelFormat::RGB8>, // 1
|
||||
MortonCopy<false, PixelFormat::RGB5A1>, // 2
|
||||
MortonCopy<false, PixelFormat::RGB565>, // 3
|
||||
MortonCopy<false, PixelFormat::RGBA4>, // 4
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // 5 - 13
|
||||
MortonCopy<false, PixelFormat::D16>, // 14
|
||||
nullptr, // 15
|
||||
MortonCopy<false, PixelFormat::D24>, // 16
|
||||
MortonCopy<false, PixelFormat::D24S8> // 17
|
||||
};
|
||||
|
||||
// Allocate an uninitialized texture of appropriate size and format for the surface
|
||||
OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& format_tuple, u32 width,
|
||||
u32 height) {
|
||||
|
@ -264,7 +101,7 @@ OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& form
|
|||
|
||||
if (GL_ARB_texture_storage) {
|
||||
// Allocate all possible mipmap levels upfront
|
||||
auto levels = std::log2(std::max(width, height)) + 1;
|
||||
const GLsizei levels = std::log2(std::max(width, height)) + 1;
|
||||
glTexStorage2D(GL_TEXTURE_2D, levels, format_tuple.internal_format, width, height);
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0,
|
||||
|
@ -293,7 +130,7 @@ static void AllocateTextureCube(GLuint texture, const FormatTuple& format_tuple,
|
|||
glActiveTexture(TextureUnits::TextureCube.Enum());
|
||||
if (GL_ARB_texture_storage) {
|
||||
// Allocate all possible mipmap levels in case the game uses them later
|
||||
auto levels = std::log2(width) + 1;
|
||||
const GLsizei levels = std::log2(width) + 1;
|
||||
glTexStorage2D(GL_TEXTURE_CUBE_MAP, levels, format_tuple.internal_format, width, width);
|
||||
} else {
|
||||
for (auto faces : {
|
||||
|
@ -418,10 +255,10 @@ static bool FillSurface(const Surface& surface, const u8* fill_data,
|
|||
u32 value_32bit = 0;
|
||||
GLfloat value_float;
|
||||
|
||||
if (surface->pixel_format == SurfaceParams::PixelFormat::D16) {
|
||||
if (surface->pixel_format == PixelFormat::D16) {
|
||||
std::memcpy(&value_32bit, fill_data, 2);
|
||||
value_float = value_32bit / 65535.0f; // 2^16 - 1
|
||||
} else if (surface->pixel_format == SurfaceParams::PixelFormat::D24) {
|
||||
} else if (surface->pixel_format == PixelFormat::D24) {
|
||||
std::memcpy(&value_32bit, fill_data, 3);
|
||||
value_float = value_32bit / 16777215.0f; // 2^24 - 1
|
||||
}
|
||||
|
@ -545,7 +382,7 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
|
|||
return;
|
||||
|
||||
if (gl_buffer.empty()) {
|
||||
gl_buffer.resize(width * height * GetGLBytesPerPixel(pixel_format));
|
||||
gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format));
|
||||
}
|
||||
|
||||
// TODO: Should probably be done in ::Memory:: and check for other regions too
|
||||
|
@ -617,7 +454,7 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
|
|||
if (dst_buffer == nullptr)
|
||||
return;
|
||||
|
||||
ASSERT(gl_buffer.size() == width * height * GetGLBytesPerPixel(pixel_format));
|
||||
ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format));
|
||||
|
||||
// TODO: Should probably be done in ::Memory:: and check for other regions too
|
||||
// same as loadglbuffer()
|
||||
|
@ -771,7 +608,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_
|
|||
|
||||
MICROPROFILE_SCOPE(OpenGL_TextureUL);
|
||||
|
||||
ASSERT(gl_buffer.size() == width * height * GetGLBytesPerPixel(pixel_format));
|
||||
ASSERT(gl_buffer.size() == width * height * GetBytesPerPixel(pixel_format));
|
||||
|
||||
u64 tex_hash = 0;
|
||||
|
||||
|
@ -786,7 +623,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_
|
|||
// Load data from memory to the surface
|
||||
GLint x0 = static_cast<GLint>(rect.left);
|
||||
GLint y0 = static_cast<GLint>(rect.bottom);
|
||||
std::size_t buffer_offset = (y0 * stride + x0) * GetGLBytesPerPixel(pixel_format);
|
||||
std::size_t buffer_offset = (y0 * stride + x0) * GetBytesPerPixel(pixel_format);
|
||||
|
||||
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
||||
GLuint target_tex = texture.handle;
|
||||
|
@ -814,7 +651,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_
|
|||
cur_state.Apply();
|
||||
|
||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
||||
ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0);
|
||||
ASSERT(stride * GetBytesPerPixel(pixel_format) % 4 == 0);
|
||||
if (is_custom) {
|
||||
if (res_scale == 1) {
|
||||
texture = owner.AllocateSurfaceTexture(GetFormatTuple(PixelFormat::RGBA8),
|
||||
|
@ -873,7 +710,7 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint
|
|||
MICROPROFILE_SCOPE(OpenGL_TextureDL);
|
||||
|
||||
if (gl_buffer.empty()) {
|
||||
gl_buffer.resize(width * height * GetGLBytesPerPixel(pixel_format));
|
||||
gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format));
|
||||
}
|
||||
|
||||
OpenGLState state = OpenGLState::GetCurState();
|
||||
|
@ -883,10 +720,10 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint
|
|||
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
||||
|
||||
// Ensure no bad interactions with GL_PACK_ALIGNMENT
|
||||
ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0);
|
||||
ASSERT(stride * GetBytesPerPixel(pixel_format) % 4 == 0);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(stride));
|
||||
std::size_t buffer_offset =
|
||||
(rect.bottom * stride + rect.left) * GetGLBytesPerPixel(pixel_format);
|
||||
(rect.bottom * stride + rect.left) * GetBytesPerPixel(pixel_format);
|
||||
|
||||
// If not 1x scale, blit scaled texture to a new 1x texture and use that to flush
|
||||
if (res_scale != 1) {
|
||||
|
@ -1084,7 +921,7 @@ bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface,
|
|||
const Common::Rectangle<u32>& dst_rect) {
|
||||
MICROPROFILE_SCOPE(OpenGL_BlitSurface);
|
||||
|
||||
if (!SurfaceParams::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format))
|
||||
if (!CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format))
|
||||
return false;
|
||||
|
||||
dst_surface->InvalidateAllWatcher();
|
||||
|
@ -1239,7 +1076,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInf
|
|||
params.width = info.width;
|
||||
params.height = info.height;
|
||||
params.is_tiled = true;
|
||||
params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(info.format);
|
||||
params.pixel_format = PixelFormatFromTextureFormat(info.format);
|
||||
params.res_scale = texture_filterer->IsNull() ? 1 : resolution_scale_factor;
|
||||
params.UpdateParams();
|
||||
|
||||
|
@ -1411,7 +1248,7 @@ const CachedTextureCube& RasterizerCacheOpenGL::GetTextureCube(const TextureCube
|
|||
cube.texture.Create();
|
||||
AllocateTextureCube(
|
||||
cube.texture.handle,
|
||||
GetFormatTuple(CachedSurface::PixelFormatFromTextureFormat(config.format)),
|
||||
GetFormatTuple(PixelFormatFromTextureFormat(config.format)),
|
||||
cube.res_scale * config.width);
|
||||
}
|
||||
|
||||
|
@ -1459,7 +1296,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
|||
const auto& config = regs.framebuffer.framebuffer;
|
||||
|
||||
// update resolution_scale_factor and reset cache if changed
|
||||
if ((resolution_scale_factor != VideoCore::GetResolutionScaleFactor()) |
|
||||
if ((resolution_scale_factor != VideoCore::GetResolutionScaleFactor()) ||
|
||||
(VideoCore::g_texture_filter_update_requested.exchange(false) &&
|
||||
texture_filterer->Reset(Settings::values.texture_filter_name, resolution_scale_factor))) {
|
||||
resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
|
||||
|
@ -1485,11 +1322,11 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
|||
SurfaceParams depth_params = color_params;
|
||||
|
||||
color_params.addr = config.GetColorBufferPhysicalAddress();
|
||||
color_params.pixel_format = SurfaceParams::PixelFormatFromColorFormat(config.color_format);
|
||||
color_params.pixel_format = PixelFormatFromColorFormat(config.color_format);
|
||||
color_params.UpdateParams();
|
||||
|
||||
depth_params.addr = config.GetDepthBufferPhysicalAddress();
|
||||
depth_params.pixel_format = SurfaceParams::PixelFormatFromDepthFormat(config.depth_format);
|
||||
depth_params.pixel_format = PixelFormatFromDepthFormat(config.depth_format);
|
||||
depth_params.UpdateParams();
|
||||
|
||||
auto color_vp_interval = color_params.GetSubRectInterval(viewport_clamped);
|
||||
|
@ -1693,7 +1530,7 @@ bool RasterizerCacheOpenGL::NoUnimplementedReinterpretations(const Surface& surf
|
|||
};
|
||||
bool implemented = true;
|
||||
for (PixelFormat format : all_formats) {
|
||||
if (SurfaceParams::GetFormatBpp(format) == surface->GetFormatBpp()) {
|
||||
if (GetFormatBpp(format) == surface->GetFormatBpp()) {
|
||||
params.pixel_format = format;
|
||||
// This could potentially be expensive,
|
||||
// although experimentally it hasn't been too bad
|
||||
|
@ -1701,8 +1538,8 @@ bool RasterizerCacheOpenGL::NoUnimplementedReinterpretations(const Surface& surf
|
|||
FindMatch<MatchFlags::Copy>(surface_cache, params, ScaleMatch::Ignore, interval);
|
||||
if (test_surface != nullptr) {
|
||||
LOG_WARNING(Render_OpenGL, "Missing pixel_format reinterpreter: {} -> {}",
|
||||
SurfaceParams::PixelFormatAsString(format),
|
||||
SurfaceParams::PixelFormatAsString(surface->pixel_format));
|
||||
PixelFormatAsString(format),
|
||||
PixelFormatAsString(surface->pixel_format));
|
||||
implemented = false;
|
||||
}
|
||||
}
|
||||
|
@ -1751,9 +1588,8 @@ bool RasterizerCacheOpenGL::ValidateByReinterpretation(const Surface& surface,
|
|||
reinterpreter->second->Reinterpret(reinterpret_surface->texture.handle, src_rect,
|
||||
read_framebuffer.handle, tmp_tex.handle,
|
||||
tmp_rect, draw_framebuffer.handle);
|
||||
SurfaceParams::SurfaceType type =
|
||||
SurfaceParams::GetFormatType(reinterpreter->first.dst_format);
|
||||
|
||||
const SurfaceType type = GetFormatType(reinterpreter->first.dst_format);
|
||||
if (!texture_filterer->Filter(tmp_tex.handle, tmp_rect, surface->texture.handle,
|
||||
dest_rect, type, read_framebuffer.handle,
|
||||
draw_framebuffer.handle)) {
|
||||
|
|
|
@ -45,7 +45,7 @@ struct FormatTuple {
|
|||
|
||||
constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
|
||||
|
||||
const FormatTuple& GetFormatTuple(SurfaceParams::PixelFormat pixel_format);
|
||||
const FormatTuple& GetFormatTuple(PixelFormat pixel_format);
|
||||
|
||||
struct HostTextureTag {
|
||||
FormatTuple format_tuple;
|
||||
|
@ -205,15 +205,6 @@ struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface
|
|||
bool is_custom = false;
|
||||
Core::CustomTexInfo custom_tex_info;
|
||||
|
||||
static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) {
|
||||
// OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type
|
||||
return format == PixelFormat::Invalid
|
||||
? 0
|
||||
: (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture)
|
||||
? 4
|
||||
: SurfaceParams::GetFormatBpp(format) / 8;
|
||||
}
|
||||
|
||||
std::vector<u8> gl_buffer;
|
||||
|
||||
// Read/Write data in 3DS memory to/from gl_buffer
|
||||
|
|
|
@ -12,10 +12,11 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
|
|||
SurfaceParams params = *this;
|
||||
const u32 tiled_size = is_tiled ? 8 : 1;
|
||||
const u32 stride_tiled_bytes = BytesInPixels(stride * tiled_size);
|
||||
|
||||
PAddr aligned_start =
|
||||
addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes);
|
||||
addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes);
|
||||
PAddr aligned_end =
|
||||
addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes);
|
||||
addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes);
|
||||
|
||||
if (aligned_end - aligned_start > stride_tiled_bytes) {
|
||||
params.addr = aligned_start;
|
||||
|
@ -24,17 +25,19 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
|
|||
// 1 row
|
||||
ASSERT(aligned_end - aligned_start == stride_tiled_bytes);
|
||||
const u32 tiled_alignment = BytesInPixels(is_tiled ? 8 * 8 : 1);
|
||||
|
||||
aligned_start =
|
||||
addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment);
|
||||
addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment);
|
||||
aligned_end =
|
||||
addr + Common::AlignUp(boost::icl::last_next(interval) - addr, tiled_alignment);
|
||||
addr + Common::AlignUp(boost::icl::last_next(interval) - addr, tiled_alignment);
|
||||
|
||||
params.addr = aligned_start;
|
||||
params.width = PixelsInBytes(aligned_end - aligned_start) / tiled_size;
|
||||
params.stride = params.width;
|
||||
params.height = tiled_size;
|
||||
}
|
||||
params.UpdateParams();
|
||||
|
||||
params.UpdateParams();
|
||||
return params;
|
||||
}
|
||||
|
||||
|
@ -158,6 +161,7 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const {
|
|||
end < texcopy_params.end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texcopy_params.width != texcopy_params.stride) {
|
||||
const u32 tile_stride = BytesInPixels(stride * (is_tiled ? 8 : 1));
|
||||
return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 &&
|
||||
|
@ -165,6 +169,7 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const {
|
|||
(texcopy_params.height == 1 || texcopy_params.stride == tile_stride) &&
|
||||
((texcopy_params.addr - addr) % tile_stride) + texcopy_params.width <= tile_stride;
|
||||
}
|
||||
|
||||
return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,8 @@
|
|||
#include <array>
|
||||
#include <climits>
|
||||
#include <boost/icl/interval.hpp>
|
||||
#include "common/assert.h"
|
||||
#include "common/math_util.h"
|
||||
#include "core/hw/gpu.h"
|
||||
#include "video_core/regs_framebuffer.h"
|
||||
#include "video_core/regs_texturing.h"
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
|
@ -21,180 +18,8 @@ using Surface = std::shared_ptr<CachedSurface>;
|
|||
using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
|
||||
|
||||
struct SurfaceParams {
|
||||
private:
|
||||
static constexpr std::array<unsigned int, 18> BPP_TABLE = {
|
||||
32, // RGBA8
|
||||
24, // RGB8
|
||||
16, // RGB5A1
|
||||
16, // RGB565
|
||||
16, // RGBA4
|
||||
16, // IA8
|
||||
16, // RG8
|
||||
8, // I8
|
||||
8, // A8
|
||||
8, // IA4
|
||||
4, // I4
|
||||
4, // A4
|
||||
4, // ETC1
|
||||
8, // ETC1A4
|
||||
16, // D16
|
||||
0,
|
||||
24, // D24
|
||||
32, // D24S8
|
||||
};
|
||||
|
||||
public:
|
||||
enum class PixelFormat {
|
||||
// First 5 formats are shared between textures and color buffers
|
||||
RGBA8 = 0,
|
||||
RGB8 = 1,
|
||||
RGB5A1 = 2,
|
||||
RGB565 = 3,
|
||||
RGBA4 = 4,
|
||||
|
||||
// Texture-only formats
|
||||
IA8 = 5,
|
||||
RG8 = 6,
|
||||
I8 = 7,
|
||||
A8 = 8,
|
||||
IA4 = 9,
|
||||
I4 = 10,
|
||||
A4 = 11,
|
||||
ETC1 = 12,
|
||||
ETC1A4 = 13,
|
||||
|
||||
// Depth buffer-only formats
|
||||
D16 = 14,
|
||||
// gap
|
||||
D24 = 16,
|
||||
D24S8 = 17,
|
||||
|
||||
Invalid = 255,
|
||||
};
|
||||
|
||||
enum class SurfaceType {
|
||||
Color = 0,
|
||||
Texture = 1,
|
||||
Depth = 2,
|
||||
DepthStencil = 3,
|
||||
Fill = 4,
|
||||
Invalid = 5
|
||||
};
|
||||
|
||||
static constexpr unsigned int GetFormatBpp(PixelFormat format) {
|
||||
const auto format_idx = static_cast<std::size_t>(format);
|
||||
DEBUG_ASSERT_MSG(format_idx < BPP_TABLE.size(), "Invalid pixel format {}", format_idx);
|
||||
return BPP_TABLE[format_idx];
|
||||
}
|
||||
|
||||
unsigned int GetFormatBpp() const {
|
||||
return GetFormatBpp(pixel_format);
|
||||
}
|
||||
|
||||
static std::string_view PixelFormatAsString(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::RGBA8:
|
||||
return "RGBA8";
|
||||
case PixelFormat::RGB8:
|
||||
return "RGB8";
|
||||
case PixelFormat::RGB5A1:
|
||||
return "RGB5A1";
|
||||
case PixelFormat::RGB565:
|
||||
return "RGB565";
|
||||
case PixelFormat::RGBA4:
|
||||
return "RGBA4";
|
||||
case PixelFormat::IA8:
|
||||
return "IA8";
|
||||
case PixelFormat::RG8:
|
||||
return "RG8";
|
||||
case PixelFormat::I8:
|
||||
return "I8";
|
||||
case PixelFormat::A8:
|
||||
return "A8";
|
||||
case PixelFormat::IA4:
|
||||
return "IA4";
|
||||
case PixelFormat::I4:
|
||||
return "I4";
|
||||
case PixelFormat::A4:
|
||||
return "A4";
|
||||
case PixelFormat::ETC1:
|
||||
return "ETC1";
|
||||
case PixelFormat::ETC1A4:
|
||||
return "ETC1A4";
|
||||
case PixelFormat::D16:
|
||||
return "D16";
|
||||
case PixelFormat::D24:
|
||||
return "D24";
|
||||
case PixelFormat::D24S8:
|
||||
return "D24S8";
|
||||
default:
|
||||
return "Not a real pixel format";
|
||||
}
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) {
|
||||
return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid;
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) {
|
||||
return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid;
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) {
|
||||
return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14)
|
||||
: PixelFormat::Invalid;
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) {
|
||||
switch (format) {
|
||||
// RGB565 and RGB5A1 are switched in PixelFormat compared to ColorFormat
|
||||
case GPU::Regs::PixelFormat::RGB565:
|
||||
return PixelFormat::RGB565;
|
||||
case GPU::Regs::PixelFormat::RGB5A1:
|
||||
return PixelFormat::RGB5A1;
|
||||
default:
|
||||
return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) {
|
||||
SurfaceType a_type = GetFormatType(pixel_format_a);
|
||||
SurfaceType b_type = GetFormatType(pixel_format_b);
|
||||
|
||||
if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) &&
|
||||
(b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a_type == SurfaceType::Depth && b_type == SurfaceType::Depth) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a_type == SurfaceType::DepthStencil && b_type == SurfaceType::DepthStencil) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) {
|
||||
if ((unsigned int)pixel_format < 5) {
|
||||
return SurfaceType::Color;
|
||||
}
|
||||
|
||||
if ((unsigned int)pixel_format < 14) {
|
||||
return SurfaceType::Texture;
|
||||
}
|
||||
|
||||
if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) {
|
||||
return SurfaceType::Depth;
|
||||
}
|
||||
|
||||
if (pixel_format == PixelFormat::D24S8) {
|
||||
return SurfaceType::DepthStencil;
|
||||
}
|
||||
|
||||
return SurfaceType::Invalid;
|
||||
return OpenGL::GetFormatBpp(pixel_format);
|
||||
}
|
||||
|
||||
/// Update the params "size", "end" and "type" from the already set "addr", "width", "height"
|
||||
|
@ -238,11 +63,11 @@ public:
|
|||
}
|
||||
|
||||
u32 PixelsInBytes(u32 size) const {
|
||||
return size * CHAR_BIT / GetFormatBpp(pixel_format);
|
||||
return size * 8 / GetFormatBpp();
|
||||
}
|
||||
|
||||
u32 BytesInPixels(u32 pixels) const {
|
||||
return pixels * GetFormatBpp(pixel_format) / CHAR_BIT;
|
||||
return pixels * GetFormatBpp() / 8;
|
||||
}
|
||||
|
||||
bool ExactMatch(const SurfaceParams& other_surface) const;
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
namespace OpenGL {
|
||||
|
||||
using PixelFormat = SurfaceParams::PixelFormat;
|
||||
|
||||
class RGBA4toRGB5A1 final : public FormatReinterpreterBase {
|
||||
public:
|
||||
RGBA4toRGB5A1() {
|
||||
|
|
|
@ -9,27 +9,27 @@
|
|||
#include <glad/glad.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/math_util.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/rasterizer_cache/surface_params.h"
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class RasterizerCacheOpenGL;
|
||||
|
||||
struct PixelFormatPair {
|
||||
const SurfaceParams::PixelFormat dst_format, src_format;
|
||||
const PixelFormat dst_format, src_format;
|
||||
|
||||
struct less {
|
||||
using is_transparent = void;
|
||||
constexpr bool operator()(OpenGL::PixelFormatPair lhs, OpenGL::PixelFormatPair rhs) const {
|
||||
constexpr bool operator()(PixelFormatPair lhs, PixelFormatPair rhs) const {
|
||||
return std::tie(lhs.dst_format, lhs.src_format) <
|
||||
std::tie(rhs.dst_format, rhs.src_format);
|
||||
}
|
||||
constexpr bool operator()(OpenGL::SurfaceParams::PixelFormat lhs,
|
||||
OpenGL::PixelFormatPair rhs) const {
|
||||
|
||||
constexpr bool operator()(PixelFormat lhs, PixelFormatPair rhs) const {
|
||||
return lhs < rhs.dst_format;
|
||||
}
|
||||
constexpr bool operator()(OpenGL::PixelFormatPair lhs,
|
||||
OpenGL::SurfaceParams::PixelFormat rhs) const {
|
||||
|
||||
constexpr bool operator()(PixelFormatPair lhs, PixelFormat rhs) const {
|
||||
return lhs.dst_format < rhs;
|
||||
}
|
||||
};
|
||||
|
@ -52,8 +52,8 @@ public:
|
|||
explicit FormatReinterpreterOpenGL();
|
||||
~FormatReinterpreterOpenGL();
|
||||
|
||||
std::pair<ReinterpreterMap::iterator, ReinterpreterMap::iterator> GetPossibleReinterpretations(
|
||||
SurfaceParams::PixelFormat dst_format);
|
||||
auto GetPossibleReinterpretations(PixelFormat dst_format) ->
|
||||
std::pair<ReinterpreterMap::iterator, ReinterpreterMap::iterator>;
|
||||
|
||||
private:
|
||||
ReinterpreterMap reinterpreters;
|
||||
|
|
|
@ -29,9 +29,6 @@
|
|||
|
||||
namespace OpenGL {
|
||||
|
||||
using PixelFormat = SurfaceParams::PixelFormat;
|
||||
using SurfaceType = SurfaceParams::SurfaceType;
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(255, 128, 0));
|
||||
MICROPROFILE_DEFINE(OpenGL_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(192, 128, 128));
|
||||
MICROPROFILE_DEFINE(OpenGL_GS, "OpenGL", "Geometry Shader Setup", MP_RGB(128, 192, 128));
|
||||
|
@ -1445,7 +1442,7 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
|
|||
src_params.stride = config.input_width;
|
||||
src_params.height = config.output_height;
|
||||
src_params.is_tiled = !config.input_linear;
|
||||
src_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.input_format);
|
||||
src_params.pixel_format = PixelFormatFromGPUPixelFormat(config.input_format);
|
||||
src_params.UpdateParams();
|
||||
|
||||
SurfaceParams dst_params;
|
||||
|
@ -1455,7 +1452,7 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
|
|||
dst_params.height = config.scaling == config.ScaleXY ? config.output_height.Value() / 2
|
||||
: config.output_height.Value();
|
||||
dst_params.is_tiled = config.input_linear != config.dont_swizzle;
|
||||
dst_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.output_format);
|
||||
dst_params.pixel_format = PixelFormatFromGPUPixelFormat(config.output_format);
|
||||
dst_params.UpdateParams();
|
||||
|
||||
Common::Rectangle<u32> src_rect;
|
||||
|
@ -1595,7 +1592,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
|
|||
src_params.height = config.height;
|
||||
src_params.stride = pixel_stride;
|
||||
src_params.is_tiled = false;
|
||||
src_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.color_format);
|
||||
src_params.pixel_format = PixelFormatFromGPUPixelFormat(config.color_format);
|
||||
src_params.UpdateParams();
|
||||
|
||||
Common::Rectangle<u32> src_rect;
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/math_util.h"
|
||||
#include "video_core/rasterizer_cache/surface_params.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
|
|
|
@ -60,12 +60,13 @@ bool TextureFilterer::IsNull() const {
|
|||
|
||||
bool TextureFilterer::Filter(GLuint src_tex, const Common::Rectangle<u32>& src_rect, GLuint dst_tex,
|
||||
const Common::Rectangle<u32>& dst_rect,
|
||||
SurfaceParams::SurfaceType type, GLuint read_fb_handle,
|
||||
SurfaceType type, GLuint read_fb_handle,
|
||||
GLuint draw_fb_handle) {
|
||||
// depth / stencil texture filtering is not supported for now
|
||||
if (IsNull() ||
|
||||
(type != SurfaceParams::SurfaceType::Color && type != SurfaceParams::SurfaceType::Texture))
|
||||
if (IsNull() || (type != SurfaceType::Color && type != SurfaceType::Texture)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
filter->Filter(src_tex, src_rect, dst_tex, dst_rect, read_fb_handle, draw_fb_handle);
|
||||
return true;
|
||||
}
|
||||
|
@ -85,4 +86,4 @@ std::vector<std::string_view> TextureFilterer::GetFilterNames() {
|
|||
return ret;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
} // namespace OpenGL
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/math_util.h"
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
#include "video_core/renderer_opengl/texture_filters/texture_filter_base.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
@ -25,7 +23,7 @@ public:
|
|||
bool IsNull() const;
|
||||
// returns true if the texture was able to be filtered
|
||||
bool Filter(GLuint src_tex, const Common::Rectangle<u32>& src_rect, GLuint dst_tex,
|
||||
const Common::Rectangle<u32>& dst_rect, SurfaceParams::SurfaceType type,
|
||||
const Common::Rectangle<u32>& dst_rect, SurfaceType type,
|
||||
GLuint read_fb_handle, GLuint draw_fb_handle);
|
||||
|
||||
static std::vector<std::string_view> GetFilterNames();
|
||||
|
|
Loading…
Reference in a new issue