video_core: Move pixel format functions to cpp file

This commit is contained in:
GPUCode
2022-12-21 23:02:22 +02:00
parent 618c80c803
commit 3ef5ab7323
11 changed files with 173 additions and 492 deletions

View File

@@ -29,6 +29,7 @@ add_library(video_core STATIC
renderer_base.cpp
renderer_base.h
rasterizer_cache/morton_swizzle.h
rasterizer_cache/pixel_format.cpp
rasterizer_cache/pixel_format.h
rasterizer_cache/rasterizer_cache.cpp
rasterizer_cache/rasterizer_cache.h
@@ -41,6 +42,8 @@ add_library(video_core STATIC
renderer_opengl/frame_dumper_opengl.h
renderer_opengl/gl_driver.cpp
renderer_opengl/gl_driver.h
renderer_opengl/gl_format_reinterpreter.cpp
renderer_opengl/gl_format_reinterpreter.h
renderer_opengl/gl_rasterizer.cpp
renderer_opengl/gl_rasterizer.h
renderer_opengl/gl_resource_manager.cpp
@@ -68,8 +71,6 @@ add_library(video_core STATIC
renderer_opengl/post_processing_opengl.h
renderer_opengl/renderer_opengl.cpp
renderer_opengl/renderer_opengl.h
renderer_opengl/texture_downloader_es.cpp
renderer_opengl/texture_downloader_es.h
renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.cpp
renderer_opengl/texture_filters/anime4k/anime4k_ultrafast.h
renderer_opengl/texture_filters/bicubic/bicubic.cpp
@@ -83,9 +84,6 @@ add_library(video_core STATIC
renderer_opengl/texture_filters/texture_filterer.h
renderer_opengl/texture_filters/xbrz/xbrz_freescale.cpp
renderer_opengl/texture_filters/xbrz/xbrz_freescale.h
#temporary, move these back in alphabetical order before merging
renderer_opengl/gl_format_reinterpreter.cpp
renderer_opengl/gl_format_reinterpreter.h
renderer_vulkan/pica_to_vk.h
renderer_vulkan/renderer_vulkan.cpp
renderer_vulkan/renderer_vulkan.h

View File

@@ -0,0 +1,98 @@
// Copyright 2022 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "video_core/rasterizer_cache/pixel_format.h"
namespace VideoCore {
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";
}
}
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;
}
PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) {
const u32 format_index = static_cast<u32>(format);
return (format_index < 14) ? static_cast<PixelFormat>(format) : PixelFormat::Invalid;
}
PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) {
const u32 format_index = static_cast<u32>(format);
return (format_index < 5) ? static_cast<PixelFormat>(format) : PixelFormat::Invalid;
}
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;
}
PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) {
const u32 format_index = static_cast<u32>(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 (format_index < 5) ? static_cast<PixelFormat>(format) : PixelFormat::Invalid;
}
}
} // namespace VideoCore

View File

@@ -11,16 +11,14 @@
namespace VideoCore {
constexpr u32 PIXEL_FORMAT_COUNT = 18;
constexpr std::size_t PIXEL_FORMAT_COUNT = 18;
enum class PixelFormat : u32 {
// 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,
@@ -30,159 +28,77 @@ enum class PixelFormat : u32 {
A4 = 11,
ETC1 = 12,
ETC1A4 = 13,
// Depth buffer-only formats
D16 = 14,
D24 = 16,
D24S8 = 17,
Max = 18,
Invalid = 255,
};
enum class SurfaceType {
enum class SurfaceType : u32 {
Color = 0,
Texture = 1,
Depth = 2,
DepthStencil = 3,
Fill = 4,
Invalid = 5
Invalid = 5,
};
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";
}
}
enum class TextureType : u32 {
Texture2D = 0,
CubeMap = 1,
};
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;
}
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;
}
constexpr 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;
}
constexpr PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format) {
const u32 format_index = static_cast<u32>(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 (format_index < 5) ? static_cast<PixelFormat>(format) : PixelFormat::Invalid;
}
}
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;
}
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;
}
constexpr std::array<u8, PIXEL_FORMAT_COUNT> BITS_PER_BLOCK_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
}};
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;
default:
return 1;
}
ASSERT(static_cast<std::size_t>(format) < BITS_PER_BLOCK_TABLE.size());
return BITS_PER_BLOCK_TABLE[static_cast<std::size_t>(format)];
}
constexpr std::array<SurfaceType, PIXEL_FORMAT_COUNT> FORMAT_TYPE_TABLE = {{
SurfaceType::Color, // RGBA8
SurfaceType::Color, // RGB8
SurfaceType::Color, // RGB5A1
SurfaceType::Color, // RGB565
SurfaceType::Color, // RGBA4
SurfaceType::Texture, // IA8
SurfaceType::Texture, // RG8
SurfaceType::Texture, // I8
SurfaceType::Texture, // A8
SurfaceType::Texture, // IA4
SurfaceType::Texture, // I4
SurfaceType::Texture, // A4
SurfaceType::Texture, // ETC1
SurfaceType::Texture, // ETC1A4
SurfaceType::Depth, // D16
SurfaceType::Invalid,
SurfaceType::Depth, // D24
SurfaceType::DepthStencil, // D24S8
}};
constexpr SurfaceType GetFormatType(PixelFormat format) {
ASSERT(static_cast<std::size_t>(format) < FORMAT_TYPE_TABLE.size());
return FORMAT_TYPE_TABLE[static_cast<std::size_t>(format)];
}
constexpr u32 GetBytesPerPixel(PixelFormat format) {
@@ -194,4 +110,16 @@ constexpr u32 GetBytesPerPixel(PixelFormat format) {
return GetFormatBpp(format) / 8;
}
std::string_view PixelFormatAsString(PixelFormat format);
bool CheckFormatsBlittable(PixelFormat source_format, PixelFormat dest_format);
PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format);
PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format);
PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format);
PixelFormat PixelFormatFromGPUPixelFormat(GPU::Regs::PixelFormat format);
} // namespace VideoCore

View File

@@ -15,8 +15,6 @@ namespace VideoCore {
using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
enum class TextureType { Texture2D = 0, CubeMap = 1 };
class SurfaceParams {
public:
/// Surface match traits

View File

@@ -1,10 +0,0 @@
//? #version 320 es
out highp uint color;
uniform highp sampler2D depth;
uniform int lod;
void main() {
color = uint(texelFetch(depth, ivec2(gl_FragCoord.xy), lod).x * (exp2(32.0) - 1.0));
}

View File

@@ -1,8 +0,0 @@
//? #version 320 es
const vec2 vertices[4] =
vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0));
void main() {
gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0);
}

View File

@@ -1,9 +0,0 @@
//? #version 320 es
#extension GL_ARM_shader_framebuffer_fetch_depth_stencil : enable
out highp uint color;
void main() {
color = uint(gl_LastFragDepthARM * (exp2(24.0) - 1.0)) << 8;
color |= uint(gl_LastFragStencilARM);
}

View File

@@ -59,7 +59,7 @@ constexpr u32 DOWNLOAD_BUFFER_SIZE = 32 * 1024 * 1024;
TextureRuntime::TextureRuntime(Driver& driver)
: driver{driver}, filterer{Settings::values.texture_filter_name.GetValue(),
VideoCore::GetResolutionScaleFactor()},
downloader_es{false}, upload_buffer{GL_PIXEL_UNPACK_BUFFER, UPLOAD_BUFFER_SIZE},
upload_buffer{GL_PIXEL_UNPACK_BUFFER, UPLOAD_BUFFER_SIZE},
download_buffer{GL_PIXEL_PACK_BUFFER, DOWNLOAD_BUFFER_SIZE, true} {
read_fbo.Create();
@@ -466,9 +466,9 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
const auto& tuple = runtime.GetFormatTuple(pixel_format);
if (driver.IsOpenGLES()) {
const auto& downloader_es = runtime.GetDownloaderES();
downloader_es.GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, rect_height,
rect_width, reinterpret_cast<void*>(staging.buffer_offset));
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, 0, GL_TEXTURE_2D, type, unscaled_surface.texture);
glReadPixels(0, 0, rect_width, rect_height, tuple.format, tuple.type,
reinterpret_cast<void*>(staging.buffer_offset));
} else {
glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type,
reinterpret_cast<void*>(staging.buffer_offset));

