N64: Support loading UI textures as 16bpp instead of 32bpp to squeeze even more out of the 4 KB TMEM

This commit is contained in:
UnknownShadow200 2023-12-04 22:07:55 +11:00
parent 9661c34b4f
commit cc048431f6
7 changed files with 62 additions and 27 deletions

View File

@ -301,13 +301,15 @@ void Drawer2D_MakeTextTexture(struct Texture* tex, struct DrawTextArgs* args) {
}
void Context2D_MakeTexture(struct Texture* tex, struct Context2D* ctx) {
Gfx_RecreateTexture(&tex->ID, &ctx->bmp, TEXTURE_FLAG_NONPOW2, false);
int flags = TEXTURE_FLAG_NONPOW2 | TEXTURE_FLAG_LOWRES;
Gfx_RecreateTexture(&tex->ID, &ctx->bmp, flags, false);
tex->Width = ctx->width;
tex->Height = ctx->height;
tex->uv.U1 = 0.0f; tex->uv.V1 = 0.0f;
tex->uv.U2 = (float)ctx->width / (float)ctx->bmp.width;
tex->uv.V2 = (float)ctx->height / (float)ctx->bmp.height;
tex->uv.U1 = 0.0f; tex->uv.V1 = 0.0f;
tex->uv.U2 = (float)ctx->width / (float)ctx->bmp.width;
tex->uv.V2 = (float)ctx->height / (float)ctx->bmp.height;
}
cc_bool Drawer2D_ValidColorCodeAt(const cc_string* text, int i) {
@ -687,4 +689,4 @@ struct IGameComponent Drawer2D_Component = {
OnInit, /* Init */
OnFree, /* Free */
OnReset, /* Reset */
};
};

View File

