mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-15 09:30:06 +00:00
D24S8 to RGBA8 conversion
This commit is contained in:
parent
db21154142
commit
d813bc5eb5
@ -943,6 +943,52 @@ Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params
|
||||
RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
|
||||
read_framebuffer.Create();
|
||||
draw_framebuffer.Create();
|
||||
|
||||
attributeless_vao.Create();
|
||||
|
||||
d24s8_abgr_buffer.Create();
|
||||
d24s8_abgr_buffer_size = 0;
|
||||
|
||||
const char* vs_source = R"(
|
||||
#version 330 core
|
||||
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);
|
||||
}
|
||||
)";
|
||||
const char* fs_source = R"(
|
||||
#version 330 core
|
||||
|
||||
uniform samplerBuffer tbo;
|
||||
uniform vec2 tbo_size;
|
||||
uniform vec4 viewport;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
vec2 tbo_coord = (gl_FragCoord.xy - viewport.xy) * tbo_size / viewport.zw;
|
||||
int tbo_offset = int(tbo_coord.y) * int(tbo_size.x) + int(tbo_coord.x);
|
||||
color = texelFetch(tbo, tbo_offset).rabg;
|
||||
}
|
||||
)";
|
||||
d24s8_abgr_shader.Create(vs_source, fs_source);
|
||||
|
||||
OpenGLState state = OpenGLState::GetCurState();
|
||||
GLuint old_program = state.draw.shader_program;
|
||||
state.draw.shader_program = d24s8_abgr_shader.handle;
|
||||
state.Apply();
|
||||
|
||||
GLint tbo_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "tbo");
|
||||
ASSERT(tbo_u_id != -1);
|
||||
glUniform1i(tbo_u_id, 0);
|
||||
|
||||
state.draw.shader_program = old_program;
|
||||
state.Apply();
|
||||
|
||||
d24s8_abgr_tbo_size_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "tbo_size");
|
||||
ASSERT(d24s8_abgr_tbo_size_u_id != -1);
|
||||
d24s8_abgr_viewport_u_id = glGetUniformLocation(d24s8_abgr_shader.handle, "viewport");
|
||||
ASSERT(d24s8_abgr_viewport_u_id != -1);
|
||||
}
|
||||
|
||||
RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
|
||||
@ -963,6 +1009,63 @@ bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface,
|
||||
draw_framebuffer.handle);
|
||||
}
|
||||
|
||||
void RasterizerCacheOpenGL::ConvertD24S8toABGR(GLuint src_tex,
|
||||
const MathUtil::Rectangle<u32>& src_rect,
|
||||
GLuint dst_tex,
|
||||
const MathUtil::Rectangle<u32>& dst_rect) {
|
||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
SCOPE_EXIT({ prev_state.Apply(); });
|
||||
|
||||
OpenGLState state;
|
||||
state.draw.read_framebuffer = read_framebuffer.handle;
|
||||
state.draw.draw_framebuffer = draw_framebuffer.handle;
|
||||
state.Apply();
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, d24s8_abgr_buffer.handle);
|
||||
|
||||
GLsizeiptr target_pbo_size = src_rect.GetWidth() * src_rect.GetHeight() * 4;
|
||||
if (target_pbo_size > d24s8_abgr_buffer_size) {
|
||||
d24s8_abgr_buffer_size = target_pbo_size * 2;
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, d24s8_abgr_buffer_size, nullptr, GL_STREAM_COPY);
|
||||
}
|
||||
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, src_tex,
|
||||
0);
|
||||
glReadPixels(static_cast<GLint>(src_rect.left), static_cast<GLint>(src_rect.bottom),
|
||||
static_cast<GLsizei>(src_rect.GetWidth()),
|
||||
static_cast<GLsizei>(src_rect.GetHeight()), GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8,
|
||||
0);
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
|
||||
// PBO now contains src_tex in RABG format
|
||||
state.draw.shader_program = d24s8_abgr_shader.handle;
|
||||
state.draw.vertex_array = attributeless_vao.handle;
|
||||
state.viewport.x = static_cast<GLint>(dst_rect.left);
|
||||
state.viewport.y = static_cast<GLint>(dst_rect.bottom);
|
||||
state.viewport.width = static_cast<GLsizei>(dst_rect.GetWidth());
|
||||
state.viewport.height = static_cast<GLsizei>(dst_rect.GetHeight());
|
||||
state.Apply();
|
||||
|
||||
OGLTexture tbo;
|
||||
tbo.Create();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, tbo.handle);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA8, d24s8_abgr_buffer.handle);
|
||||
|
||||
glUniform2f(d24s8_abgr_tbo_size_u_id, static_cast<GLfloat>(src_rect.GetWidth()),
|
||||
static_cast<GLfloat>(src_rect.GetHeight()));
|
||||
glUniform4f(d24s8_abgr_viewport_u_id, static_cast<GLfloat>(state.viewport.x),
|
||||
static_cast<GLfloat>(state.viewport.y), static_cast<GLfloat>(state.viewport.width),
|
||||
static_cast<GLfloat>(state.viewport.height));
|
||||
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex, 0);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
}
|
||||
|
||||
Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
|
||||
bool load_if_create) {
|
||||
if (params.addr == 0 || params.height * params.width == 0) {
|
||||
@ -988,6 +1091,15 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatc
|
||||
if (expandable != nullptr && expandable->res_scale > target_res_scale) {
|
||||
target_res_scale = expandable->res_scale;
|
||||
}
|
||||
// Keep res_scale when reinterpreting d24s8 -> rgba8
|
||||
if (params.pixel_format == PixelFormat::RGBA8) {
|
||||
find_params.pixel_format = PixelFormat::D24S8;
|
||||
expandable = FindMatch<MatchFlags::Expand | MatchFlags::Invalid>(
|
||||
surface_cache, find_params, match_res_scale);
|
||||
if (expandable != nullptr && expandable->res_scale > target_res_scale) {
|
||||
target_res_scale = expandable->res_scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
SurfaceParams new_params = params;
|
||||
new_params.res_scale = target_res_scale;
|
||||
@ -1305,6 +1417,27 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr,
|
||||
continue;
|
||||
}
|
||||
|
||||
// D24S8 to RGBA8
|
||||
if (surface->pixel_format == PixelFormat::RGBA8) {
|
||||
params.pixel_format = PixelFormat::D24S8;
|
||||
Surface reinterpret_surface =
|
||||
FindMatch<MatchFlags::Copy>(surface_cache, params, ScaleMatch::Ignore, interval);
|
||||
if (reinterpret_surface != nullptr) {
|
||||
ASSERT(reinterpret_surface->pixel_format == PixelFormat::D24S8);
|
||||
|
||||
SurfaceInterval convert_interval = params.GetCopyableInterval(reinterpret_surface);
|
||||
SurfaceParams convert_params = surface->FromInterval(convert_interval);
|
||||
auto src_rect = reinterpret_surface->GetScaledSubRect(convert_params);
|
||||
auto dest_rect = surface->GetScaledSubRect(convert_params);
|
||||
|
||||
ConvertD24S8toABGR(reinterpret_surface->texture.handle, src_rect,
|
||||
surface->texture.handle, dest_rect);
|
||||
|
||||
surface->invalid_regions.erase(convert_interval);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Load data from 3DS memory
|
||||
FlushRegion(params.addr, params.size);
|
||||
surface->LoadGLBuffer(params.addr, params.end);
|
||||
|
@ -305,6 +305,9 @@ public:
|
||||
bool BlitSurfaces(const Surface& src_surface, const MathUtil::Rectangle<u32>& src_rect,
|
||||
const Surface& dst_surface, const MathUtil::Rectangle<u32>& dst_rect);
|
||||
|
||||
void ConvertD24S8toABGR(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect,
|
||||
GLuint dst_tex, const MathUtil::Rectangle<u32>& dst_rect);
|
||||
|
||||
/// Copy one surface's region to another
|
||||
void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
SurfaceInterval copy_interval);
|
||||
@ -365,4 +368,11 @@ private:
|
||||
|
||||
OGLFramebuffer read_framebuffer;
|
||||
OGLFramebuffer draw_framebuffer;
|
||||
|
||||
OGLVertexArray attributeless_vao;
|
||||
OGLBuffer d24s8_abgr_buffer;
|
||||
GLsizeiptr d24s8_abgr_buffer_size;
|
||||
OGLShader d24s8_abgr_shader;
|
||||
GLint d24s8_abgr_tbo_size_u_id;
|
||||
GLint d24s8_abgr_viewport_u_id;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user