diff options
author | Jelle Raaijmakers <jelle@gmta.nl> | 2022-08-24 23:47:49 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-08-27 12:28:05 +0200 |
commit | eb7c3d16fbfd805f9fbb3b819a661db10088fb56 (patch) | |
tree | 51e65bff9fead51d7c8f367d5e522d2f24deec31 /Userland/Libraries/LibGPU | |
parent | d7cfdfe6335de83f25d205cd9863fc18e2854763 (diff) | |
download | serenity-eb7c3d16fbfd805f9fbb3b819a661db10088fb56.zip |
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. :^)
Diffstat (limited to 'Userland/Libraries/LibGPU')
-rw-r--r-- | Userland/Libraries/LibGPU/Device.h | 16 | ||||
-rw-r--r-- | Userland/Libraries/LibGPU/Image.h | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibGPU/ImageDataLayout.h | 39 | ||||
-rw-r--r-- | Userland/Libraries/LibGPU/ImageFormat.h | 169 |
4 files changed, 198 insertions, 32 deletions
diff --git a/Userland/Libraries/LibGPU/Device.h b/Userland/Libraries/LibGPU/Device.h index c90f1a1c93..5f4ef2a691 100644 --- a/Userland/Libraries/LibGPU/Device.h +++ b/Userland/Libraries/LibGPU/Device.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Stephan Unverwerth <s.unverwerth@serenityos.org> + * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -15,7 +16,7 @@ #include <LibGPU/DeviceInfo.h> #include <LibGPU/Enums.h> #include <LibGPU/Image.h> -#include <LibGPU/ImageFormat.h> +#include <LibGPU/ImageDataLayout.h> #include <LibGPU/Light.h> #include <LibGPU/LightModelParameters.h> #include <LibGPU/Material.h> @@ -30,13 +31,14 @@ #include <LibGfx/Matrix4x4.h> #include <LibGfx/Rect.h> #include <LibGfx/Size.h> +#include <LibGfx/Vector2.h> #include <LibGfx/Vector4.h> namespace GPU { class Device { public: - virtual ~Device() { } + virtual ~Device() = default; virtual DeviceInfo info() const = 0; @@ -46,16 +48,16 @@ public: virtual void clear_depth(DepthType) = 0; virtual void clear_stencil(StencilType) = 0; virtual void blit_color_buffer_to(Gfx::Bitmap& target) = 0; - virtual void blit_to_color_buffer_at_raster_position(Gfx::Bitmap const&) = 0; - virtual void blit_to_depth_buffer_at_raster_position(Vector<DepthType> const&, int, int) = 0; + virtual void blit_from_color_buffer(void*, Vector2<i32> offset, GPU::ImageDataLayout const&) = 0; + virtual void blit_from_depth_buffer(void*, Vector2<i32> offset, GPU::ImageDataLayout const&) = 0; + virtual void blit_to_color_buffer_at_raster_position(void const*, GPU::ImageDataLayout const&) = 0; + virtual void blit_to_depth_buffer_at_raster_position(void const*, GPU::ImageDataLayout const&) = 0; virtual void set_options(RasterizerOptions const&) = 0; virtual void set_light_model_params(LightModelParameters const&) = 0; virtual RasterizerOptions options() const = 0; virtual LightModelParameters light_model() const = 0; - virtual ColorType get_color_buffer_pixel(int x, int y) = 0; - virtual DepthType get_depthbuffer_value(int x, int y) = 0; - virtual NonnullRefPtr<Image> create_image(ImageFormat format, unsigned width, unsigned height, unsigned depth, unsigned levels, unsigned layers) = 0; + virtual NonnullRefPtr<Image> create_image(PixelType const&, u32 width, u32 height, u32 depth, u32 levels, u32 layers) = 0; virtual void set_sampler_config(unsigned, SamplerConfig const&) = 0; virtual void set_light_state(unsigned, Light const&) = 0; diff --git a/Userland/Libraries/LibGPU/Image.h b/Userland/Libraries/LibGPU/Image.h index 4803d4ec17..1f2e189c39 100644 --- a/Userland/Libraries/LibGPU/Image.h +++ b/Userland/Libraries/LibGPU/Image.h @@ -21,9 +21,9 @@ public: virtual ~Image() { } - virtual void write_texels(unsigned layer, unsigned level, Vector3<unsigned> const& offset, Vector3<unsigned> const& size, void const* data, ImageDataLayout const& layout) = 0; - virtual void read_texels(unsigned layer, unsigned level, Vector3<unsigned> const& offset, Vector3<unsigned> const& size, void* data, ImageDataLayout const& layout) const = 0; - virtual void copy_texels(Image const& source, unsigned source_layer, unsigned source_level, Vector3<unsigned> const& source_offset, Vector3<unsigned> const& size, unsigned destination_layer, unsigned destination_level, Vector3<unsigned> const& destination_offset) = 0; + virtual void write_texels(u32 layer, u32 level, Vector3<i32> const& output_offset, void const* data, ImageDataLayout const&) = 0; + virtual void read_texels(u32 layer, u32 level, Vector3<i32> const& input_offset, void* data, ImageDataLayout const&) const = 0; + virtual void copy_texels(Image const& source, u32 source_layer, u32 source_level, Vector3<u32> const& source_offset, Vector3<u32> const& size, u32 destination_layer, u32 destination_level, Vector3<u32> const& destination_offset) = 0; void const* ownership_token() const { return m_ownership_token; } bool has_same_ownership_token(Image const& other) const { return other.ownership_token() == ownership_token(); } diff --git a/Userland/Libraries/LibGPU/ImageDataLayout.h b/Userland/Libraries/LibGPU/ImageDataLayout.h index 60e135ee48..1a3604bef7 100644 --- a/Userland/Libraries/LibGPU/ImageDataLayout.h +++ b/Userland/Libraries/LibGPU/ImageDataLayout.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org> + * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -10,11 +11,41 @@ namespace GPU { +// Order of bytes within a single component +enum class ComponentBytesOrder { + Normal, + Reversed, +}; + +struct PackingSpecification final { + u32 depth_stride { 0 }; + u32 row_stride { 0 }; + u8 byte_alignment { 1 }; + ComponentBytesOrder component_bytes_order { ComponentBytesOrder::Normal }; +}; + +// Full dimensions of the image +struct DimensionSpecification final { + u32 width; + u32 height; + u32 depth; +}; + +// Subselection (source or target) within the image +struct ImageSelection final { + i32 offset_x { 0 }; + i32 offset_y { 0 }; + i32 offset_z { 0 }; + u32 width; + u32 height; + u32 depth; +}; + struct ImageDataLayout final { - GPU::ImageFormat format; - size_t column_stride; - size_t row_stride; - size_t depth_stride; + PixelType pixel_type; + PackingSpecification packing {}; + DimensionSpecification dimensions; + ImageSelection selection; }; } diff --git a/Userland/Libraries/LibGPU/ImageFormat.h b/Userland/Libraries/LibGPU/ImageFormat.h index acae63d96a..7d4dc86d11 100644 --- a/Userland/Libraries/LibGPU/ImageFormat.h +++ b/Userland/Libraries/LibGPU/ImageFormat.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org> + * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl> * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause @@ -7,37 +8,169 @@ #pragma once -#include <AK/Types.h> +#include <AK/Array.h> namespace GPU { -enum class ImageFormat { - RGB565, - RGB888, - BGR888, - RGBA8888, - BGRA8888, - L8, - L8A8, +// The pixel data's representation +enum class PixelFormat { + Alpha, + BGR, + BGRA, + Blue, + ColorIndex, + DepthComponent, + Green, + Luminance, + LuminanceAlpha, + Red, + RGB, + RGBA, + StencilIndex, }; -static constexpr size_t element_size(ImageFormat format) +// Bit width assigned to individual components within a single pixel's value +enum class PixelComponentBits { + AllBits, + B1_5_5_5, + B2_3_3, + B2_10_10_10, + B3_3_2, + B4_4_4_4, + B5_5_5_1, + B5_6_5, + B8_8_8_8, + B10_10_10_2, +}; + +// The base data type used as pixel storage +enum class PixelDataType { + Bitmap, + Byte, + Float, + HalfFloat, + Int, + Short, + UnsignedByte, + UnsignedInt, + UnsignedShort, +}; + +// Order of components within a single pixel +enum class ComponentsOrder { + Normal, + Reversed, +}; + +struct PixelType final { + PixelFormat format; + PixelComponentBits bits; + PixelDataType data_type; + ComponentsOrder components_order { ComponentsOrder::Normal }; +}; + +static constexpr int number_of_components(PixelFormat format) { switch (format) { - case ImageFormat::L8: + case PixelFormat::Alpha: + case PixelFormat::Blue: + case PixelFormat::ColorIndex: + case PixelFormat::DepthComponent: + case PixelFormat::Green: + case PixelFormat::Luminance: + case PixelFormat::Red: + case PixelFormat::StencilIndex: return 1; - case ImageFormat::RGB565: - case ImageFormat::L8A8: + case PixelFormat::LuminanceAlpha: return 2; - case ImageFormat::RGB888: - case ImageFormat::BGR888: + case PixelFormat::BGR: + case PixelFormat::RGB: + return 3; + case PixelFormat::BGRA: + case PixelFormat::RGBA: + return 4; + } + VERIFY_NOT_REACHED(); +} + +static constexpr int number_of_components(PixelComponentBits bits) +{ + switch (bits) { + case PixelComponentBits::AllBits: + return 1; + case PixelComponentBits::B2_3_3: + case PixelComponentBits::B3_3_2: + case PixelComponentBits::B5_6_5: return 3; - case ImageFormat::RGBA8888: - case ImageFormat::BGRA8888: + case PixelComponentBits::B1_5_5_5: + case PixelComponentBits::B2_10_10_10: + case PixelComponentBits::B4_4_4_4: + case PixelComponentBits::B5_5_5_1: + case PixelComponentBits::B8_8_8_8: + case PixelComponentBits::B10_10_10_2: return 4; - default: + } + VERIFY_NOT_REACHED(); +} + +static constexpr Array<u8, 4> pixel_component_bitfield_lengths(PixelComponentBits bits) +{ + switch (bits) { + case PixelComponentBits::AllBits: VERIFY_NOT_REACHED(); + case PixelComponentBits::B1_5_5_5: + return { 1, 5, 5, 5 }; + case PixelComponentBits::B2_3_3: + return { 2, 3, 3 }; + case PixelComponentBits::B2_10_10_10: + return { 2, 10, 10, 10 }; + case PixelComponentBits::B3_3_2: + return { 3, 3, 2 }; + case PixelComponentBits::B4_4_4_4: + return { 4, 4, 4, 4 }; + case PixelComponentBits::B5_5_5_1: + return { 5, 5, 5, 1 }; + case PixelComponentBits::B5_6_5: + return { 5, 6, 5 }; + case PixelComponentBits::B8_8_8_8: + return { 8, 8, 8, 8 }; + case PixelComponentBits::B10_10_10_2: + return { 10, 10, 10, 2 }; } + VERIFY_NOT_REACHED(); +} + +static constexpr size_t pixel_data_type_size_in_bytes(PixelDataType data_type) +{ + switch (data_type) { + case PixelDataType::Bitmap: + return sizeof(u8); + case PixelDataType::Byte: + return sizeof(u8); + case PixelDataType::Float: + return sizeof(float); + case PixelDataType::HalfFloat: + return sizeof(float) / 2; + case PixelDataType::Int: + return sizeof(i32); + case PixelDataType::Short: + return sizeof(i16); + case PixelDataType::UnsignedByte: + return sizeof(u8); + case PixelDataType::UnsignedInt: + return sizeof(u32); + case PixelDataType::UnsignedShort: + return sizeof(u16); + } + VERIFY_NOT_REACHED(); +} + +static constexpr u8 pixel_size_in_bytes(PixelType pixel_type) +{ + auto component_size_in_bytes = pixel_data_type_size_in_bytes(pixel_type.data_type); + if (pixel_type.bits == PixelComponentBits::AllBits) + return component_size_in_bytes * number_of_components(pixel_type.format); + return component_size_in_bytes; } } |