Przeglądaj źródła

LibGL+LibGPU+LibSoftGPU: Remove concept of `layer` in favor of `depth`

Looking at how Khronos defines layers:

  https://www.khronos.org/opengl/wiki/Array_Texture

We both have 3D textures and layers of 2D textures, which can both be
encoded in our existing `Typed3DBuffer` as depth. Since we support
depth already in the GPU API, remove layer everywhere.

Also pass in `Texture2D::LOG2_MAX_TEXTURE_SIZE` as the maximum number
of mipmap levels, so we do not allocate 999 levels on each Image
instantiation.
Jelle Raaijmakers 2 lat temu
rodzic
commit
dda5987684

+ 1 - 1
Userland/Libraries/LibGL/Tex/Texture2D.cpp

@@ -14,7 +14,7 @@ namespace GL {
 void Texture2D::download_texture_data(GLuint lod, GPU::ImageDataLayout output_layout, GLvoid* pixels)
 {
     VERIFY(!device_image().is_null());
-    device_image()->read_texels(0, lod, { 0, 0, 0 }, pixels, output_layout);
+    device_image()->read_texels(lod, { 0, 0, 0 }, pixels, output_layout);
 }
 
 void Texture2D::upload_texture_data(GLuint lod, GLenum internal_format, GPU::ImageDataLayout input_layout, GLvoid const* pixels)

+ 2 - 2
Userland/Libraries/LibGL/Texture.cpp

@@ -97,7 +97,7 @@ void GLContext::gl_copy_tex_image_2d(GLenum target, GLint level, GLenum internal
 
     auto internal_pixel_format = pixel_format_for_internal_format(internalformat);
     if (level == 0) {
-        texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, 999, 1));
+        texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, Texture2D::LOG2_MAX_TEXTURE_SIZE));
         m_sampler_config_is_dirty = true;
     }
 
@@ -550,7 +550,7 @@ void GLContext::gl_tex_image_2d(GLenum target, GLint level, GLint internal_forma
         // To be spec compliant we should create the device image once the texture has become complete and is used for rendering the first time.
         // All images that were attached before the device image was created need to be stored somewhere to be used to initialize the device image once complete.
         auto internal_pixel_format = pixel_format_for_internal_format(internal_format);
-        texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, 999, 1));
+        texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, Texture2D::LOG2_MAX_TEXTURE_SIZE));
         m_sampler_config_is_dirty = true;
     }
 

+ 1 - 1
Userland/Libraries/LibGPU/Device.h

@@ -55,7 +55,7 @@ public:
     virtual RasterizerOptions options() const = 0;
     virtual LightModelParameters light_model() const = 0;
 
-    virtual NonnullRefPtr<Image> create_image(PixelFormat const&, u32 width, u32 height, u32 depth, u32 levels, u32 layers) = 0;
+    virtual NonnullRefPtr<Image> create_image(PixelFormat const&, u32 width, u32 height, u32 depth, u32 max_levels) = 0;
 
     virtual void set_sampler_config(unsigned, SamplerConfig const&) = 0;
     virtual void set_light_state(unsigned, Light const&) = 0;

+ 3 - 3
Userland/Libraries/LibGPU/Image.h

@@ -21,9 +21,9 @@ public:
 
     virtual ~Image() { }
 
