summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibSoftGPU
diff options
context:
space:
mode:
authorStephan Unverwerth <s.unverwerth@serenityos.org>2022-09-17 17:52:34 +0200
committerAndrew Kaster <andrewdkaster@gmail.com>2022-12-17 22:39:09 -0700
commitb18bf702eab3e3c08faffaac810ae1ac94bbc8fa (patch)
tree2048cbcf49d069af713a0857527629e171601060 /Userland/Libraries/LibSoftGPU
parent1e548a84d69dcfba28ca705f2eb9889d0789836b (diff)
downloadserenity-b18bf702eab3e3c08faffaac810ae1ac94bbc8fa.zip
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.
Diffstat (limited to 'Userland/Libraries/LibSoftGPU')
-rw-r--r--Userland/Libraries/LibSoftGPU/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibSoftGPU/Device.cpp6
-rw-r--r--Userland/Libraries/LibSoftGPU/Device.h2
-rw-r--r--Userland/Libraries/LibSoftGPU/ShaderProcessor.cpp115
-rw-r--r--Userland/Libraries/LibSoftGPU/ShaderProcessor.h46
5 files changed, 170 insertions, 0 deletions
diff --git a/Userland/Libraries/LibSoftGPU/CMakeLists.txt b/Userland/Libraries/LibSoftGPU/CMakeLists.txt
index c97b476e30..5ff50c066b 100644
--- a/Userland/Libraries/LibSoftGPU/CMakeLists.txt
+++ b/Userland/Libraries/LibSoftGPU/CMakeLists.txt
@@ -3,6 +3,7 @@ set(SOURCES
Device.cpp
Image.cpp
PixelConverter.cpp
+ ShaderProcessor.cpp
Sampler.cpp
Shader.cpp
)
diff --git a/Userland/Libraries/LibSoftGPU/Device.cpp b/Userland/Libraries/LibSoftGPU/Device.cpp
index 356b078bbe..9d7637d32a 100644
--- a/Userland/Libraries/LibSoftGPU/Device.cpp
+++ b/Userland/Libraries/LibSoftGPU/Device.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);
diff --git a/Userland/Libraries/LibSoftGPU/Device.h b/Userland/Libraries/LibSoftGPU/Device.h
index a7660b0154..92a59b056e 100644
--- a/Userland/Libraries/LibSoftGPU/Device.h
+++ b/Userland/Libraries/LibSoftGPU/Device.h
@@ -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;
};
}
diff --git a/Userland/Libraries/LibSoftGPU/ShaderProcessor.cpp b/Userland/Libraries/LibSoftGPU/ShaderProcessor.cpp
new file mode 100644
index 0000000000..7e9f1d84e9
--- /dev/null
+++ b/Userland/Libraries/LibSoftGPU/ShaderProcessor.cpp
@@ -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
+
+}
diff --git a/Userland/Libraries/LibSoftGPU/ShaderProcessor.h b/Userland/Libraries/LibSoftGPU/ShaderProcessor.h
new file mode 100644
index 0000000000..33bcc29f04
--- /dev/null
+++ b/Userland/Libraries/LibSoftGPU/ShaderProcessor.h
@@ -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];
+};
+
+}