diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 109ef0d89..a8ca57c8c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -849,21 +849,25 @@ void RasterizerOpenGL::ReloadColorBuffer() { std::unique_ptr temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); // Directly copy pixels. The OpenGL internal formats match the 3DS ones, so no conversion is necessary. + using VideoCore::CopyTextureAndUntile; switch (bytes_per_pixel) { case 4: - VideoCore::CopyTextureAndTile((u32*)temp_fb_color_buffer.get(), (u32*)color_buffer, fb_color_texture.width, fb_color_texture.height); + CopyTextureAndUntile(reinterpret_cast(temp_fb_color_buffer.get()), + reinterpret_cast(color_buffer), + fb_color_texture.width, fb_color_texture.height); break; case 3: - VideoCore::CopyTextureAndTile((u24_be*)temp_fb_color_buffer.get(), (u24_be*)color_buffer, fb_color_texture.width, fb_color_texture.height); + CopyTextureAndUntile(reinterpret_cast(temp_fb_color_buffer.get()), + reinterpret_cast(color_buffer), + fb_color_texture.width, fb_color_texture.height); break; case 2: - VideoCore::CopyTextureAndTile((u16*)temp_fb_color_buffer.get(), (u16*)color_buffer, fb_color_texture.width, fb_color_texture.height); - break; - case 1: - VideoCore::CopyTextureAndTile(temp_fb_color_buffer.get(), color_buffer, fb_color_texture.width, fb_color_texture.height); + CopyTextureAndUntile(reinterpret_cast(temp_fb_color_buffer.get()), + reinterpret_cast(color_buffer), + fb_color_texture.width, fb_color_texture.height); break; default: - LOG_ERROR(Render_OpenGL, "Unimplemented pixel size %u bytes per pixel", bytes_per_pixel); + UNREACHABLE(); } state.texture_units[0].texture_2d = fb_color_texture.texture.handle; @@ -968,21 +972,25 @@ void RasterizerOpenGL::CommitColorBuffer() { state.Apply(); // Directly copy pixels. The OpenGL internal formats match the 3DS ones, so no conversion is necessary. + using VideoCore::CopyTextureAndTile; switch (bytes_per_pixel) { case 4: - VideoCore::CopyTextureAndTile((u32*)color_buffer, (u32*)temp_gl_color_buffer.get(), fb_color_texture.width, fb_color_texture.height); + CopyTextureAndTile(reinterpret_cast(color_buffer), + reinterpret_cast(temp_gl_color_buffer.get()), + fb_color_texture.width, fb_color_texture.height); break; case 3: - VideoCore::CopyTextureAndTile((u24_be*)color_buffer, (u24_be*)temp_gl_color_buffer.get(), fb_color_texture.width, fb_color_texture.height); + CopyTextureAndTile(reinterpret_cast(color_buffer), + reinterpret_cast(temp_gl_color_buffer.get()), + fb_color_texture.width, fb_color_texture.height); break; case 2: - VideoCore::CopyTextureAndTile((u16*)color_buffer, (u16*)temp_gl_color_buffer.get(), fb_color_texture.width, fb_color_texture.height); - break; - case 1: - VideoCore::CopyTextureAndTile(color_buffer, temp_gl_color_buffer.get(), fb_color_texture.width, fb_color_texture.height); + CopyTextureAndTile(reinterpret_cast(color_buffer), + reinterpret_cast(temp_gl_color_buffer.get()), + fb_color_texture.width, fb_color_texture.height); break; default: - LOG_ERROR(Render_OpenGL, "Unimplemented pixel size %u bytes per pixel", bytes_per_pixel); + UNREACHABLE(); } } } diff --git a/src/video_core/utils.h b/src/video_core/utils.h index ba61b2a70..887601d2a 100644 --- a/src/video_core/utils.h +++ b/src/video_core/utils.h @@ -37,9 +37,9 @@ void DumpTGA(std::string filename, short width, short height, u8* raw_data); /// Lookup table for the offsets used to convert an image to Morton order. static const u8 morton_lut[64] = { - 0, 1, 4, 5, 16, 17, 20, 21, - 2, 3, 6, 7, 18, 19, 22, 23, - 8, 9, 12, 13, 24, 25, 28, 29, + 0, 1, 4, 5, 16, 17, 20, 21, + 2, 3, 6, 7, 18, 19, 22, 23, + 8, 9, 12, 13, 24, 25, 28, 29, 10, 11, 14, 15, 26, 27, 30, 31, 32, 33, 36, 37, 48, 49, 52, 53, 34, 35, 38, 39, 50, 51, 54, 55, @@ -57,13 +57,15 @@ static inline u32 MortonInterleave(u32 x, u32 y) { } /** - * Copies the texture data from the source address to the destination address, - * applying a Morton-order transformation while copying. + * Copies the texture data from the source address to the destination address, applying a + * Morton-order transformation while copying. + * + * @param T Type of the source and destination pointers, the swizzling process depends on the size + * of this parameter. * @param dst Pointer to which the texture will be copied. * @param src Pointer to the source texture data. * @param width Width of the texture, should be a multiple of 8. * @param height Height of the texture, should be a multiple of 8. - * @param T Type of the source and destination pointers, the swizzling process depends on the size of this parameter. */ template static inline void CopyTextureAndTile(T* dst, const T* src, unsigned int width, unsigned int height) { @@ -83,6 +85,34 @@ static inline void CopyTextureAndTile(T* dst, const T* src, unsigned int width, } } +/** + * Copies texture data while undoing the transformation applied by `CopyTextureAndTile`. + * + * @param T Type of the source and destination pointers, the swizzling process depends on the size + * of this parameter. + * @param dst Pointer to which the texture will be copied. + * @param src Pointer to the source texture data. + * @param width Width of the texture, should be a multiple of 8. + * @param height Height of the texture, should be a multiple of 8. + */ +template +static inline void CopyTextureAndUntile(T* dst, const T* src, unsigned int width, unsigned int height) { + for (unsigned int y = 0; y + 8 <= height; y += 8) { + for (unsigned int x = 0; x + 8 <= width; x += 8) { + T* line = &dst[y * width + x]; + + for (unsigned int yy = 0; yy < 8; ++yy) { + for (unsigned int xx = 0; xx < 8; ++xx) { + line[xx] = src[morton_lut[yy * 8 + xx]]; + } + line += width; + } + + src += 8 * 8; + } + } +} + /** * Calculates the offset of the position of the pixel in Morton order */