#pragma once #include "gpu.h" #include #include #include class HostDisplayTexture; class GPU_SW final : public GPU { public: GPU_SW(); ~GPU_SW() override; bool IsHardwareRenderer() const override; bool Initialize(HostDisplay* host_display) override; void Reset() override; u16 GetPixel(u32 x, u32 y) const { return m_vram[VRAM_WIDTH * y + x]; } const u16* GetPixelPtr(u32 x, u32 y) const { return &m_vram[VRAM_WIDTH * y + x]; } u16* GetPixelPtr(u32 x, u32 y) { return &m_vram[VRAM_WIDTH * y + x]; } void SetPixel(u32 x, u32 y, u16 value) { m_vram[VRAM_WIDTH * y + x] = value; } // this is actually (31 * 255) >> 4) == 494, but to simplify addressing we use the next power of two (512) static constexpr u32 DITHER_LUT_SIZE = 512; using DitherLUT = std::array, DITHER_MATRIX_SIZE>, DITHER_MATRIX_SIZE>; static constexpr DitherLUT ComputeDitherLUT(); protected: struct SWVertex { s32 x, y; u8 r, g, b; u8 u, v; ALWAYS_INLINE void SetPosition(VertexPosition p, s32 offset_x, s32 offset_y) { x = TruncateVertexPosition(offset_x + p.x); y = TruncateVertexPosition(offset_y + p.y); } ALWAYS_INLINE void SetColorRGB24(u32 color) { std::tie(r, g, b) = UnpackColorRGB24(color); } ALWAYS_INLINE void SetTexcoord(u16 value) { std::tie(u, v) = UnpackTexcoord(value); } }; ////////////////////////////////////////////////////////////////////////// // Scanout ////////////////////////////////////////////////////////////////////////// void CopyOut15Bit(u32 src_x, u32 src_y, u32* dst_ptr, u32 dst_stride, u32 width, u32 height, bool interlaced, bool interleaved); void CopyOut24Bit(u32 src_x, u32 src_y, u32* dst_ptr, u32 dst_stride, u32 width, u32 height, bool interlaced, bool interleaved); void ClearDisplay() override; void UpdateDisplay() override; ////////////////////////////////////////////////////////////////////////// // Rasterization ////////////////////////////////////////////////////////////////////////// void DispatchRenderCommand() override; template void ShadePixel(u32 x, u32 y, u8 color_r, u8 color_g, u8 color_b, u8 texcoord_x, u8 texcoord_y); template void DrawRectangle(s32 origin_x, s32 origin_y, u32 width, u32 height, u8 r, u8 g, u8 b, u8 origin_texcoord_x, u8 origin_texcoord_y); using DrawRectangleFunction = void (GPU_SW::*)(s32 origin_x, s32 origin_y, u32 width, u32 height, u8 r, u8 g, u8 b, u8 origin_texcoord_x, u8 origin_texcoord_y); DrawRectangleFunction GetDrawRectangleFunction(bool texture_enable, bool raw_texture_enable, bool transparency_enable); ////////////////////////////////////////////////////////////////////////// // Polygon and line rasterization ported from Mednafen ////////////////////////////////////////////////////////////////////////// struct i_deltas { u32 du_dx, dv_dx; u32 dr_dx, dg_dx, db_dx; u32 du_dy, dv_dy; u32 dr_dy, dg_dy, db_dy; }; struct i_group { u32 u, v; u32 r, g, b; }; template bool CalcIDeltas(i_deltas& idl, const SWVertex* A, const SWVertex* B, const SWVertex* C); template void AddIDeltas_DX(i_group& ig, const i_deltas& idl, u32 count = 1); template void AddIDeltas_DY(i_group& ig, const i_deltas& idl, u32 count = 1); template void DrawSpan(s32 y, s32 x_start, s32 x_bound, i_group ig, const i_deltas& idl); template void DrawTriangle(const SWVertex* v0, const SWVertex* v1, const SWVertex* v2); using DrawTriangleFunction = void (GPU_SW::*)(const SWVertex* v0, const SWVertex* v1, const SWVertex* v2); DrawTriangleFunction GetDrawTriangleFunction(bool shading_enable, bool texture_enable, bool raw_texture_enable, bool transparency_enable, bool dithering_enable); template void DrawLine(const SWVertex* p0, const SWVertex* p1); using DrawLineFunction = void (GPU_SW::*)(const SWVertex* p0, const SWVertex* p1); DrawLineFunction GetDrawLineFunction(bool shading_enable, bool transparency_enable, bool dithering_enable); std::vector m_display_texture_buffer; std::unique_ptr m_display_texture; std::array m_vram; };