View File

@@ -9,7 +9,6 @@
#include "video_core/rasterizer_cache/surface_base.h"
#include "video_core/renderer_opengl/gl_format_reinterpreter.h"
#include "video_core/renderer_opengl/gl_stream_buffer.h"
#include "video_core/renderer_opengl/texture_downloader_es.h"
#include "video_core/renderer_opengl/texture_filters/texture_filterer.h"
namespace OpenGL {
@@ -87,11 +86,6 @@ private:
return driver;
}
/// Returns the class that handles texture downloads for OpenGL ES
const TextureDownloaderES& GetDownloaderES() const {
return downloader_es;
}
/// Returns the class that handles texture filtering
const TextureFilterer& GetFilterer() const {
return filterer;
@@ -100,7 +94,6 @@ private:
private:
Driver& driver;
TextureFilterer filterer;
TextureDownloaderES downloader_es;
std::array<ReinterpreterList, VideoCore::PIXEL_FORMAT_COUNT> reinterpreters;
std::unordered_multimap<VideoCore::HostTextureTag, OGLTexture> texture_recycler;
OGLStreamBuffer upload_buffer, download_buffer;

View File

@@ -1,250 +0,0 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <chrono>
#include <vector>
#include <fmt/chrono.h>
#include "common/logging/log.h"
#include "video_core/rasterizer_cache/utils.h"
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/gl_texture_runtime.h"
#include "video_core/renderer_opengl/texture_downloader_es.h"
#include "shaders/depth_to_color.frag"
#include "shaders/depth_to_color.vert"
#include "shaders/ds_to_color.frag"
namespace OpenGL {
static constexpr std::array DEPTH_TUPLES_HACK = {
FormatTuple{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
FormatTuple{}, FormatTuple{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24
FormatTuple{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8
};
const FormatTuple& GetFormatTuple(VideoCore::PixelFormat format) {
return DEPTH_TUPLES_HACK[static_cast<u32>(format)];
}
void TextureDownloaderES::Test() {
auto cur_state = OpenGLState::GetCurState();
OpenGLState state;
{
GLint range[2];
GLint precision;
#define PRECISION_TEST(type) \
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, type, range, &precision); \
LOG_INFO(Render_OpenGL, #type " range: [{}, {}], precision: {}", range[0], range[1], precision);
PRECISION_TEST(GL_LOW_INT);
PRECISION_TEST(GL_MEDIUM_INT);
PRECISION_TEST(GL_HIGH_INT);
PRECISION_TEST(GL_LOW_FLOAT);
PRECISION_TEST(GL_MEDIUM_FLOAT);
PRECISION_TEST(GL_HIGH_FLOAT);
#undef PRECISION_TEST
}
glActiveTexture(GL_TEXTURE0);
const auto test = [this, &state]<typename T>(FormatTuple tuple, std::vector<T> original_data,
std::size_t tex_size, auto data_generator) {
OGLTexture texture;
texture.Create();
state.texture_units[0].texture_2d = texture.handle;
state.Apply();
original_data.resize(tex_size * tex_size);
for (std::size_t idx = 0; idx < original_data.size(); ++idx) {
original_data[idx] = data_generator(idx);
}
GLsizei tex_sizei = static_cast<GLsizei>(tex_size);
glTexStorage2D(GL_TEXTURE_2D, 1, tuple.internal_format, tex_sizei, tex_sizei);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_sizei, tex_sizei, tuple.format, tuple.type,
original_data.data());
std::vector<T> new_data(original_data.size());
glFinish();
auto start = std::chrono::high_resolution_clock::now();
GetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, tex_sizei, tex_sizei,
new_data.data());
glFinish();
auto time = std::chrono::high_resolution_clock::now() - start;
LOG_INFO(Render_OpenGL, "test took {}", std::chrono::duration<double, std::milli>(time));
int diff = 0;
for (std::size_t idx = 0; idx < original_data.size(); ++idx)
if (new_data[idx] - original_data[idx] != diff) {
diff = new_data[idx] - original_data[idx];
// every time the error between the real and expected value changes, log it
// some error is expected in D24 due to floating point precision
LOG_WARNING(Render_OpenGL, "difference changed at {:#X}: {:#X} -> {:#X}", idx,
original_data[idx], new_data[idx]);
}
};
LOG_INFO(Render_OpenGL, "GL_DEPTH24_STENCIL8 download test starting");
test(GetFormatTuple(VideoCore::PixelFormat::D24S8), std::vector<u32>{}, 4096,
[](std::size_t idx) { return static_cast<u32>((idx << 8) | (idx & 0xFF)); });
LOG_INFO(Render_OpenGL, "GL_DEPTH_COMPONENT24 download test starting");
test(GetFormatTuple(VideoCore::PixelFormat::D24), std::vector<u32>{}, 4096,
[](std::size_t idx) { return static_cast<u32>(idx << 8); });
LOG_INFO(Render_OpenGL, "GL_DEPTH_COMPONENT16 download test starting");
test(GetFormatTuple(VideoCore::PixelFormat::D16), std::vector<u16>{}, 256,
[](std::size_t idx) { return static_cast<u16>(idx); });
cur_state.Apply();
}
TextureDownloaderES::TextureDownloaderES(bool enable_depth_stencil) {
vao.Create();
read_fbo_generic.Create();
depth32_fbo.Create();
r32ui_renderbuffer.Create();
depth16_fbo.Create();
r16_renderbuffer.Create();
const auto init_program = [](ConversionShader& converter, std::string_view frag) {
converter.program.Create(depth_to_color_vert.data(), frag.data());
converter.lod_location = glGetUniformLocation(converter.program.handle, "lod");
};
// xperia64: The depth stencil shader currently uses a GLES extension that is not supported
// across all devices Reportedly broken on Tegra devices and the Nexus 6P, so enabling it can be
// toggled
if (enable_depth_stencil) {
init_program(d24s8_r32ui_conversion_shader, ds_to_color_frag);
}
init_program(d24_r32ui_conversion_shader, depth_to_color_frag);
init_program(d16_r16_conversion_shader, R"(
out highp float color;
uniform highp sampler2D depth;
uniform int lod;
void main(){
color = texelFetch(depth, ivec2(gl_FragCoord.xy), lod).x;
}
)");
sampler.Create();
glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(sampler.handle, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
auto cur_state = OpenGLState::GetCurState();
auto state = cur_state;
state.draw.shader_program = d24s8_r32ui_conversion_shader.program.handle;
state.draw.draw_framebuffer = depth32_fbo.handle;
state.renderbuffer = r32ui_renderbuffer.handle;
state.Apply();
glRenderbufferStorage(GL_RENDERBUFFER, GL_R32UI, MAX_SIZE, MAX_SIZE);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
r32ui_renderbuffer.handle);
state.draw.draw_framebuffer = depth16_fbo.handle;
state.renderbuffer = r16_renderbuffer.handle;
state.Apply();
glRenderbufferStorage(GL_RENDERBUFFER, GL_R16, MAX_SIZE, MAX_SIZE);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
r16_renderbuffer.handle);
cur_state.Apply();
}
GLuint TextureDownloaderES::ConvertDepthToColor(GLuint level, GLenum& format, GLenum& type,
GLint height, GLint width) const {
ASSERT(width <= MAX_SIZE && height <= MAX_SIZE);
const OpenGLState cur_state = OpenGLState::GetCurState();
OpenGLState state;
state.texture_units[0] = {cur_state.texture_units[0].texture_2d, sampler.handle};
state.draw.vertex_array = vao.handle;
OGLTexture texture_view;
const ConversionShader* converter = nullptr;
switch (type) {
case GL_UNSIGNED_SHORT:
state.draw.draw_framebuffer = depth16_fbo.handle;
converter = &d16_r16_conversion_shader;
format = GL_RED;
break;
case GL_UNSIGNED_INT:
state.draw.draw_framebuffer = depth32_fbo.handle;
converter = &d24_r32ui_conversion_shader;
format = GL_RED_INTEGER;
break;
case GL_UNSIGNED_INT_24_8:
state.draw.draw_framebuffer = depth32_fbo.handle;
converter = &d24s8_r32ui_conversion_shader;
format = GL_RED_INTEGER;
type = GL_UNSIGNED_INT;
break;
default:
UNREACHABLE_MSG("Destination type not recognized");
}
state.draw.shader_program = converter->program.handle;
state.viewport = {0, 0, width, height};
state.Apply();
if (converter->program.handle == d24s8_r32ui_conversion_shader.program.handle) {
// TODO BreadFish64: the ARM framebuffer reading extension is probably not the most optimal
// way to do this, search for another solution
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
state.texture_units[0].texture_2d, level);
}
glUniform1i(converter->lod_location, level);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (texture_view.handle) {
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
}
return state.draw.draw_framebuffer;
}
void TextureDownloaderES::GetTexImage(GLenum target, GLuint level, GLenum format, GLenum type,
GLint height, GLint width, void* pixels) const {
OpenGLState state = OpenGLState::GetCurState();
GLuint texture{};
const GLuint old_read_buffer = state.draw.read_framebuffer;
switch (target) {
case GL_TEXTURE_2D:
texture = state.texture_units[0].texture_2d;
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
texture = state.texture_cube_unit.texture_cube;
break;
default:
UNIMPLEMENTED_MSG("Unexpected target {:x}", target);
}
switch (format) {
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL:
// unfortunately, the accurate way is too slow for release
return;
state.draw.read_framebuffer = ConvertDepthToColor(level, format, type, height, width);
state.Apply();
break;
default:
state.draw.read_framebuffer = read_fbo_generic.handle;
state.Apply();
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
level);
}
GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
LOG_DEBUG(Render_OpenGL, "Framebuffer is incomplete, status: {:X}", status);
}
glReadPixels(0, 0, width, height, format, type, pixels);
state.draw.read_framebuffer = old_read_buffer;
state.Apply();
}
} // namespace OpenGL

