2019-09-11 04:01:19 +00:00
|
|
|
#pragma once
|
|
|
|
#include "common/bitfield.h"
|
|
|
|
#include "types.h"
|
|
|
|
#include <array>
|
2019-09-13 16:07:31 +00:00
|
|
|
#include <deque>
|
|
|
|
#include <vector>
|
2019-09-11 04:01:19 +00:00
|
|
|
|
2019-09-14 10:28:47 +00:00
|
|
|
class StateWrapper;
|
|
|
|
|
2019-09-12 14:18:13 +00:00
|
|
|
class System;
|
2019-09-11 04:01:19 +00:00
|
|
|
class DMA;
|
2019-09-17 14:22:41 +00:00
|
|
|
class InterruptController;
|
2019-09-11 04:01:19 +00:00
|
|
|
|
|
|
|
class GPU
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
GPU();
|
2019-09-12 02:53:04 +00:00
|
|
|
virtual ~GPU();
|
2019-09-11 04:01:19 +00:00
|
|
|
|
2019-09-17 14:22:41 +00:00
|
|
|
virtual bool Initialize(System* system, DMA* dma, InterruptController* interrupt_controller);
|
2019-09-12 02:53:04 +00:00
|
|
|
virtual void Reset();
|
2019-09-14 10:28:47 +00:00
|
|
|
virtual bool DoState(StateWrapper& sw);
|
2019-09-11 04:01:19 +00:00
|
|
|
|
|
|
|
u32 ReadRegister(u32 offset);
|
|
|
|
void WriteRegister(u32 offset, u32 value);
|
|
|
|
|
2019-09-11 04:59:41 +00:00
|
|
|
// DMA access
|
|
|
|
u32 DMARead();
|
|
|
|
void DMAWrite(u32 value);
|
|
|
|
|
2019-09-12 02:53:04 +00:00
|
|
|
// gpu_hw_opengl.cpp
|
|
|
|
static std::unique_ptr<GPU> CreateHardwareOpenGLRenderer();
|
|
|
|
|
2019-09-17 04:25:25 +00:00
|
|
|
void Execute(TickCount ticks);
|
2019-09-14 13:49:55 +00:00
|
|
|
|
2019-09-12 02:53:04 +00:00
|
|
|
protected:
|
|
|
|
static constexpr u32 VRAM_WIDTH = 1024;
|
|
|
|
static constexpr u32 VRAM_HEIGHT = 512;
|
|
|
|
static constexpr u32 VRAM_SIZE = VRAM_WIDTH * VRAM_HEIGHT * sizeof(u16);
|
2019-09-13 16:07:31 +00:00
|
|
|
static constexpr u32 TEXTURE_PAGE_WIDTH = 256;
|
|
|
|
static constexpr u32 TEXTURE_PAGE_HEIGHT = 256;
|
2019-09-12 02:53:04 +00:00
|
|
|
|
|
|
|
static constexpr s32 S11ToS32(u32 value)
|
|
|
|
{
|
|
|
|
if (value & (UINT16_C(1) << 10))
|
|
|
|
return static_cast<s32>(UINT32_C(0xFFFFF800) | value);
|
|
|
|
else
|
|
|
|
return value;
|
|
|
|
}
|
2019-09-11 06:04:31 +00:00
|
|
|
|
2019-09-18 05:43:25 +00:00
|
|
|
// Helper/format conversion functions.
|
|
|
|
static constexpr u32 RGBA5551ToRGBA8888(u16 color)
|
|
|
|
{
|
|
|
|
u8 r = Truncate8(color & 31);
|
|
|
|
u8 g = Truncate8((color >> 5) & 31);
|
|
|
|
u8 b = Truncate8((color >> 10) & 31);
|
|
|
|
u8 a = Truncate8((color >> 15) & 1);
|
|
|
|
|
|
|
|
// 00012345 -> 1234545
|
|
|
|
b = (b << 3) | (b & 0b111);
|
|
|
|
g = (g << 3) | (g & 0b111);
|
|
|
|
r = (r << 3) | (r & 0b111);
|
|
|
|
a = a ? 255 : 0;
|
|
|
|
|
|
|
|
return ZeroExtend32(r) | (ZeroExtend32(g) << 8) | (ZeroExtend32(b) << 16) | (ZeroExtend32(a) << 24);
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr u16 RGBA8888ToRGBA5551(u32 color)
|
|
|
|
{
|
|
|
|
const u16 r = Truncate16((color >> 3) & 0x1Fu);
|
|
|
|
const u16 g = Truncate16((color >> 11) & 0x1Fu);
|
|
|
|
const u16 b = Truncate16((color >> 19) & 0x1Fu);
|
|
|
|
const u16 a = Truncate16((color >> 31) & 0x01u);
|
|
|
|
|
|
|
|
return r | (g << 5) | (b << 10) | (a << 15);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer,
|
|
|
|
bool remove_alpha);
|
|
|
|
|
2019-09-11 04:59:41 +00:00
|
|
|
enum class DMADirection : u32
|
|
|
|
{
|
|
|
|
Off = 0,
|
|
|
|
FIFO = 1,
|
|
|
|
CPUtoGP0 = 2,
|
|
|
|
GPUREADtoCPU = 3
|
|
|
|
};
|
|
|
|
|
2019-09-12 02:53:04 +00:00
|
|
|
enum class Primitive : u8
|
|
|
|
{
|
|
|
|
Reserved = 0,
|
|
|
|
Polygon = 1,
|
|
|
|
Line = 2,
|
|
|
|
Rectangle = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class DrawRectangleSize : u8
|
|
|
|
{
|
|
|
|
Variable = 0,
|
|
|
|
R1x1 = 1,
|
|
|
|
R8x8 = 2,
|
|
|
|
R16x16 = 3
|
|
|
|
};
|
|
|
|
|
2019-09-13 16:07:31 +00:00
|
|
|
enum class TextureColorMode : u8
|
|
|
|
{
|
|
|
|
Palette4Bit = 0,
|
|
|
|
Palette8Bit = 1,
|
|
|
|
Direct16Bit = 2,
|
|
|
|
Reserved_Direct16Bit = 3
|
|
|
|
};
|
|
|
|
|
2019-09-12 02:53:04 +00:00
|
|
|
union RenderCommand
|
|
|
|
{
|
|
|
|
u32 bits;
|
|
|
|
|
2019-09-14 14:17:43 +00:00
|
|
|
BitField<u32, u32, 0, 24> color_for_first_vertex;
|
2019-09-14 12:47:20 +00:00
|
|
|
BitField<u32, bool, 24, 1> texture_blend_disable; // not valid for lines
|
2019-09-12 02:53:04 +00:00
|
|
|
BitField<u32, bool, 25, 1> transparency_enable;
|
2019-09-13 16:07:31 +00:00
|
|
|
BitField<u32, bool, 26, 1> texture_enable;
|
2019-09-12 02:53:04 +00:00
|
|
|
BitField<u32, DrawRectangleSize, 27, 2> rectangle_size; // only for rectangles
|
|
|
|
BitField<u32, bool, 27, 1> quad_polygon; // only for polygons
|
|
|
|
BitField<u32, bool, 27, 1> polyline; // only for lines
|
2019-09-13 16:07:31 +00:00
|
|
|
BitField<u32, bool, 28, 1> shading_enable; // 0 - flat, 1 = gouroud
|
2019-09-12 02:53:04 +00:00
|
|
|
BitField<u32, Primitive, 29, 21> primitive;
|
2019-09-14 12:47:20 +00:00
|
|
|
|
|
|
|
// Helper functions.
|
|
|
|
bool IsTextureEnabled() const { return (primitive != Primitive::Line && texture_enable); }
|
|
|
|
bool IsTextureBlendingEnabled() const { return (IsTextureEnabled() && !texture_blend_disable); }
|
2019-09-12 02:53:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: Use BitField to do sign extending instead
|
|
|
|
union VertexPosition
|
|
|
|
{
|
|
|
|
u32 bits;
|
|
|
|
|
|
|
|
BitField<u32, u32, 0, 11> x_s11;
|
|
|
|
BitField<u32, u32, 16, 11> y_s11;
|
|
|
|
|
|
|
|
u32 x() const { return S11ToS32(x_s11); }
|
|
|
|
u32 y() const { return S11ToS32(y_s11); }
|
|
|
|
};
|
|
|
|
|
2019-09-11 04:01:19 +00:00
|
|
|
void SoftReset();
|
2019-09-13 16:07:31 +00:00
|
|
|
|
2019-09-17 04:25:25 +00:00
|
|
|
// Sets dots per scanline
|
|
|
|
void UpdateCRTCConfig();
|
|
|
|
|
|
|
|
// Update ticks for this execution slice
|
|
|
|
void UpdateSliceTicks();
|
|
|
|
|
2019-09-13 16:07:31 +00:00
|
|
|
// Updates dynamic bits in GPUSTAT (ready to send VRAM/ready to receive DMA)
|
|
|
|
void UpdateGPUSTAT();
|
|
|
|
|
2019-09-11 04:59:41 +00:00
|
|
|
u32 ReadGPUREAD();
|
2019-09-11 04:01:19 +00:00
|
|
|
void WriteGP0(u32 value);
|
|
|
|
void WriteGP1(u32 value);
|
|
|
|
|
2019-09-11 06:04:31 +00:00
|
|
|
// Rendering commands, returns false if not enough data is provided
|
2019-09-12 02:53:04 +00:00
|
|
|
bool HandleRenderCommand();
|
2019-09-14 06:43:39 +00:00
|
|
|
bool HandleFillRectangleCommand();
|
2019-09-12 15:10:08 +00:00
|
|
|
bool HandleCopyRectangleCPUToVRAMCommand();
|
2019-09-13 16:07:31 +00:00
|
|
|
bool HandleCopyRectangleVRAMToCPUCommand();
|
2019-09-17 14:58:30 +00:00
|
|
|
bool HandleCopyRectangleVRAMToVRAMCommand();
|
2019-09-12 02:53:04 +00:00
|
|
|
|
|
|
|
// Rendering in the backend
|
2019-09-13 16:07:31 +00:00
|
|
|
virtual void UpdateDisplay();
|
2019-09-14 10:45:26 +00:00
|
|
|
virtual void ReadVRAM(u32 x, u32 y, u32 width, u32 height, void* buffer);
|
2019-09-14 06:43:39 +00:00
|
|
|
virtual void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color);
|
2019-09-12 15:10:08 +00:00
|
|
|
virtual void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data);
|
2019-09-17 14:58:30 +00:00
|
|
|
virtual void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height);
|
2019-09-12 02:53:04 +00:00
|
|
|
virtual void DispatchRenderCommand(RenderCommand rc, u32 num_vertices);
|
|
|
|
virtual void FlushRender();
|
2019-09-11 06:04:31 +00:00
|
|
|
|
2019-09-12 14:18:13 +00:00
|
|
|
System* m_system = nullptr;
|
2019-09-11 04:01:19 +00:00
|
|
|
DMA* m_dma = nullptr;
|
2019-09-17 14:22:41 +00:00
|
|
|
InterruptController* m_interrupt_controller = nullptr;
|
2019-09-11 04:01:19 +00:00
|
|
|
|
|
|
|
union GPUSTAT
|
|
|
|
{
|
|
|
|
u32 bits;
|
|
|
|
BitField<u32, u8, 0, 4> texture_page_x_base;
|
|
|
|
BitField<u32, u8, 4, 1> texture_page_y_base;
|
|
|
|
BitField<u32, u8, 5, 2> semi_transparency;
|
2019-09-13 16:07:31 +00:00
|
|
|
BitField<u32, TextureColorMode, 7, 2> texture_color_mode;
|
2019-09-11 04:01:19 +00:00
|
|
|
BitField<u32, bool, 9, 1> dither_enable;
|
|
|
|
BitField<u32, bool, 10, 1> draw_to_display_area;
|
|
|
|
BitField<u32, bool, 11, 1> draw_set_mask_bit;
|
|
|
|
BitField<u32, bool, 12, 1> draw_to_masked_pixels;
|
|
|
|
BitField<u32, bool, 13, 1> interlaced_field;
|
|
|
|
BitField<u32, bool, 14, 1> reverse_flag;
|
|
|
|
BitField<u32, bool, 15, 1> texture_disable;
|
|
|
|
BitField<u32, u8, 16, 1> horizontal_resolution_2;
|
|
|
|
BitField<u32, u8, 17, 2> horizontal_resolution_1;
|
2019-09-17 04:25:25 +00:00
|
|
|
BitField<u32, u8, 19, 1> vertical_resolution;
|
2019-09-11 04:01:19 +00:00
|
|
|
BitField<u32, bool, 20, 1> pal_mode;
|
|
|
|
BitField<u32, bool, 21, 1> display_area_color_depth_24;
|
|
|
|
BitField<u32, bool, 22, 1> vertical_interlace;
|
|
|
|
BitField<u32, bool, 23, 1> display_enable;
|
|
|
|
BitField<u32, bool, 24, 1> interrupt_request;
|
|
|
|
BitField<u32, bool, 25, 1> dma_data_request;
|
|
|
|
BitField<u32, bool, 26, 1> ready_to_recieve_cmd;
|
|
|
|
BitField<u32, bool, 27, 1> ready_to_send_vram;
|
|
|
|
BitField<u32, bool, 28, 1> ready_to_recieve_dma;
|
2019-09-11 04:59:41 +00:00
|
|
|
BitField<u32, DMADirection, 29, 2> dma_direction;
|
2019-09-11 04:01:19 +00:00
|
|
|
BitField<u32, bool, 31, 1> drawing_even_line;
|
|
|
|
} m_GPUSTAT = {};
|
2019-09-11 06:04:31 +00:00
|
|
|
|
|
|
|
struct TextureConfig
|
|
|
|
{
|
2019-09-13 16:07:31 +00:00
|
|
|
static constexpr u16 PAGE_ATTRIBUTE_MASK = UINT16_C(0b0000100111111111);
|
|
|
|
static constexpr u16 PALETTE_ATTRIBUTE_MASK = UINT16_C(0b0111111111111111);
|
|
|
|
|
|
|
|
// decoded values
|
|
|
|
s32 base_x;
|
|
|
|
s32 base_y;
|
|
|
|
s32 palette_x;
|
|
|
|
s32 palette_y;
|
|
|
|
|
|
|
|
// original values
|
|
|
|
u16 page_attribute; // from register in rectangle modes/vertex in polygon modes
|
|
|
|
u16 palette_attribute; // from vertex
|
|
|
|
TextureColorMode color_mode; // from register/vertex in polygon modes
|
|
|
|
|
|
|
|
bool page_changed = false;
|
|
|
|
|
|
|
|
bool IsPageChanged() const { return page_changed; }
|
|
|
|
void ClearPageChangedFlag() { page_changed = false; }
|
|
|
|
|
|
|
|
void SetColorMode(TextureColorMode new_color_mode);
|
|
|
|
|
|
|
|
void SetFromPolygonTexcoord(u32 texcoord0, u32 texcoord1);
|
|
|
|
void SetFromRectangleTexcoord(u32 texcoord);
|
|
|
|
|
|
|
|
void SetFromPageAttribute(u16 value);
|
|
|
|
void SetFromPaletteAttribute(u16 value);
|
|
|
|
|
2019-09-11 06:04:31 +00:00
|
|
|
u8 window_mask_x; // in 8 pixel steps
|
|
|
|
u8 window_mask_y; // in 8 pixel steps
|
|
|
|
u8 window_offset_x; // in 8 pixel steps
|
|
|
|
u8 window_offset_y; // in 8 pixel steps
|
|
|
|
bool x_flip;
|
|
|
|
bool y_flip;
|
|
|
|
} m_texture_config = {};
|
|
|
|
|
|
|
|
struct DrawingArea
|
|
|
|
{
|
|
|
|
u32 top_left_x, top_left_y;
|
|
|
|
u32 bottom_right_x, bottom_right_y;
|
|
|
|
} m_drawing_area = {};
|
|
|
|
|
|
|
|
struct DrawingOffset
|
|
|
|
{
|
|
|
|
s32 x;
|
|
|
|
s32 y;
|
|
|
|
} m_drawing_offset = {};
|
|
|
|
|
2019-09-17 04:25:25 +00:00
|
|
|
struct CRTCState
|
|
|
|
{
|
|
|
|
struct Regs
|
|
|
|
{
|
|
|
|
static constexpr u32 DISPLAY_ADDRESS_START_MASK = 0b111'11111111'11111111;
|
|
|
|
static constexpr u32 HORIZONTAL_DISPLAY_RANGE_MASK = 0b11111111'11111111'11111111;
|
|
|
|
static constexpr u32 VERTICAL_DISPLAY_RANGE_MASK = 0b1111'11111111'11111111;
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
u32 display_address_start;
|
|
|
|
BitField<u32, u32, 0, 10> X;
|
|
|
|
BitField<u32, u32, 10, 9> Y;
|
|
|
|
};
|
|
|
|
union
|
|
|
|
{
|
|
|
|
u32 horizontal_display_range;
|
|
|
|
BitField<u32, u32, 0, 12> X1;
|
|
|
|
BitField<u32, u32, 12, 12> X2;
|
|
|
|
};
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
u32 vertical_display_range;
|
|
|
|
BitField<u32, u32, 0, 10> Y1;
|
|
|
|
BitField<u32, u32, 10, 10> Y2;
|
|
|
|
};
|
|
|
|
} regs;
|
|
|
|
|
|
|
|
u32 horizontal_resolution;
|
|
|
|
u32 vertical_resolution;
|
|
|
|
TickCount dot_clock_divider;
|
|
|
|
|
|
|
|
u32 visible_horizontal_resolution;
|
|
|
|
u32 visible_vertical_resolution;
|
|
|
|
|
|
|
|
TickCount ticks_per_scanline;
|
|
|
|
TickCount visible_ticks_per_scanline;
|
|
|
|
u32 total_scanlines_per_frame;
|
|
|
|
|
|
|
|
TickCount fractional_ticks;
|
|
|
|
TickCount current_tick_in_scanline;
|
|
|
|
u32 current_scanline;
|
|
|
|
|
|
|
|
bool in_hblank;
|
|
|
|
bool in_vblank;
|
|
|
|
} m_crtc_state = {};
|
|
|
|
|
2019-09-12 02:53:04 +00:00
|
|
|
std::vector<u32> m_GP0_command;
|
2019-09-13 16:07:31 +00:00
|
|
|
std::deque<u32> m_GPUREAD_buffer;
|
2019-09-18 05:43:25 +00:00
|
|
|
|
|
|
|
// debug options
|
|
|
|
static bool DUMP_CPU_TO_VRAM_COPIES;
|
|
|
|
static bool DUMP_VRAM_TO_CPU_COPIES;
|
2019-09-11 04:01:19 +00:00
|
|
|
};
|