diff options
author | Stephan Unverwerth <s.unverwerth@serenityos.org> | 2021-12-19 00:02:32 +0100 |
---|---|---|
committer | Brian Gianforcaro <b.gianfo@gmail.com> | 2021-12-24 05:10:28 -0800 |
commit | b8bb72abbe66fa1e4ad5e4b197347e481e68f4bc (patch) | |
tree | e3e6bcf560983642f1fcaaa2414f4060c108f755 | |
parent | 91ccf9958ff2be4026b9bfa21a2a3fa52fc7f265 (diff) | |
download | serenity-b8bb72abbe66fa1e4ad5e4b197347e481e68f4bc.zip |
LibSoftGPU: Add device method for creating images
-rw-r--r-- | Userland/Libraries/LibSoftGPU/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Device.cpp | 11 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Device.h | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Sampler.cpp | 119 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Sampler.h | 56 |
5 files changed, 192 insertions, 0 deletions
diff --git a/Userland/Libraries/LibSoftGPU/CMakeLists.txt b/Userland/Libraries/LibSoftGPU/CMakeLists.txt index b2870d3cb2..11e603e1b8 100644 --- a/Userland/Libraries/LibSoftGPU/CMakeLists.txt +++ b/Userland/Libraries/LibSoftGPU/CMakeLists.txt @@ -3,6 +3,7 @@ set(SOURCES DepthBuffer.cpp Device.cpp Image.cpp + Sampler.cpp ) serenity_lib(LibSoftGPU softgpu) diff --git a/Userland/Libraries/LibSoftGPU/Device.cpp b/Userland/Libraries/LibSoftGPU/Device.cpp index 9c39ba01a4..e678c2db0d 100644 --- a/Userland/Libraries/LibSoftGPU/Device.cpp +++ b/Userland/Libraries/LibSoftGPU/Device.cpp @@ -801,4 +801,15 @@ float Device::get_depthbuffer_value(int x, int y) return m_depth_buffer->scanline(y)[x]; } +NonnullRefPtr<Image> Device::create_image(ImageFormat format, unsigned width, unsigned height, unsigned depth, unsigned levels, unsigned layers) +{ + VERIFY(width > 0); + VERIFY(height > 0); + VERIFY(depth > 0); + VERIFY(levels > 0); + VERIFY(layers > 0); + + return adopt_ref(*new Image(format, width, height, depth, levels, layers)); +} + } diff --git a/Userland/Libraries/LibSoftGPU/Device.h b/Userland/Libraries/LibSoftGPU/Device.h index 2835588882..789eb5ea9a 100644 --- a/Userland/Libraries/LibSoftGPU/Device.h +++ b/Userland/Libraries/LibSoftGPU/Device.h @@ -7,6 +7,7 @@ #pragma once #include <AK/Array.h> +#include <AK/NonnullRefPtr.h> #include <AK/OwnPtr.h> #include <LibGL/GL/gl.h> #include <LibGL/Tex/Texture2D.h> @@ -17,6 +18,8 @@ #include <LibGfx/Vector4.h> #include <LibSoftGPU/Clipper.h> #include <LibSoftGPU/DepthBuffer.h> +#include <LibSoftGPU/Image.h> +#include <LibSoftGPU/ImageFormat.h> #include <LibSoftGPU/Triangle.h> #include <LibSoftGPU/Vertex.h> @@ -74,6 +77,8 @@ public: Gfx::RGBA32 get_backbuffer_pixel(int x, int y); float get_depthbuffer_value(int x, int y); + NonnullRefPtr<Image> create_image(ImageFormat, unsigned width, unsigned height, unsigned depth, unsigned levels, unsigned layers); + private: void submit_triangle(Triangle const& triangle, GL::TextureUnit::BoundList const& bound_texture_units); diff --git a/Userland/Libraries/LibSoftGPU/Sampler.cpp b/Userland/Libraries/LibSoftGPU/Sampler.cpp new file mode 100644 index 0000000000..fe6b5db98a --- /dev/null +++ b/Userland/Libraries/LibSoftGPU/Sampler.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibSoftGPU/Image.h> +#include <LibSoftGPU/Sampler.h> +#include <math.h> + +namespace SoftGPU { + +constexpr static float fracf(float value) +{ + return value - floorf(value); +} + +constexpr static float wrap_repeat(float value) +{ + return fracf(value); +} + +static constexpr float wrap_clamp(float value) +{ + return clamp(value, 0.0f, 1.0f); +} + +static constexpr float wrap_clamp_to_edge(float value, unsigned num_texels) +{ + float const clamp_limit = 1.f / (2 * num_texels); + return clamp(value, clamp_limit, 1.0f - clamp_limit); +} + +static constexpr float wrap_mirrored_repeat(float value, unsigned num_texels) +{ + float integer = floorf(value); + float frac = value - integer; + bool iseven = fmodf(integer, 2.0f) == 0.0f; + return wrap_clamp_to_edge(iseven ? frac : 1 - frac, num_texels); +} + +constexpr static float wrap(float value, TextureWrapMode mode, unsigned num_texels) +{ + switch (mode) { + case TextureWrapMode::Repeat: + return wrap_repeat(value); + case TextureWrapMode::MirroredRepeat: + return wrap_mirrored_repeat(value, num_texels); + case TextureWrapMode::Clamp: + return wrap_clamp(value); + case TextureWrapMode::ClampToBorder: + case TextureWrapMode::ClampToEdge: + return wrap_clamp_to_edge(value, num_texels); + default: + VERIFY_NOT_REACHED(); + } +} + +FloatVector4 Sampler::sample_2d(FloatVector2 const& uv) const +{ + if (m_config.bound_image.is_null()) + return { 0, 0, 0, 1 }; + + auto const& image = *m_config.bound_image; + + unsigned const layer = 0; + // FIXME: calculate actual mipmap level to use + unsigned const level = 0; + + unsigned width = image.level_width(level); + unsigned height = image.level_height(level); + + float s = wrap(uv.x(), m_config.texture_wrap_u, width); + float t = wrap(uv.y(), m_config.texture_wrap_v, height); + + float u = s * width; + float v = t * height; + + if (m_config.texture_mag_filter == TextureFilter::Nearest) { + unsigned i = min(static_cast<unsigned>(u), width - 1); + unsigned j = min(static_cast<unsigned>(v), height - 1); + return image.texel(layer, level, i, j, 0); + } + + int i0 = m_config.texture_wrap_u == TextureWrapMode::Repeat ? static_cast<unsigned>(floorf(u - 0.5f)) % width : floorf(u - 0.5f); + int j0 = m_config.texture_wrap_v == TextureWrapMode::Repeat ? static_cast<unsigned>(floorf(v - 0.5f)) % height : floorf(v - 0.5f); + + int i1 = m_config.texture_wrap_u == TextureWrapMode::Repeat ? (i0 + 1) % width : i0 + 1; + int j1 = m_config.texture_wrap_v == TextureWrapMode::Repeat ? (j0 + 1) % height : j0 + 1; + + FloatVector4 t0, t1, t2, t3; + + if (m_config.texture_wrap_u == TextureWrapMode::Repeat && m_config.texture_wrap_v == TextureWrapMode::Repeat) { + t0 = image.texel(layer, level, i0, j0, 0); + t1 = image.texel(layer, level, i1, j0, 0); + t2 = image.texel(layer, level, i0, j1, 0); + t3 = image.texel(layer, level, i1, j1, 0); + } else { + int w = static_cast<int>(width); + int h = static_cast<int>(height); + t0 = (i0 < 0 || i0 >= w || j0 < 0 || j0 >= h) ? m_config.border_color : image.texel(layer, level, i0, j0, 0); + t1 = (i1 < 0 || i1 >= w || j0 < 0 || j0 >= h) ? m_config.border_color : image.texel(layer, level, i1, j0, 0); + t2 = (i0 < 0 || i0 >= w || j1 < 0 || j1 >= h) ? m_config.border_color : image.texel(layer, level, i0, j1, 0); + t3 = (i1 < 0 || i1 >= w || j1 < 0 || j1 >= h) ? m_config.border_color : image.texel(layer, level, i1, j1, 0); + } + + float alpha = fracf(u - 0.5f); + float beta = fracf(v - 0.5f); + + float one_minus_alpha = 1 - alpha; + float one_minus_beta = 1 - beta; + + auto lerp_0 = t0 * one_minus_alpha + t1 * alpha; + auto lerp_1 = t2 * one_minus_alpha + t3 * alpha; + + return lerp_0 * one_minus_beta + lerp_1 * beta; +} + +} diff --git a/Userland/Libraries/LibSoftGPU/Sampler.h b/Userland/Libraries/LibSoftGPU/Sampler.h new file mode 100644 index 0000000000..66335735c6 --- /dev/null +++ b/Userland/Libraries/LibSoftGPU/Sampler.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/RefPtr.h> +#include <LibGfx/Vector2.h> +#include <LibGfx/Vector4.h> +#include <LibSoftGPU/Image.h> + +namespace SoftGPU { + +enum class TextureFilter { + Nearest, + Linear, +}; + +enum class MipMapFilter { + None, + Nearest, + Linear, +}; + +enum class TextureWrapMode { + Repeat, + MirroredRepeat, + Clamp, + ClampToBorder, + ClampToEdge, +}; + +struct SamplerConfig final { + RefPtr<Image> bound_image; + MipMapFilter mipmap_filter { MipMapFilter::Nearest }; + TextureFilter texture_mag_filter { TextureFilter::Linear }; + TextureFilter texture_min_filter { TextureFilter::Linear }; + TextureWrapMode texture_wrap_u { TextureWrapMode::Repeat }; + TextureWrapMode texture_wrap_v { TextureWrapMode::Repeat }; + TextureWrapMode texture_wrap_w { TextureWrapMode::Repeat }; + FloatVector4 border_color { 0, 0, 0, 1 }; +}; + +class Sampler final { +public: + FloatVector4 sample_2d(FloatVector2 const& uv) const; + + void set_config(SamplerConfig const& config) { m_config = config; } + +private: + SamplerConfig m_config; +}; + +} |