diff options
author | Stephan Unverwerth <s.unverwerth@serenityos.org> | 2022-09-17 17:52:34 +0200 |
---|---|---|
committer | Andrew Kaster <andrewdkaster@gmail.com> | 2022-12-17 22:39:09 -0700 |
commit | b18bf702eab3e3c08faffaac810ae1ac94bbc8fa (patch) | |
tree | 2048cbcf49d069af713a0857527629e171601060 /Userland/Libraries/LibSoftGPU | |
parent | 1e548a84d69dcfba28ca705f2eb9889d0789836b (diff) | |
download | serenity-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.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Device.cpp | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Device.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/ShaderProcessor.cpp | 115 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/ShaderProcessor.h | 46 |
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]; +}; + +} |