View File

@@ -1,57 +0,0 @@
// Copyright 2020 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
namespace OpenGL {
class OpenGLState;
class TextureDownloaderES {
static constexpr u16 MAX_SIZE = 1024;
public:
TextureDownloaderES(bool enable_depth_stencil);
/**
* OpenGL ES does not support glGetTexImage. Obtain the pixels by attaching the
* texture to a framebuffer.
* Originally from https://github.com/apitrace/apitrace/blob/master/retrace/glstate_images.cpp
* Depth texture download assumes that the texture's format tuple matches what is found
* OpenGL::depth_format_tuples
*/
void GetTexImage(GLenum target, GLuint level, GLenum format, const GLenum type, GLint height,
GLint width, void* pixels) const;
private:
/**
* OpenGL ES does not support glReadBuffer for depth/stencil formats.
* This gets around it by converting to a Red surface before downloading
*/
GLuint ConvertDepthToColor(GLuint level, GLenum& format, GLenum& type, GLint height,
GLint width) const;
/// Self tests for the texture downloader
void Test();
private:
struct ConversionShader {
OGLProgram program;
GLint lod_location{-1};
};
OGLVertexArray vao;
OGLFramebuffer read_fbo_generic;
OGLFramebuffer depth32_fbo, depth16_fbo;
OGLRenderbuffer r32ui_renderbuffer, r16_renderbuffer;
ConversionShader d24_r32ui_conversion_shader;
ConversionShader d16_r16_conversion_shader;
ConversionShader d24s8_r32ui_conversion_shader;
OGLSampler sampler;
};
} // namespace OpenGL