mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:37:46 +00:00
LibGL+LibGPU+LibSoftGPU: Implement flexible pixel format conversion
A GPU (driver) is now responsible for reading and writing pixels from and to user data. The client (LibGL) is responsible for specifying how the user data must be interpreted or written to. This allows us to centralize all pixel format conversion in one class, `LibSoftGPU::PixelConverter`. For both the input and output image, it takes a specification containing the image dimensions, the pixel type and the selection (basically a clipping rect), and converts the pixels from the input image to the output image. Effectively this means we now support almost all OpenGL 1.5 formats, and all custom logic has disappeared from: - `glDrawPixels` - `glReadPixels` - `glTexImage2D` - `glTexSubImage2D` The new logic is still unoptimized, but on my machine I experienced no noticeable slowdown. :^)
This commit is contained in:
parent
d7cfdfe633
commit
eb7c3d16fb
24 changed files with 1350 additions and 705 deletions
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
|
||||
* Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
|
||||
* Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -10,87 +11,33 @@
|
|||
|
||||
namespace GL {
|
||||
|
||||
void Texture2D::upload_texture_data(GLuint lod, GLint internal_format, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid const* pixels, GLsizei pixels_per_row, u8 byte_alignment)
|
||||
void Texture2D::upload_texture_data(GLuint lod, GLenum internal_format, GPU::ImageDataLayout input_layout, GLvoid const* pixels)
|
||||
{
|
||||
// NOTE: Some target, format, and internal formats are currently unsupported.
|
||||
// Considering we control this library, and `gl.h` itself, we don't need to add any
|
||||
// checks here to see if we support them; the program will simply fail to compile..
|
||||
|
||||
auto& mip = m_mipmaps[lod];
|
||||
mip.set_width(width);
|
||||
mip.set_height(height);
|
||||
|
||||
m_internal_format = internal_format;
|
||||
mip.set_width(input_layout.selection.width);
|
||||
mip.set_height(input_layout.selection.height);
|
||||
|
||||
// No pixel data was supplied; leave the texture memory uninitialized.
|
||||
if (pixels == nullptr)
|
||||
return;
|
||||
|
||||
replace_sub_texture_data(lod, 0, 0, width, height, format, type, pixels, pixels_per_row, byte_alignment);
|
||||
replace_sub_texture_data(lod, input_layout, { 0, 0, 0 }, pixels);
|
||||
}
|
||||
|
||||
void Texture2D::replace_sub_texture_data(GLuint lod, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid const* pixels, GLsizei pixels_per_row, u8 byte_alignment)
|
||||
void Texture2D::replace_sub_texture_data(GLuint lod, GPU::ImageDataLayout input_layout, Vector3<i32> const& output_offset, GLvoid const* pixels)
|
||||
{
|
||||
auto& mip = m_mipmaps[lod];
|
||||
|
||||
// FIXME: We currently only support GL_UNSIGNED_BYTE and GL_UNSIGNED_SHORT_5_6_5 pixel data
|
||||
VERIFY(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT_5_6_5);
|
||||
VERIFY(xoffset >= 0 && yoffset >= 0 && xoffset + width <= mip.width() && yoffset + height <= mip.height());
|
||||
VERIFY(pixels_per_row == 0 || pixels_per_row >= xoffset + width);
|
||||
|
||||
// FIXME: We currently depend on the first glTexImage2D call to attach an image to mipmap level 0, which initializes the GPU image
|
||||
// Ideally we would create separate GPU images for each level and merge them into a final image
|
||||
// once used for rendering for the first time.
|
||||
if (device_image().is_null())
|
||||
return;
|
||||
|
||||
u8 pixel_size_bytes;
|
||||
switch (type) {
|
||||
case GL_UNSIGNED_BYTE:
|
||||
pixel_size_bytes = (format == GL_RGBA || format == GL_BGRA) ? 4 : 3;
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT_5_6_5:
|
||||
pixel_size_bytes = sizeof(u16);
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
// Calculate row offset at end to fit alignment
|
||||
int const physical_width = pixels_per_row > 0 ? pixels_per_row : width;
|
||||
size_t const physical_width_bytes = physical_width * pixel_size_bytes;
|
||||
|
||||
GPU::ImageDataLayout layout;
|
||||
layout.column_stride = pixel_size_bytes;
|
||||
layout.row_stride = physical_width_bytes + (byte_alignment - physical_width_bytes % byte_alignment) % byte_alignment;
|
||||
layout.depth_stride = 0;
|
||||
|
||||
if (type == GL_UNSIGNED_SHORT_5_6_5) {
|
||||
layout.format = GPU::ImageFormat::RGB565;
|
||||
} else if (type == GL_UNSIGNED_BYTE) {
|
||||
if (format == GL_RGB)
|
||||
layout.format = GPU::ImageFormat::RGB888;
|
||||
else if (format == GL_BGR)
|
||||
layout.format = GPU::ImageFormat::BGR888;
|
||||
else if (format == GL_RGBA)
|
||||
layout.format = GPU::ImageFormat::RGBA8888;
|
||||
else if (format == GL_BGRA)
|
||||
layout.format = GPU::ImageFormat::BGRA8888;
|
||||
}
|
||||
|
||||
Vector3<unsigned> offset {
|
||||
static_cast<unsigned>(xoffset),
|
||||
static_cast<unsigned>(yoffset),
|
||||
0
|
||||
};
|
||||
|
||||
Vector3<unsigned> size {
|
||||
static_cast<unsigned>(width),
|
||||
static_cast<unsigned>(height),
|
||||
1
|
||||
};
|
||||
|
||||
device_image()->write_texels(0, lod, offset, size, pixels, layout);
|
||||
device_image()->write_texels(0, lod, output_offset, pixels, input_layout);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue