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.
This commit is contained in:
Jelle Raaijmakers 2022-09-04 21:38:39 +02:00 committed by Linus Groh
parent 44953a4301
commit dda5987684
Notes: sideshowbarker 2024-07-17 07:15:38 +09:00
9 changed files with 54 additions and 65 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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(); }

View File

@ -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)

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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);