mirror of
https://github.com/RGBCube/serenity
synced 2025-07-17 07:27:35 +00:00
LibSoftGPU: Add device method for creating images
This commit is contained in:
parent
91ccf9958f
commit
b8bb72abbe
5 changed files with 192 additions and 0 deletions
|
@ -3,6 +3,7 @@ set(SOURCES
|
|||
DepthBuffer.cpp
|
||||
Device.cpp
|
||||
Image.cpp
|
||||
Sampler.cpp
|
||||
)
|
||||
|
||||
serenity_lib(LibSoftGPU softgpu)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
119
Userland/Libraries/LibSoftGPU/Sampler.cpp
Normal file
119
Userland/Libraries/LibSoftGPU/Sampler.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
56
Userland/Libraries/LibSoftGPU/Sampler.h
Normal file
56
Userland/Libraries/LibSoftGPU/Sampler.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue