/* Copyright (c) 2020 Themaister * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once namespace Vulkan { class Program; class Shader; } namespace RDP { template struct Shaders; using ShaderBank = Shaders; // list of command IDs enum class Op { Nop = 0, MetaSignalTimeline = 1, MetaFlush = 2, MetaIdle = 3, MetaSetQuirks = 4, FillTriangle = 0x08, FillZBufferTriangle = 0x09, TextureTriangle = 0x0a, TextureZBufferTriangle = 0x0b, ShadeTriangle = 0x0c, ShadeZBufferTriangle = 0x0d, ShadeTextureTriangle = 0x0e, ShadeTextureZBufferTriangle = 0x0f, TextureRectangle = 0x24, TextureRectangleFlip = 0x25, SyncLoad = 0x26, SyncPipe = 0x27, SyncTile = 0x28, SyncFull = 0x29, SetKeyGB = 0x2a, SetKeyR = 0x2b, SetConvert = 0x2c, SetScissor = 0x2d, SetPrimDepth = 0x2e, SetOtherModes = 0x2f, LoadTLut = 0x30, SetTileSize = 0x32, LoadBlock = 0x33, LoadTile = 0x34, SetTile = 0x35, FillRectangle = 0x36, SetFillColor = 0x37, SetFogColor = 0x38, SetBlendColor = 0x39, SetPrimColor = 0x3a, SetEnvColor = 0x3b, SetCombine = 0x3c, SetTextureImage = 0x3d, SetMaskImage = 0x3e, SetColorImage = 0x3f }; enum class RGBMul : uint8_t { Combined = 0, Texel0 = 1, Texel1 = 2, Primitive = 3, Shade = 4, Env = 5, KeyScale = 6, CombinedAlpha = 7, Texel0Alpha = 8, Texel1Alpha = 9, PrimitiveAlpha = 10, ShadeAlpha = 11, EnvAlpha = 12, LODFrac = 13, PrimLODFrac = 14, ConvertK5 = 15, Zero = 16 }; enum class RGBMulAdd : uint8_t { Combined = 0, Texel0 = 1, Texel1 = 2, Primitive = 3, Shade = 4, Env = 5, One = 6, Noise = 7, Zero = 8 }; enum class RGBMulSub : uint8_t { Combined = 0, Texel0 = 1, Texel1 = 2, Primitive = 3, Shade = 4, Env = 5, KeyCenter = 6, ConvertK4 = 7, Zero = 8 }; enum class RGBAdd : uint8_t { Combined = 0, Texel0 = 1, Texel1 = 2, Primitive = 3, Shade = 4, Env = 5, One = 6, Zero = 7 }; enum class AlphaAddSub : uint8_t { CombinedAlpha = 0, Texel0Alpha = 1, Texel1Alpha = 2, PrimitiveAlpha = 3, ShadeAlpha = 4, EnvAlpha = 5, One = 6, Zero = 7 }; enum class AlphaMul : uint8_t { LODFrac = 0, Texel0Alpha = 1, Texel1Alpha = 2, PrimitiveAlpha = 3, ShadeAlpha = 4, EnvAlpha = 5, PrimLODFrac = 6, Zero = 7 }; enum class TextureSize : uint8_t { Bpp4 = 0, Bpp8 = 1, Bpp16 = 2, Bpp32 = 3 }; enum class TextureFormat : uint8_t { RGBA = 0, YUV = 1, CI = 2, IA = 3, I = 4 }; enum class RGBDitherMode : uint8_t { Magic = 0, Bayer = 1, Noise = 2, Off = 3 }; enum class AlphaDitherMode : uint8_t { Pattern = 0, InvPattern = 1, Noise = 2, Off = 3 }; enum class CycleType : uint8_t { Cycle1 = 0, Cycle2 = 1, Copy = 2, Fill = 3 }; enum class BlendMode1A : uint8_t { PixelColor = 0, MemoryColor = 1, BlendColor = 2, FogColor = 3 }; enum class BlendMode1B : uint8_t { PixelAlpha = 0, FogAlpha = 1, ShadeAlpha = 2, Zero = 3 }; enum class BlendMode2A : uint8_t { PixelColor = 0, MemoryColor = 1, BlendColor = 2, FogColor = 3 }; enum class BlendMode2B : uint8_t { InvPixelAlpha = 0, MemoryAlpha = 1, One = 2, Zero = 3 }; enum class CoverageMode : uint8_t { Clamp = 0, Wrap = 1, Zap = 2, Save = 3 }; enum class ZMode : uint8_t { Opaque = 0, Interpenetrating = 1, Transparent = 2, Decal = 3 }; enum TileInfoFlagBits { TILE_INFO_CLAMP_S_BIT = 1 << 0, TILE_INFO_MIRROR_S_BIT = 1 << 1, TILE_INFO_CLAMP_T_BIT = 1 << 2, TILE_INFO_MIRROR_T_BIT = 1 << 3 }; using TileInfoFlags = uint8_t; struct TileSize { uint32_t slo = 0; uint32_t shi = 0; uint32_t tlo = 0; uint32_t thi = 0; }; struct TileMeta { uint32_t offset = 0; uint32_t stride = 0; TextureFormat fmt = TextureFormat::RGBA; TextureSize size = TextureSize::Bpp16; uint8_t palette = 0; uint8_t mask_s = 0; uint8_t shift_s = 0; uint8_t mask_t = 0; uint8_t shift_t = 0; TileInfoFlags flags = 0; }; struct TileInfo { TileSize size; TileMeta meta; }; struct CombinerInputsRGB { RGBMulAdd muladd; RGBMulSub mulsub; RGBMul mul; RGBAdd add; }; struct CombinerInputsAlpha { AlphaAddSub muladd; AlphaAddSub mulsub; AlphaMul mul; AlphaAddSub add; }; struct CombinerInputs { CombinerInputsRGB rgb; CombinerInputsAlpha alpha; }; struct BlendModes { BlendMode1A blend_1a; BlendMode1B blend_1b; BlendMode2A blend_2a; BlendMode2B blend_2b; }; static_assert(sizeof(TileInfo) == 32, "TileInfo must be 32 bytes."); enum class VIRegister { Control = 0, Origin, Width, Intr, VCurrentLine, Timing, VSync, HSync, Leap, HStart, VStart, VBurst, XScale, YScale, Count }; enum VIControlFlagBits { VI_CONTROL_TYPE_BLANK_BIT = 0 << 0, VI_CONTROL_TYPE_RESERVED_BIT = 1 << 0, VI_CONTROL_TYPE_RGBA5551_BIT = 2 << 0, VI_CONTROL_TYPE_RGBA8888_BIT = 3 << 0, VI_CONTROL_TYPE_MASK = 3 << 0, VI_CONTROL_GAMMA_DITHER_ENABLE_BIT = 1 << 2, VI_CONTROL_GAMMA_ENABLE_BIT = 1 << 3, VI_CONTROL_DIVOT_ENABLE_BIT = 1 << 4, VI_CONTROL_SERRATE_BIT = 1 << 6, VI_CONTROL_AA_MODE_RESAMP_EXTRA_ALWAYS_BIT = 0 << 8, VI_CONTROL_AA_MODE_RESAMP_EXTRA_BIT = 1 << 8, VI_CONTROL_AA_MODE_RESAMP_ONLY_BIT = 2 << 8, VI_CONTROL_AA_MODE_RESAMP_REPLICATE_BIT = 3 << 8, VI_CONTROL_AA_MODE_MASK = 3 << 8, VI_CONTROL_DITHER_FILTER_ENABLE_BIT = 1 << 16, VI_CONTROL_META_AA_BIT = 1 << 17, VI_CONTROL_META_SCALE_BIT = 1 << 18 }; using VIControlFlags = uint32_t; static inline uint32_t make_vi_start_register(uint32_t start_value, uint32_t end_value) { return ((start_value & 0x3ff) << 16) | (end_value & 0x3ff); } static inline uint32_t make_vi_scale_register(uint32_t scale_factor, uint32_t bias) { return ((bias & 0xfff) << 16) | (scale_factor & 0xfff); } constexpr uint32_t VI_V_SYNC_NTSC = 525; constexpr uint32_t VI_V_SYNC_PAL = 625; constexpr uint32_t VI_H_OFFSET_NTSC = 108; constexpr uint32_t VI_H_OFFSET_PAL = 128; constexpr uint32_t VI_V_OFFSET_NTSC = 34; constexpr uint32_t VI_V_OFFSET_PAL = 44; constexpr uint32_t VI_V_RES_NTSC = 480; constexpr uint32_t VI_V_RES_PAL = 576; constexpr int VI_SCANOUT_WIDTH = 640; constexpr uint32_t VI_V_RES_MAX = VI_V_RES_PAL > VI_V_RES_NTSC ? VI_V_RES_PAL : VI_V_RES_NTSC; // Handle odd v_start as well. Needed for rounding to work in our favor. constexpr uint32_t VI_V_END_PAL = (VI_V_OFFSET_PAL + VI_V_RES_PAL) | 1; constexpr uint32_t VI_V_END_NTSC = (VI_V_OFFSET_NTSC + VI_V_RES_NTSC) | 1; constexpr uint32_t VI_V_END_MAX = VI_V_END_PAL > VI_V_END_NTSC ? VI_V_END_PAL : VI_V_END_NTSC; constexpr uint32_t VI_MAX_OUTPUT_SCANLINES = (VI_V_RES_MAX >> 1); static inline uint32_t make_default_v_start() { return make_vi_start_register(VI_V_OFFSET_NTSC, VI_V_OFFSET_NTSC + 224 * 2); } static inline uint32_t make_default_h_start() { return make_vi_start_register(VI_H_OFFSET_NTSC, VI_H_OFFSET_NTSC + VI_SCANOUT_WIDTH); } template static int32_t sext(int32_t v) { struct { int32_t dummy : bits; } d; d.dummy = v; return d.dummy; } }