diff --git a/src/Drawer2D.c b/src/Drawer2D.c index af7859c6a..084860008 100644 --- a/src/Drawer2D.c +++ b/src/Drawer2D.c @@ -152,7 +152,7 @@ void Context2D_Alloc(struct Context2D* ctx, int width, int height) { ctx->height = height; ctx->meta = NULL; - if (!Gfx.SupportsNonPowTwoTextures) { + if (Gfx.NonPowTwoTexturesSupport != GFX_NONPOW2_FULL) { /* Allocate power-of-2 sized bitmap equal to or greater than the given size */ width = Math_NextPowOf2(width); height = Math_NextPowOf2(height); diff --git a/src/Graphics.h b/src/Graphics.h index 7dab6932a..509dc421b 100644 --- a/src/Graphics.h +++ b/src/Graphics.h @@ -66,8 +66,8 @@ CC_VAR extern struct _GfxData { /* Whether graphics context has been created */ cc_bool Created; struct Matrix View, Projection; - /* Whether the graphics backend supports non power of two textures */ - cc_bool SupportsNonPowTwoTextures; + /* Level of support for non power of two textures */ + cc_uint8 NonPowTwoTexturesSupport; /* Limitations of the graphics backend, see GFX_LIMIT values */ cc_uint8 Limitations; /* Type of the backend (e.g. OpenGL, Direct3D 9, etc)*/ @@ -85,6 +85,14 @@ CC_VAR extern struct _GfxData { GfxResourceID DefaultIb; } Gfx; +/* Backend has no support at all for non power of two textures */ +#define GFX_NONPOW2_NONE 0x00 +/* Backend only supports uploading non power of two textures */ +/* E.g. 64x20 texture may only occupy 64x20 in VRAM, but is addressed as if it was 64x32 */ +#define GFX_NONPOW2_UPLOAD 0x01 +/* Backend fully supports uploading and addressing non power of two textures */ +#define GFX_NONPOW2_FULL 0x02 + /* Whether the graphics backend supports U/V that don't occupy whole texture */ /* e.g. Saturn, 3D0 systems don't support it */ #define GFX_LIMIT_NO_UV_SUPPORT 0x01 diff --git a/src/Graphics_Dreamcast.c b/src/Graphics_Dreamcast.c index c1cefae9f..7fad6d077 100644 --- a/src/Graphics_Dreamcast.c +++ b/src/Graphics_Dreamcast.c @@ -66,15 +66,6 @@ static void CommandsList_Append(struct CommandsList* list, const void* cmd) { list->length++; } -static CC_INLINE cc_uint32 TextureSize(TextureObject* tex) { - // 16 bpp = 1 pixel in 2 bytes - if (tex->format == PVR_TXRFMT_ARGB4444) return tex->width * tex->height * 2; - - // 4bpp = 2 pixels in 1 byte - return tex->width * tex->height / 2; -} - - /*########################################################################################################################* *-----------------------------------------------------Texture memory------------------------------------------------------* *#########################################################################################################################*/ @@ -133,12 +124,11 @@ static int texmem_defragment(void) { TextureObject* tex = &TEXTURE_LIST[i]; if (!tex->data) continue; - cc_uint32 size = TextureSize(tex); - int moved = texmem_move(tex->data, size); + int moved = texmem_move(tex->data, tex->size); if (!moved) continue; moved_any = true; - memmove(tex->data - moved, tex->data, size); + memmove(tex->data - moved, tex->data, tex->size); tex->data -= moved; } return moved_any; @@ -660,6 +650,8 @@ static TextureObject* FindFreeTexture(void) { return NULL; } +static int Log2Dimension(int len) { return Math_ilog2(Math_NextPowOf2(len)); } + GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { TextureObject* tex = FindFreeTexture(); if (!tex) return NULL; @@ -673,11 +665,20 @@ GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, if (pal_count > 0) ApplyPalette(palette, pal_count, pal_index); } - tex->width = bmp->width; - tex->height = bmp->height; - tex->format = pal_count > 0 ? (PVR_TXRFMT_PAL4BPP | PVR_TXRFMT_4BPP_PAL(pal_index)) : PVR_TXRFMT_ARGB4444; + tex->log2_width = Log2Dimension(bmp->width); + tex->log2_height = Log2Dimension(bmp->height); - tex->data = texmem_alloc(TextureSize(tex)); + if (pal_count > 0) { + tex->format = PVR_TXRFMT_PAL4BPP | PVR_TXRFMT_4BPP_PAL(pal_index); + // 4bpp = 2 pixels in 1 byte + tex->size = bmp->width * bmp->height / 2; + } else { + tex->format = PVR_TXRFMT_ARGB4444; + // 16 bpp = 1 pixel in 2 bytes + tex->size = bmp->width * bmp->height * 2; + } + + tex->data = texmem_alloc(tex->size); if (!tex->data) { Platform_LogConst("Out of PVR VRAM!"); return NULL; } if (tex->format == PVR_TXRFMT_ARGB4444) { @@ -694,7 +695,7 @@ void Gfx_UpdateTexture(GfxResourceID texId, int originX, int originY, struct Bit int width = part->width, height = part->height; unsigned maskX, maskY; unsigned X = 0, Y = 0; - TwiddleCalcFactors(tex->width, tex->height, &maskX, &maskY); + TwiddleCalcFactors(1 << tex->log2_width, 1 << tex->log2_height, &maskX, &maskY); // Calculate start twiddled X and Y values for (int x = 0; x < originX; x++) { X = (X - maskX) & maskX; } @@ -726,8 +727,7 @@ void Gfx_DeleteTexture(GfxResourceID* texId) { TextureObject* tex = (TextureObject*)(*texId); if (!tex) return; - cc_uint32 size = TextureSize(tex); - texmem_free(tex->data, size); + texmem_free(tex->data, tex->size); if (tex->format != PVR_TXRFMT_ARGB4444) { int index = (tex->format & PVR_TXRFMT_4BPP_PAL(63)) >> 21; diff --git a/src/Graphics_N64.c b/src/Graphics_N64.c index dea7d1f2f..5b011cb6e 100644 --- a/src/Graphics_N64.c +++ b/src/Graphics_N64.c @@ -45,7 +45,7 @@ void Gfx_Create(void) { Gfx.MaxTexSize = 1024; Gfx.MaxLowResTexSize = 2048; - Gfx.SupportsNonPowTwoTextures = true; + Gfx.NonPowTwoTexturesSupport = GFX_NONPOW2_FULL; Gfx_RestoreState(); Gfx_SetFaceCulling(false); diff --git a/src/_GraphicsBase.h b/src/_GraphicsBase.h index 5e5d91dff..aba23fff6 100644 --- a/src/_GraphicsBase.h +++ b/src/_GraphicsBase.h @@ -429,9 +429,9 @@ GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipm } GfxResourceID Gfx_CreateTexture2(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { - if (Gfx.SupportsNonPowTwoTextures && (flags & TEXTURE_FLAG_NONPOW2)) { + if (Gfx.NonPowTwoTexturesSupport && (flags & TEXTURE_FLAG_NONPOW2)) { /* Texture is being deliberately created and can be successfully created */ - /* with non power of two dimensions. Typically used for UI textures */ + /* with non power of two dimensions. Typically only used for UI textures */ } else if (!Math_IsPowOf2(bmp->width) || !Math_IsPowOf2(bmp->height)) { Process_Abort("Textures must have power of two dimensions"); } diff --git a/third_party/gldc/gldc.h b/third_party/gldc/gldc.h index 01b08492e..c9d932303 100644 --- a/third_party/gldc/gldc.h +++ b/third_party/gldc/gldc.h @@ -17,8 +17,9 @@ typedef struct { typedef struct { uint32_t format; void *data; - uint16_t width; - uint16_t height; + uint32_t log2_width: 4; + uint32_t log2_height: 4; + uint32_t size: 24; } TextureObject; void GLDC_NO_INLINE SubmitCommands(Vertex* v3, int n); diff --git a/third_party/gldc/state.c b/third_party/gldc/state.c index ebcbe5005..6b33e0867 100644 --- a/third_party/gldc/state.c +++ b/third_party/gldc/state.c @@ -19,21 +19,6 @@ static uint8_t BLEND_ENABLED; static uint8_t TEXTURES_ENABLED; static uint8_t AUTOSORT_ENABLED; -static inline int DimensionFlag(int w) { - switch(w) { - case 16: return 1; - case 32: return 2; - case 64: return 3; - case 128: return 4; - case 256: return 5; - case 512: return 6; - case 1024: return 7; - case 8: - default: - return 0; - } -} - static GLDC_NO_INLINE void apply_poly_header(pvr_poly_hdr_t* dst, int list_type) { TextureObject* tx1 = TEXTURE_ACTIVE; @@ -100,8 +85,8 @@ static GLDC_NO_INLINE void apply_poly_header(pvr_poly_hdr_t* dst, int list_type) dst->mode2 |= (PVR_MIPBIAS_NORMAL << PVR_TA_PM2_MIPBIAS_SHIFT) & PVR_TA_PM2_MIPBIAS_MASK; dst->mode2 |= (PVR_TXRENV_MODULATEALPHA << PVR_TA_PM2_TXRENV_SHIFT) & PVR_TA_PM2_TXRENV_MASK; - dst->mode2 |= (DimensionFlag(tx1->width) << PVR_TA_PM2_USIZE_SHIFT) & PVR_TA_PM2_USIZE_MASK; - dst->mode2 |= (DimensionFlag(tx1->height) << PVR_TA_PM2_VSIZE_SHIFT) & PVR_TA_PM2_VSIZE_MASK; + dst->mode2 |= ((tx1->log2_width - 3) << PVR_TA_PM2_USIZE_SHIFT) & PVR_TA_PM2_USIZE_MASK; + dst->mode2 |= ((tx1->log2_height - 3) << PVR_TA_PM2_VSIZE_SHIFT) & PVR_TA_PM2_VSIZE_MASK; dst->mode3 = (0 << PVR_TA_PM3_MIPMAP_SHIFT) & PVR_TA_PM3_MIPMAP_MASK; dst->mode3 |= (tx1->format << PVR_TA_PM3_TXRFMT_SHIFT) & PVR_TA_PM3_TXRFMT_MASK;