gpu_sw_backend.h (7603B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "gpu.h" 7 #include "gpu_backend.h" 8 9 #include <array> 10 11 class GPU_SW_Backend final : public GPUBackend 12 { 13 public: 14 GPU_SW_Backend(); 15 ~GPU_SW_Backend() override; 16 17 bool Initialize(bool force_thread) override; 18 void Reset() override; 19 20 ALWAYS_INLINE_RELEASE u16 GetPixel(const u32 x, const u32 y) const { return g_vram[VRAM_WIDTH * y + x]; } 21 ALWAYS_INLINE_RELEASE const u16* GetPixelPtr(const u32 x, const u32 y) const { return &g_vram[VRAM_WIDTH * y + x]; } 22 ALWAYS_INLINE_RELEASE u16* GetPixelPtr(const u32 x, const u32 y) { return &g_vram[VRAM_WIDTH * y + x]; } 23 ALWAYS_INLINE_RELEASE void SetPixel(const u32 x, const u32 y, const u16 value) { g_vram[VRAM_WIDTH * y + x] = value; } 24 25 // this is actually (31 * 255) >> 4) == 494, but to simplify addressing we use the next power of two (512) 26 static constexpr u32 DITHER_LUT_SIZE = 512; 27 using DitherLUT = std::array<std::array<std::array<u8, 512>, DITHER_MATRIX_SIZE>, DITHER_MATRIX_SIZE>; 28 static constexpr DitherLUT ComputeDitherLUT(); 29 30 protected: 31 union VRAMPixel 32 { 33 u16 bits; 34 35 BitField<u16, u8, 0, 5> r; 36 BitField<u16, u8, 5, 5> g; 37 BitField<u16, u8, 10, 5> b; 38 BitField<u16, bool, 15, 1> c; 39 40 void Set(u8 r_, u8 g_, u8 b_, bool c_ = false) 41 { 42 bits = (ZeroExtend16(r_)) | (ZeroExtend16(g_) << 5) | (ZeroExtend16(b_) << 10) | (static_cast<u16>(c_) << 15); 43 } 44 45 void ClampAndSet(u8 r_, u8 g_, u8 b_, bool c_ = false) 46 { 47 Set(std::min<u8>(r_, 0x1F), std::min<u8>(g_, 0x1F), std::min<u8>(b_, 0x1F), c_); 48 } 49 50 void SetRGB24(u32 rgb24, bool c_ = false) 51 { 52 bits = Truncate16(((rgb24 >> 3) & 0x1F) | (((rgb24 >> 11) & 0x1F) << 5) | (((rgb24 >> 19) & 0x1F) << 10)) | 53 (static_cast<u16>(c_) << 15); 54 } 55 56 void SetRGB24(u8 r8, u8 g8, u8 b8, bool c_ = false) 57 { 58 bits = (ZeroExtend16(r8 >> 3)) | (ZeroExtend16(g8 >> 3) << 5) | (ZeroExtend16(b8 >> 3) << 10) | 59 (static_cast<u16>(c_) << 15); 60 } 61 62 void SetRGB24Dithered(u32 x, u32 y, u8 r8, u8 g8, u8 b8, bool c_ = false) 63 { 64 const s32 offset = DITHER_MATRIX[y & 3][x & 3]; 65 r8 = static_cast<u8>(std::clamp<s32>(static_cast<s32>(ZeroExtend32(r8)) + offset, 0, 255)); 66 g8 = static_cast<u8>(std::clamp<s32>(static_cast<s32>(ZeroExtend32(g8)) + offset, 0, 255)); 67 b8 = static_cast<u8>(std::clamp<s32>(static_cast<s32>(ZeroExtend32(b8)) + offset, 0, 255)); 68 SetRGB24(r8, g8, b8, c_); 69 } 70 71 u32 ToRGB24() const 72 { 73 const u32 r_ = ZeroExtend32(r.GetValue()); 74 const u32 g_ = ZeroExtend32(g.GetValue()); 75 const u32 b_ = ZeroExtend32(b.GetValue()); 76 77 return ((r_ << 3) | (r_ & 7)) | (((g_ << 3) | (g_ & 7)) << 8) | (((b_ << 3) | (b_ & 7)) << 16); 78 } 79 }; 80 81 static constexpr std::tuple<u8, u8> UnpackTexcoord(u16 texcoord) 82 { 83 return std::make_tuple(static_cast<u8>(texcoord), static_cast<u8>(texcoord >> 8)); 84 } 85 86 static constexpr std::tuple<u8, u8, u8> UnpackColorRGB24(u32 rgb24) 87 { 88 return std::make_tuple(static_cast<u8>(rgb24), static_cast<u8>(rgb24 >> 8), static_cast<u8>(rgb24 >> 16)); 89 } 90 91 void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color, GPUBackendCommandParameters params) override; 92 void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, GPUBackendCommandParameters params) override; 93 void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height, 94 GPUBackendCommandParameters params) override; 95 96 void DrawPolygon(const GPUBackendDrawPolygonCommand* cmd) override; 97 void DrawLine(const GPUBackendDrawLineCommand* cmd) override; 98 void DrawRectangle(const GPUBackendDrawRectangleCommand* cmd) override; 99 void FlushRender() override; 100 void DrawingAreaChanged() override; 101 void UpdateCLUT(GPUTexturePaletteReg reg, bool clut_is_8bit) override; 102 103 ////////////////////////////////////////////////////////////////////////// 104 // Rasterization 105 ////////////////////////////////////////////////////////////////////////// 106 template<bool texture_enable, bool raw_texture_enable, bool transparency_enable, bool dithering_enable> 107 void ShadePixel(const GPUBackendDrawCommand* cmd, u32 x, u32 y, u8 color_r, u8 color_g, u8 color_b, u8 texcoord_x, 108 u8 texcoord_y); 109 110 template<bool texture_enable, bool raw_texture_enable, bool transparency_enable> 111 void DrawRectangle(const GPUBackendDrawRectangleCommand* cmd); 112 113 using DrawRectangleFunction = void (GPU_SW_Backend::*)(const GPUBackendDrawRectangleCommand* cmd); 114 DrawRectangleFunction GetDrawRectangleFunction(bool texture_enable, bool raw_texture_enable, 115 bool transparency_enable); 116 117 ////////////////////////////////////////////////////////////////////////// 118 // Polygon and line rasterization ported from Mednafen 119 ////////////////////////////////////////////////////////////////////////// 120 struct i_deltas 121 { 122 u32 du_dx, dv_dx; 123 u32 dr_dx, dg_dx, db_dx; 124 125 u32 du_dy, dv_dy; 126 u32 dr_dy, dg_dy, db_dy; 127 }; 128 129 struct i_group 130 { 131 u32 u, v; 132 u32 r, g, b; 133 }; 134 135 template<bool shading_enable, bool texture_enable> 136 bool CalcIDeltas(i_deltas& idl, const GPUBackendDrawPolygonCommand::Vertex* A, 137 const GPUBackendDrawPolygonCommand::Vertex* B, const GPUBackendDrawPolygonCommand::Vertex* C); 138 139 template<bool shading_enable, bool texture_enable> 140 void AddIDeltas_DX(i_group& ig, const i_deltas& idl, u32 count = 1); 141 142 template<bool shading_enable, bool texture_enable> 143 void AddIDeltas_DY(i_group& ig, const i_deltas& idl, u32 count = 1); 144 145 template<bool shading_enable, bool texture_enable, bool raw_texture_enable, bool transparency_enable, 146 bool dithering_enable> 147 void DrawSpan(const GPUBackendDrawPolygonCommand* cmd, s32 y, s32 x_start, s32 x_bound, i_group ig, 148 const i_deltas& idl); 149 150 template<bool shading_enable, bool texture_enable, bool raw_texture_enable, bool transparency_enable, 151 bool dithering_enable> 152 void DrawTriangle(const GPUBackendDrawPolygonCommand* cmd, const GPUBackendDrawPolygonCommand::Vertex* v0, 153 const GPUBackendDrawPolygonCommand::Vertex* v1, const GPUBackendDrawPolygonCommand::Vertex* v2); 154 155 using DrawTriangleFunction = void (GPU_SW_Backend::*)(const GPUBackendDrawPolygonCommand* cmd, 156 const GPUBackendDrawPolygonCommand::Vertex* v0, 157 const GPUBackendDrawPolygonCommand::Vertex* v1, 158 const GPUBackendDrawPolygonCommand::Vertex* v2); 159 DrawTriangleFunction GetDrawTriangleFunction(bool shading_enable, bool texture_enable, bool raw_texture_enable, 160 bool transparency_enable, bool dithering_enable); 161 162 template<bool shading_enable, bool transparency_enable, bool dithering_enable> 163 void DrawLine(const GPUBackendDrawLineCommand* cmd, const GPUBackendDrawLineCommand::Vertex* p0, 164 const GPUBackendDrawLineCommand::Vertex* p1); 165 166 using DrawLineFunction = void (GPU_SW_Backend::*)(const GPUBackendDrawLineCommand* cmd, 167 const GPUBackendDrawLineCommand::Vertex* p0, 168 const GPUBackendDrawLineCommand::Vertex* p1); 169 DrawLineFunction GetDrawLineFunction(bool shading_enable, bool transparency_enable, bool dithering_enable); 170 };