532 lines
17 KiB
C++
532 lines
17 KiB
C++
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <unordered_map>
|
|
#include <map>
|
|
#include <list>
|
|
#include <cstddef>
|
|
#include <vector>
|
|
#include <stack>
|
|
#include <string>
|
|
|
|
#include "fast/lus_gbi.h"
|
|
#include "fast/types.h"
|
|
#include "fast/ucodehandlers.h"
|
|
#include "backends/gfx_rendering_api.h"
|
|
|
|
#include "fast/resource/type/Texture.h"
|
|
#include "ship/resource/Resource.h"
|
|
|
|
// TODO figure out why changing these to 640x480 makes the game only render in a quarter of the window
|
|
#define SCREEN_WIDTH 320
|
|
#define SCREEN_HEIGHT 240
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#ifdef __cplusplus
|
|
#include <compare>
|
|
#endif
|
|
|
|
/*enum {
|
|
CC_0,
|
|
CC_TEXEL0,
|
|
CC_TEXEL1,
|
|
CC_PRIM,
|
|
CC_SHADE,
|
|
CC_ENV,
|
|
CC_TEXEL0A,
|
|
CC_LOD
|
|
};*/
|
|
|
|
enum {
|
|
SHADER_0,
|
|
SHADER_INPUT_1,
|
|
SHADER_INPUT_2,
|
|
SHADER_INPUT_3,
|
|
SHADER_INPUT_4,
|
|
SHADER_INPUT_5,
|
|
SHADER_INPUT_6,
|
|
SHADER_INPUT_7,
|
|
SHADER_TEXEL0,
|
|
SHADER_TEXEL0A,
|
|
SHADER_TEXEL1,
|
|
SHADER_TEXEL1A,
|
|
SHADER_1,
|
|
SHADER_COMBINED,
|
|
SHADER_NOISE
|
|
};
|
|
|
|
#ifdef __cplusplus
|
|
enum class ShaderOpts {
|
|
ALPHA,
|
|
FOG,
|
|
TEXTURE_EDGE,
|
|
NOISE,
|
|
_2CYC,
|
|
ALPHA_THRESHOLD,
|
|
INVISIBLE,
|
|
GRAYSCALE,
|
|
TEXEL0_CLAMP_S,
|
|
TEXEL0_CLAMP_T,
|
|
TEXEL1_CLAMP_S,
|
|
TEXEL1_CLAMP_T,
|
|
TEXEL0_MASK,
|
|
TEXEL1_MASK,
|
|
TEXEL0_BLEND,
|
|
TEXEL1_BLEND,
|
|
USE_SHADER,
|
|
MAX
|
|
};
|
|
|
|
#define SHADER_OPT(opt) ((uint64_t)(1 << static_cast<int>(ShaderOpts::opt)))
|
|
#endif
|
|
|
|
struct ColorCombinerKey {
|
|
uint64_t combine_mode;
|
|
uint64_t options;
|
|
|
|
#ifdef __cplusplus
|
|
auto operator<=>(const ColorCombinerKey&) const = default;
|
|
#endif
|
|
};
|
|
|
|
#define SHADER_MAX_TEXTURES 6
|
|
#define SHADER_FIRST_TEXTURE 0
|
|
#define SHADER_FIRST_MASK_TEXTURE 2
|
|
#define SHADER_FIRST_REPLACEMENT_TEXTURE 4
|
|
|
|
struct CCFeatures {
|
|
int c[2][2][4];
|
|
bool opt_alpha;
|
|
bool opt_fog;
|
|
bool opt_texture_edge;
|
|
bool opt_noise;
|
|
bool opt_2cyc;
|
|
bool opt_alpha_threshold;
|
|
bool opt_invisible;
|
|
bool opt_grayscale;
|
|
bool usedTextures[2];
|
|
bool used_masks[2];
|
|
bool used_blend[2];
|
|
bool clamp[2][2];
|
|
int numInputs;
|
|
bool do_single[2][2];
|
|
bool do_multiply[2][2];
|
|
bool do_mix[2][2];
|
|
bool color_alpha_same[2];
|
|
int16_t shader_id;
|
|
};
|
|
|
|
void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features);
|
|
|
|
union Gfx;
|
|
|
|
namespace Fast {
|
|
|
|
class GfxRenderingAPI;
|
|
class GfxWindowBackend;
|
|
|
|
constexpr size_t MAX_SEGMENT_POINTERS = 16;
|
|
|
|
struct GfxExecStack {
|
|
// This is a dlist stack used to handle dlist calls.
|
|
std::stack<F3DGfx*> cmd_stack = {};
|
|
// This is also a dlist stack but a std::vector is used to make it possible
|
|
// to iterate on the elements.
|
|
// The purpose of this is to identify an instruction at a poin in time
|
|
// which would not be possible with just a F3DGfx* because a dlist can be called multiple times
|
|
// what we do instead is store the call path that leads to the instruction (including branches)
|
|
std::vector<const F3DGfx*> gfx_path = {};
|
|
struct CodeDisp {
|
|
const char* file;
|
|
int line;
|
|
};
|
|
// stack for OpenDisp/CloseDisps
|
|
std::vector<CodeDisp> disp_stack{};
|
|
|
|
void start(F3DGfx* dlist);
|
|
void stop();
|
|
F3DGfx*& currCmd();
|
|
void openDisp(const char* file, int line);
|
|
void closeDisp();
|
|
const std::vector<CodeDisp>& getDisp() const;
|
|
void branch(F3DGfx* caller);
|
|
void call(F3DGfx* caller, F3DGfx* callee);
|
|
F3DGfx* ret();
|
|
};
|
|
|
|
struct XYWidthHeight {
|
|
int16_t x, y;
|
|
uint32_t width, height;
|
|
};
|
|
|
|
struct GfxDimensions {
|
|
float internal_mul;
|
|
uint32_t width, height;
|
|
float aspect_ratio;
|
|
};
|
|
|
|
struct TextureCacheKey {
|
|
const uint8_t* texture_addr;
|
|
const uint8_t* palette_addrs[2];
|
|
uint8_t fmt, siz;
|
|
uint8_t palette_index;
|
|
uint32_t size_bytes;
|
|
|
|
bool operator==(const TextureCacheKey&) const noexcept = default;
|
|
|
|
struct Hasher {
|
|
size_t operator()(const TextureCacheKey& key) const noexcept {
|
|
uintptr_t addr = (uintptr_t)key.texture_addr;
|
|
return (size_t)(addr ^ (addr >> 5));
|
|
}
|
|
};
|
|
};
|
|
|
|
typedef std::unordered_map<TextureCacheKey, struct TextureCacheValue, TextureCacheKey::Hasher> TextureCacheMap;
|
|
typedef std::pair<const TextureCacheKey, struct TextureCacheValue> TextureCacheNode;
|
|
|
|
struct TextureCacheValue {
|
|
uint32_t texture_id;
|
|
uint8_t cms, cmt;
|
|
bool linear_filter;
|
|
|
|
std::list<struct TextureCacheMapIter>::iterator lru_location;
|
|
};
|
|
|
|
struct TextureCacheMapIter {
|
|
TextureCacheMap::iterator it;
|
|
};
|
|
|
|
struct RGBA {
|
|
uint8_t r, g, b, a;
|
|
};
|
|
|
|
struct LoadedVertex {
|
|
float x, y, z, w;
|
|
float u, v;
|
|
struct RGBA color;
|
|
uint8_t clip_rej;
|
|
};
|
|
|
|
struct RawTexMetadata {
|
|
uint16_t width, height;
|
|
float h_byte_scale = 1, v_pixel_scale = 1;
|
|
std::shared_ptr<Fast::Texture> resource;
|
|
Fast::TextureType type;
|
|
};
|
|
|
|
struct ShaderMod {
|
|
bool enabled = false;
|
|
int16_t id;
|
|
uint8_t type;
|
|
};
|
|
|
|
#define MAX_LIGHTS 32
|
|
#define MAX_VERTICES 64
|
|
|
|
struct RSP {
|
|
float modelview_matrix_stack[11][4][4];
|
|
uint8_t modelview_matrix_stack_size;
|
|
|
|
float MP_matrix[4][4];
|
|
float P_matrix[4][4];
|
|
|
|
F3DLight_t lookat[2];
|
|
F3DLight current_lights[MAX_LIGHTS + 1];
|
|
float current_lights_coeffs[MAX_LIGHTS][3];
|
|
float current_lookat_coeffs[2][3]; // lookat_x, lookat_y
|
|
uint8_t current_num_lights; // includes ambient light
|
|
bool lights_changed;
|
|
|
|
uint32_t geometry_mode;
|
|
int16_t fog_mul, fog_offset;
|
|
|
|
uint32_t extra_geometry_mode;
|
|
|
|
struct {
|
|
// U0.16
|
|
uint16_t s, t;
|
|
} texture_scaling_factor;
|
|
|
|
struct LoadedVertex loaded_vertices[MAX_VERTICES + 4];
|
|
ShaderMod current_shader;
|
|
};
|
|
|
|
struct RDP {
|
|
const uint8_t* palettes[2];
|
|
struct {
|
|
const uint8_t* addr;
|
|
uint8_t siz;
|
|
uint32_t width;
|
|
uint32_t tex_flags;
|
|
struct RawTexMetadata raw_tex_metadata;
|
|
} texture_to_load;
|
|
struct {
|
|
const uint8_t* addr;
|
|
uint32_t orig_size_bytes;
|
|
uint32_t size_bytes;
|
|
uint32_t full_image_line_size_bytes;
|
|
uint32_t line_size_bytes;
|
|
uint32_t tex_flags;
|
|
struct RawTexMetadata raw_tex_metadata;
|
|
bool masked;
|
|
bool blended;
|
|
} loaded_texture[2];
|
|
struct {
|
|
uint8_t fmt;
|
|
uint8_t siz;
|
|
uint8_t cms, cmt;
|
|
uint8_t shifts, shiftt;
|
|
float uls, ult, lrs, lrt;
|
|
uint16_t tmem; // 0-511, in 64-bit word units
|
|
uint32_t line_size_bytes;
|
|
uint8_t palette;
|
|
uint8_t tmem_index; // 0 or 1 for offset 0 kB or offset 2 kB, respectively
|
|
} texture_tile[8];
|
|
bool textures_changed[2];
|
|
|
|
uint8_t first_tile_index;
|
|
|
|
uint32_t other_mode_l, other_mode_h;
|
|
uint64_t combine_mode;
|
|
bool grayscale;
|
|
ShaderMod current_shader;
|
|
|
|
uint8_t prim_lod_fraction;
|
|
struct RGBA env_color, prim_color, fog_color, fill_color, grayscale_color;
|
|
struct XYWidthHeight viewport, scissor;
|
|
bool viewport_or_scissor_changed;
|
|
void* z_buf_address;
|
|
void* color_image_address;
|
|
};
|
|
|
|
typedef enum Attribute {
|
|
MTX_PROJECTION,
|
|
MTX_LOAD,
|
|
MTX_PUSH,
|
|
MTX_NOPUSH,
|
|
CULL_FRONT,
|
|
CULL_BACK,
|
|
CULL_BOTH,
|
|
MV_VIEWPORT,
|
|
MV_LIGHT,
|
|
} Attribute;
|
|
|
|
extern GfxExecStack g_exec_stack;
|
|
|
|
struct GfxTextureCache {
|
|
TextureCacheMap map;
|
|
std::list<TextureCacheMapIter> lru;
|
|
std::vector<uint32_t> free_texture_ids;
|
|
};
|
|
|
|
struct ColorCombiner {
|
|
uint64_t shader_id0;
|
|
uint32_t shader_id1;
|
|
bool usedTextures[2];
|
|
struct ShaderProgram* prg[16];
|
|
uint8_t shader_input_mapping[2][7];
|
|
};
|
|
|
|
struct RenderingState {
|
|
uint8_t depth_test_and_mask; // 1: depth test, 2: depth mask
|
|
bool decal_mode;
|
|
bool alpha_blend;
|
|
struct XYWidthHeight viewport, scissor;
|
|
struct ShaderProgram* mShaderProgram;
|
|
TextureCacheNode* mTextures[SHADER_MAX_TEXTURES];
|
|
};
|
|
|
|
struct FBInfo {
|
|
uint32_t orig_width, orig_height; // Original shape
|
|
uint32_t applied_width, applied_height; // Up-scaled for the viewport
|
|
uint32_t native_width, native_height; // Max "native" size of the screen, used for up-scaling
|
|
bool resize; // Scale to match the viewport
|
|
};
|
|
|
|
struct MaskedTextureEntry {
|
|
uint8_t* mask;
|
|
uint8_t* replacementData;
|
|
};
|
|
|
|
class Interpreter {
|
|
public:
|
|
Interpreter();
|
|
~Interpreter();
|
|
|
|
void Init(GfxWindowBackend* wapi, class GfxRenderingAPI* rapi, const char* game_name, bool start_in_fullscreen,
|
|
uint32_t width, uint32_t height, uint32_t posX, uint32_t posY);
|
|
void Destroy();
|
|
void GetDimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY);
|
|
GfxRenderingAPI* GetCurrentRenderingAPI();
|
|
void StartFrame();
|
|
void RunGuiOnly();
|
|
void Run(Gfx* commands, const std::unordered_map<Mtx*, MtxF>& mtx_replacements);
|
|
void EndFrame();
|
|
void HandleWindowEvents();
|
|
bool IsFrameReady();
|
|
bool ViewportMatchesRendererResolution();
|
|
int GetTargetFps();
|
|
void SetTargetFps(int fps);
|
|
void SetMaxFrameLatency(int latency);
|
|
int CreateFrameBuffer(uint32_t width, uint32_t height, uint32_t native_width, uint32_t native_height,
|
|
uint8_t resize);
|
|
void SetFrameBuffer(int fb, float noiseScale);
|
|
void CopyFrameBuffer(int fb_dst_id, int fb_src_id, bool copyOnce, bool* hasCopiedPtr);
|
|
void ResetFrameBuffer();
|
|
void AdjustPixelDepthCoordinates(float& x, float& y);
|
|
void GetPixelDepthPrepare(float x, float y);
|
|
uint16_t GetPixelDepth(float x, float y);
|
|
void RegisterBlendedTexture(const char* name, uint8_t* mask, uint8_t* replacement);
|
|
void UnregisterBlendedTexture(const char* name);
|
|
|
|
void SetNativeDimensions(float width, float height);
|
|
void SetResolutionMultiplier(float multiplier);
|
|
void SetMsaaLevel(uint32_t level);
|
|
void GetCurDimensions(uint32_t* width, uint32_t* height);
|
|
|
|
// private: TODO make these private
|
|
void Flush();
|
|
ShaderProgram* LookupOrCreateShaderProgram(uint64_t id0, uint64_t id1);
|
|
ColorCombiner* LookupOrCreateColorCombiner(const ColorCombinerKey& key);
|
|
void TextureCacheClear();
|
|
bool TextureCacheLookup(int i, const TextureCacheKey& key);
|
|
void TextureCacheDelete(const uint8_t* origAddr);
|
|
void ImportTextureRgba16(int tile, bool importReplacement);
|
|
void ImportTextureRgba32(int tile, bool importReplacement);
|
|
void ImportTextureIA4(int tile, bool importReplacement);
|
|
void ImportTextureIA8(int tile, bool importReplacement);
|
|
void ImportTextureIA16(int tile, bool importReplacement);
|
|
void ImportTextureI4(int tile, bool importReplacement);
|
|
void ImportTextureI8(int tile, bool importReplacement);
|
|
void ImportTextureCi4(int tile, bool importReplacement);
|
|
void ImportTextureCi8(int tile, bool importReplacement);
|
|
void ImportTextureRaw(int tile, bool importReplacement);
|
|
void ImportTextureImg(int tile, bool importReplacement);
|
|
void ImportTexture(int i, int tile, bool importReplacement);
|
|
void ImportTextureMask(int i, int tile);
|
|
void CalculateNormalDir(const F3DLight_t*, float coeffs[3]);
|
|
|
|
void GfxSpMatrix(uint8_t params, const int32_t* addr);
|
|
void GfxSpPopMatrix(uint32_t count);
|
|
void GfxSpVertex(size_t numVertices, size_t destIndex, const F3DVtx* vertices);
|
|
void GfxSpModifyVertex(uint16_t vtxIdx, uint8_t where, uint32_t val);
|
|
void GfxSpTri1(uint8_t vtx1Idx, uint8_t vtx2Idx, uint8_t vtx3Idx, bool isRect);
|
|
void GfxSpGeometryMode(uint32_t clear, uint32_t set);
|
|
void GfxSpExtraGeometryMode(uint32_t clear, uint32_t set);
|
|
void GfxSpMovememF3dex2(uint8_t index, uint8_t offset, const void* data);
|
|
void GfxSpMovememF3d(uint8_t index, uint8_t offset, const void* data);
|
|
void GfxSpMovewordF3dex2(uint8_t index, uint16_t offset, uintptr_t data);
|
|
void GfxSpMovewordF3d(uint8_t index, uint16_t offset, uintptr_t data);
|
|
void GfxSpTexture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile, uint8_t on);
|
|
void GfxDpSetScissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32_t lrx, uint32_t lry);
|
|
void GfxDpSetTextureImage(uint32_t format, uint32_t size, uint32_t width, const char* texPath, uint32_t texFlags,
|
|
RawTexMetadata rawTexMetdata, const void* addr);
|
|
void GfxDpSetTile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t tmem, uint8_t tile, uint32_t palette,
|
|
uint32_t cmt, uint32_t maskt, uint32_t shiftt, uint32_t cms, uint32_t masks, uint32_t shifts);
|
|
void GfxDpSetTileSize(uint8_t tile, uint16_t uls, uint16_t ult, uint16_t lrs, uint16_t lrt);
|
|
void GfxDpLoadTlut(uint8_t tile, uint32_t high_index);
|
|
void GfxDpLoadBlock(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t dxt);
|
|
void GfxDpLoadTile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt);
|
|
void GfxDpSetCombineMode(uint32_t rgb, uint32_t alpha, uint32_t rgb_cyc2, uint32_t alpha_cyc2);
|
|
void GfxDpSetGrayscaleColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
|
void GfxDpSetEnvColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
|
void GfxDpSetPrimColor(uint8_t m, uint8_t r, uint8_t l, uint8_t g, uint8_t b, uint8_t a);
|
|
void GfxDpSetFogColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
|
void GfxDpSetBlendColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
|
void GfxDpSetFillColor(uint32_t pickedColor);
|
|
void GfxDrawRectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry);
|
|
void GfxDpTextureRectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint8_t tile, int16_t uls,
|
|
int16_t ult, int16_t dsdx, int16_t dtdy, bool flip);
|
|
void GfxDpImageRectangle(int32_t tile, int32_t w, int32_t h, int32_t ulx, int32_t uly, int16_t uls, int16_t ult,
|
|
int32_t lrx, int32_t lry, int16_t lrs, int16_t lrt);
|
|
void GfxDpFillRectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry);
|
|
void GfxDpSetZImage(void* zBufAddr);
|
|
void GfxDpSetColorImage(uint32_t format, uint32_t size, uint32_t width, void* address);
|
|
void GfxSpSetOtherMode(uint32_t shift, uint32_t num_bits, uint64_t mode);
|
|
void GfxDpSetOtherMode(uint32_t h, uint32_t l);
|
|
|
|
void Gfxs2dexBgCopy(F3DuObjBg* bg);
|
|
void Gfxs2dexBg1cyc(F3DuObjBg* bg);
|
|
void Gfxs2dexRecyCopy(F3DuObjSprite* spr);
|
|
|
|
void AdjustWidthHeightForScale(uint32_t& width, uint32_t& height, uint32_t nativeWidth,
|
|
uint32_t nativeHeight) const;
|
|
float AdjXForAspectRatio(float x) const;
|
|
void AdjustVIewportOrScissor(XYWidthHeight* area);
|
|
void CalcAndSetViewport(const F3DVp_t* viewport);
|
|
int16_t CreateShader(const std::string& path);
|
|
|
|
void SpReset();
|
|
void* SegAddr(uintptr_t w1);
|
|
|
|
static const char* CCMUXtoStr(uint32_t ccmux);
|
|
static const char* ACMUXtoStr(uint32_t acmux);
|
|
static void GenerateCC(ColorCombiner* comb, const ColorCombinerKey& key);
|
|
static std::string GetBaseTexturePath(const std::string& path);
|
|
static void NormalizeVector(float v[3]);
|
|
static void TransposedMatrixMul(float res[3], const float a[3], const float b[4][4]);
|
|
static void MatrixMul(float res[4][4], const float a[4][4], const float b[4][4]);
|
|
|
|
RSP* mRsp;
|
|
RDP* mRdp;
|
|
RenderingState mRenderingState{};
|
|
|
|
GfxTextureCache mTextureCache{};
|
|
std::map<ColorCombinerKey, ColorCombiner> mColorCombinerPool; // color_combiner_pool;
|
|
std::map<ColorCombinerKey, ColorCombiner>::iterator mPrevCombiner = mColorCombinerPool.end();
|
|
uint8_t* mTexUploadBuffer = nullptr;
|
|
|
|
GfxDimensions mGfxCurrentWindowDimensions{}; // gfx_current_window_dimensions;
|
|
int32_t mCurWindowPosX{};
|
|
int32_t mCurWindowPosY{};
|
|
GfxDimensions mCurDimensions{}; // gfx_current_dimensions;
|
|
GfxDimensions mPrvDimensions{}; // gfx_prev_dimensions;
|
|
XYWidthHeight mGameWindowViewport{}; // gfx_current_game_window_viewport;
|
|
XYWidthHeight mNativeDimensions{}; // gfx_native_dimensions;
|
|
XYWidthHeight mPrevNativeDimensions{}; // gfx_prev_native_dimensions;
|
|
uintptr_t mGfxFrameBuffer{};
|
|
|
|
unsigned int mMsaaLevel = 1;
|
|
bool mDroppedFrame{};
|
|
float* mBufVbo; // 3 vertices in a triangle and 32 floats per vtx
|
|
size_t mBufVboLen{};
|
|
size_t mBufVboNumTris{};
|
|
GfxWindowBackend* mWapi = nullptr;
|
|
GfxRenderingAPI* mRapi = nullptr;
|
|
|
|
uintptr_t mSegmentPointers[MAX_SEGMENT_POINTERS]{};
|
|
|
|
bool mFbActive{};
|
|
bool mRendersToFb{}; // game_renders_to_framebuffer;
|
|
std::map<int, FBInfo>::iterator mActiveFrameBuffer;
|
|
std::map<int, FBInfo> mFrameBuffers;
|
|
|
|
int mGameFb{}; // game_framebuffer;
|
|
int mGameFbMsaaResolved{}; // game_framebuffer_msaa_resolved;
|
|
|
|
std::set<std::pair<float, float>> mGetPixelDepthPending; // get_pixel_depth_pending;
|
|
std::unordered_map<std::pair<float, float>, uint16_t, hash_pair_ff> mGetPixelDepthCached; // get_pixel_depth_cached;
|
|
std::map<std::string, MaskedTextureEntry> mMaskedTextures;
|
|
|
|
const std::unordered_map<Mtx*, MtxF>* mCurMtxReplacements;
|
|
bool mMarkerOn; // This was originally a debug feature. Now it seems to control s2dex?
|
|
std::vector<std::string> shader_ids;
|
|
int mInterpolationIndex;
|
|
int mInterpolationIndexTarget;
|
|
};
|
|
|
|
void gfx_set_target_ucode(UcodeHandlers ucode);
|
|
void gfx_push_current_dir(char* path);
|
|
int32_t gfx_check_image_signature(const char* imgData);
|
|
const char* GfxGetOpcodeName(int8_t opcode);
|
|
|
|
} // namespace Fast
|
|
|
|
extern "C" void gfx_texture_cache_clear();
|
|
extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, uint32_t native_width, uint32_t native_height,
|
|
uint8_t resize);
|