Serenity Operating System
1/*
2 * Copyright (c) 2022, Stephan Unverwerth <s.unverwerth@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibGfx/Vector2.h>
8#include <LibGfx/Vector4.h>
9#include <LibSoftGPU/Shader.h>
10#include <LibSoftGPU/ShaderProcessor.h>
11
12namespace SoftGPU {
13
14using AK::SIMD::f32x4;
15
16void ShaderProcessor::execute(PixelQuad& quad, Shader const& shader)
17{
18 auto& instructions = shader.instructions();
19 for (size_t program_counter = 0; program_counter < instructions.size(); ++program_counter) {
20 auto instruction = instructions[program_counter];
21 switch (instruction.operation) {
22 case Opcode::Input:
23 op_input(quad, instruction.arguments);
24 break;
25 case Opcode::Output:
26 op_output(quad, instruction.arguments);
27 break;
28 case Opcode::Sample2D:
29 op_sample2d(instruction.arguments);
30 break;
31 case Opcode::Swizzle:
32 op_swizzle(instruction.arguments);
33 break;
34 case Opcode::Add:
35 op_add(instruction.arguments);
36 break;
37 case Opcode::Sub:
38 op_sub(instruction.arguments);
39 break;
40 case Opcode::Mul:
41 op_mul(instruction.arguments);
42 break;
43 case Opcode::Div:
44 op_div(instruction.arguments);
45 break;
46 default:
47 VERIFY_NOT_REACHED();
48 }
49 }
50}
51
52void ShaderProcessor::op_input(PixelQuad const& quad, Instruction::Arguments arguments)
53{
54 set_register(arguments.input.target_register, quad.get_input_float(arguments.input.input_index));
55 set_register(arguments.input.target_register + 1, quad.get_input_float(arguments.input.input_index + 1));
56 set_register(arguments.input.target_register + 2, quad.get_input_float(arguments.input.input_index + 2));
57 set_register(arguments.input.target_register + 3, quad.get_input_float(arguments.input.input_index + 3));
58}
59
60void ShaderProcessor::op_output(PixelQuad& quad, Instruction::Arguments arguments)
61{
62 quad.set_output(arguments.output.output_index, get_register(arguments.output.source_register));
63 quad.set_output(arguments.output.output_index + 1, get_register(arguments.output.source_register + 1));
64 quad.set_output(arguments.output.output_index + 2, get_register(arguments.output.source_register + 2));
65 quad.set_output(arguments.output.output_index + 3, get_register(arguments.output.source_register + 3));
66}
67
68void ShaderProcessor::op_sample2d(Instruction::Arguments arguments)
69{
70 Vector2<AK::SIMD::f32x4> coordinates = {
71 get_register(arguments.sample.coordinates_register),
72 get_register(arguments.sample.coordinates_register + 1),
73 };
74 auto sample = m_samplers[arguments.sample.sampler_index].sample_2d(coordinates);
75 set_register(arguments.sample.target_register, sample.x());
76 set_register(arguments.sample.target_register + 1, sample.y());
77 set_register(arguments.sample.target_register + 2, sample.z());
78 set_register(arguments.sample.target_register + 3, sample.w());
79}
80
81void ShaderProcessor::op_swizzle(Instruction::Arguments arguments)
82{
83 f32x4 inputs[] {
84 get_register(arguments.swizzle.source_register),
85 get_register(arguments.swizzle.source_register + 1),
86 get_register(arguments.swizzle.source_register + 2),
87 get_register(arguments.swizzle.source_register + 3)
88 };
89
90 set_register(arguments.swizzle.target_register, inputs[swizzle_index(arguments.swizzle.pattern, 0)]);
91 set_register(arguments.swizzle.target_register + 1, inputs[swizzle_index(arguments.swizzle.pattern, 1)]);
92 set_register(arguments.swizzle.target_register + 2, inputs[swizzle_index(arguments.swizzle.pattern, 2)]);
93 set_register(arguments.swizzle.target_register + 3, inputs[swizzle_index(arguments.swizzle.pattern, 3)]);
94}
95
96#define SHADER_BINOP(NAME, OP) \
97 void ShaderProcessor::op_##NAME(Instruction::Arguments arguments) \
98 { \
99 auto const target = arguments.binop.target_register; \
100 auto const source1 = arguments.binop.source_register1; \
101 auto const source2 = arguments.binop.source_register2; \
102 set_register(target, get_register(source1) OP get_register(source2)); \
103 set_register(target + 1, get_register(source1 + 1) OP get_register(source2 + 1)); \
104 set_register(target + 2, get_register(source1 + 2) OP get_register(source2 + 2)); \
105 set_register(target + 3, get_register(source1 + 3) OP get_register(source2 + 3)); \
106 }
107
108SHADER_BINOP(add, +)
109SHADER_BINOP(sub, -)
110SHADER_BINOP(mul, *)
111SHADER_BINOP(div, /)
112
113#undef SHADER_BINOP
114
115}