mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2024-06-01 19:17:33 -04:00
298 lines
8 KiB
C++
298 lines
8 KiB
C++
// Flipper GFX Engine
|
|
|
|
/*
|
|
|
|
Very limited Flipper GFXEngine emulation. Basic OpenGL 1.2 is used as a backend.
|
|
|
|
This code is out-of-phase because the graphical subsystem has been substantially redesigned. So there is now a mixture of new developments and old code.
|
|
|
|
What's supported:
|
|
- Software implementation of transform unit (XF). Very inaccurate - lighting is partially supported. The transformation of texture coordinates is not completed yet.
|
|
- All texture formats are supported, but TLUT versions may be buggy
|
|
|
|
What's not supported:
|
|
- The main drawback is the lack of TEV support. Because of this, complex scenes with effects are drawn with bugs or not drawn at all.
|
|
- Emulation of Advanced GX features such as Bump-mapping, indirect texturing, Z-textures not supported
|
|
- No texture caching
|
|
- There is no emulation of direct access to the EFB
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "cp.h"
|
|
#include "pe.h"
|
|
#include "xf.h"
|
|
#include "su.h"
|
|
#include "ras.h"
|
|
#include "tev.h"
|
|
#include "tx.h"
|
|
|
|
#define GFX_BLACKJACK_AND_SHADERS 0 // 1: Use modern OpenGL (VBO + Shaders). Under development, do not enable
|
|
|
|
// 1: Use SDL_Window as a render target; the appropriate SDL API calls are invoked to service it
|
|
#ifdef _LINUX
|
|
#define GFX_USE_SDL_WINDOW 1
|
|
#endif
|
|
#if defined(_WINDOWS) && !defined(GFX_USE_SDL_WINDOW)
|
|
#define GFX_USE_SDL_WINDOW 0
|
|
#endif
|
|
|
|
namespace GX
|
|
{
|
|
class GXCore
|
|
{
|
|
void DONE_INT();
|
|
void TOKEN_INT();
|
|
void CP_BREAK();
|
|
void CP_OVF();
|
|
void CP_UVF();
|
|
|
|
static void CPThread(void* Param);
|
|
|
|
FifoProcessor * fifo = nullptr; // Internal CP FIFO
|
|
|
|
bool gxOpened = false;
|
|
bool frame_done = true;
|
|
bool disableDraw = false;
|
|
bool frameReady = false;
|
|
bool backend_started = false;
|
|
|
|
// logging
|
|
bool logOpcode = false;
|
|
bool logDrawCommands = false;
|
|
bool GpRegsLog = false;
|
|
|
|
#if GFX_USE_SDL_WINDOW
|
|
SDL_Window* render_window = nullptr;
|
|
SDL_GLContext context{};
|
|
#else
|
|
// Windows OpenGL stuff
|
|
HWND hwndMain;
|
|
HGLRC hglrc = 0;
|
|
HDC hdcgl = 0;
|
|
PAINTSTRUCT psFrame{};
|
|
#endif
|
|
|
|
bool make_shot = false;
|
|
FILE* snap_file = nullptr;
|
|
uint32_t snap_w, snap_h;
|
|
|
|
// optionable
|
|
uint32_t scr_w = 640, scr_h = 480;
|
|
|
|
public:
|
|
GXCore();
|
|
~GXCore();
|
|
|
|
void Open(HWConfig* config);
|
|
void Close();
|
|
|
|
bool GL_LazyOpenSubsystem();
|
|
bool GL_OpenSubsystem();
|
|
void GL_CloseSubsystem();
|
|
void GL_BeginFrame();
|
|
void GL_EndFrame();
|
|
void GPFrameDone();
|
|
|
|
void ResizeRenderTarget(size_t width, size_t height);
|
|
|
|
// Debug
|
|
void DumpPIFIFO();
|
|
void DumpCPFIFO();
|
|
|
|
GLuint vert_shader;
|
|
GLuint frag_shader;
|
|
GLuint shader_prog;
|
|
|
|
void UploadShaders(const char* vert_source, const char* frag_source);
|
|
void DisposeShaders();
|
|
void InitVBO();
|
|
void DisposeVBO();
|
|
void BindShadersWithVBO();
|
|
|
|
// You probably don't need to reset the internal state of GFX because GXInit from Dolphin SDK is working hard on it
|
|
|
|
#pragma region "Interface to Flipper"
|
|
|
|
// PI FIFO
|
|
volatile uint32_t pi_cp_base;
|
|
volatile uint32_t pi_cp_top;
|
|
volatile uint32_t pi_cp_wrptr; // also WRAP bit
|
|
volatile uint32_t wrap_bit = 0; // When the CPU writes to the CPWRT register, this bit is cleared. When the FIFO writes by the CPWRT address, this bit remains asserted
|
|
|
|
// CP Registers
|
|
uint16_t CpReadReg(CPMappedRegister id);
|
|
void CpWriteReg(CPMappedRegister id, uint16_t value);
|
|
|
|
// PI->CP Registers
|
|
uint32_t PiCpReadReg(PI_CPMappedRegister id);
|
|
void PiCpWriteReg(PI_CPMappedRegister id, uint32_t value);
|
|
|
|
// Streaming FIFO (32-byte burst-only)
|
|
void FifoWriteBurst(uint8_t data[32]);
|
|
|
|
#pragma endregion "Interface to Flipper"
|
|
|
|
|
|
#pragma region "Gfx Common"
|
|
|
|
GenMode genmode;
|
|
GenMsloc msloc[4];
|
|
|
|
#pragma endregion "Gfx Common"
|
|
|
|
|
|
#pragma region "Command Processor"
|
|
|
|
CPHostRegs cpregs; // Mapped command processor registers
|
|
CPState cp; // Internal registers (for setting VCD/VAT, etc.)
|
|
|
|
Thread* cp_thread; // CP FIFO thread
|
|
size_t tickPerFifo;
|
|
int64_t updateTbrValue;
|
|
|
|
// Stats
|
|
size_t cpLoads;
|
|
size_t xfLoads;
|
|
size_t bpLoads;
|
|
|
|
GLuint vao;
|
|
GLuint vbo;
|
|
size_t vbo_size = 0x10000; // Maximum number of vertices that can be used in Draw primitive parameters
|
|
Vertex* vertex_data = nullptr;
|
|
|
|
void GXWriteFifo(uint8_t dataPtr[32]);
|
|
void loadCPReg(size_t index, uint32_t value, FifoProcessor* gxfifo);
|
|
std::string AttrToString(VertexAttr attr);
|
|
int gx_vtxsize(unsigned v);
|
|
void FifoReconfigure(FifoProcessor* gxfifo);
|
|
void* GetArrayPtr(ArrayId arrayId, int idx, int compSize);
|
|
void FetchComp(float* comp, int count, int type, int fmt, int shft, FifoProcessor* gxfifo, ArrayId arrayId);
|
|
void FetchNorm(float* comp, int count, int type, int fmt, int shft, FifoProcessor* gxfifo, ArrayId arrayId, bool nrmidx3);
|
|
Color FetchColor(int type, int fmt, FifoProcessor* gxfifo, ArrayId arrayId);
|
|
void FifoWalk(unsigned vatnum, Vertex* vtx, FifoProcessor* gxfifo);
|
|
void GxBadFifo(uint8_t command);
|
|
void GxCommand(FifoProcessor* gxfifo);
|
|
void CPAbortFifo();
|
|
|
|
#pragma endregion "Command Processor"
|
|
|
|
|
|
#pragma region "Transform Unit"
|
|
|
|
XFState xf;
|
|
|
|
TexGenOut tgout[8]{};
|
|
Color colora[2]{}; // lighting stage output colors (COLOR0A0 / COLOR1A1)
|
|
|
|
bool XF_LightColorEnabled(int chan, int light);
|
|
bool XF_LightAlphaEnabled(int chan, int light);
|
|
void XF_DoLights(const Vertex* v);
|
|
void XF_DoTexGen(const Vertex* v);
|
|
void VECNormalize(float vec[3]);
|
|
void XF_ApplyModelview(const Vertex* v, float* out, const float* in);
|
|
void NormalTransform(const Vertex* v, float* out, const float* in);
|
|
void GL_SetProjection(float* mtx);
|
|
void GL_SetViewport(int x, int y, int w, int h, float znear, float zfar);
|
|
void loadXFRegs(size_t startIdx, size_t amount, FifoProcessor* gxfifo);
|
|
|
|
#pragma endregion "Transform Unit"
|
|
|
|
|
|
#pragma region "Setup Unit"
|
|
|
|
SU_SCIS0 scis0; // 0x20
|
|
SU_SCIS1 scis1; // 0x21
|
|
SU_TS0 ssize[8]; // 0x3n
|
|
SU_TS1 tsize[8]; // 0x3n
|
|
|
|
void GL_SetScissor(int x, int y, int w, int h);
|
|
void GL_SetCullMode(int mode);
|
|
void loadBPReg(size_t index, uint32_t value);
|
|
|
|
#pragma endregion "Setup Unit"
|
|
|
|
|
|
#pragma region "Rasterizers"
|
|
|
|
// perfomance counters
|
|
size_t tris = 0, pts = 0, lines = 0;
|
|
|
|
bool ras_wireframe = false; // Enable wireframe drawing of primitives (DEBUG)
|
|
bool ras_use_texture = false;
|
|
|
|
void RAS_Begin(RAS_Primitive prim, size_t vtx_num);
|
|
void RAS_End();
|
|
void RAS_SendVertex(const Vertex* v);
|
|
|
|
#pragma endregion "Rasterizers"
|
|
|
|
|
|
#pragma region "Texture Engine"
|
|
|
|
LoadTlut0 loadtlut0; // 0x64
|
|
LoadTlut1 loadtlut1; // 0x65
|
|
TexMode0 texmode0[8]; // 0x80-0x83, 0xA0-0xA3
|
|
TexMode1 texmode1[8]; // 0x84-0x87, 0xA4-0xA7
|
|
TexImage0 teximg0[8]; // 0x88-0x8B, 0xA8-0xAB
|
|
TexImage1 teximg1[8]; // 0x8C-0x8F, 0xAC-0xAF
|
|
TexImage2 teximg2[8]; // 0x90-0x93, 0xB0-0xB3
|
|
TexImage3 teximg3[8]; // 0x94-0x97, 0xB4-0xB7
|
|
SetTlut settlut[8]; // 0x98-0x9B, 0xB8-0xBB
|
|
bool texvalid[4][8];
|
|
|
|
#define GFX_MAX_TEXTURES 32
|
|
|
|
TexEntry* tID[8];
|
|
Color rgbabuf[1024 * 1024];
|
|
TexEntry tcache[GFX_MAX_TEXTURES];
|
|
unsigned tptr;
|
|
GLuint texlist[GFX_MAX_TEXTURES + 1]; // gl texture list (0 entry reserved)
|
|
uint8_t tlut[1024 * 1024]; // temporary TLUT buffer
|
|
|
|
void TexInit();
|
|
void TexFree();
|
|
void DumpTexture(Color* rgbaBuf, uint32_t addr, int fmt, int width, int height);
|
|
void tryLoadTex(int id);
|
|
void GetTlutCol(Color* c, unsigned id, unsigned entry);
|
|
void RebindTexture(unsigned id);
|
|
void LoadTexture(uint32_t addr, int id, int fmt, int width, int height);
|
|
void LoadTlut(uint32_t addr, uint32_t tmem, uint32_t cnt);
|
|
|
|
#pragma endregion "Texture Engine"
|
|
|
|
|
|
#pragma region "TEV"
|
|
|
|
TEVState tev{};
|
|
|
|
// TBD: Konst regs where to?
|
|
|
|
#pragma endregion "TEV"
|
|
|
|
|
|
#pragma region "Pixel Engine"
|
|
|
|
size_t frames = 0;
|
|
size_t pe_done_num = 0; // number of drawdone (PE_FINISH) events
|
|
|
|
PERegs peregs; // PE PI regs
|
|
|
|
PEState pe{}; // Internal PE state
|
|
|
|
void GL_DoSnapshot(bool sel, FILE* f, uint8_t* dst, int width, int height);
|
|
void GL_MakeSnapshot(char* path);
|
|
void GL_SaveBitmap(uint8_t* buf);
|
|
|
|
// Pixel Engine mapped regs
|
|
uint16_t PeReadReg(PEMappedRegister id);
|
|
void PeWriteReg(PEMappedRegister id, uint16_t value);
|
|
uint32_t EfbPeek(uint32_t addr);
|
|
void EfbPoke(uint32_t addr, uint32_t value);
|
|
|
|
#pragma endregion "Pixel Engine"
|
|
|
|
};
|
|
}
|