Serenity Operating System
at master 199 lines 8.1 kB view raw
1/* 2 * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org> 3 * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <LibGfx/Bitmap.h> 9#include <LibGfx/Painter.h> 10#include <LibGfx/Size.h> 11#include <LibSoftGPU/Image.h> 12#include <LibSoftGPU/PixelConverter.h> 13 14namespace SoftGPU { 15 16Image::Image(void const* ownership_token, GPU::PixelFormat const& pixel_format, u32 width, u32 height, u32 depth, u32 max_levels) 17 : GPU::Image(ownership_token, pixel_format, width, height, depth, max_levels) 18 , m_mipmap_buffers(FixedArray<RefPtr<Typed3DBuffer<FloatVector4>>>::must_create_but_fixme_should_propagate_errors(number_of_levels())) 19{ 20 VERIFY(pixel_format == GPU::PixelFormat::Alpha 21 || pixel_format == GPU::PixelFormat::Intensity 22 || pixel_format == GPU::PixelFormat::Luminance 23 || pixel_format == GPU::PixelFormat::LuminanceAlpha 24 || pixel_format == GPU::PixelFormat::RGB 25 || pixel_format == GPU::PixelFormat::RGBA); 26 27 m_width_is_power_of_two = is_power_of_two(width); 28 m_height_is_power_of_two = is_power_of_two(height); 29 m_depth_is_power_of_two = is_power_of_two(depth); 30 31 for (u32 level = 0; level < number_of_levels(); ++level) { 32 m_mipmap_buffers[level] = MUST(Typed3DBuffer<FloatVector4>::try_create(width_at_level(level), height_at_level(level), depth_at_level(level))); 33 } 34} 35 36GPU::ImageDataLayout Image::image_data_layout(u32 level, Vector3<i32> offset) const 37{ 38 auto const width = width_at_level(level); 39 auto const height = height_at_level(level); 40 auto const depth = depth_at_level(level); 41 42 // FIXME: we are directly writing to FloatVector4s. We should probably find a better way to do this 43 return { 44 .pixel_type = { 45 .format = GPU::PixelFormat::RGBA, 46 .bits = GPU::PixelComponentBits::AllBits, 47 .data_type = GPU::PixelDataType::Float, 48 }, 49 .dimensions = { 50 .width = width, 51 .height = height, 52 .depth = depth, 53 }, 54 .selection = { 55 .offset_x = offset.x(), 56 .offset_y = offset.y(), 57 .offset_z = offset.z(), 58 .width = width - offset.x(), 59 .height = height - offset.y(), 60 .depth = depth - offset.z(), 61 }, 62 }; 63} 64 65void Image::write_texels(u32 level, Vector3<i32> const& output_offset, void const* input_data, GPU::ImageDataLayout const& input_layout) 66{ 67 VERIFY(level < number_of_levels()); 68 69 auto output_layout = image_data_layout(level, output_offset); 70 auto texel_data = texel_pointer(level, 0, 0, 0); 71 72 PixelConverter converter { input_layout, output_layout }; 73 ErrorOr<void> conversion_result; 74 switch (pixel_format()) { 75 case GPU::PixelFormat::Luminance: 76 case GPU::PixelFormat::RGB: 77 // Both Luminance and RGB set the alpha to 1, regardless of the source texel 78 conversion_result = converter.convert(input_data, texel_data, [](auto& components) { components[3] = 1.f; }); 79 break; 80 default: 81 conversion_result = converter.convert(input_data, texel_data, {}); 82 } 83 if (conversion_result.is_error()) 84 dbgln("Pixel conversion failed: {}", conversion_result.error().string_literal()); 85} 86 87void Image::read_texels(u32 level, Vector3<i32> const& input_offset, void* output_data, GPU::ImageDataLayout const& output_layout) const 88{ 89 VERIFY(level < number_of_levels()); 90 91 auto input_layout = image_data_layout(level, input_offset); 92 93 PixelConverter converter { input_layout, output_layout }; 94 auto conversion_result = converter.convert(texel_pointer(level, 0, 0, 0), output_data, {}); 95 if (conversion_result.is_error()) 96 dbgln("Pixel conversion failed: {}", conversion_result.error().string_literal()); 97} 98 99void Image::copy_texels(GPU::Image const& source, u32 source_level, Vector3<u32> const& source_offset, Vector3<u32> const& size, u32 destination_level, Vector3<u32> const& destination_offset) 100{ 101 VERIFY(source.has_same_ownership_token(*this)); 102 103 auto const& src_image = static_cast<Image const&>(source); 104 105 VERIFY(source_level < src_image.number_of_levels()); 106 VERIFY(source_offset.x() + size.x() <= src_image.width_at_level(source_level)); 107 VERIFY(source_offset.y() + size.y() <= src_image.height_at_level(source_level)); 108 VERIFY(source_offset.z() + size.z() <= src_image.depth_at_level(source_level)); 109 VERIFY(destination_level < number_of_levels()); 110 VERIFY(destination_offset.x() + size.x() <= width_at_level(destination_level)); 111 VERIFY(destination_offset.y() + size.y() <= height_at_level(destination_level)); 112 VERIFY(destination_offset.z() + size.z() <= depth_at_level(destination_level)); 113 114 for (u32 z = 0; z < size.z(); ++z) { 115 for (u32 y = 0; y < size.y(); ++y) { 116 for (u32 x = 0; x < size.x(); ++x) { 117 auto const& color = src_image.texel(source_level, source_offset.x() + x, source_offset.y() + y, source_offset.z() + z); 118 set_texel(destination_level, destination_offset.x() + x, destination_offset.y() + y, destination_offset.z() + z, color); 119 } 120 } 121 } 122} 123 124static GPU::ImageDataLayout image_data_layout_for_bitmap(Gfx::Bitmap& bitmap) 125{ 126 VERIFY(bitmap.format() == Gfx::BitmapFormat::BGRA8888); 127 return GPU::ImageDataLayout { 128 .pixel_type = { 129 .format = GPU::PixelFormat::BGRA, 130 .bits = GPU::PixelComponentBits::B8_8_8_8, 131 .data_type = GPU::PixelDataType::UnsignedInt, 132 .components_order = GPU::ComponentsOrder::Reversed, 133 }, 134 .dimensions = { 135 .width = static_cast<u32>(bitmap.width()), 136 .height = static_cast<u32>(bitmap.height()), 137 .depth = 1, 138 }, 139 .selection = { 140 .width = static_cast<u32>(bitmap.width()), 141 .height = static_cast<u32>(bitmap.height()), 142 .depth = 1, 143 }, 144 }; 145} 146 147void Image::regenerate_mipmaps() 148{ 149 // FIXME: currently this only works for 2D Images 150 VERIFY(depth_at_level(0) == 1); 151 152 auto empty_bitmap_for_level = [&](u32 level) -> NonnullRefPtr<Gfx::Bitmap> { 153 Gfx::IntSize size = { width_at_level(level), height_at_level(level) }; 154 return MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, size)); 155 }; 156 auto copy_image_into_bitmap = [&](u32 level) -> NonnullRefPtr<Gfx::Bitmap> { 157 auto bitmap = empty_bitmap_for_level(level); 158 159 auto input_layout = image_data_layout(level, { 0, 0, 0 }); 160 auto const* input_data = texel_pointer(level, 0, 0, 0); 161 162 auto output_layout = image_data_layout_for_bitmap(bitmap); 163 auto* output_data = bitmap->scanline(0); 164 165 PixelConverter converter { input_layout, output_layout }; 166 MUST(converter.convert(input_data, output_data, {})); 167 return bitmap; 168 }; 169 auto copy_bitmap_into_level = [&](NonnullRefPtr<Gfx::Bitmap> bitmap, u32 level) { 170 VERIFY(level >= 1); 171 172 auto input_layout = image_data_layout_for_bitmap(bitmap); 173 auto const* input_data = bitmap->scanline(0); 174 175 auto output_layout = image_data_layout(level, { 0, 0, 0 }); 176 auto* output_data = texel_pointer(level, 0, 0, 0); 177 178 PixelConverter converter { input_layout, output_layout }; 179 MUST(converter.convert(input_data, output_data, {})); 180 }; 181 182 // For levels 1..number_of_levels-1, we generate downscaled versions of the level above 183 for (u32 level = 1; level < number_of_levels(); ++level) { 184 auto higher_level_bitmap = copy_image_into_bitmap(level - 1); 185 auto current_level_bitmap = empty_bitmap_for_level(level); 186 187 Gfx::Painter current_level_painter { current_level_bitmap }; 188 current_level_painter.draw_scaled_bitmap( 189 current_level_bitmap->rect(), 190 higher_level_bitmap, 191 higher_level_bitmap->rect(), 192 1.f, 193 Gfx::Painter::ScalingMode::BilinearBlend); 194 195 copy_bitmap_into_level(current_level_bitmap, level); 196 } 197} 198 199}