-    virtual void write_texels(u32 layer, u32 level, Vector3<i32> const& output_offset, void const* input_data, ImageDataLayout const&) = 0;
-    virtual void read_texels(u32 layer, u32 level, Vector3<i32> const& input_offset, void* output_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;
+    virtual void write_texels(u32 level, Vector3<i32> const& output_offset, void const* input_data, ImageDataLayout const&) = 0;
+    virtual void read_texels(u32 level, Vector3<i32> const& input_offset, void* output_data, ImageDataLayout const&) const = 0;
+    virtual void copy_texels(Image const& source, u32 source_level, Vector3<u32> const& source_offset, Vector3<u32> const& size, 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(); }

+ 5 - 6
Userland/Libraries/LibSoftGPU/Device.cpp

@@ -1473,7 +1473,7 @@ void Device::blit_from_color_buffer(NonnullRefPtr<GPU::Image> image, u32 level,
 
     auto const& softgpu_image = reinterpret_cast<Image*>(image.ptr());
     auto output_layout = softgpu_image->image_data_layout(level, output_offset);
-    auto* output_data = softgpu_image->texel_pointer(0, level, 0, 0, 0);
+    auto* output_data = softgpu_image->texel_pointer(level, 0, 0, 0);
 
     PixelConverter converter { input_layout, output_layout };
     auto conversion_result = converter.convert(input_data, output_data, {});
@@ -1512,7 +1512,7 @@ void Device::blit_from_depth_buffer(NonnullRefPtr<GPU::Image> image, u32 level,
 
     auto const& softgpu_image = reinterpret_cast<Image*>(image.ptr());
     auto output_layout = softgpu_image->image_data_layout(level, output_offset);
-    auto* output_data = softgpu_image->texel_pointer(0, level, 0, 0, 0);
+    auto* output_data = softgpu_image->texel_pointer(level, 0, 0, 0);
 
     PixelConverter converter { input_layout, output_layout };
     auto conversion_result = converter.convert(input_data, output_data, {});
@@ -1629,15 +1629,14 @@ void Device::set_light_model_params(GPU::LightModelParameters const& lighting_mo
     m_lighting_model = lighting_model;
 }
 
-NonnullRefPtr<GPU::Image> Device::create_image(GPU::PixelFormat const& pixel_format, u32 width, u32 height, u32 depth, u32 levels, u32 layers)
+NonnullRefPtr<GPU::Image> Device::create_image(GPU::PixelFormat const& pixel_format, u32 width, u32 height, u32 depth, u32 max_levels)
 {
     VERIFY(width > 0);
     VERIFY(height > 0);
     VERIFY(depth > 0);
-    VERIFY(levels > 0);
-    VERIFY(layers > 0);
+    VERIFY(max_levels > 0);
 
-    return adopt_ref(*new Image(this, pixel_format, width, height, depth, levels, layers));
+    return adopt_ref(*new Image(this, pixel_format, width, height, depth, max_levels));
 }
 
 void Device::set_sampler_config(unsigned sampler, GPU::SamplerConfig const& config)

+ 1 - 1
Userland/Libraries/LibSoftGPU/Device.h

@@ -64,7 +64,7 @@ public:
     virtual GPU::RasterizerOptions options() const override { return m_options; }
     virtual GPU::LightModelParameters light_model() const override { return m_lighting_model; }
 
-    virtual NonnullRefPtr<GPU::Image> create_image(GPU::PixelFormat const&, u32 width, u32 height, u32 depth, u32 levels, u32 layers) override;
+    virtual NonnullRefPtr<GPU::Image> create_image(GPU::PixelFormat const&, u32 width, u32 height, u32 depth, u32 max_levels) override;
 
     virtual void set_sampler_config(unsigned, GPU::SamplerConfig const&) override;
     virtual void set_light_state(unsigned, GPU::Light const&) override;

+ 10 - 17
Userland/Libraries/LibSoftGPU/Image.cpp

@@ -10,11 +10,10 @@
 
 namespace SoftGPU {
 
-Image::Image(void const* ownership_token, GPU::PixelFormat const& pixel_format, u32 width, u32 height, u32 depth, u32 max_levels, u32 layers)
+Image::Image(void const* ownership_token, GPU::PixelFormat const& pixel_format, u32 width, u32 height, u32 depth, u32 max_levels)
     : GPU::Image(ownership_token)
-    , m_num_layers(layers)
     , m_pixel_format(pixel_format)
-    , m_mipmap_buffers(FixedArray<RefPtr<Typed3DBuffer<FloatVector4>>>::must_create_but_fixme_should_propagate_errors(layers * max_levels))
+    , m_mipmap_buffers(FixedArray<RefPtr<Typed3DBuffer<FloatVector4>>>::must_create_but_fixme_should_propagate_errors(max_levels))
 {
     VERIFY(pixel_format == GPU::PixelFormat::Alpha
         || pixel_format == GPU::PixelFormat::Intensity
@@ -26,7 +25,6 @@ Image::Image(void const* ownership_token, GPU::PixelFormat const& pixel_format,
     VERIFY(height > 0);
     VERIFY(depth > 0);
     VERIFY(max_levels > 0);
-    VERIFY(layers > 0);
 
     m_width_is_power_of_two = is_power_of_two(width);
     m_height_is_power_of_two = is_power_of_two(height);
@@ -34,8 +32,7 @@ Image::Image(void const* ownership_token, GPU::PixelFormat const& pixel_format,
 
     u32 level;
     for (level = 0; level < max_levels; ++level) {
-        for (u32 layer = 0; layer < layers; ++layer)
-            m_mipmap_buffers[layer * layers + level] = MUST(Typed3DBuffer<FloatVector4>::try_create(width, height, depth));
+        m_mipmap_buffers[level] = MUST(Typed3DBuffer<FloatVector4>::try_create(width, height, depth));
 
         if (width <= 1 && height <= 1 && depth <= 1)
             break;
@@ -77,13 +74,12 @@ GPU::ImageDataLayout Image::image_data_layout(u32 level, Vector3<i32> offset) co
     };
 }
 
-void Image::write_texels(u32 layer, u32 level, Vector3<i32> const& output_offset, void const* input_data, GPU::ImageDataLayout const& input_layout)
+void Image::write_texels(u32 level, Vector3<i32> const& output_offset, void const* input_data, GPU::ImageDataLayout const& input_layout)
 {
-    VERIFY(layer < num_layers());
     VERIFY(level < num_levels());
 
     auto output_layout = image_data_layout(level, output_offset);
-    auto texel_data = texel_pointer(layer, level, 0, 0, 0);
+    auto texel_data = texel_pointer(level, 0, 0, 0);
 
     PixelConverter converter { input_layout, output_layout };
     ErrorOr<void> conversion_result;
@@ -100,31 +96,28 @@ void Image::write_texels(u32 layer, u32 level, Vector3<i32> const& output_offset
         dbgln("Pixel conversion failed: {}", conversion_result.error().string_literal());
 }
 
-void Image::read_texels(u32 layer, u32 level, Vector3<i32> const& input_offset, void* output_data, GPU::ImageDataLayout const& output_layout) const
+void Image::read_texels(u32 level, Vector3<i32> const& input_offset, void* output_data, GPU::ImageDataLayout const& output_layout) const
 {
-    VERIFY(layer < num_layers());
     VERIFY(level < num_levels());
 
     auto input_layout = image_data_layout(level, input_offset);
 
     PixelConverter converter { input_layout, output_layout };
-    auto conversion_result = converter.convert(texel_pointer(layer, level, 0, 0, 0), output_data, {});
+    auto conversion_result = converter.convert(texel_pointer(level, 0, 0, 0), output_data, {});
     if (conversion_result.is_error())
         dbgln("Pixel conversion failed: {}", conversion_result.error().string_literal());
 }
 
-void Image::copy_texels(GPU::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)
+void 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)
 {
     VERIFY(source.has_same_ownership_token(*this));
 
     auto const& src_image = static_cast<Image const&>(source);
 
-    VERIFY(source_layer < src_image.num_layers());
     VERIFY(source_level < src_image.num_levels());
     VERIFY(source_offset.x() + size.x() <= src_image.level_width(source_level));
     VERIFY(source_offset.y() + size.y() <= src_image.level_height(source_level));
     VERIFY(source_offset.z() + size.z() <= src_image.level_depth(source_level));
-    VERIFY(destination_layer < num_layers());
     VERIFY(destination_level < num_levels());
     VERIFY(destination_offset.x() + size.x() <= level_width(destination_level));
     VERIFY(destination_offset.y() + size.y() <= level_height(destination_level));
@@ -133,8 +126,8 @@ void Image::copy_texels(GPU::Image const& source, u32 source_layer, u32 source_l
     for (u32 z = 0; z < size.z(); ++z) {
         for (u32 y = 0; y < size.y(); ++y) {
             for (u32 x = 0; x < size.x(); ++x) {
-                auto color = src_image.texel(source_layer, source_level, source_offset.x() + x, source_offset.y() + y, source_offset.z() + z);
-                set_texel(destination_layer, destination_level, destination_offset.x() + x, destination_offset.y() + y, destination_offset.z() + z, color);
+                auto color = src_image.texel(source_level, source_offset.x() + x, source_offset.y() + y, source_offset.z() + z);
+                set_texel(destination_level, destination_offset.x() + x, destination_offset.y() + y, destination_offset.z() + z, color);
             }
         }
     }

+ 12 - 14
Userland/Libraries/LibSoftGPU/Image.h

@@ -20,46 +20,44 @@ namespace SoftGPU {
 
 class Image final : public GPU::Image {
 public:
-    Image(void const* ownership_token, GPU::PixelFormat const&, u32 width, u32 height, u32 depth, u32 max_levels, u32 layers);
+    Image(void const* ownership_token, GPU::PixelFormat const&, u32 width, u32 height, u32 depth, u32 max_levels);
 
     u32 level_width(u32 level) const { return m_mipmap_buffers[level]->width(); }
     u32 level_height(u32 level) const { return m_mipmap_buffers[level]->height(); }
     u32 level_depth(u32 level) const { return m_mipmap_buffers[level]->depth(); }
     u32 num_levels() const { return m_num_levels; }
-    u32 num_layers() const { return m_num_layers; }
     bool width_is_power_of_two() const { return m_width_is_power_of_two; }
     bool height_is_power_of_two() const { return m_height_is_power_of_two; }
     bool depth_is_power_of_two() const { return m_depth_is_power_of_two; }
 
     GPU::ImageDataLayout image_data_layout(u32 level, Vector3<i32> offset) const;
 
-    FloatVector4 texel(u32 layer, u32 level, int x, int y, int z) const
+    FloatVector4 texel(u32 level, int x, int y, int z) const
     {
-        return *texel_pointer(layer, level, x, y, z);
+        return *texel_pointer(level, x, y, z);
     }
 
-    void set_texel(u32 layer, u32 level, int x, int y, int z, FloatVector4 const& color)
+    void set_texel(u32 level, int x, int y, int z, FloatVector4 const& color)
     {
-        *texel_pointer(layer, level, x, y, z) = color;
+        *texel_pointer(level, x, y, z) = color;
     }
 
-    virtual void write_texels(u32 layer, u32 level, Vector3<i32> const& output_offset, void const* input_data, GPU::ImageDataLayout const&) override;
-    virtual void read_texels(u32 layer, u32 level, Vector3<i32> const& input_offset, void* output_data, GPU::ImageDataLayout const&) const override;
-    virtual void copy_texels(GPU::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) override;
+    virtual void write_texels(u32 level, Vector3<i32> const& output_offset, void const* input_data, GPU::ImageDataLayout const&) override;
+    virtual void read_texels(u32 level, Vector3<i32> const& input_offset, void* output_data, GPU::ImageDataLayout const&) const override;
+    virtual void 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) override;
 
-    FloatVector4 const* texel_pointer(u32 layer, u32 level, int x, int y, int z) const
+    FloatVector4 const* texel_pointer(u32 level, int x, int y, int z) const
     {
-        return m_mipmap_buffers[layer * m_num_layers + level]->buffer_pointer(x, y, z);
+        return m_mipmap_buffers[level]->buffer_pointer(x, y, z);
     }
 
-    FloatVector4* texel_pointer(u32 layer, u32 level, int x, int y, int z)
+    FloatVector4* texel_pointer(u32 level, int x, int y, int z)
     {
-        return m_mipmap_buffers[layer * m_num_layers + level]->buffer_pointer(x, y, z);
+        return m_mipmap_buffers[level]->buffer_pointer(x, y, z);
     }
 
 private:
     u32 m_num_levels { 0 };
-    u32 m_num_layers { 0 };
 
     GPU::PixelFormat m_pixel_format;
     FixedArray<RefPtr<Typed3DBuffer<FloatVector4>>> m_mipmap_buffers;

+ 19 - 20
Userland/Libraries/LibSoftGPU/Sampler.cpp

@@ -71,12 +71,12 @@ static f32x4 wrap(f32x4 value, GPU::TextureWrapMode mode, f32x4 num_texels)
     }
 }
 
-ALWAYS_INLINE static Vector4<f32x4> texel4(Image const& image, u32x4 layer, u32x4 level, u32x4 x, u32x4 y, u32x4 z)
+ALWAYS_INLINE static Vector4<f32x4> texel4(Image const& image, u32x4 level, u32x4 x, u32x4 y, u32x4 z)
 {
-    auto t0 = image.texel(layer[0], level[0], x[0], y[0], z[0]);
-    auto t1 = image.texel(layer[1], level[1], x[1], y[1], z[1]);
-    auto t2 = image.texel(layer[2], level[2], x[2], y[2], z[2]);
-    auto t3 = image.texel(layer[3], level[3], x[3], y[3], z[3]);
+    auto t0 = image.texel(level[0], x[0], y[0], z[0]);
+    auto t1 = image.texel(level[1], x[1], y[1], z[1]);
+    auto t2 = image.texel(level[2], x[2], y[2], z[2]);
+    auto t3 = image.texel(level[3], x[3], y[3], z[3]);
 
     return Vector4<f32x4> {
         f32x4 { t0.x(), t1.x(), t2.x(), t3.x() },
@@ -86,14 +86,14 @@ ALWAYS_INLINE static Vector4<f32x4> texel4(Image const& image, u32x4 layer, u32x
     };
 }
 
-ALWAYS_INLINE static Vector4<f32x4> texel4border(Image const& image, u32x4 layer, u32x4 level, u32x4 x, u32x4 y, u32x4 z, FloatVector4 const& border, u32x4 w, u32x4 h)
+ALWAYS_INLINE static Vector4<f32x4> texel4border(Image const& image, u32x4 level, u32x4 x, u32x4 y, u32x4 z, FloatVector4 const& border, u32x4 w, u32x4 h)
 {
     auto border_mask = maskbits(x < 0 || x >= w || y < 0 || y >= h);
 
-    auto t0 = border_mask & 1 ? border : image.texel(layer[0], level[0], x[0], y[0], z[0]);
-    auto t1 = border_mask & 2 ? border : image.texel(layer[1], level[1], x[1], y[1], z[1]);
-    auto t2 = border_mask & 4 ? border : image.texel(layer[2], level[2], x[2], y[2], z[2]);
-    auto t3 = border_mask & 8 ? border : image.texel(layer[3], level[3], x[3], y[3], z[3]);
+    auto t0 = border_mask & 1 ? border : image.texel(level[0], x[0], y[0], z[0]);
+    auto t1 = border_mask & 2 ? border : image.texel(level[1], x[1], y[1], z[1]);
+    auto t2 = border_mask & 4 ? border : image.texel(level[2], x[2], y[2], z[2]);
+    auto t3 = border_mask & 8 ? border : image.texel(level[3], x[3], y[3], z[3]);
 
     return Vector4<f32x4> {
         f32x4 { t0.x(), t1.x(), t2.x(), t3.x() },
@@ -155,7 +155,6 @@ Vector4<AK::SIMD::f32x4> Sampler::sample_2d(Vector2<AK::SIMD::f32x4> const& uv)
 Vector4<AK::SIMD::f32x4> Sampler::sample_2d_lod(Vector2<AK::SIMD::f32x4> const& uv, AK::SIMD::u32x4 level, GPU::TextureFilter filter) const
 {
     auto const& image = *static_ptr_cast<Image>(m_config.bound_image);
-    u32x4 const layer = expand4(0u);
 
     u32x4 const width = {
         image.level_width(level[0]),
@@ -187,7 +186,7 @@ Vector4<AK::SIMD::f32x4> Sampler::sample_2d_lod(Vector2<AK::SIMD::f32x4> const&
         i = image.width_is_power_of_two() ? i & width_mask : i % width;
         j = image.height_is_power_of_two() ? j & height_mask : j % height;
 
-        return texel4(image, layer, level, i, j, k);
+        return texel4(image, level, i, j, k);
     }
 
     u -= 0.5f;
@@ -223,15 +222,15 @@ Vector4<AK::SIMD::f32x4> Sampler::sample_2d_lod(Vector2<AK::SIMD::f32x4> const&
     Vector4<f32x4> t0, t1, t2, t3;
 
     if (m_config.texture_wrap_u == GPU::TextureWrapMode::Repeat && m_config.texture_wrap_v == GPU::TextureWrapMode::Repeat) {
-        t0 = texel4(image, layer, level, i0, j0, k);
-        t1 = texel4(image, layer, level, i1, j0, k);
-        t2 = texel4(image, layer, level, i0, j1, k);
-        t3 = texel4(image, layer, level, i1, j1, k);
+        t0 = texel4(image, level, i0, j0, k);
+        t1 = texel4(image, level, i1, j0, k);
+        t2 = texel4(image, level, i0, j1, k);
+        t3 = texel4(image, level, i1, j1, k);
     } else {
-        t1 = texel4border(image, layer, level, i1, j0, k, m_config.border_color, width, height);
-        t0 = texel4border(image, layer, level, i0, j0, k, m_config.border_color, width, height);
-        t2 = texel4border(image, layer, level, i0, j1, k, m_config.border_color, width, height);
-        t3 = texel4border(image, layer, level, i1, j1, k, m_config.border_color, width, height);
+        t1 = texel4border(image, level, i1, j0, k, m_config.border_color, width, height);
+        t0 = texel4border(image, level, i0, j0, k, m_config.border_color, width, height);
+        t2 = texel4border(image, level, i0, j1, k, m_config.border_color, width, height);
+        t3 = texel4border(image, level, i1, j1, k, m_config.border_color, width, height);
     }
 
     f32x4 const alpha = frac_int_range(u);