GPU: Extract heavier helper functions to own header
Some checks failed
Automated Builds / 💻 Windows (push) Waiting to run
Automated Builds / 🐧 Linux AppImage (push) Waiting to run
Automated Builds / 🐧 Linux Cross-Compiled AppImage (push) Waiting to run
Automated Builds / 🍎 MacOS (push) Waiting to run
Automated Builds / 📤 Create Release (push) Blocked by required conditions
GameDB Lint / gamedb-lint (push) Has been cancelled

This commit is contained in:
Stenzek 2025-12-23 19:55:33 +10:00
parent 095fef524d
commit 56d79c76a7
No known key found for this signature in database
19 changed files with 283 additions and 275 deletions

View File

@ -61,6 +61,7 @@ add_library(core
gpu_commands.cpp
gpu_dump.cpp
gpu_dump.h
gpu_helpers.h
gpu_hw.cpp
gpu_hw.h
gpu_hw_shadergen.cpp

View File

@ -127,6 +127,7 @@
<ClInclude Include="gdb_server.h" />
<ClInclude Include="gpu_backend.h" />
<ClInclude Include="gpu_dump.h" />
<ClInclude Include="gpu_helpers.h" />
<ClInclude Include="gpu_hw_shadergen.h" />
<ClInclude Include="gpu_hw_texture_cache.h" />
<ClInclude Include="gpu_presenter.h" />

View File

@ -157,6 +157,7 @@
<ClInclude Include="core.h" />
<ClInclude Include="core_private.h" />
<ClInclude Include="sound_effect_manager.h" />
<ClInclude Include="gpu_helpers.h" />
</ItemGroup>
<ItemGroup>
<None Include="gpu_sw_rasterizer.inl" />

View File

@ -10,7 +10,7 @@
#include "cpu_core.h"
#include "cpu_core_private.h"
#include "cpu_disasm.h"
#include "gpu_types.h"
#include "gpu_helpers.h"
#include "settings.h"
#include "util/gpu_device.h"

View File

@ -6,6 +6,7 @@
#include "dma.h"
#include "gpu_backend.h"
#include "gpu_dump.h"
#include "gpu_helpers.h"
#include "gpu_hw_texture_cache.h"
#include "gpu_shadergen.h"
#include "gpu_sw_rasterizer.h"

View File

@ -4,12 +4,8 @@
#pragma once
#include "gpu_types.h"
#include "timers.h"
#include "types.h"
#include "util/gpu_device.h"
#include "util/gpu_texture.h"
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/gsvector.h"

View File

@ -5,6 +5,7 @@
#include "gpu.h"
#include "gpu_backend.h"
#include "gpu_dump.h"
#include "gpu_helpers.h"
#include "gpu_thread_commands.h"
#include "interrupt_controller.h"
#include "system.h"

View File

@ -4,6 +4,7 @@
#pragma once
#include "gpu_types.h"
#include "types.h"
#include "common/bitfield.h"
#include "common/file_system.h"

262
src/core/gpu_helpers.h Normal file
View File

@ -0,0 +1,262 @@
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
#include "gpu_types.h"
#include "util/gpu_types.h"
#include "common/bitutils.h"
#include "common/gsvector.h"
ALWAYS_INLINE static constexpr bool TextureModeHasPalette(GPUTextureMode mode)
{
return (mode < GPUTextureMode::Direct16Bit);
}
ALWAYS_INLINE constexpr u32 VRAMRGBA5551ToRGBA8888(u32 color)
{
// Helper/format conversion functions - constants from https://stackoverflow.com/a/9069480
#define E5TO8(color) ((((color) * 527u) + 23u) >> 6)
const u32 r = E5TO8(color & 31u);
const u32 g = E5TO8((color >> 5) & 31u);
const u32 b = E5TO8((color >> 10) & 31u);
const u32 a = ((color >> 15) != 0) ? 255 : 0;
return ZeroExtend32(r) | (ZeroExtend32(g) << 8) | (ZeroExtend32(b) << 16) | (ZeroExtend32(a) << 24);
#undef E5TO8
}
ALWAYS_INLINE constexpr u16 VRAMRGBA8888ToRGBA5551(u32 color)
{
const u32 r = (color & 0xFFu) >> 3;
const u32 g = ((color >> 8) & 0xFFu) >> 3;
const u32 b = ((color >> 16) & 0xFFu) >> 3;
const u32 a = ((color >> 24) & 0x01u);
return Truncate16(r | (g << 5) | (b << 10) | (a << 15));
}
#ifdef CPU_ARCH_SIMD
ALWAYS_INLINE GSVector4i VRAM5BitTo8Bit(GSVector4i val)
{
return val.mul32l(GSVector4i::cxpr(527)).add32(GSVector4i::cxpr(23)).srl32<6>();
}
ALWAYS_INLINE GSVector4i VRAMRGB5A1ToRGBA8888(GSVector4i val)
{
static constexpr GSVector4i cmask = GSVector4i::cxpr(0x1F);
const GSVector4i r = VRAM5BitTo8Bit(val & cmask);
const GSVector4i g = VRAM5BitTo8Bit((val.srl32<5>() & cmask));
const GSVector4i b = VRAM5BitTo8Bit((val.srl32<10>() & cmask));
const GSVector4i a = val.srl32<15>().sll32<31>().sra32<7>();
return r | g.sll32<8>() | b.sll32<16>() | a;
}
template<GPUTextureFormat format>
ALWAYS_INLINE void ConvertVRAMPixels(u8*& dest, GSVector4i c16)
{
if constexpr (format == GPUTextureFormat::RGBA8)
{
const GSVector4i low = VRAMRGB5A1ToRGBA8888(c16.upl16());
const GSVector4i high = VRAMRGB5A1ToRGBA8888(c16.uph16());
GSVector4i::store<false>(dest, low);
dest += sizeof(GSVector4i);
GSVector4i::store<false>(dest, high);
dest += sizeof(GSVector4i);
}
else if constexpr (format == GPUTextureFormat::RGB5A1)
{
static constexpr GSVector4i cmask = GSVector4i::cxpr16(0x1F);
const GSVector4i repacked =
(c16 & GSVector4i::cxpr16(static_cast<s16>(0x83E0))) | (c16.srl16<10>() & cmask) | (c16 & cmask).sll16<10>();
GSVector4i::store<false>(dest, repacked);
dest += sizeof(GSVector4i);
}
else if constexpr (format == GPUTextureFormat::A1BGR5)
{
const GSVector4i repacked = (c16 & GSVector4i::cxpr16(static_cast<s16>(0x3E0))).sll16<1>() |
(c16.srl16<9>() & GSVector4i::cxpr16(0x3E)) |
(c16 & GSVector4i::cxpr16(0x1F)).sll16<11>() | c16.srl16<15>();
GSVector4i::store<false>(dest, repacked);
dest += sizeof(GSVector4i);
}
else if constexpr (format == GPUTextureFormat::RGB565)
{
constexpr GSVector4i single_mask = GSVector4i::cxpr16(0x1F);
const GSVector4i a = (c16 & GSVector4i::cxpr16(0x3E0)).sll16<1>(); // (value & 0x3E0) << 1
const GSVector4i b = (c16 & GSVector4i::cxpr16(0x20)).sll16<1>(); // (value & 0x20) << 1
const GSVector4i c = (c16.srl16<10>() & single_mask); // ((value >> 10) & 0x1F)
const GSVector4i d = (c16 & single_mask).sll16<11>(); // ((value & 0x1F) << 11)
GSVector4i::store<false>(dest, (((a | b) | c) | d));
dest += sizeof(GSVector4i);
}
}
#endif
template<GPUTextureFormat format>
ALWAYS_INLINE void ConvertVRAMPixel(u8*& dest, u16 c16)
{
if constexpr (format == GPUTextureFormat::RGBA8)
{
const u32 c32 = VRAMRGBA5551ToRGBA8888(c16);
std::memcpy(std::assume_aligned<sizeof(c32)>(dest), &c32, sizeof(c32));
dest += sizeof(c32);
}
else if constexpr (format == GPUTextureFormat::RGB5A1)
{
const u16 repacked = (c16 & 0x83E0) | ((c16 >> 10) & 0x1F) | ((c16 & 0x1F) << 10);
std::memcpy(std::assume_aligned<sizeof(repacked)>(dest), &repacked, sizeof(repacked));
dest += sizeof(repacked);
}
else if constexpr (format == GPUTextureFormat::A1BGR5)
{
const u16 repacked = ((c16 & 0x3E0) << 1) | ((c16 >> 9) & 0x3E) | ((c16 & 0x1F) << 11) | (c16 >> 15);
std::memcpy(std::assume_aligned<sizeof(repacked)>(dest), &repacked, sizeof(repacked));
dest += sizeof(repacked);
}
else if constexpr (format == GPUTextureFormat::RGB565)
{
const u16 repacked = ((c16 & 0x3E0) << 1) | ((c16 & 0x20) << 1) | ((c16 >> 10) & 0x1F) | ((c16 & 0x1F) << 11);
std::memcpy(std::assume_aligned<sizeof(repacked)>(dest), &repacked, sizeof(repacked));
dest += sizeof(repacked);
}
}
// Sprites/rectangles should be clipped to 11 bits before drawing.
inline constexpr s32 TruncateGPUVertexPosition(s32 x)
{
return SignExtendN<11, s32>(x);
}
ALWAYS_INLINE constexpr u32 VRAMPageIndex(u32 px, u32 py)
{
return ((py * VRAM_PAGES_WIDE) + px);
}
ALWAYS_INLINE constexpr GSVector4i VRAMPageRect(u32 px, u32 py)
{
return GSVector4i::cxpr(px * VRAM_PAGE_WIDTH, py * VRAM_PAGE_HEIGHT, (px + 1) * VRAM_PAGE_WIDTH,
(py + 1) * VRAM_PAGE_HEIGHT);
}
ALWAYS_INLINE constexpr GSVector4i VRAMPageRect(u32 pn)
{
// TODO: Put page rects in a LUT instead?
return VRAMPageRect(pn % VRAM_PAGES_WIDE, pn / VRAM_PAGES_WIDE);
}
ALWAYS_INLINE constexpr u32 VRAMCoordinateToPage(u32 x, u32 y)
{
return VRAMPageIndex(x / VRAM_PAGE_WIDTH, y / VRAM_PAGE_HEIGHT);
}
ALWAYS_INLINE constexpr u32 VRAMPageStartX(u32 pn)
{
return (pn % VRAM_PAGES_WIDE) * VRAM_PAGE_WIDTH;
}
ALWAYS_INLINE constexpr u32 VRAMPageStartY(u32 pn)
{
return (pn / VRAM_PAGES_WIDE) * VRAM_PAGE_HEIGHT;
}
ALWAYS_INLINE constexpr u8 GetTextureModeShift(GPUTextureMode mode)
{
return ((mode < GPUTextureMode::Direct16Bit) ? (2 - static_cast<u8>(mode)) : 0);
}
ALWAYS_INLINE constexpr u32 ApplyTextureModeShift(GPUTextureMode mode, u32 vram_width)
{
return vram_width << GetTextureModeShift(mode);
}
ALWAYS_INLINE GSVector4i ApplyTextureModeShift(GPUTextureMode mode, const GSVector4i rect)
{
return rect.sll32(GetTextureModeShift(mode));
}
ALWAYS_INLINE constexpr u32 TexturePageCountForMode(GPUTextureMode mode)
{
return ((mode < GPUTextureMode::Direct16Bit) ? (1 + static_cast<u8>(mode)) : 4);
}
ALWAYS_INLINE constexpr u32 TexturePageWidthForMode(GPUTextureMode mode)
{
return TEXTURE_PAGE_WIDTH >> GetTextureModeShift(mode);
}
ALWAYS_INLINE constexpr bool TexturePageIsWrapping(GPUTextureMode mode, u32 pn)
{
return ((VRAMPageStartX(pn) + TexturePageWidthForMode(mode)) > VRAM_WIDTH);
}
ALWAYS_INLINE constexpr u32 PalettePageCountForMode(GPUTextureMode mode)
{
return (mode == GPUTextureMode::Palette4Bit) ? 1 : 4;
}
ALWAYS_INLINE constexpr u32 PalettePageNumber(GPUTexturePaletteReg reg)
{
return VRAMCoordinateToPage(reg.GetXBase(), reg.GetYBase());
}
ALWAYS_INLINE constexpr GSVector4i GetTextureRect(u32 pn, GPUTextureMode mode)
{
u32 left = VRAMPageStartX(pn);
u32 top = VRAMPageStartY(pn);
u32 right = left + TexturePageWidthForMode(mode);
u32 bottom = top + VRAM_PAGE_HEIGHT;
if (right > VRAM_WIDTH) [[unlikely]]
{
left = 0;
right = VRAM_WIDTH;
}
if (bottom > VRAM_HEIGHT) [[unlikely]]
{
top = 0;
bottom = VRAM_HEIGHT;
}
return GSVector4i::cxpr(left, top, right, bottom);
}
ALWAYS_INLINE constexpr GSVector4i GetTextureRectWithoutWrap(u32 pn, GPUTextureMode mode)
{
const u32 left = VRAMPageStartX(pn);
const u32 top = VRAMPageStartY(pn);
const u32 right = std::min<u32>(left + TexturePageWidthForMode(mode), VRAM_WIDTH);
const u32 bottom = top + VRAM_PAGE_HEIGHT;
return GSVector4i::cxpr(left, top, right, bottom);
}
/// Returns the maximum index for a paletted texture.
ALWAYS_INLINE constexpr u32 GetPaletteWidth(GPUTextureMode mode)
{
return (mode == GPUTextureMode::Palette4Bit ? 16 : ((mode == GPUTextureMode::Palette8Bit) ? 256 : 0));
}
/// Returns a rectangle comprising the texture palette area.
ALWAYS_INLINE constexpr GSVector4i GetPaletteRect(GPUTexturePaletteReg palette, GPUTextureMode mode,
bool clamp_instead_of_wrapping = false)
{
const u32 width = GetPaletteWidth(mode);
u32 left = palette.GetXBase();
u32 top = palette.GetYBase();
u32 right = left + width;
u32 bottom = top + 1;
if (right > VRAM_WIDTH) [[unlikely]]
{
right = VRAM_WIDTH;
left = clamp_instead_of_wrapping ? left : 0;
}
return GSVector4i::cxpr(left, top, right, bottom);
}

View File

@ -7,6 +7,7 @@
#include "cpu_pgxp.h"
#include "fullscreenui_widgets.h"
#include "gpu.h"
#include "gpu_helpers.h"
#include "gpu_hw_shadergen.h"
#include "gpu_presenter.h"
#include "gpu_sw_rasterizer.h"

View File

@ -5,6 +5,7 @@
//
#include "gpu_hw_shadergen.h"
#include "gpu_types.h"
#include "common/assert.h"

View File

@ -4,6 +4,7 @@
#include "gpu_hw_texture_cache.h"
#include "fullscreenui_widgets.h"
#include "game_database.h"
#include "gpu_helpers.h"
#include "gpu_hw.h"
#include "gpu_hw_shadergen.h"
#include "gpu_sw_rasterizer.h"

View File

@ -5,6 +5,8 @@
#include "gpu_types.h"
#include "common/gsvector.h"
class Error;
class Image;
class GPUTexture;

View File

@ -3,6 +3,7 @@
#include "gpu_sw.h"
#include "gpu.h"
#include "gpu_helpers.h"
#include "gpu_presenter.h"
#include "gpu_sw_rasterizer.h"
#include "settings.h"

View File

@ -3,6 +3,7 @@
#include "gpu_sw_rasterizer.h"
#include "gpu.h"
#include "gpu_helpers.h"
#include "cpuinfo.h"

View File

@ -97,7 +97,7 @@ namespace {
struct ALIGN_TO_CACHE_LINE State
{
// Owned by CPU thread.
ALIGN_TO_CACHE_LINE Timer::Value thread_spin_time = 0;
Timer::Value thread_spin_time = 0;
Threading::ThreadHandle gpu_thread;
Common::unique_aligned_ptr<u8[]> command_fifo_data;
WindowInfo render_window_info;

View File

@ -1,17 +1,11 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
#include "types.h"
#include "util/gpu_texture.h"
#include "common/bitfield.h"
#include "common/bitutils.h"
#include "common/gsvector.h"
#include <array>
#include "common/types.h"
enum : u32
{
@ -79,11 +73,6 @@ enum class GPUTextureMode : u8
IMPLEMENT_ENUM_CLASS_BITWISE_OPERATORS(GPUTextureMode);
ALWAYS_INLINE static constexpr bool TextureModeHasPalette(GPUTextureMode mode)
{
return (mode < GPUTextureMode::Direct16Bit);
}
enum class GPUTransparencyMode : u8
{
HalfBackgroundPlusHalfForeground = 0,
@ -227,124 +216,6 @@ union GPUSTAT
}
};
ALWAYS_INLINE constexpr u32 VRAMRGBA5551ToRGBA8888(u32 color)
{
// Helper/format conversion functions - constants from https://stackoverflow.com/a/9069480
#define E5TO8(color) ((((color) * 527u) + 23u) >> 6)
const u32 r = E5TO8(color & 31u);
const u32 g = E5TO8((color >> 5) & 31u);
const u32 b = E5TO8((color >> 10) & 31u);
const u32 a = ((color >> 15) != 0) ? 255 : 0;
return ZeroExtend32(r) | (ZeroExtend32(g) << 8) | (ZeroExtend32(b) << 16) | (ZeroExtend32(a) << 24);
#undef E5TO8
}
ALWAYS_INLINE constexpr u16 VRAMRGBA8888ToRGBA5551(u32 color)
{
const u32 r = (color & 0xFFu) >> 3;
const u32 g = ((color >> 8) & 0xFFu) >> 3;
const u32 b = ((color >> 16) & 0xFFu) >> 3;
const u32 a = ((color >> 24) & 0x01u);
return Truncate16(r | (g << 5) | (b << 10) | (a << 15));
}
#ifdef CPU_ARCH_SIMD
ALWAYS_INLINE GSVector4i VRAM5BitTo8Bit(GSVector4i val)
{
return val.mul32l(GSVector4i::cxpr(527)).add32(GSVector4i::cxpr(23)).srl32<6>();
}
ALWAYS_INLINE GSVector4i VRAMRGB5A1ToRGBA8888(GSVector4i val)
{
static constexpr GSVector4i cmask = GSVector4i::cxpr(0x1F);
const GSVector4i r = VRAM5BitTo8Bit(val & cmask);
const GSVector4i g = VRAM5BitTo8Bit((val.srl32<5>() & cmask));
const GSVector4i b = VRAM5BitTo8Bit((val.srl32<10>() & cmask));
const GSVector4i a = val.srl32<15>().sll32<31>().sra32<7>();
return r | g.sll32<8>() | b.sll32<16>() | a;
}
template<GPUTextureFormat format>
ALWAYS_INLINE void ConvertVRAMPixels(u8*& dest, GSVector4i c16)
{
if constexpr (format == GPUTextureFormat::RGBA8)
{
const GSVector4i low = VRAMRGB5A1ToRGBA8888(c16.upl16());
const GSVector4i high = VRAMRGB5A1ToRGBA8888(c16.uph16());
GSVector4i::store<false>(dest, low);
dest += sizeof(GSVector4i);
GSVector4i::store<false>(dest, high);
dest += sizeof(GSVector4i);
}
else if constexpr (format == GPUTextureFormat::RGB5A1)
{
static constexpr GSVector4i cmask = GSVector4i::cxpr16(0x1F);
const GSVector4i repacked =
(c16 & GSVector4i::cxpr16(static_cast<s16>(0x83E0))) | (c16.srl16<10>() & cmask) | (c16 & cmask).sll16<10>();
GSVector4i::store<false>(dest, repacked);
dest += sizeof(GSVector4i);
}
else if constexpr (format == GPUTextureFormat::A1BGR5)
{
const GSVector4i repacked = (c16 & GSVector4i::cxpr16(static_cast<s16>(0x3E0))).sll16<1>() |
(c16.srl16<9>() & GSVector4i::cxpr16(0x3E)) |
(c16 & GSVector4i::cxpr16(0x1F)).sll16<11>() | c16.srl16<15>();
GSVector4i::store<false>(dest, repacked);
dest += sizeof(GSVector4i);
}
else if constexpr (format == GPUTextureFormat::RGB565)
{
constexpr GSVector4i single_mask = GSVector4i::cxpr16(0x1F);
const GSVector4i a = (c16 & GSVector4i::cxpr16(0x3E0)).sll16<1>(); // (value & 0x3E0) << 1
const GSVector4i b = (c16 & GSVector4i::cxpr16(0x20)).sll16<1>(); // (value & 0x20) << 1
const GSVector4i c = (c16.srl16<10>() & single_mask); // ((value >> 10) & 0x1F)
const GSVector4i d = (c16 & single_mask).sll16<11>(); // ((value & 0x1F) << 11)
GSVector4i::store<false>(dest, (((a | b) | c) | d));
dest += sizeof(GSVector4i);
}
}
#endif
template<GPUTextureFormat format>
ALWAYS_INLINE void ConvertVRAMPixel(u8*& dest, u16 c16)
{
if constexpr (format == GPUTextureFormat::RGBA8)
{
const u32 c32 = VRAMRGBA5551ToRGBA8888(c16);
std::memcpy(std::assume_aligned<sizeof(c32)>(dest), &c32, sizeof(c32));
dest += sizeof(c32);
}
else if constexpr (format == GPUTextureFormat::RGB5A1)
{
const u16 repacked = (c16 & 0x83E0) | ((c16 >> 10) & 0x1F) | ((c16 & 0x1F) << 10);
std::memcpy(std::assume_aligned<sizeof(repacked)>(dest), &repacked, sizeof(repacked));
dest += sizeof(repacked);
}
else if constexpr (format == GPUTextureFormat::A1BGR5)
{
const u16 repacked = ((c16 & 0x3E0) << 1) | ((c16 >> 9) & 0x3E) | ((c16 & 0x1F) << 11) | (c16 >> 15);
std::memcpy(std::assume_aligned<sizeof(repacked)>(dest), &repacked, sizeof(repacked));
dest += sizeof(repacked);
}
else if constexpr (format == GPUTextureFormat::RGB565)
{
const u16 repacked = ((c16 & 0x3E0) << 1) | ((c16 & 0x20) << 1) | ((c16 >> 10) & 0x1F) | ((c16 & 0x1F) << 11);
std::memcpy(std::assume_aligned<sizeof(repacked)>(dest), &repacked, sizeof(repacked));
dest += sizeof(repacked);
}
}
union GPUVertexPosition
{
u32 bits;
@ -353,12 +224,6 @@ union GPUVertexPosition
BitField<u32, s32, 16, 11> y;
};
// Sprites/rectangles should be clipped to 11 bits before drawing.
inline constexpr s32 TruncateGPUVertexPosition(s32 x)
{
return SignExtendN<11, s32>(x);
}
// bits in GP0(E1h) or texpage part of polygon
union GPUDrawModeReg
{
@ -416,139 +281,10 @@ union GPUTextureWindow
u32 bits;
ALWAYS_INLINE bool operator==(const GPUTextureWindow& rhs) const
{
return (std::memcmp(this, &rhs, sizeof(*this)) == 0);
}
ALWAYS_INLINE bool operator!=(const GPUTextureWindow& rhs) const
{
return (std::memcmp(this, &rhs, sizeof(*this)) != 0);
}
ALWAYS_INLINE bool operator==(const GPUTextureWindow& rhs) const { return (bits == rhs.bits); }
ALWAYS_INLINE bool operator!=(const GPUTextureWindow& rhs) const { return (bits != rhs.bits); }
};
ALWAYS_INLINE constexpr u32 VRAMPageIndex(u32 px, u32 py)
{
return ((py * VRAM_PAGES_WIDE) + px);
}
ALWAYS_INLINE constexpr GSVector4i VRAMPageRect(u32 px, u32 py)
{
return GSVector4i::cxpr(px * VRAM_PAGE_WIDTH, py * VRAM_PAGE_HEIGHT, (px + 1) * VRAM_PAGE_WIDTH,
(py + 1) * VRAM_PAGE_HEIGHT);
}
ALWAYS_INLINE constexpr GSVector4i VRAMPageRect(u32 pn)
{
// TODO: Put page rects in a LUT instead?
return VRAMPageRect(pn % VRAM_PAGES_WIDE, pn / VRAM_PAGES_WIDE);
}
ALWAYS_INLINE constexpr u32 VRAMCoordinateToPage(u32 x, u32 y)
{
return VRAMPageIndex(x / VRAM_PAGE_WIDTH, y / VRAM_PAGE_HEIGHT);
}
ALWAYS_INLINE constexpr u32 VRAMPageStartX(u32 pn)
{
return (pn % VRAM_PAGES_WIDE) * VRAM_PAGE_WIDTH;
}
ALWAYS_INLINE constexpr u32 VRAMPageStartY(u32 pn)
{
return (pn / VRAM_PAGES_WIDE) * VRAM_PAGE_HEIGHT;
}
ALWAYS_INLINE constexpr u8 GetTextureModeShift(GPUTextureMode mode)
{
return ((mode < GPUTextureMode::Direct16Bit) ? (2 - static_cast<u8>(mode)) : 0);
}
ALWAYS_INLINE constexpr u32 ApplyTextureModeShift(GPUTextureMode mode, u32 vram_width)
{
return vram_width << GetTextureModeShift(mode);
}
ALWAYS_INLINE GSVector4i ApplyTextureModeShift(GPUTextureMode mode, const GSVector4i rect)
{
return rect.sll32(GetTextureModeShift(mode));
}
ALWAYS_INLINE constexpr u32 TexturePageCountForMode(GPUTextureMode mode)
{
return ((mode < GPUTextureMode::Direct16Bit) ? (1 + static_cast<u8>(mode)) : 4);
}
ALWAYS_INLINE constexpr u32 TexturePageWidthForMode(GPUTextureMode mode)
{
return TEXTURE_PAGE_WIDTH >> GetTextureModeShift(mode);
}
ALWAYS_INLINE constexpr bool TexturePageIsWrapping(GPUTextureMode mode, u32 pn)
{
return ((VRAMPageStartX(pn) + TexturePageWidthForMode(mode)) > VRAM_WIDTH);
}
ALWAYS_INLINE constexpr u32 PalettePageCountForMode(GPUTextureMode mode)
{
return (mode == GPUTextureMode::Palette4Bit) ? 1 : 4;
}
ALWAYS_INLINE constexpr u32 PalettePageNumber(GPUTexturePaletteReg reg)
{
return VRAMCoordinateToPage(reg.GetXBase(), reg.GetYBase());
}
ALWAYS_INLINE constexpr GSVector4i GetTextureRect(u32 pn, GPUTextureMode mode)
{
u32 left = VRAMPageStartX(pn);
u32 top = VRAMPageStartY(pn);
u32 right = left + TexturePageWidthForMode(mode);
u32 bottom = top + VRAM_PAGE_HEIGHT;
if (right > VRAM_WIDTH) [[unlikely]]
{
left = 0;
right = VRAM_WIDTH;
}
if (bottom > VRAM_HEIGHT) [[unlikely]]
{
top = 0;
bottom = VRAM_HEIGHT;
}
return GSVector4i::cxpr(left, top, right, bottom);
}
ALWAYS_INLINE constexpr GSVector4i GetTextureRectWithoutWrap(u32 pn, GPUTextureMode mode)
{
const u32 left = VRAMPageStartX(pn);
const u32 top = VRAMPageStartY(pn);
const u32 right = std::min<u32>(left + TexturePageWidthForMode(mode), VRAM_WIDTH);
const u32 bottom = top + VRAM_PAGE_HEIGHT;
return GSVector4i::cxpr(left, top, right, bottom);
}
/// Returns the maximum index for a paletted texture.
ALWAYS_INLINE constexpr u32 GetPaletteWidth(GPUTextureMode mode)
{
return (mode == GPUTextureMode::Palette4Bit ? 16 : ((mode == GPUTextureMode::Palette8Bit) ? 256 : 0));
}
/// Returns a rectangle comprising the texture palette area.
ALWAYS_INLINE constexpr GSVector4i GetPaletteRect(GPUTexturePaletteReg palette, GPUTextureMode mode,
bool clamp_instead_of_wrapping = false)
{
const u32 width = GetPaletteWidth(mode);
u32 left = palette.GetXBase();
u32 top = palette.GetYBase();
u32 right = left + width;
u32 bottom = top + 1;
if (right > VRAM_WIDTH) [[unlikely]]
{
right = VRAM_WIDTH;
left = clamp_instead_of_wrapping ? left : 0;
}
return GSVector4i::cxpr(left, top, right, bottom);
}
// 4x4 dither matrix.
inline constexpr s32 DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE] = {{-4, +0, -3, +1}, // row 0
{+2, -2, +3, -1}, // row 1

View File

@ -20,6 +20,7 @@
#include "settings.h"
#include "spu.h"
#include "system.h"
#include "timers.h"
#include "util/gpu_device.h"
#include "util/imgui_animated.h"

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "memory_card_image.h"
#include "gpu_types.h"
#include "gpu_helpers.h"
#include "system.h"
#include "util/shiftjis.h"