diff options
| author | ameerj <52414509+ameerj@users.noreply.github.com> | 2021-03-04 14:14:19 -0500 |
|---|---|---|
| committer | ameerj <52414509+ameerj@users.noreply.github.com> | 2021-03-04 14:14:19 -0500 |
| commit | 0639244d856f403cc9bdec5ca927df7a61edd1d8 (patch) | |
| tree | a87c6e3142665bfb632001507cf04c973a88e1a6 /src/video_core/renderer_opengl/util_shaders.cpp | |
| parent | 394475c4e379699903f34690a6c6fc83e6280d31 (diff) | |
renderer_opengl: Swizzle BGR textures on copy
OpenGL does not natively support BGR internal formats, which causes many BGR textures to render incorrectly, with Red and Blue channels swapped.
This commit aims to address this by swizzling the blue and red channels on texture copies when a BGR format is encountered.
Diffstat (limited to 'src/video_core/renderer_opengl/util_shaders.cpp')
| -rw-r--r-- | src/video_core/renderer_opengl/util_shaders.cpp | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/src/video_core/renderer_opengl/util_shaders.cpp b/src/video_core/renderer_opengl/util_shaders.cpp index 31ec68505..2fe4799bc 100644 --- a/src/video_core/renderer_opengl/util_shaders.cpp +++ b/src/video_core/renderer_opengl/util_shaders.cpp @@ -14,6 +14,7 @@ #include "video_core/host_shaders/block_linear_unswizzle_2d_comp.h" #include "video_core/host_shaders/block_linear_unswizzle_3d_comp.h" #include "video_core/host_shaders/opengl_copy_bc4_comp.h" +#include "video_core/host_shaders/opengl_copy_bgra_comp.h" #include "video_core/host_shaders/pitch_unswizzle_comp.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_manager.h" @@ -48,6 +49,11 @@ OGLProgram MakeProgram(std::string_view source) { return program; } +size_t NumPixelsInCopy(const VideoCommon::ImageCopy& copy) { + return static_cast<size_t>(copy.extent.width * copy.extent.height * + copy.src_subresource.num_layers); +} + } // Anonymous namespace UtilShaders::UtilShaders(ProgramManager& program_manager_) @@ -55,6 +61,7 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_) block_linear_unswizzle_2d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_2D_COMP)), block_linear_unswizzle_3d_program(MakeProgram(BLOCK_LINEAR_UNSWIZZLE_3D_COMP)), pitch_unswizzle_program(MakeProgram(PITCH_UNSWIZZLE_COMP)), + copy_bgra_program(MakeProgram(OPENGL_COPY_BGRA_COMP)), copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)) { const auto swizzle_table = Tegra::Texture::MakeSwizzleTable(); swizzle_table_buffer.Create(); @@ -205,6 +212,43 @@ void UtilShaders::CopyBC4(Image& dst_image, Image& src_image, std::span<const Im program_manager.RestoreGuestCompute(); } +void UtilShaders::CopyBGR(Image& dst_image, Image& src_image, + std::span<const VideoCommon::ImageCopy> copies) { + static constexpr GLuint BINDING_INPUT_IMAGE = 0; + static constexpr GLuint BINDING_OUTPUT_IMAGE = 1; + static constexpr VideoCommon::Offset3D zero_offset{0, 0, 0}; + const u32 bytes_per_block = BytesPerBlock(dst_image.info.format); + switch (bytes_per_block) { + case 2: + // BGR565 copy + for (const ImageCopy& copy : copies) { + ASSERT(copy.src_offset == zero_offset); + ASSERT(copy.dst_offset == zero_offset); + bgr_copy_pass.Execute(dst_image, src_image, copy); + } + break; + case 4: { + // BGRA8 copy + program_manager.BindHostCompute(copy_bgra_program.handle); + constexpr GLenum FORMAT = GL_RGBA8; + for (const ImageCopy& copy : copies) { + ASSERT(copy.src_offset == zero_offset); + ASSERT(copy.dst_offset == zero_offset); + glBindImageTexture(BINDING_INPUT_IMAGE, src_image.StorageHandle(), + copy.src_subresource.base_level, GL_FALSE, 0, GL_READ_ONLY, FORMAT); + glBindImageTexture(BINDING_OUTPUT_IMAGE, dst_image.StorageHandle(), + copy.dst_subresource.base_level, GL_FALSE, 0, GL_WRITE_ONLY, FORMAT); + glDispatchCompute(copy.extent.width, copy.extent.height, copy.extent.depth); + } + program_manager.RestoreGuestCompute(); + break; + } + default: + UNREACHABLE(); + break; + } +} + GLenum StoreFormat(u32 bytes_per_block) { switch (bytes_per_block) { case 1: @@ -222,4 +266,36 @@ GLenum StoreFormat(u32 bytes_per_block) { return GL_R8UI; } +void Bgr565CopyPass::Execute(const Image& dst_image, const Image& src_image, + const ImageCopy& copy) { + if (CopyBufferCreationNeeded(copy)) { + CreateNewCopyBuffer(copy, GL_TEXTURE_2D_ARRAY, GL_RGB565); + } + // Copy from source to PBO + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ROW_LENGTH, copy.extent.width); + glBindBuffer(GL_PIXEL_PACK_BUFFER, bgr16_pbo.handle); + glGetTextureSubImage(src_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height, + copy.src_subresource.num_layers, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, + static_cast<GLsizei>(bgr16_pbo_size), nullptr); + + // Copy from PBO to destination in reverse order + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ROW_LENGTH, copy.extent.width); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bgr16_pbo.handle); + glTextureSubImage3D(dst_image.Handle(), 0, 0, 0, 0, copy.extent.width, copy.extent.height, + copy.dst_subresource.num_layers, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, + nullptr); +} + +bool Bgr565CopyPass::CopyBufferCreationNeeded(const ImageCopy& copy) { + return bgr16_pbo_size < NumPixelsInCopy(copy) * sizeof(u16); +} + +void Bgr565CopyPass::CreateNewCopyBuffer(const ImageCopy& copy, GLenum target, GLuint format) { + bgr16_pbo.Create(); + bgr16_pbo_size = NumPixelsInCopy(copy) * sizeof(u16); + glNamedBufferData(bgr16_pbo.handle, bgr16_pbo_size, nullptr, GL_STREAM_COPY); +} + } // namespace OpenGL |
