Serenity Operating System
at master 115 lines 4.9 kB view raw
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}