duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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 };