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
|
@ -23,6 +23,8 @@ add_library(video_core STATIC
|
||||||
regs_texturing.h
|
regs_texturing.h
|
||||||
renderer_base.cpp
|
renderer_base.cpp
|
||||||
renderer_base.h
|
renderer_base.h
|
||||||
|
rasterizer_cache/morton_swizzle.h
|
||||||
|
rasterizer_cache/pixel_format.h
|
||||||
rasterizer_cache/rasterizer_cache.cpp
|
rasterizer_cache/rasterizer_cache.cpp
|
||||||
rasterizer_cache/rasterizer_cache.h
|
rasterizer_cache/rasterizer_cache.h
|
||||||
rasterizer_cache/surface_params.cpp
|
rasterizer_cache/surface_params.cpp
|
||||||
|
|
|
@ -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
|
|
@ -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/custom_tex_cache.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/memory.h"
|
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "video_core/pica_state.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/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/rasterizer_cache/rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_state.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_downloader_es.h"
|
||||||
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
|
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
|
||||||
#include "video_core/utils.h"
|
|
||||||
#include "video_core/video_core.h"
|
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
using SurfaceType = SurfaceParams::SurfaceType;
|
|
||||||
using PixelFormat = SurfaceParams::PixelFormat;
|
|
||||||
|
|
||||||
static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{
|
static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{
|
||||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}, // RGBA8
|
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}, // RGBA8
|
||||||
{GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE}, // RGB8
|
{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 FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
|
||||||
const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
|
const SurfaceType type = GetFormatType(pixel_format);
|
||||||
if (type == SurfaceType::Color) {
|
if (type == SurfaceType::Color) {
|
||||||
ASSERT(static_cast<std::size_t>(pixel_format) < fb_format_tuples.size());
|
ASSERT(static_cast<std::size_t>(pixel_format) < fb_format_tuples.size());
|
||||||
if (GLES) {
|
if (GLES) {
|
||||||
|
@ -87,162 +80,6 @@ static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
||||||
return boost::make_iterator_range(map.equal_range(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
|
// Allocate an uninitialized texture of appropriate size and format for the surface
|
||||||
OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& format_tuple, u32 width,
|
OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& format_tuple, u32 width,
|
||||||
u32 height) {
|
u32 height) {
|
||||||
|
@ -264,7 +101,7 @@ OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& form
|
||||||
|
|
||||||
if (GL_ARB_texture_storage) {
|
if (GL_ARB_texture_storage) {
|
||||||
// Allocate all possible mipmap levels upfront
|
// 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);
|
glTexStorage2D(GL_TEXTURE_2D, levels, format_tuple.internal_format, width, height);
|
||||||
} else {
|
} else {
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0,
|
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());
|
glActiveTexture(TextureUnits::TextureCube.Enum());
|
||||||
if (GL_ARB_texture_storage) {
|
if (GL_ARB_texture_storage) {
|
||||||
// Allocate all possible mipmap levels in case the game uses them later
|
// 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);
|
glTexStorage2D(GL_TEXTURE_CUBE_MAP, levels, format_tuple.internal_format, width, width);
|
||||||
} else {
|
} else {
|
||||||
for (auto faces : {
|
for (auto faces : {
|
||||||
|
@ -418,10 +255,10 @@ static bool FillSurface(const Surface& surface, const u8* fill_data,
|
||||||
u32 value_32bit = 0;
|
u32 value_32bit = 0;
|
||||||
GLfloat value_float;
|
GLfloat value_float;
|
||||||
|
|
||||||
if (surface->pixel_format == SurfaceParams::PixelFormat::D16) {
|
if (surface->pixel_format == PixelFormat::D16) {
|
||||||
std::memcpy(&value_32bit, fill_data, 2);
|
std::memcpy(&value_32bit, fill_data, 2);
|
||||||
value_float = value_32bit / 65535.0f; // 2^16 - 1
|
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);
|
std::memcpy(&value_32bit, fill_data, 3);
|
||||||
value_float = value_32bit / 16777215.0f; // 2^24 - 1
|
value_float = value_32bit / 16777215.0f; // 2^24 - 1
|
||||||
}
|
}
|
||||||
|
@ -545,7 +382,7 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gl_buffer.empty()) {
|
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
|
// 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)
|
if (dst_buffer == nullptr)
|
||||||
return;
|
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
|
// TODO: Should probably be done in ::Memory:: and check for other regions too
|
||||||
// same as loadglbuffer()
|
// same as loadglbuffer()
|
||||||
|
@ -771,7 +608,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(OpenGL_TextureUL);
|
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;
|
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
|
// Load data from memory to the surface
|
||||||
GLint x0 = static_cast<GLint>(rect.left);
|
GLint x0 = static_cast<GLint>(rect.left);
|
||||||
GLint y0 = static_cast<GLint>(rect.bottom);
|
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);
|
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
||||||
GLuint target_tex = texture.handle;
|
GLuint target_tex = texture.handle;
|
||||||
|
@ -814,7 +651,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_
|
||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
|
|
||||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
// 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 (is_custom) {
|
||||||
if (res_scale == 1) {
|
if (res_scale == 1) {
|
||||||
texture = owner.AllocateSurfaceTexture(GetFormatTuple(PixelFormat::RGBA8),
|
texture = owner.AllocateSurfaceTexture(GetFormatTuple(PixelFormat::RGBA8),
|
||||||
|
@ -873,7 +710,7 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint
|
||||||
MICROPROFILE_SCOPE(OpenGL_TextureDL);
|
MICROPROFILE_SCOPE(OpenGL_TextureDL);
|
||||||
|
|
||||||
if (gl_buffer.empty()) {
|
if (gl_buffer.empty()) {
|
||||||
gl_buffer.resize(width * height * GetGLBytesPerPixel(pixel_format));
|
gl_buffer.resize(width * height * GetBytesPerPixel(pixel_format));
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLState state = OpenGLState::GetCurState();
|
OpenGLState state = OpenGLState::GetCurState();
|
||||||
|
@ -883,10 +720,10 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint
|
||||||
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
const FormatTuple& tuple = GetFormatTuple(pixel_format);
|
||||||
|
|
||||||
// Ensure no bad interactions with GL_PACK_ALIGNMENT
|
// 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));
|
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(stride));
|
||||||
std::size_t buffer_offset =
|
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 not 1x scale, blit scaled texture to a new 1x texture and use that to flush
|
||||||
if (res_scale != 1) {
|
if (res_scale != 1) {
|
||||||
|
@ -1084,7 +921,7 @@ bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface,
|
||||||
const Common::Rectangle<u32>& dst_rect) {
|
const Common::Rectangle<u32>& dst_rect) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_BlitSurface);
|
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;
|
return false;
|
||||||
|
|
||||||
dst_surface->InvalidateAllWatcher();
|
dst_surface->InvalidateAllWatcher();
|
||||||
|
@ -1239,7 +1076,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInf
|
||||||
params.width = info.width;
|
params.width = info.width;
|
||||||
params.height = info.height;
|
params.height = info.height;
|
||||||
params.is_tiled = true;
|
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.res_scale = texture_filterer->IsNull() ? 1 : resolution_scale_factor;
|
||||||
params.UpdateParams();
|
params.UpdateParams();
|
||||||
|
|
||||||
|
@ -1411,7 +1248,7 @@ const CachedTextureCube& RasterizerCacheOpenGL::GetTextureCube(const TextureCube
|
||||||
cube.texture.Create();
|
cube.texture.Create();
|
||||||
AllocateTextureCube(
|
AllocateTextureCube(
|
||||||
cube.texture.handle,
|
cube.texture.handle,
|
||||||
GetFormatTuple(CachedSurface::PixelFormatFromTextureFormat(config.format)),
|
GetFormatTuple(PixelFormatFromTextureFormat(config.format)),
|
||||||
cube.res_scale * config.width);
|
cube.res_scale * config.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1459,7 +1296,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
||||||
const auto& config = regs.framebuffer.framebuffer;
|
const auto& config = regs.framebuffer.framebuffer;
|
||||||
|
|
||||||
// update resolution_scale_factor and reset cache if changed
|
// 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) &&
|
(VideoCore::g_texture_filter_update_requested.exchange(false) &&
|
||||||
texture_filterer->Reset(Settings::values.texture_filter_name, resolution_scale_factor))) {
|
texture_filterer->Reset(Settings::values.texture_filter_name, resolution_scale_factor))) {
|
||||||
resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
|
resolution_scale_factor = VideoCore::GetResolutionScaleFactor();
|
||||||
|
@ -1485,11 +1322,11 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
||||||
SurfaceParams depth_params = color_params;
|
SurfaceParams depth_params = color_params;
|
||||||
|
|
||||||
color_params.addr = config.GetColorBufferPhysicalAddress();
|
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();
|
color_params.UpdateParams();
|
||||||
|
|
||||||
depth_params.addr = config.GetDepthBufferPhysicalAddress();
|
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();
|
depth_params.UpdateParams();
|
||||||
|
|
||||||
auto color_vp_interval = color_params.GetSubRectInterval(viewport_clamped);
|
auto color_vp_interval = color_params.GetSubRectInterval(viewport_clamped);
|
||||||
|
@ -1693,7 +1530,7 @@ bool RasterizerCacheOpenGL::NoUnimplementedReinterpretations(const Surface& surf
|
||||||
};
|
};
|
||||||
bool implemented = true;
|
bool implemented = true;
|
||||||
for (PixelFormat format : all_formats) {
|
for (PixelFormat format : all_formats) {
|
||||||
if (SurfaceParams::GetFormatBpp(format) == surface->GetFormatBpp()) {
|
if (GetFormatBpp(format) == surface->GetFormatBpp()) {
|
||||||
params.pixel_format = format;
|
params.pixel_format = format;
|
||||||
// This could potentially be expensive,
|
// This could potentially be expensive,
|
||||||
// although experimentally it hasn't been too bad
|
// 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);
|
FindMatch<MatchFlags::Copy>(surface_cache, params, ScaleMatch::Ignore, interval);
|
||||||
if (test_surface != nullptr) {
|
if (test_surface != nullptr) {
|
||||||
LOG_WARNING(Render_OpenGL, "Missing pixel_format reinterpreter: {} -> {}",
|
LOG_WARNING(Render_OpenGL, "Missing pixel_format reinterpreter: {} -> {}",
|
||||||
SurfaceParams::PixelFormatAsString(format),
|
PixelFormatAsString(format),
|
||||||
SurfaceParams::PixelFormatAsString(surface->pixel_format));
|
PixelFormatAsString(surface->pixel_format));
|
||||||
implemented = false;
|
implemented = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1751,9 +1588,8 @@ bool RasterizerCacheOpenGL::ValidateByReinterpretation(const Surface& surface,
|
||||||
reinterpreter->second->Reinterpret(reinterpret_surface->texture.handle, src_rect,
|
reinterpreter->second->Reinterpret(reinterpret_surface->texture.handle, src_rect,
|
||||||
read_framebuffer.handle, tmp_tex.handle,
|
read_framebuffer.handle, tmp_tex.handle,
|
||||||
tmp_rect, draw_framebuffer.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,
|
if (!texture_filterer->Filter(tmp_tex.handle, tmp_rect, surface->texture.handle,
|
||||||
dest_rect, type, read_framebuffer.handle,
|
dest_rect, type, read_framebuffer.handle,
|
||||||
draw_framebuffer.handle)) {
|
draw_framebuffer.handle)) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct FormatTuple {
|
||||||
|
|
||||||
constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
|
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 {
|
struct HostTextureTag {
|
||||||
FormatTuple format_tuple;
|
FormatTuple format_tuple;
|
||||||
|
@ -205,15 +205,6 @@ struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface
|
||||||
bool is_custom = false;
|
bool is_custom = false;
|
||||||
Core::CustomTexInfo custom_tex_info;
|
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;
|
std::vector<u8> gl_buffer;
|
||||||
|
|
||||||
// Read/Write data in 3DS memory to/from 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;
|
SurfaceParams params = *this;
|
||||||
const u32 tiled_size = is_tiled ? 8 : 1;
|
const u32 tiled_size = is_tiled ? 8 : 1;
|
||||||
const u32 stride_tiled_bytes = BytesInPixels(stride * tiled_size);
|
const u32 stride_tiled_bytes = BytesInPixels(stride * tiled_size);
|
||||||
|
|
||||||
PAddr aligned_start =
|
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 =
|
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) {
|
if (aligned_end - aligned_start > stride_tiled_bytes) {
|
||||||
params.addr = aligned_start;
|
params.addr = aligned_start;
|
||||||
|
@ -24,17 +25,19 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
|
||||||
// 1 row
|
// 1 row
|
||||||
ASSERT(aligned_end - aligned_start == stride_tiled_bytes);
|
ASSERT(aligned_end - aligned_start == stride_tiled_bytes);
|
||||||
const u32 tiled_alignment = BytesInPixels(is_tiled ? 8 * 8 : 1);
|
const u32 tiled_alignment = BytesInPixels(is_tiled ? 8 * 8 : 1);
|
||||||
|
|
||||||
aligned_start =
|
aligned_start =
|
||||||
addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment);
|
addr + Common::AlignDown(boost::icl::first(interval) - addr, tiled_alignment);
|
||||||
aligned_end =
|
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.addr = aligned_start;
|
||||||
params.width = PixelsInBytes(aligned_end - aligned_start) / tiled_size;
|
params.width = PixelsInBytes(aligned_end - aligned_start) / tiled_size;
|
||||||
params.stride = params.width;
|
params.stride = params.width;
|
||||||
params.height = tiled_size;
|
params.height = tiled_size;
|
||||||
}
|
}
|
||||||
params.UpdateParams();
|
|
||||||
|
|
||||||
|
params.UpdateParams();
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +161,7 @@ bool SurfaceParams::CanTexCopy(const SurfaceParams& texcopy_params) const {
|
||||||
end < texcopy_params.end) {
|
end < texcopy_params.end) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texcopy_params.width != texcopy_params.stride) {
|
if (texcopy_params.width != texcopy_params.stride) {
|
||||||
const u32 tile_stride = BytesInPixels(stride * (is_tiled ? 8 : 1));
|
const u32 tile_stride = BytesInPixels(stride * (is_tiled ? 8 : 1));
|
||||||
return (texcopy_params.addr - addr) % BytesInPixels(is_tiled ? 64 : 1) == 0 &&
|
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.height == 1 || texcopy_params.stride == tile_stride) &&
|
||||||
((texcopy_params.addr - addr) % tile_stride) + texcopy_params.width <= tile_stride;
|
((texcopy_params.addr - addr) % tile_stride) + texcopy_params.width <= tile_stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval();
|
return FromInterval(texcopy_params.GetInterval()).GetInterval() == texcopy_params.GetInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,8 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <boost/icl/interval.hpp>
|
#include <boost/icl/interval.hpp>
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "core/hw/gpu.h"
|
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||||
#include "video_core/regs_framebuffer.h"
|
|
||||||
#include "video_core/regs_texturing.h"
|
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
|
@ -21,180 +18,8 @@ using Surface = std::shared_ptr<CachedSurface>;
|
||||||
using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
|
using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
|
||||||
|
|
||||||
struct SurfaceParams {
|
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 {
|
unsigned int GetFormatBpp() const {
|
||||||
return GetFormatBpp(pixel_format);
|
return OpenGL::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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the params "size", "end" and "type" from the already set "addr", "width", "height"
|
/// Update the params "size", "end" and "type" from the already set "addr", "width", "height"
|
||||||
|
@ -238,11 +63,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 PixelsInBytes(u32 size) const {
|
u32 PixelsInBytes(u32 size) const {
|
||||||
return size * CHAR_BIT / GetFormatBpp(pixel_format);
|
return size * 8 / GetFormatBpp();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 BytesInPixels(u32 pixels) const {
|
u32 BytesInPixels(u32 pixels) const {
|
||||||
return pixels * GetFormatBpp(pixel_format) / CHAR_BIT;
|
return pixels * GetFormatBpp() / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExactMatch(const SurfaceParams& other_surface) const;
|
bool ExactMatch(const SurfaceParams& other_surface) const;
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
using PixelFormat = SurfaceParams::PixelFormat;
|
|
||||||
|
|
||||||
class RGBA4toRGB5A1 final : public FormatReinterpreterBase {
|
class RGBA4toRGB5A1 final : public FormatReinterpreterBase {
|
||||||
public:
|
public:
|
||||||
RGBA4toRGB5A1() {
|
RGBA4toRGB5A1() {
|
||||||
|
|
|
@ -9,27 +9,27 @@
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||||
#include "video_core/rasterizer_cache/surface_params.h"
|
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
class RasterizerCacheOpenGL;
|
class RasterizerCacheOpenGL;
|
||||||
|
|
||||||
struct PixelFormatPair {
|
struct PixelFormatPair {
|
||||||
const SurfaceParams::PixelFormat dst_format, src_format;
|
const PixelFormat dst_format, src_format;
|
||||||
|
|
||||||
struct less {
|
struct less {
|
||||||
using is_transparent = void;
|
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) <
|
return std::tie(lhs.dst_format, lhs.src_format) <
|
||||||
std::tie(rhs.dst_format, rhs.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;
|
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;
|
return lhs.dst_format < rhs;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -52,8 +52,8 @@ public:
|
||||||
explicit FormatReinterpreterOpenGL();
|
explicit FormatReinterpreterOpenGL();
|
||||||
~FormatReinterpreterOpenGL();
|
~FormatReinterpreterOpenGL();
|
||||||
|
|
||||||
std::pair<ReinterpreterMap::iterator, ReinterpreterMap::iterator> GetPossibleReinterpretations(
|
auto GetPossibleReinterpretations(PixelFormat dst_format) ->
|
||||||
SurfaceParams::PixelFormat dst_format);
|
std::pair<ReinterpreterMap::iterator, ReinterpreterMap::iterator>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReinterpreterMap reinterpreters;
|
ReinterpreterMap reinterpreters;
|
||||||
|
|
|
@ -29,9 +29,6 @@
|
||||||
|
|
||||||
namespace OpenGL {
|
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_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_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(192, 128, 128));
|
||||||
MICROPROFILE_DEFINE(OpenGL_GS, "OpenGL", "Geometry Shader Setup", MP_RGB(128, 192, 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.stride = config.input_width;
|
||||||
src_params.height = config.output_height;
|
src_params.height = config.output_height;
|
||||||
src_params.is_tiled = !config.input_linear;
|
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();
|
src_params.UpdateParams();
|
||||||
|
|
||||||
SurfaceParams dst_params;
|
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
|
dst_params.height = config.scaling == config.ScaleXY ? config.output_height.Value() / 2
|
||||||
: config.output_height.Value();
|
: config.output_height.Value();
|
||||||
dst_params.is_tiled = config.input_linear != config.dont_swizzle;
|
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();
|
dst_params.UpdateParams();
|
||||||
|
|
||||||
Common::Rectangle<u32> src_rect;
|
Common::Rectangle<u32> src_rect;
|
||||||
|
@ -1595,7 +1592,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
|
||||||
src_params.height = config.height;
|
src_params.height = config.height;
|
||||||
src_params.stride = pixel_stride;
|
src_params.stride = pixel_stride;
|
||||||
src_params.is_tiled = false;
|
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();
|
src_params.UpdateParams();
|
||||||
|
|
||||||
Common::Rectangle<u32> src_rect;
|
Common::Rectangle<u32> src_rect;
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "video_core/rasterizer_cache/surface_params.h"
|
|
||||||
|
|
||||||
namespace OpenGL {
|
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,
|
bool TextureFilterer::Filter(GLuint src_tex, const Common::Rectangle<u32>& src_rect, GLuint dst_tex,
|
||||||
const Common::Rectangle<u32>& dst_rect,
|
const Common::Rectangle<u32>& dst_rect,
|
||||||
SurfaceParams::SurfaceType type, GLuint read_fb_handle,
|
SurfaceType type, GLuint read_fb_handle,
|
||||||
GLuint draw_fb_handle) {
|
GLuint draw_fb_handle) {
|
||||||
// depth / stencil texture filtering is not supported for now
|
// depth / stencil texture filtering is not supported for now
|
||||||
if (IsNull() ||
|
if (IsNull() || (type != SurfaceType::Color && type != SurfaceType::Texture)) {
|
||||||
(type != SurfaceParams::SurfaceType::Color && type != SurfaceParams::SurfaceType::Texture))
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
filter->Filter(src_tex, src_rect, dst_tex, dst_rect, read_fb_handle, draw_fb_handle);
|
filter->Filter(src_tex, src_rect, dst_tex, dst_rect, read_fb_handle, draw_fb_handle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -85,4 +86,4 @@ std::vector<std::string_view> TextureFilterer::GetFilterNames() {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <glad/glad.h>
|
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/math_util.h"
|
|
||||||
#include "video_core/renderer_opengl/texture_filters/texture_filter_base.h"
|
#include "video_core/renderer_opengl/texture_filters/texture_filter_base.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
@ -25,7 +23,7 @@ public:
|
||||||
bool IsNull() const;
|
bool IsNull() const;
|
||||||
// returns true if the texture was able to be filtered
|
// returns true if the texture was able to be filtered
|
||||||
bool Filter(GLuint src_tex, const Common::Rectangle<u32>& src_rect, GLuint dst_tex,
|
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);
|
GLuint read_fb_handle, GLuint draw_fb_handle);
|
||||||
|
|
||||||
static std::vector<std::string_view> GetFilterNames();
|
static std::vector<std::string_view> GetFilterNames();
|
||||||
|
|
Reference in New Issue