mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-03 21:10:30 +00:00
LibSoftGPU: Implement shader processor for SoftGPU ISA
This adds a shader processor that executes our ISA when a fragment shader is currently bound to the device.
This commit is contained in:
parent
1e548a84d6
commit
b18bf702ea
Notes:
sideshowbarker
2024-07-17 03:01:14 +09:00
Author: https://github.com/sunverwerth Commit: https://github.com/SerenityOS/serenity/commit/b18bf702ea Pull-request: https://github.com/SerenityOS/serenity/pull/16225 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/gmta ✅ Reviewed-by: https://github.com/supercomputer7
5 changed files with 170 additions and 0 deletions
|
@ -3,6 +3,7 @@ set(SOURCES
|
|||
Device.cpp
|
||||
Image.cpp
|
||||
PixelConverter.cpp
|
||||
ShaderProcessor.cpp
|
||||
Sampler.cpp
|
||||
Shader.cpp
|
||||
)
|
||||
|
|
|
@ -829,6 +829,7 @@ void Device::rasterize_triangle(Triangle& triangle)
|
|||
|
||||
Device::Device(Gfx::IntSize size)
|
||||
: m_frame_buffer(FrameBuffer<GPU::ColorType, GPU::DepthType, GPU::StencilType>::try_create(size).release_value_but_fixme_should_propagate_errors())
|
||||
, m_shader_processor(m_samplers)
|
||||
{
|
||||
m_options.scissor_box = m_frame_buffer->rect();
|
||||
m_options.viewport = m_frame_buffer->rect();
|
||||
|
@ -1211,6 +1212,11 @@ void Device::draw_primitives(GPU::PrimitiveType primitive_type, FloatMatrix4x4 c
|
|||
|
||||
ALWAYS_INLINE void Device::shade_fragments(PixelQuad& quad)
|
||||
{
|
||||
if (m_current_fragment_shader) {
|
||||
m_shader_processor.execute(quad, *m_current_fragment_shader);
|
||||
return;
|
||||
}
|
||||
|
||||
Array<Vector4<f32x4>, GPU::NUM_TEXTURE_UNITS> texture_stage_texel;
|
||||
|
||||
auto current_color = quad.get_input_vector4(SHADER_INPUT_VERTEX_COLOR);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <LibSoftGPU/Config.h>
|
||||
#include <LibSoftGPU/Sampler.h>
|
||||
#include <LibSoftGPU/Shader.h>
|
||||
#include <LibSoftGPU/ShaderProcessor.h>
|
||||
#include <LibSoftGPU/Triangle.h>
|
||||
|
||||
namespace SoftGPU {
|
||||
|
@ -120,6 +121,7 @@ private:
|
|||
Array<GPU::StencilConfiguration, 2u> m_stencil_configuration;
|
||||
Array<GPU::TextureUnitConfiguration, GPU::NUM_TEXTURE_UNITS> m_texture_unit_configuration;
|
||||
RefPtr<Shader> m_current_fragment_shader;
|
||||
ShaderProcessor m_shader_processor;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
115
Userland/Libraries/LibSoftGPU/ShaderProcessor.cpp
Normal file
115
Userland/Libraries/LibSoftGPU/ShaderProcessor.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Stephan Unverwerth <s.unverwerth@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGfx/Vector2.h>
|
||||
#include <LibGfx/Vector4.h>
|
||||
#include <LibSoftGPU/Shader.h>
|
||||
#include <LibSoftGPU/ShaderProcessor.h>
|
||||
|
||||
namespace SoftGPU {
|
||||
|
||||
using AK::SIMD::f32x4;
|
||||
|
||||
void ShaderProcessor::execute(PixelQuad& quad, Shader const& shader)
|
||||
{
|
||||
auto& instructions = shader.instructions();
|
||||
for (size_t program_counter = 0; program_counter < instructions.size(); ++program_counter) {
|
||||
auto instruction = instructions[program_counter];
|
||||
switch (instruction.operation) {
|
||||
case Opcode::Input:
|
||||
op_input(quad, instruction.arguments);
|
||||
break;
|
||||
case Opcode::Output:
|
||||
op_output(quad, instruction.arguments);
|
||||
break;
|
||||
case Opcode::Sample2D:
|
||||
op_sample2d(instruction.arguments);
|
||||
break;
|
||||
case Opcode::Swizzle:
|
||||
op_swizzle(instruction.arguments);
|
||||
break;
|
||||
case Opcode::Add:
|
||||
op_add(instruction.arguments);
|
||||
break;
|
||||
case Opcode::Sub:
|
||||
op_sub(instruction.arguments);
|
||||
break;
|
||||
case Opcode::Mul:
|
||||
op_mul(instruction.arguments);
|
||||
break;
|
||||
case Opcode::Div:
|
||||
op_div(instruction.arguments);
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderProcessor::op_input(PixelQuad const& quad, Instruction::Arguments arguments)
|
||||
{
|
||||
set_register(arguments.input.target_register, quad.get_input_float(arguments.input.input_index));
|
||||
set_register(arguments.input.target_register + 1, quad.get_input_float(arguments.input.input_index + 1));
|
||||
set_register(arguments.input.target_register + 2, quad.get_input_float(arguments.input.input_index + 2));
|
||||
set_register(arguments.input.target_register + 3, quad.get_input_float(arguments.input.input_index + 3));
|
||||
}
|
||||
|
||||
void ShaderProcessor::op_output(PixelQuad& quad, Instruction::Arguments arguments)
|
||||
{
|
||||
quad.set_output(arguments.output.output_index, get_register(arguments.output.source_register));
|
||||
quad.set_output(arguments.output.output_index + 1, get_register(arguments.output.source_register + 1));
|
||||
quad.set_output(arguments.output.output_index + 2, get_register(arguments.output.source_register + 2));
|
||||
quad.set_output(arguments.output.output_index + 3, get_register(arguments.output.source_register + 3));
|
||||
}
|
||||
|
||||
void ShaderProcessor::op_sample2d(Instruction::Arguments arguments)
|
||||
{
|
||||
Vector2<AK::SIMD::f32x4> coordinates = {
|
||||
get_register(arguments.sample.coordinates_register),
|
||||
get_register(arguments.sample.coordinates_register + 1),
|
||||
};
|
||||
auto sample = m_samplers[arguments.sample.sampler_index].sample_2d(coordinates);
|
||||
set_register(arguments.sample.target_register, sample.x());
|
||||
set_register(arguments.sample.target_register + 1, sample.y());
|
||||
set_register(arguments.sample.target_register + 2, sample.z());
|
||||
set_register(arguments.sample.target_register + 3, sample.w());
|
||||
}
|
||||
|
||||
void ShaderProcessor::op_swizzle(Instruction::Arguments arguments)
|
||||
{
|
||||
f32x4 inputs[] {
|
||||
get_register(arguments.swizzle.source_register),
|
||||
get_register(arguments.swizzle.source_register + 1),
|
||||
get_register(arguments.swizzle.source_register + 2),
|
||||
get_register(arguments.swizzle.source_register + 3)
|
||||
};
|
||||
|
||||
set_register(arguments.swizzle.target_register, inputs[swizzle_index(arguments.swizzle.pattern, 0)]);
|
||||
set_register(arguments.swizzle.target_register + 1, inputs[swizzle_index(arguments.swizzle.pattern, 1)]);
|
||||
set_register(arguments.swizzle.target_register + 2, inputs[swizzle_index(arguments.swizzle.pattern, 2)]);
|
||||
set_register(arguments.swizzle.target_register + 3, inputs[swizzle_index(arguments.swizzle.pattern, 3)]);
|
||||
}
|
||||
|
||||
#define SHADER_BINOP(NAME, OP) \
|
||||
void ShaderProcessor::op_##NAME(Instruction::Arguments arguments) \
|
||||
{ \
|
||||
auto const target = arguments.binop.target_register; \
|
||||
auto const source1 = arguments.binop.source_register1; \
|
||||
auto const source2 = arguments.binop.source_register2; \
|
||||
set_register(target, get_register(source1) OP get_register(source2)); \
|
||||
set_register(target + 1, get_register(source1 + 1) OP get_register(source2 + 1)); \
|
||||
set_register(target + 2, get_register(source1 + 2) OP get_register(source2 + 2)); \
|
||||
set_register(target + 3, get_register(source1 + 3) OP get_register(source2 + 3)); \
|
||||
}
|
||||
|
||||
SHADER_BINOP(add, +)
|
||||
SHADER_BINOP(sub, -)
|
||||
SHADER_BINOP(mul, *)
|
||||
SHADER_BINOP(div, /)
|
||||
|
||||
#undef SHADER_BINOP
|
||||
|
||||
}
|
46
Userland/Libraries/LibSoftGPU/ShaderProcessor.h
Normal file
46
Userland/Libraries/LibSoftGPU/ShaderProcessor.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Stephan Unverwerth <s.unverwerth@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/SIMD.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGPU/Config.h>
|
||||
#include <LibSoftGPU/PixelQuad.h>
|
||||
#include <LibSoftGPU/Sampler.h>
|
||||
|
||||
namespace SoftGPU {
|
||||
|
||||
class Shader;
|
||||
|
||||
class ShaderProcessor final {
|
||||
public:
|
||||
ShaderProcessor(Array<Sampler, GPU::NUM_TEXTURE_UNITS>& samplers)
|
||||
: m_samplers { samplers }
|
||||
{
|
||||
}
|
||||
|
||||
void execute(PixelQuad&, Shader const&);
|
||||
|
||||
ALWAYS_INLINE AK::SIMD::f32x4 get_register(u16 index) const { return m_registers[index]; }
|
||||
ALWAYS_INLINE void set_register(u16 index, AK::SIMD::f32x4 value) { m_registers[index] = value; }
|
||||
|
||||
private:
|
||||
void op_input(PixelQuad const&, Instruction::Arguments);
|
||||
void op_output(PixelQuad&, Instruction::Arguments);
|
||||
void op_sample2d(Instruction::Arguments);
|
||||
void op_swizzle(Instruction::Arguments);
|
||||
void op_add(Instruction::Arguments);
|
||||
void op_sub(Instruction::Arguments);
|
||||
void op_mul(Instruction::Arguments);
|
||||
void op_div(Instruction::Arguments);
|
||||
|
||||
Array<Sampler, GPU::NUM_TEXTURE_UNITS>& m_samplers;
|
||||
AK::SIMD::f32x4 m_registers[1024];
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in a new issue