diff options
author | Jelle Raaijmakers <jelle@gmta.nl> | 2022-09-04 21:38:39 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-09-11 22:37:07 +0100 |
commit | dda5987684227e31e1d7b2fca749d43f734bfc47 (patch) | |
tree | 0815e577932a70dff260f46adcfc8586314d1850 | |
parent | 44953a430159117fcfbbee6f3e47bfac89f5e215 (diff) | |
download | serenity-dda5987684227e31e1d7b2fca749d43f734bfc47.zip |
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.
-rw-r--r-- | Userland/Libraries/LibGL/Tex/Texture2D.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/Texture.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibGPU/Device.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibGPU/Image.h | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Device.cpp | 11 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Device.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Image.cpp | 27 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Image.h | 26 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Sampler.cpp | 39 |
9 files changed, 54 insertions, 65 deletions
diff --git a/Userland/Libraries/LibGL/Tex/Texture2D.cpp b/Userland/Libraries/LibGL/Tex/Texture2D.cpp index c62d7c465e..1f6c2351d0 100644 --- a/Userland/Libraries/LibGL/Tex/Texture2D.cpp +++ b/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) diff --git a/Userland/Libraries/LibGL/Texture.cpp b/Userland/Libraries/LibGL/Texture.cpp index b0da6554d3..c8f9ff9d77 100644 --- a/Userland/Libraries/LibGL/Texture.cpp +++ b/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; } diff --git a/Userland/Libraries/LibGPU/Device.h b/Userland/Libraries/LibGPU/Device.h index 3c019b68e5..279a1355ce 100644 --- a/Userland/Libraries/LibGPU/Device.h +++ b/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; diff --git a/Userland/Libraries/LibGPU/Image.h b/Userland/Libraries/LibGPU/Image.h index 6c882f59b0..5c9147cf41 100644 --- a/Userland/Libraries/LibGPU/Image.h +++ b/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(); } diff --git a/Userland/Libraries/LibSoftGPU/Device.cpp b/Userland/Libraries/LibSoftGPU/Device.cpp index 0033ba6d87..d0a44f9bad 100644 --- a/Userland/Libraries/LibSoftGPU/Device.cpp +++ b/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) diff --git a/Userland/Libraries/LibSoftGPU/Device.h b/Userland/Libraries/LibSoftGPU/Device.h index c0b839d008..4fd6fcafac 100644 --- a/Userland/Libraries/LibSoftGPU/Device.h +++ b/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; diff --git a/Userland/Libraries/LibSoftGPU/Image.cpp b/Userland/Libraries/LibSoftGPU/Image.cpp index 9332021c48..795fc93206 100644 --- a/Userland/Libraries/LibSoftGPU/Image.cpp +++ b/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); } } } diff --git a/Userland/Libraries/LibSoftGPU/Image.h b/Userland/Libraries/LibSoftGPU/Image.h index 6f92cc3ce5..23c7941155 100644 --- a/Userland/Libraries/LibSoftGPU/Image.h +++ b/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; diff --git a/Userland/Libraries/LibSoftGPU/Sampler.cpp b/Userland/Libraries/LibSoftGPU/Sampler.cpp index 42c6287d0a..b027e99af4 100644 --- a/Userland/Libraries/LibSoftGPU/Sampler.cpp +++ b/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); |