diff --git a/src/xenia/gpu/gl4/blitter.cc b/src/xenia/gpu/gl4/blitter.cc index 74f6d032a..e528c8952 100644 --- a/src/xenia/gpu/gl4/blitter.cc +++ b/src/xenia/gpu/gl4/blitter.cc @@ -23,12 +23,15 @@ extern "C" WGLEWContext* wglewGetContext(); Blitter::Blitter() : vertex_program_(0), - fragment_program_(0), - pipeline_(0), + color_fragment_program_(0), + depth_fragment_program_(0), + color_pipeline_(0), + depth_pipeline_(0), vbo_(0), vao_(0), nearest_sampler_(0), - linear_sampler_(0) {} + linear_sampler_(0), + scratch_framebuffer_(0) {} Blitter::~Blitter() = default; @@ -43,7 +46,7 @@ precision highp int; \n\ layout(std140, column_major) uniform; \n\ layout(std430, column_major) buffer; \n\ struct VertexData { \n\ -vec2 uv; \n\ + vec2 uv; \n\ }; \n\ "; const std::string vs_source = header + @@ -55,37 +58,51 @@ out gl_PerVertex { \n\ float gl_ClipDistance[]; \n\ }; \n\ struct VertexFetch { \n\ -vec2 pos; \n\ + vec2 pos; \n\ };\n\ layout(location = 0) in VertexFetch vfetch; \n\ layout(location = 0) out VertexData vtx; \n\ void main() { \n\ - gl_Position = vec4(vfetch.pos.xy * vec2(2.0, 2.0) - vec2(1.0, 1.0), 0.0, 1.0); \n\ + gl_Position = vec4(vfetch.pos.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0), 0.0, 1.0); \n\ vtx.uv = vfetch.pos.xy * src_uv_params.zw + src_uv_params.xy; \n\ } \n\ "; - const std::string fs_source = header + - "\n\ + const std::string color_fs_source = header + + "\n\ layout(location = 1) uniform sampler2D src_texture; \n\ layout(location = 0) in VertexData vtx; \n\ layout(location = 0) out vec4 oC; \n\ void main() { \n\ -vec4 color = texture(src_texture, vtx.uv); \n\ -oC = color; \n\ + oC = texture(src_texture, vtx.uv); \n\ +} \n\ +"; + const std::string depth_fs_source = header + + "\n\ +layout(location = 1) uniform sampler2D src_texture; \n\ +layout(location = 0) in VertexData vtx; \n\ +layout(location = 0) out vec4 oC; \n\ +void main() { \n\ + vec4 c = texture(src_texture, vtx.uv); \n\ + gl_FragDepth = c.r; \n\ } \n\ "; auto vs_source_str = vs_source.c_str(); vertex_program_ = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vs_source_str); - auto fs_source_str = fs_source.c_str(); - fragment_program_ = - glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fs_source_str); - char log[2048]; - GLsizei log_length; - glGetProgramInfoLog(vertex_program_, 2048, &log_length, log); - glCreateProgramPipelines(1, &pipeline_); - glUseProgramStages(pipeline_, GL_VERTEX_SHADER_BIT, vertex_program_); - glUseProgramStages(pipeline_, GL_FRAGMENT_SHADER_BIT, fragment_program_); + auto color_fs_source_str = color_fs_source.c_str(); + color_fragment_program_ = + glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &color_fs_source_str); + auto depth_fs_source_str = depth_fs_source.c_str(); + depth_fragment_program_ = + glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &depth_fs_source_str); + glCreateProgramPipelines(1, &color_pipeline_); + glUseProgramStages(color_pipeline_, GL_VERTEX_SHADER_BIT, vertex_program_); + glUseProgramStages(color_pipeline_, GL_FRAGMENT_SHADER_BIT, + color_fragment_program_); + glCreateProgramPipelines(1, &depth_pipeline_); + glUseProgramStages(depth_pipeline_, GL_VERTEX_SHADER_BIT, vertex_program_); + glUseProgramStages(depth_pipeline_, GL_FRAGMENT_SHADER_BIT, + depth_fragment_program_); glCreateBuffers(1, &vbo_); static const GLfloat vbo_data[] = { @@ -110,38 +127,96 @@ oC = color; \n\ glSamplerParameteri(linear_sampler_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glSamplerParameteri(linear_sampler_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glCreateFramebuffers(1, &scratch_framebuffer_); + return true; } void Blitter::Shutdown() { - if (vertex_program_) { - glDeleteProgram(vertex_program_); - } - if (fragment_program_) { - glDeleteProgram(fragment_program_); - } - if (pipeline_) { - glDeleteProgramPipelines(1, &pipeline_); - } - if (vbo_) { - glDeleteBuffers(1, &vbo_); - } - if (vao_) { - glDeleteVertexArrays(1, &vao_); - } - if (nearest_sampler_) { - glDeleteSamplers(1, &nearest_sampler_); - } - if (linear_sampler_) { - glDeleteSamplers(1, &linear_sampler_); - } + glDeleteFramebuffers(1, &scratch_framebuffer_); + glDeleteProgram(vertex_program_); + glDeleteProgram(color_fragment_program_); + glDeleteProgram(depth_fragment_program_); + glDeleteProgramPipelines(1, &color_pipeline_); + glDeleteProgramPipelines(1, &depth_pipeline_); + glDeleteBuffers(1, &vbo_); + glDeleteVertexArrays(1, &vao_); + glDeleteSamplers(1, &nearest_sampler_); + glDeleteSamplers(1, &linear_sampler_); } +struct SavedState { + GLboolean scissor_test_enabled; + GLboolean depth_test_enabled; + GLboolean depth_mask_enabled; + GLint depth_func; + GLboolean stencil_test_enabled; + GLboolean cull_face_enabled; + GLint cull_face; + GLint front_face; + GLint polygon_mode; + GLboolean color_mask_0_enabled[4]; + GLboolean blend_0_enabled; + GLint draw_buffer; + GLfloat viewport[4]; + GLint program_pipeline; + GLint vertex_array; + GLint texture_0; + GLint sampler_0; + + void Save() { + scissor_test_enabled = glIsEnabled(GL_SCISSOR_TEST); + depth_test_enabled = glIsEnabled(GL_DEPTH_TEST); + glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask_enabled); + glGetIntegerv(GL_DEPTH_FUNC, &depth_func); + stencil_test_enabled = glIsEnabled(GL_STENCIL_TEST); + cull_face_enabled = glIsEnabled(GL_CULL_FACE); + glGetIntegerv(GL_CULL_FACE_MODE, &cull_face); + glGetIntegerv(GL_FRONT_FACE, &front_face); + glGetIntegerv(GL_POLYGON_MODE, &polygon_mode); + glGetBooleani_v(GL_COLOR_WRITEMASK, 0, (GLboolean*)&color_mask_0_enabled); + blend_0_enabled = glIsEnabledi(GL_BLEND, 0); + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_buffer); + glGetFloati_v(GL_VIEWPORT, 0, viewport); + glGetIntegerv(GL_PROGRAM_PIPELINE_BINDING, &program_pipeline); + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vertex_array); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture_0); + glGetIntegeri_v(GL_SAMPLER_BINDING, 0, &sampler_0); + } + + void Restore() { + scissor_test_enabled ? glEnable(GL_SCISSOR_TEST) + : glDisable(GL_SCISSOR_TEST); + depth_test_enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST); + glDepthMask(depth_mask_enabled); + glDepthFunc(depth_func); + stencil_test_enabled ? glEnable(GL_STENCIL_TEST) + : glDisable(GL_STENCIL_TEST); + cull_face_enabled ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE); + glCullFace(cull_face); + glFrontFace(front_face); + glPolygonMode(GL_FRONT_AND_BACK, polygon_mode); + glColorMaski(0, color_mask_0_enabled[0], color_mask_0_enabled[1], + color_mask_0_enabled[2], color_mask_0_enabled[3]); + blend_0_enabled ? glEnablei(GL_BLEND, 0) : glDisablei(GL_BLEND, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_buffer); + glViewportIndexedf(0, viewport[0], viewport[1], viewport[2], viewport[3]); + glBindProgramPipeline(program_pipeline); + glBindVertexArray(vertex_array); + glBindTexture(GL_TEXTURE_2D, texture_0); + glBindSampler(0, sampler_0); + } +}; + void Blitter::Draw(GLuint src_texture, uint32_t src_x, uint32_t src_y, uint32_t src_width, uint32_t src_height, GLenum filter) { + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); glDisablei(GL_BLEND, 0); - glDisable(GL_DEPTH_TEST); - glBindProgramPipeline(pipeline_); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CW); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBindVertexArray(vao_); glBindTextures(0, 1, &src_texture); switch (filter) { @@ -167,12 +242,6 @@ void Blitter::Draw(GLuint src_texture, uint32_t src_x, uint32_t src_y, src_height / float(src_texture_height)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - glBindProgramPipeline(0); - glBindVertexArray(0); - GLuint zero = 0; - glBindTextures(0, 1, &zero); - glBindSampler(0, 0); } void Blitter::BlitTexture2D(GLuint src_texture, uint32_t src_x, uint32_t src_y, @@ -180,17 +249,70 @@ void Blitter::BlitTexture2D(GLuint src_texture, uint32_t src_x, uint32_t src_y, uint32_t dest_x, uint32_t dest_y, uint32_t dest_width, uint32_t dest_height, GLenum filter) { + SavedState state; + state.Save(); + glViewport(dest_x, dest_y, dest_width, dest_height); + glColorMaski(0, true, true, true, true); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + glBindProgramPipeline(color_pipeline_); + Draw(src_texture, src_x, src_y, src_width, src_height, filter); + + state.Restore(); } -void Blitter::CopyTexture2D(GLuint src_texture, uint32_t src_x, uint32_t src_y, - uint32_t src_width, uint32_t src_height, - uint32_t dest_texture, uint32_t dest_x, - uint32_t dest_y, uint32_t dest_width, - uint32_t dest_height, GLenum filter) { +void Blitter::CopyColorTexture2D(GLuint src_texture, uint32_t src_x, + uint32_t src_y, uint32_t src_width, + uint32_t src_height, uint32_t dest_texture, + uint32_t dest_x, uint32_t dest_y, + uint32_t dest_width, uint32_t dest_height, + GLenum filter) { + SavedState state; + state.Save(); + glViewport(dest_x, dest_y, dest_width, dest_height); - // + glColorMaski(0, true, true, true, true); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + glBindProgramPipeline(color_pipeline_); + + glNamedFramebufferTexture(scratch_framebuffer_, GL_COLOR_ATTACHMENT0, + dest_texture, 0); + glNamedFramebufferDrawBuffer(scratch_framebuffer_, GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, scratch_framebuffer_); + Draw(src_texture, src_x, src_y, src_width, src_height, filter); + glNamedFramebufferDrawBuffer(scratch_framebuffer_, GL_NONE); + glNamedFramebufferTexture(scratch_framebuffer_, GL_COLOR_ATTACHMENT0, GL_NONE, + 0); + + state.Restore(); +} + +void Blitter::CopyDepthTexture(GLuint src_texture, uint32_t src_x, + uint32_t src_y, uint32_t src_width, + uint32_t src_height, uint32_t dest_texture, + uint32_t dest_x, uint32_t dest_y, + uint32_t dest_width, uint32_t dest_height) { + SavedState state; + state.Save(); + + glViewport(dest_x, dest_y, dest_width, dest_height); + glColorMaski(0, false, false, false, false); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glDepthMask(true); + glBindProgramPipeline(depth_pipeline_); + + glNamedFramebufferTexture(scratch_framebuffer_, GL_DEPTH_STENCIL_ATTACHMENT, + dest_texture, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, scratch_framebuffer_); + Draw(src_texture, src_x, src_y, src_width, src_height, GL_NEAREST); + glNamedFramebufferTexture(scratch_framebuffer_, GL_DEPTH_STENCIL_ATTACHMENT, + GL_NONE, 0); + + state.Restore(); } } // namespace gl4 diff --git a/src/xenia/gpu/gl4/blitter.h b/src/xenia/gpu/gl4/blitter.h index 2a2f72fde..f58e841e0 100644 --- a/src/xenia/gpu/gl4/blitter.h +++ b/src/xenia/gpu/gl4/blitter.h @@ -32,22 +32,30 @@ class Blitter { uint32_t dest_y, uint32_t dest_width, uint32_t dest_height, GLenum filter); - void CopyTexture2D(GLuint src_texture, uint32_t src_x, uint32_t src_y, - uint32_t src_width, uint32_t src_height, - uint32_t dest_texture, uint32_t dest_x, uint32_t dest_y, - uint32_t dest_width, uint32_t dest_height, GLenum filter); + void CopyColorTexture2D(GLuint src_texture, uint32_t src_x, uint32_t src_y, + uint32_t src_width, uint32_t src_height, + uint32_t dest_texture, uint32_t dest_x, + uint32_t dest_y, uint32_t dest_width, + uint32_t dest_height, GLenum filter); + void CopyDepthTexture(GLuint src_texture, uint32_t src_x, uint32_t src_y, + uint32_t src_width, uint32_t src_height, + uint32_t dest_texture, uint32_t dest_x, uint32_t dest_y, + uint32_t dest_width, uint32_t dest_height); private: void Draw(GLuint src_texture, uint32_t src_x, uint32_t src_y, uint32_t src_width, uint32_t src_height, GLenum filter); GLuint vertex_program_; - GLuint fragment_program_; - GLuint pipeline_; + GLuint color_fragment_program_; + GLuint depth_fragment_program_; + GLuint color_pipeline_; + GLuint depth_pipeline_; GLuint vbo_; GLuint vao_; GLuint nearest_sampler_; GLuint linear_sampler_; + GLuint scratch_framebuffer_; }; } // namespace gl4 diff --git a/src/xenia/gpu/gl4/command_processor.cc b/src/xenia/gpu/gl4/command_processor.cc index 10aee7288..28565095f 100644 --- a/src/xenia/gpu/gl4/command_processor.cc +++ b/src/xenia/gpu/gl4/command_processor.cc @@ -2472,7 +2472,7 @@ bool CommandProcessor::IssueCopy() { glPixelStorei(GL_PACK_SWAP_BYTES, GL_TRUE); break; default: - //assert_unhandled_case(copy_dest_endian); + // assert_unhandled_case(copy_dest_endian); glPixelStorei(GL_PACK_SWAP_BYTES, GL_TRUE); break; } @@ -2498,29 +2498,26 @@ bool CommandProcessor::IssueCopy() { uint32_t h = copy_dest_height; // Make active so glReadPixels reads from us. - glBindFramebuffer(GL_READ_FRAMEBUFFER, source_framebuffer->framebuffer); switch (copy_command) { case CopyCommand::kRaw: { // This performs a byte-for-byte copy of the textures from src to dest // with no conversion. Byte swapping may still occur. if (copy_src_select <= 3) { // Source from a bound render target. - glNamedFramebufferReadBuffer(source_framebuffer->framebuffer, - GL_COLOR_ATTACHMENT0 + copy_src_select); // TODO(benvanik): RAW copy. - last_framebuffer_texture_ = texture_cache_.CopyReadBufferTexture( - copy_dest_base, x, y, w, h, + last_framebuffer_texture_ = texture_cache_.CopyTexture( + context_->blitter(), copy_dest_base, x, y, w, h, ColorFormatToTextureFormat(copy_dest_format), - copy_dest_swap ? true : false); + copy_dest_swap ? true : false, color_targets[copy_src_select]); if (!FLAGS_disable_framebuffer_readback) { // glReadPixels(x, y, w, h, read_format, read_type, ptr); } } else { // Source from the bound depth/stencil target. // TODO(benvanik): RAW copy. - texture_cache_.CopyReadBufferTexture(copy_dest_base, x, y, w, h, - src_format, - copy_dest_swap ? true : false); + texture_cache_.CopyTexture(context_->blitter(), copy_dest_base, x, y, w, + h, src_format, copy_dest_swap ? true : false, + depth_target); if (!FLAGS_disable_framebuffer_readback) { // glReadPixels(x, y, w, h, GL_DEPTH_STENCIL, read_type, ptr); } @@ -2530,22 +2527,20 @@ bool CommandProcessor::IssueCopy() { case CopyCommand::kConvert: { if (copy_src_select <= 3) { // Source from a bound render target. - glNamedFramebufferReadBuffer(source_framebuffer->framebuffer, - GL_COLOR_ATTACHMENT0 + copy_src_select); // Either copy the readbuffer into an existing texture or create a new // one in the cache so we can service future upload requests. - last_framebuffer_texture_ = texture_cache_.CopyReadBufferTexture( - copy_dest_base, x, y, w, h, + last_framebuffer_texture_ = texture_cache_.ConvertTexture( + context_->blitter(), copy_dest_base, x, y, w, h, ColorFormatToTextureFormat(copy_dest_format), - copy_dest_swap ? true : false); + copy_dest_swap ? true : false, color_targets[copy_src_select]); if (!FLAGS_disable_framebuffer_readback) { // glReadPixels(x, y, w, h, read_format, read_type, ptr); } } else { // Source from the bound depth/stencil target. - texture_cache_.CopyReadBufferTexture(copy_dest_base, x, y, w, h, - src_format, - copy_dest_swap ? true : false); + texture_cache_.ConvertTexture( + context_->blitter(), copy_dest_base, x, y, w, h, src_format, + copy_dest_swap ? true : false, depth_target); if (!FLAGS_disable_framebuffer_readback) { // glReadPixels(x, y, w, h, GL_DEPTH_STENCIL, read_type, ptr); } @@ -2558,7 +2553,6 @@ bool CommandProcessor::IssueCopy() { // assert_unhandled_case(copy_command); return false; } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); // Perform any requested clears. uint32_t copy_depth_clear = regs[XE_GPU_REG_RB_DEPTH_CLEAR].u32; diff --git a/src/xenia/gpu/gl4/texture_cache.cc b/src/xenia/gpu/gl4/texture_cache.cc index 5696391e6..0503e90c4 100644 --- a/src/xenia/gpu/gl4/texture_cache.cc +++ b/src/xenia/gpu/gl4/texture_cache.cc @@ -33,112 +33,112 @@ struct TextureConfig { // http://dench.flatlib.jp/opengl/textures // http://fossies.org/linux/WebKit/Source/ThirdParty/ANGLE/src/libGLESv2/formatutils.cpp static const TextureConfig texture_configs[64] = { - { TextureFormat::k_1_REVERSE, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_8, GL_R8, GL_RED, GL_UNSIGNED_BYTE }, - { TextureFormat::k_1_5_5_5, GL_RGB5_A1, GL_RGBA, - GL_UNSIGNED_SHORT_1_5_5_5_REV }, - { TextureFormat::k_5_6_5, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, - { TextureFormat::k_6_5_5, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_8_8_8_8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, - { TextureFormat::k_2_10_10_10, GL_RGB10_A2, GL_RGBA, - GL_UNSIGNED_INT_2_10_10_10_REV }, - { TextureFormat::k_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_8_B, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_8_8, GL_RG8, GL_RG, GL_UNSIGNED_BYTE }, - { TextureFormat::k_Cr_Y1_Cb_Y0, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_Y1_Cr_Y0_Cb, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_8_8_8_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_4_4_4_4, GL_RGBA4, GL_RGBA, - GL_UNSIGNED_SHORT_4_4_4_4_REV }, - { TextureFormat::k_10_11_11, GL_R11F_G11F_B10F, GL_RGB, - GL_UNSIGNED_INT_10F_11F_11F_REV }, // ? - { TextureFormat::k_11_11_10, GL_R11F_G11F_B10F, GL_RGB, - GL_UNSIGNED_INT_10F_11F_11F_REV }, // ? - { TextureFormat::k_DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE }, - { TextureFormat::k_DXT2_3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE }, - { TextureFormat::k_DXT4_5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE }, - { TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_24_8, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, - GL_UNSIGNED_INT_24_8 }, - { TextureFormat::k_24_8_FLOAT, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, - GL_FLOAT_32_UNSIGNED_INT_24_8_REV }, - { TextureFormat::k_16, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_16_16, GL_RG16, GL_RG, GL_UNSIGNED_SHORT }, - { TextureFormat::k_16_16_16_16, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_16_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_FLOAT, GL_R16F, GL_RED, GL_HALF_FLOAT }, - { TextureFormat::k_16_16_FLOAT, GL_RG16F, GL_RG, GL_HALF_FLOAT }, - { TextureFormat::k_16_16_16_16_FLOAT, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, - { TextureFormat::k_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_32_32_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_32_FLOAT, GL_R32F, GL_RED, GL_FLOAT }, - { TextureFormat::k_32_32_FLOAT, GL_RG32F, GL_RG, GL_FLOAT }, - { TextureFormat::k_32_32_32_32_FLOAT, GL_RGBA32F, GL_RGBA, GL_FLOAT }, - { TextureFormat::k_32_AS_8, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_32_AS_8_8, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_32_AS_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_32_AS_8_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_16_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::k_DXN, GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_RG_RGTC2, - GL_INVALID_ENUM }, - { TextureFormat::k_8_8_8_8_AS_16_16_16_16, GL_RGBA8, GL_RGBA, - GL_UNSIGNED_BYTE }, - { TextureFormat::k_DXT1_AS_16_16_16_16, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE }, - { TextureFormat::k_DXT2_3_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE }, - { TextureFormat::k_DXT4_5_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE }, - { TextureFormat::k_2_10_10_10_AS_16_16_16_16, GL_RGB10_A2, GL_RGBA, - GL_UNSIGNED_INT_2_10_10_10_REV }, - { TextureFormat::k_10_11_11_AS_16_16_16_16, GL_R11F_G11F_B10F, GL_RGB, - GL_UNSIGNED_INT_10F_11F_11F_REV }, - { TextureFormat::k_11_11_10_AS_16_16_16_16, GL_R11F_G11F_B10F, - GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_32_32_32_FLOAT, GL_RGB32F, GL_RGB, GL_FLOAT }, - { TextureFormat::k_DXT3A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_DXT5A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_CTX1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM }, - { TextureFormat::k_DXT3A_AS_1_1_1_1, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, - { TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM, - GL_INVALID_ENUM }, + {TextureFormat::k_1_REVERSE, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_8, GL_R8, GL_RED, GL_UNSIGNED_BYTE}, + {TextureFormat::k_1_5_5_5, GL_RGB5_A1, GL_RGBA, + GL_UNSIGNED_SHORT_1_5_5_5_REV}, + {TextureFormat::k_5_6_5, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, + {TextureFormat::k_6_5_5, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_8_8_8_8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, + {TextureFormat::k_2_10_10_10, GL_RGB10_A2, GL_RGBA, + GL_UNSIGNED_INT_2_10_10_10_REV}, + {TextureFormat::k_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_8_B, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_8_8, GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, + {TextureFormat::k_Cr_Y1_Cb_Y0, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_Y1_Cr_Y0_Cb, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_8_8_8_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_4_4_4_4, GL_RGBA4, GL_RGBA, + GL_UNSIGNED_SHORT_4_4_4_4_REV}, + {TextureFormat::k_10_11_11, GL_R11F_G11F_B10F, GL_RGB, + GL_UNSIGNED_INT_10F_11F_11F_REV}, // ? + {TextureFormat::k_11_11_10, GL_R11F_G11F_B10F, GL_RGB, + GL_UNSIGNED_INT_10F_11F_11F_REV}, // ? + {TextureFormat::k_DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE}, + {TextureFormat::k_DXT2_3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, + GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE}, + {TextureFormat::k_DXT4_5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE}, + {TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_24_8, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, + GL_UNSIGNED_INT_24_8}, + {TextureFormat::k_24_8_FLOAT, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, + GL_FLOAT_32_UNSIGNED_INT_24_8_REV}, + {TextureFormat::k_16, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_16_16, GL_RG16, GL_RG, GL_UNSIGNED_SHORT}, + {TextureFormat::k_16_16_16_16, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_16_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_FLOAT, GL_R16F, GL_RED, GL_HALF_FLOAT}, + {TextureFormat::k_16_16_FLOAT, GL_RG16F, GL_RG, GL_HALF_FLOAT}, + {TextureFormat::k_16_16_16_16_FLOAT, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT}, + {TextureFormat::k_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_32_32_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_32_FLOAT, GL_R32F, GL_RED, GL_FLOAT}, + {TextureFormat::k_32_32_FLOAT, GL_RG32F, GL_RG, GL_FLOAT}, + {TextureFormat::k_32_32_32_32_FLOAT, GL_RGBA32F, GL_RGBA, GL_FLOAT}, + {TextureFormat::k_32_AS_8, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_32_AS_8_8, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_32_AS_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_32_AS_8_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_16_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::k_DXN, GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_RG_RGTC2, + GL_INVALID_ENUM}, + {TextureFormat::k_8_8_8_8_AS_16_16_16_16, GL_RGBA8, GL_RGBA, + GL_UNSIGNED_BYTE}, + {TextureFormat::k_DXT1_AS_16_16_16_16, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE}, + {TextureFormat::k_DXT2_3_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, + GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE}, + {TextureFormat::k_DXT4_5_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE}, + {TextureFormat::k_2_10_10_10_AS_16_16_16_16, GL_RGB10_A2, GL_RGBA, + GL_UNSIGNED_INT_2_10_10_10_REV}, + {TextureFormat::k_10_11_11_AS_16_16_16_16, GL_R11F_G11F_B10F, GL_RGB, + GL_UNSIGNED_INT_10F_11F_11F_REV}, + {TextureFormat::k_11_11_10_AS_16_16_16_16, GL_R11F_G11F_B10F, + GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_32_32_32_FLOAT, GL_RGB32F, GL_RGB, GL_FLOAT}, + {TextureFormat::k_DXT3A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_DXT5A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_CTX1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM}, + {TextureFormat::k_DXT3A_AS_1_1_1_1, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, + {TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM, + GL_INVALID_ENUM}, }; TextureCache::TextureCache() : memory_(nullptr), scratch_buffer_(nullptr) { @@ -526,11 +526,24 @@ TextureCache::TextureEntry* TextureCache::LookupAddress(uint32_t guest_address, return nullptr; } -GLuint TextureCache::CopyReadBufferTexture(uint32_t guest_address, uint32_t x, - uint32_t y, uint32_t width, - uint32_t height, - TextureFormat format, - bool swap_channels) { +GLuint TextureCache::CopyTexture(Blitter* blitter, uint32_t guest_address, + uint32_t x, uint32_t y, uint32_t width, + uint32_t height, TextureFormat format, + bool swap_channels, GLuint src_texture) { + return ConvertTexture(blitter, guest_address, x, y, width, height, format, + swap_channels, src_texture); +} + +GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, + uint32_t x, uint32_t y, uint32_t width, + uint32_t height, TextureFormat format, + bool swap_channels, GLuint src_texture) { + const auto& config = texture_configs[uint32_t(format)]; + if (config.format == GL_INVALID_ENUM) { + assert_always("Unhandled destination texture format"); + return 0; + } + // See if we have used a texture at this address before. If we have, we can // reuse it. // TODO(benvanik): better lookup matching format/etc? @@ -538,8 +551,14 @@ GLuint TextureCache::CopyReadBufferTexture(uint32_t guest_address, uint32_t x, if (texture_entry) { // Have existing texture. assert_false(texture_entry->pending_invalidation); - glCopyTextureSubImage2D(texture_entry->handle, 0, 0, 0, x, y, width, - height); + if (config.format == GL_DEPTH_STENCIL) { + blitter->CopyDepthTexture(src_texture, x, y, width, height, + texture_entry->handle, 0, 0, width, height); + } else { + blitter->CopyColorTexture2D(src_texture, x, y, width, height, + texture_entry->handle, 0, 0, width, height, + GL_LINEAR); + } // HACK: remove texture from write watch list so readback won't kill us. if (texture_entry->write_watch_handle) { @@ -557,17 +576,18 @@ GLuint TextureCache::CopyReadBufferTexture(uint32_t guest_address, uint32_t x, if (entry->guest_address == guest_address && entry->width == width && entry->height == height && entry->format == format) { // Found an existing entry - just reupload. - glCopyTextureSubImage2D(entry->handle, 0, 0, 0, x, y, width, height); + if (config.format == GL_DEPTH_STENCIL) { + blitter->CopyDepthTexture(src_texture, x, y, width, height, + entry->handle, 0, 0, width, height); + } else { + blitter->CopyColorTexture2D(src_texture, x, y, width, height, + entry->handle, 0, 0, width, height, + GL_LINEAR); + } return entry->handle; } } - const auto& config = texture_configs[uint32_t(format)]; - if (config.format == GL_INVALID_ENUM) { - assert_always("Unhandled destination texture format"); - return 0; - } - // Need to create a new texture. // As we don't know anything about this texture, we'll add it to the // pending readbuffer list. If nobody claims it after a certain amount @@ -582,7 +602,13 @@ GLuint TextureCache::CopyReadBufferTexture(uint32_t guest_address, uint32_t x, glTextureParameteri(entry->handle, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(entry->handle, GL_TEXTURE_MAX_LEVEL, 1); glTextureStorage2D(entry->handle, 1, config.internal_format, width, height); - glCopyTextureSubImage2D(entry->handle, 0, 0, 0, x, y, width, height); + if (config.format == GL_DEPTH_STENCIL) { + blitter->CopyDepthTexture(src_texture, x, y, width, height, entry->handle, + 0, 0, width, height); + } else { + blitter->CopyColorTexture2D(src_texture, x, y, width, height, entry->handle, + 0, 0, width, height, GL_LINEAR); + } GLuint handle = entry->handle; read_buffer_textures_.push_back(entry.release()); diff --git a/src/xenia/gpu/gl4/texture_cache.h b/src/xenia/gpu/gl4/texture_cache.h index ac5736e83..1340e4aac 100644 --- a/src/xenia/gpu/gl4/texture_cache.h +++ b/src/xenia/gpu/gl4/texture_cache.h @@ -14,6 +14,7 @@ #include #include +#include "xenia/gpu/gl4/blitter.h" #include "xenia/gpu/gl4/circular_buffer.h" #include "xenia/gpu/gl4/gl_context.h" #include "xenia/gpu/sampler_info.h" @@ -57,9 +58,15 @@ class TextureCache { TextureEntryView* Demand(const TextureInfo& texture_info, const SamplerInfo& sampler_info); - GLuint CopyReadBufferTexture(uint32_t guest_address, uint32_t x, uint32_t y, - uint32_t width, uint32_t height, - TextureFormat format, bool swap_channels); + + GLuint CopyTexture(Blitter* blitter, uint32_t guest_address, uint32_t x, + uint32_t y, uint32_t width, uint32_t height, + TextureFormat format, bool swap_channels, + GLuint src_texture); + GLuint ConvertTexture(Blitter* blitter, uint32_t guest_address, uint32_t x, + uint32_t y, uint32_t width, uint32_t height, + TextureFormat format, bool swap_channels, + GLuint src_texture); private: struct ReadBufferTexture {