@ -326,7 +326,7 @@ static cc_result ApplySkin(struct Entity* e, struct Bitmap* bmp, struct Stream*
if ((res = EnsurePow2Skin(e, bmp))) return res;
e->SkinType = Utils_CalcSkinType(bmp);
if (!Gfx_CheckTextureSize(bmp->width, bmp->height)) {
if (!Gfx_CheckTextureSize(bmp->width, bmp->height, 0)) {
Chat_Add1("&cSkin %s is too large", skin);
} else {
if (e->Model->flags & MODEL_FLAG_CLEAR_HAT)

View File

@ -58,6 +58,9 @@ CC_VAR extern struct _GfxData {
struct Matrix View, Projection;
/* Whether the graphics backend supports non power of two textures */
cc_bool SupportsNonPowTwoTextures;
/* Maximum total size in pixels a low resolution texture can consist of */
/* NOTE: Not all graphics backends specify a value for this */
int MaxLowResTexSize;
} Gfx;
extern GfxResourceID Gfx_defaultIb;
@ -73,13 +76,15 @@ extern const cc_string Gfx_LowPerfMessage;
#define TEXTURE_FLAG_DYNAMIC 0x02
/* Texture is deliberately (and not accidentally) being created with non power of two dimensions */
#define TEXTURE_FLAG_NONPOW2 0x04
/* Texture can fallback to 16 bpp when necessary (most backends don't do this) */
#define TEXTURE_FLAG_LOWRES 0x08
#define LOWPERF_EXIT_MESSAGE "&eExited reduced performance mode"
void Gfx_RecreateTexture(GfxResourceID* tex, struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps);
void* Gfx_RecreateAndLockVb(GfxResourceID* vb, VertexFormat fmt, int count);
cc_bool Gfx_CheckTextureSize(int width, int height);
cc_bool Gfx_CheckTextureSize(int width, int height, cc_uint8 flags);
/* Creates a new texture. (and also generates mipmaps if mipmaps) */
/* See TEXTURE_FLAG values for supported flags */
/* NOTE: Only set mipmaps to true if Gfx_Mipmaps is also true, because whether textures

View File

@ -28,10 +28,15 @@ void Gfx_Create(void) {
//rdpq_debug_log(true);
zbuffer = surface_alloc(FMT_RGBA16, display_get_width(), display_get_height());
Gfx.MaxTexWidth = 128;
Gfx.MaxTexHeight = 128;
Gfx.MaxTexSize = 1024; // TMEM only has 4 KB in it
Gfx.MaxTexWidth = 256;
Gfx.MaxTexHeight = 256;
Gfx.Created = true;
// TMEM only has 4 KB in it, which can be interpreted as
// - 1024 32bpp pixels
// - 2048 16bpp pixels
Gfx.MaxTexSize = 1024;
Gfx.MaxLowResTexSize = 2048;
Gfx.SupportsNonPowTwoTextures = true;
Gfx_RestoreState();
@ -116,7 +121,12 @@ typedef struct CCTexture {
GLuint textureID;
} CCTexture;
// A8 B8 G8 R8 > A1 B5 G5 B5
#define To16BitPixel(src) \
((src & 0x80) >> 7) | ((src & 0xF800) >> 10) | ((src & 0xF80000) >> 13) | ((src & 0xF8000000) >> 16);
static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) {
cc_bool bit16 = flags & TEXTURE_FLAG_LOWRES;
CCTexture* tex = Mem_Alloc(1, sizeof(CCTexture), "texture");
glGenTextures(1, &tex->textureID);
@ -125,19 +135,34 @@ static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, cc_uint8 flags, cc_boo
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
tex->surface = surface_alloc(FMT_RGBA32, bmp->width, bmp->height);
tex->surface = surface_alloc(bit16 ? FMT_RGBA16 : FMT_RGBA32, bmp->width, bmp->height);
surface_t* fb = &tex->surface;
cc_uint32* src = (cc_uint32*)bmp->scan0;
cc_uint8* dst = (cc_uint8*)fb->buffer;
for (int y = 0; y < bmp->height; y++)
{
Mem_Copy(dst + y * fb->stride,
src + y * bmp->width,
bmp->width * 4);
if (bit16) {
// 16 bpp requires reducing A8R8G8B8 to A1R5G5B5
for (int y = 0; y < bmp->height; y++)
{
cc_uint32* src_row = src + y * bmp->width;
cc_uint16* dst_row = (cc_uint16*)(dst + y * fb->stride);
for (int x = 0; x < bmp->width; x++)
{
dst_row[x] = To16BitPixel(src_row[x]);
}
}
} else {
// 32 bpp can just be copied straight across
for (int y = 0; y < bmp->height; y++)
{
Mem_Copy(dst + y * fb->stride,
src + y * bmp->width,
bmp->width * 4);
}
}
rdpq_texparms_t params =
{
.s.repeats = (flags & TEXTURE_FLAG_NONPOW2) ? 1 : REPEAT_INFINITE,

View File

@ -153,7 +153,7 @@ cc_bool Atlas_TryChange(struct Bitmap* atlas) {
return false;
}
if (!Gfx_CheckTextureSize(tileSize, tileSize)) {
if (!Gfx_CheckTextureSize(tileSize, tileSize, 0)) {
Chat_AddRaw("&cUnable to use terrain.png from the texture pack.");
Chat_Add4("&c Tile size is (%i,%i), your GPU supports (%i,%i) at most.",
&tileSize, &tileSize, &Gfx.MaxTexWidth, &Gfx.MaxTexHeight);

View File

@ -350,13 +350,17 @@ static CC_NOINLINE int CalcMipmapsLevels(int width, int height) {
}
}
cc_bool Gfx_CheckTextureSize(int width, int height) {
cc_bool Gfx_CheckTextureSize(int width, int height, cc_uint8 flags) {
int maxSize;
if (width > Gfx.MaxTexWidth) return false;
if (height > Gfx.MaxTexHeight) return false;
maxSize = Gfx.MaxTexSize;
// low resolution textures may support higher sizes (e.g. Nintendo 64)
if ((flags & TEXTURE_FLAG_LOWRES) && Gfx.MaxLowResTexSize)
maxSize = Gfx.MaxLowResTexSize;
if (Gfx.MaxTexSize && (width * height > Gfx.MaxTexSize))
return false;
return true;
return maxSize == 0 || (width * height <= maxSize);
}
static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps);
@ -370,7 +374,7 @@ GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipm
}
if (Gfx.LostContext) return 0;
if (!Gfx_CheckTextureSize(bmp->width, bmp->height)) return 0;
if (!Gfx_CheckTextureSize(bmp->width, bmp->height, flags)) return 0;
return Gfx_AllocTexture(bmp, flags, mipmaps);
}
@ -448,4 +452,4 @@ struct IGameComponent Gfx_Component = {
/* first component freed, even though it MUST be the last */
/* Instead, Game.c calls Gfx_Free after first freeing all */
/* the other game components. */
};
};

View File

@ -2961,7 +2961,6 @@
FT_Error error;
FT_Memory memory;
FT_Module module = NULL;
FT_UInt nn;
memory = library->memory;
error = FT_Err_Ok;