D24S8 to RGBA8 conversion

This commit is contained in:
Phantom 2018-01-16 03:06:35 +01:00 committed by James Rowe
parent db21154142
commit d813bc5eb5
2 changed files with 143 additions and 0 deletions

View File

@ -943,6 +943,52 @@ Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params
RasterizerCacheOpenGL::RasterizerCacheOpenGL() { RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
read_framebuffer.Create(); read_framebuffer.Create();
draw_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() { RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
@ -963,6 +1009,63 @@ bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface,
draw_framebuffer.handle); 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, Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
bool load_if_create) { bool load_if_create) {
if (params.addr == 0 || params.height * params.width == 0) { 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) { if (expandable != nullptr && expandable->res_scale > target_res_scale) {
target_res_scale = expandable->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; SurfaceParams new_params = params;
new_params.res_scale = target_res_scale; new_params.res_scale = target_res_scale;
@ -1305,6 +1417,27 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr,
continue; 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 // Load data from 3DS memory
FlushRegion(params.addr, params.size); FlushRegion(params.addr, params.size);
surface->LoadGLBuffer(params.addr, params.end); surface->LoadGLBuffer(params.addr, params.end);

View File

@ -305,6 +305,9 @@ public:
bool BlitSurfaces(const Surface& src_surface, const MathUtil::Rectangle<u32>& src_rect, bool BlitSurfaces(const Surface& src_surface, const MathUtil::Rectangle<u32>& src_rect,
const Surface& dst_surface, const MathUtil::Rectangle<u32>& dst_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 /// Copy one surface's region to another
void CopySurface(const Surface& src_surface, const Surface& dst_surface, void CopySurface(const Surface& src_surface, const Surface& dst_surface,
SurfaceInterval copy_interval); SurfaceInterval copy_interval);
@ -365,4 +368,11 @@ private:
OGLFramebuffer read_framebuffer; OGLFramebuffer read_framebuffer;
OGLFramebuffer draw_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;
}; };