2018-05-11 14:39:28 +00:00
|
|
|
#include "private.h"
|
2018-08-07 19:22:44 +00:00
|
|
|
|
2018-08-14 08:49:31 +00:00
|
|
|
#include <stddef.h>
|
2018-05-11 14:39:28 +00:00
|
|
|
#include <stdio.h>
|
2018-09-20 14:01:13 +00:00
|
|
|
#include <stdlib.h>
|
2019-03-13 12:05:06 +00:00
|
|
|
#include <string.h>
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2019-02-25 08:30:02 +00:00
|
|
|
#include "config.h"
|
2021-04-09 15:24:47 +00:00
|
|
|
#include "platform.h"
|
2021-02-19 07:08:58 +00:00
|
|
|
|
2023-08-31 20:21:14 +00:00
|
|
|
#include "alloc/alloc.h"
|
2021-02-19 07:08:58 +00:00
|
|
|
|
|
|
|
/* We always leave this amount of vram unallocated to prevent
|
|
|
|
* issues with the allocator */
|
|
|
|
#define PVR_MEM_BUFFER_SIZE (64 * 1024)
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
#define CLAMP_U (1<<1)
|
|
|
|
#define CLAMP_V (1<<0)
|
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
static TextureObject* TEXTURE_UNITS[MAX_GLDC_TEXTURE_UNITS] = {NULL, NULL};
|
2018-05-11 14:39:28 +00:00
|
|
|
static NamedArray TEXTURE_OBJECTS;
|
2021-09-12 14:04:52 +00:00
|
|
|
GLubyte ACTIVE_TEXTURE = 0;
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2023-05-20 06:47:39 +00:00
|
|
|
static TexturePalette* SHARED_PALETTES[MAX_GLDC_SHARED_PALETTES] = {NULL, NULL, NULL, NULL};
|
2019-02-21 21:58:31 +00:00
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
static GLuint _determinePVRFormat(GLint internalFormat);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
static GLboolean BANKS_USED[MAX_GLDC_PALETTE_SLOTS]; // Each time a 256 colour bank is used, this is set to true
|
|
|
|
static GLboolean SUBBANKS_USED[MAX_GLDC_PALETTE_SLOTS][MAX_GLDC_4BPP_PALETTE_SLOTS]; // 4 counts of the used 16 colour banks within the 256 ones
|
|
|
|
|
|
|
|
static GLenum INTERNAL_PALETTE_FORMAT = GL_RGBA8;
|
2023-08-26 19:34:11 +00:00
|
|
|
static GLboolean TEXTURE_TWIDDLE_ENABLED = GL_FALSE;
|
2019-03-09 14:32:50 +00:00
|
|
|
|
2023-09-01 19:23:22 +00:00
|
|
|
#define STRINGIFY(x) #x
|
|
|
|
#define TOSTRING(x) STRINGIFY(x)
|
|
|
|
#define INFO_MSG(x) fprintf(stderr, "%s:%s > %s\n", __FILE__, TOSTRING(__LINE__), x)
|
|
|
|
|
2023-08-31 20:21:14 +00:00
|
|
|
static void* ALLOC_BASE = NULL;
|
|
|
|
static size_t ALLOC_SIZE = 0;
|
2021-02-19 07:08:58 +00:00
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
static const unsigned short MortonTable256[256] =
|
|
|
|
{
|
|
|
|
0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
|
|
|
|
0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
|
|
|
|
0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
|
|
|
|
0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
|
|
|
|
0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
|
|
|
|
0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
|
|
|
|
0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
|
|
|
|
0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
|
|
|
|
0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
|
|
|
|
0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
|
|
|
|
0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
|
|
|
|
0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
|
|
|
|
0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
|
|
|
|
0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
|
|
|
|
0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
|
|
|
|
0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
|
|
|
|
0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
|
|
|
|
0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
|
|
|
|
0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
|
|
|
|
0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
|
|
|
|
0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
|
|
|
|
0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
|
|
|
|
0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
|
|
|
|
0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
|
|
|
|
0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
|
|
|
|
0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
|
|
|
|
0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
|
|
|
|
0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
|
|
|
|
0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
|
|
|
|
0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
|
|
|
|
0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
|
|
|
|
0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* Given a 0-based texel location, and an image width/height. Return the
|
|
|
|
* new 0-based texel location */
|
|
|
|
GL_FORCE_INLINE uint32_t twid_location(uint32_t i, uint32_t w, uint32_t h) {
|
|
|
|
uint16_t y = i % w;
|
|
|
|
uint16_t x = i / w;
|
|
|
|
|
|
|
|
return MortonTable256[y >> 8] << 17 |
|
|
|
|
MortonTable256[x >> 8] << 16 |
|
|
|
|
MortonTable256[y & 0xFF] << 1 |
|
|
|
|
MortonTable256[x & 0xFF];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-08-31 20:21:14 +00:00
|
|
|
static void* alloc_malloc_and_defrag(size_t size) {
|
|
|
|
void* ret = alloc_malloc(ALLOC_BASE, size);
|
2021-02-20 15:04:40 +00:00
|
|
|
|
|
|
|
if(!ret) {
|
|
|
|
/* Tried to allocate, but out of room, let's try defragging
|
|
|
|
* and repeating the alloc */
|
2023-05-16 12:31:44 +00:00
|
|
|
fprintf(stderr, "Ran out of memory, defragmenting\n");
|
2021-02-20 15:04:40 +00:00
|
|
|
glDefragmentTextureMemory_KOS();
|
2023-08-31 20:21:14 +00:00
|
|
|
ret = alloc_malloc(ALLOC_BASE, size);
|
2021-02-20 15:04:40 +00:00
|
|
|
}
|
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(ret && "Out of PVR memory!");
|
2021-02-20 15:04:40 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-03-09 14:32:50 +00:00
|
|
|
static TexturePalette* _initTexturePalette() {
|
|
|
|
TexturePalette* palette = (TexturePalette*) malloc(sizeof(TexturePalette));
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(palette);
|
2019-03-09 14:32:50 +00:00
|
|
|
|
2021-04-09 15:24:47 +00:00
|
|
|
MEMSET4(palette, 0x0, sizeof(TexturePalette));
|
2019-03-09 14:32:50 +00:00
|
|
|
palette->bank = -1;
|
|
|
|
return palette;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GLshort _glGenPaletteSlot(GLushort size) {
|
|
|
|
GLushort i, j;
|
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(size == 16 || size == 256);
|
2019-03-09 14:32:50 +00:00
|
|
|
|
|
|
|
if(size == 16) {
|
2021-12-03 07:32:53 +00:00
|
|
|
for(i = 0; i < MAX_GLDC_PALETTE_SLOTS; ++i) {
|
|
|
|
for(j = 0; j < MAX_GLDC_4BPP_PALETTE_SLOTS; ++j) {
|
2019-03-09 14:32:50 +00:00
|
|
|
if(!SUBBANKS_USED[i][j]) {
|
|
|
|
BANKS_USED[i] = GL_TRUE;
|
|
|
|
SUBBANKS_USED[i][j] = GL_TRUE;
|
2021-12-03 07:32:53 +00:00
|
|
|
return (i * MAX_GLDC_4BPP_PALETTE_SLOTS) + j;
|
2019-03-09 14:32:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-03 07:32:53 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
for(i = 0; i < MAX_GLDC_PALETTE_SLOTS; ++i) {
|
2019-03-09 14:32:50 +00:00
|
|
|
if(!BANKS_USED[i]) {
|
|
|
|
BANKS_USED[i] = GL_TRUE;
|
2021-12-03 07:32:53 +00:00
|
|
|
for(j = 0; j < MAX_GLDC_4BPP_PALETTE_SLOTS; ++j) {
|
2019-03-09 14:32:50 +00:00
|
|
|
SUBBANKS_USED[i][j] = GL_TRUE;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "GL ERROR: No palette slots remain\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2022-05-03 13:12:27 +00:00
|
|
|
|
2021-11-30 17:23:49 +00:00
|
|
|
GLushort _glFreePaletteSlots(GLushort size)
|
|
|
|
{
|
|
|
|
GLushort i, j , slots = 0;
|
2019-03-09 14:32:50 +00:00
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(size == 16 || size == 256);
|
2021-11-30 17:23:49 +00:00
|
|
|
|
2019-03-09 14:32:50 +00:00
|
|
|
if(size == 16) {
|
2021-12-03 07:32:53 +00:00
|
|
|
for(i = 0; i < MAX_GLDC_PALETTE_SLOTS; ++i) {
|
|
|
|
for(j = 0; j < MAX_GLDC_4BPP_PALETTE_SLOTS; ++j) {
|
2021-11-30 17:23:49 +00:00
|
|
|
if(!SUBBANKS_USED[i][j]) {
|
|
|
|
slots++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-12-03 07:32:53 +00:00
|
|
|
for(i = 0; i < MAX_GLDC_PALETTE_SLOTS; ++i) {
|
2021-11-30 17:23:49 +00:00
|
|
|
if(!BANKS_USED[i]) {
|
|
|
|
slots++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return slots;
|
|
|
|
}
|
2019-03-09 14:32:50 +00:00
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
static void _glReleasePaletteSlot(GLshort slot, GLushort size)
|
|
|
|
{
|
2022-05-21 19:16:34 +00:00
|
|
|
GLushort i;
|
2019-03-09 14:32:50 +00:00
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(size == 16 || size == 256);
|
2021-12-03 07:32:53 +00:00
|
|
|
|
|
|
|
if (size == 16) {
|
2023-05-20 06:47:39 +00:00
|
|
|
GLushort bank = slot / MAX_GLDC_4BPP_PALETTE_SLOTS;
|
|
|
|
GLushort subbank = slot % MAX_GLDC_4BPP_PALETTE_SLOTS;
|
|
|
|
|
|
|
|
gl_assert(bank < MAX_GLDC_PALETTE_SLOTS);
|
|
|
|
gl_assert(subbank < MAX_GLDC_4BPP_PALETTE_SLOTS);
|
2019-03-09 14:32:50 +00:00
|
|
|
|
|
|
|
SUBBANKS_USED[bank][subbank] = GL_FALSE;
|
2021-12-03 07:32:53 +00:00
|
|
|
|
|
|
|
for (i = 0; i < MAX_GLDC_4BPP_PALETTE_SLOTS; ++i) {
|
|
|
|
if (SUBBANKS_USED[bank][i]) {
|
2019-03-09 14:32:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BANKS_USED[bank] = GL_FALSE;
|
2021-12-03 07:32:53 +00:00
|
|
|
}
|
|
|
|
else {
|
2023-05-20 06:47:39 +00:00
|
|
|
gl_assert(slot < MAX_GLDC_PALETTE_SLOTS);
|
2019-03-09 14:32:50 +00:00
|
|
|
BANKS_USED[slot] = GL_FALSE;
|
2021-12-03 07:32:53 +00:00
|
|
|
for (i = 0; i < MAX_GLDC_4BPP_PALETTE_SLOTS; ++i) {
|
2019-03-09 14:32:50 +00:00
|
|
|
SUBBANKS_USED[slot][i] = GL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
GLboolean _glGetTextureTwiddle() {
|
|
|
|
return TEXTURE_TWIDDLE_ENABLED;
|
2021-11-18 10:04:46 +00:00
|
|
|
}
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
void _glSetTextureTwiddle(GLboolean v) {
|
|
|
|
TEXTURE_TWIDDLE_ENABLED = v;
|
2021-04-09 15:24:47 +00:00
|
|
|
}
|
|
|
|
|
2019-03-10 11:18:56 +00:00
|
|
|
TexturePalette* _glGetSharedPalette(GLshort bank) {
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(bank >= 0 && bank < MAX_GLDC_SHARED_PALETTES);
|
2019-03-10 11:18:56 +00:00
|
|
|
return SHARED_PALETTES[bank];
|
|
|
|
}
|
2019-03-11 19:07:59 +00:00
|
|
|
void _glSetInternalPaletteFormat(GLenum val) {
|
|
|
|
INTERNAL_PALETTE_FORMAT = val;
|
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
switch(INTERNAL_PALETTE_FORMAT){
|
|
|
|
case GL_RGBA8:
|
|
|
|
GPUSetPaletteFormat(GPU_PAL_ARGB8888);
|
|
|
|
break;
|
|
|
|
case GL_RGBA4:
|
|
|
|
GPUSetPaletteFormat(GPU_PAL_ARGB4444);
|
|
|
|
break;
|
|
|
|
case GL_RGB5_A1:
|
|
|
|
GPUSetPaletteFormat(GPU_PAL_ARGB1555);
|
|
|
|
break;
|
|
|
|
case GL_RGB565_KOS:
|
|
|
|
GPUSetPaletteFormat(GPU_PAL_RGB565);
|
|
|
|
break;
|
|
|
|
default:
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(0);
|
2021-12-03 07:32:53 +00:00
|
|
|
|
2019-03-11 19:07:59 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-10 11:18:56 +00:00
|
|
|
void _glApplyColorTable(TexturePalette* src) {
|
|
|
|
if(!src || !src->data) {
|
2019-03-03 18:56:18 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-10 11:18:56 +00:00
|
|
|
GLushort i;
|
|
|
|
GLushort offset = src->size * src->bank;
|
2021-11-18 10:04:46 +00:00
|
|
|
|
2019-03-10 11:18:56 +00:00
|
|
|
for(i = 0; i < src->width; ++i) {
|
2019-02-21 21:58:31 +00:00
|
|
|
GLubyte* entry = &src->data[i * 4];
|
2021-12-03 07:32:53 +00:00
|
|
|
|
|
|
|
switch(INTERNAL_PALETTE_FORMAT)
|
|
|
|
{
|
|
|
|
case GL_RGBA8:
|
|
|
|
GPUSetPaletteEntry(offset + i, PACK_ARGB8888(entry[3], entry[0], entry[1], entry[2]));
|
|
|
|
break;
|
|
|
|
case GL_RGBA4:
|
|
|
|
GPUSetPaletteEntry(offset + i, PACK_ARGB4444(entry[3], entry[0], entry[1], entry[2]));
|
|
|
|
break;
|
|
|
|
case GL_RGB5_A1:
|
|
|
|
GPUSetPaletteEntry(offset + i, PACK_ARGB1555(entry[3], entry[0], entry[1], entry[2]));
|
|
|
|
break;
|
|
|
|
case GL_RGB565_KOS:
|
|
|
|
GPUSetPaletteEntry(offset + i, PACK_RGB565(entry[0], entry[1], entry[2]));
|
|
|
|
break;
|
2019-03-11 19:07:59 +00:00
|
|
|
}
|
2019-02-21 20:35:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-14 08:49:31 +00:00
|
|
|
GLubyte _glGetActiveTexture() {
|
|
|
|
return ACTIVE_TEXTURE;
|
|
|
|
}
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
static GLint _determineStrideInternal(GLenum internalFormat) {
|
|
|
|
switch(internalFormat) {
|
|
|
|
case GL_RGB565_KOS:
|
|
|
|
case GL_ARGB4444_KOS:
|
|
|
|
case GL_ARGB1555_KOS:
|
|
|
|
case GL_RGB565_TWID_KOS:
|
|
|
|
case GL_ARGB4444_TWID_KOS:
|
|
|
|
case GL_ARGB1555_TWID_KOS:
|
|
|
|
return 2;
|
|
|
|
case GL_COLOR_INDEX8_TWID_KOS:
|
|
|
|
case GL_COLOR_INDEX4_TWID_KOS:
|
|
|
|
case GL_COLOR_INDEX4_EXT:
|
|
|
|
case GL_COLOR_INDEX8_EXT:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static GLint _determineStride(GLenum format, GLenum type) {
|
2018-08-08 15:50:09 +00:00
|
|
|
switch(type) {
|
|
|
|
case GL_BYTE:
|
|
|
|
case GL_UNSIGNED_BYTE:
|
2019-09-17 01:48:06 +00:00
|
|
|
return (format == GL_RED || format == GL_ALPHA) ? 1 : (format == GL_RGB) ? 3 : 4;
|
2018-08-08 15:50:09 +00:00
|
|
|
case GL_UNSIGNED_SHORT:
|
2019-09-17 01:48:06 +00:00
|
|
|
return (format == GL_RED || format == GL_ALPHA) ? 2 : (format == GL_RGB) ? 6 : 8;
|
2018-08-13 08:18:59 +00:00
|
|
|
case GL_UNSIGNED_SHORT_5_6_5:
|
2018-08-08 15:50:09 +00:00
|
|
|
case GL_UNSIGNED_SHORT_5_6_5_REV:
|
|
|
|
case GL_UNSIGNED_SHORT_5_6_5_TWID_KOS:
|
|
|
|
case GL_UNSIGNED_SHORT_5_5_5_1:
|
|
|
|
case GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS:
|
|
|
|
case GL_UNSIGNED_SHORT_1_5_5_5_REV:
|
|
|
|
case GL_UNSIGNED_SHORT_4_4_4_4:
|
|
|
|
case GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS:
|
|
|
|
case GL_UNSIGNED_SHORT_4_4_4_4_REV:
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
static GLuint _glGetMipmapDataOffset(const TextureObject* obj, GLuint level) {
|
2018-08-08 15:50:09 +00:00
|
|
|
GLuint offset = 0;
|
2019-09-24 14:47:23 +00:00
|
|
|
GLuint size = obj->height;
|
2018-08-08 15:50:09 +00:00
|
|
|
|
2019-09-24 14:47:23 +00:00
|
|
|
if(obj->width != obj->height) {
|
|
|
|
fprintf(stderr, "ERROR: Accessing memory location of mipmaps on non-square texture\n");
|
|
|
|
return obj->baseDataOffset;
|
|
|
|
}
|
2020-05-19 20:27:34 +00:00
|
|
|
|
2019-09-24 14:47:23 +00:00
|
|
|
if(obj->isPaletted){
|
2019-09-26 08:17:07 +00:00
|
|
|
switch(size >> level){
|
2019-09-24 20:26:17 +00:00
|
|
|
case 1024:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x55558;
|
2019-09-24 20:26:17 +00:00
|
|
|
break;
|
|
|
|
case 512:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x15558;
|
2019-09-24 20:26:17 +00:00
|
|
|
break;
|
2019-09-24 14:47:23 +00:00
|
|
|
case 256:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x05558;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
|
|
|
case 128:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x01558;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
|
|
|
case 64:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x00558;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
|
|
|
case 32:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x00158;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
|
|
|
case 16:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x00058;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
|
|
|
case 8:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x00018;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x00008;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x00004;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2019-09-26 08:17:07 +00:00
|
|
|
offset = 0x00003;
|
2019-09-24 14:47:23 +00:00
|
|
|
break;
|
2018-08-08 15:50:09 +00:00
|
|
|
}
|
2020-03-05 20:09:19 +00:00
|
|
|
} else if(obj->isCompressed) {
|
|
|
|
switch(size >> level){
|
|
|
|
case 1024:
|
|
|
|
offset = 0x15556;
|
|
|
|
break;
|
|
|
|
case 512:
|
|
|
|
offset = 0x05556;
|
2020-05-19 20:27:34 +00:00
|
|
|
break;
|
2020-03-05 20:09:19 +00:00
|
|
|
case 256:
|
|
|
|
offset = 0x01556;
|
|
|
|
break;
|
|
|
|
case 128:
|
|
|
|
offset = 0x00556;
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
offset = 0x00156;
|
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
offset = 0x00056;
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
offset = 0x00016;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
offset = 0x00006;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
offset = 0x00002;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
offset = 0x00001;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
offset = 0x00000;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}else {
|
|
|
|
switch(size >> level){
|
2019-09-24 20:26:17 +00:00
|
|
|
case 1024:
|
|
|
|
offset = 0xAAAB0;
|
|
|
|
break;
|
|
|
|
case 512:
|
|
|
|
offset = 0x2AAB0;
|
|
|
|
break;
|
2019-09-24 14:47:23 +00:00
|
|
|
case 256:
|
|
|
|
offset = 0x0AAB0;
|
|
|
|
break;
|
|
|
|
case 128:
|
|
|
|
offset = 0x02AB0;
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
offset = 0x00AB0;
|
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
offset = 0x002B0;
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
offset = 0x000B0;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
offset = 0x00030;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
offset = 0x00010;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
offset = 0x00008;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
offset = 0x00006;
|
|
|
|
break;
|
2018-08-08 15:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-24 14:47:23 +00:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GLubyte* _glGetMipmapLocation(const TextureObject* obj, GLuint level) {
|
2019-09-24 14:47:23 +00:00
|
|
|
return ((GLubyte*) obj->data) + _glGetMipmapDataOffset(obj, level);
|
2018-08-08 15:50:09 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GLuint _glGetMipmapLevelCount(const TextureObject* obj) {
|
|
|
|
return 1 + floorf(log2f(MAX(obj->width, obj->height)));
|
2018-08-08 15:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static GLuint _glGetMipmapDataSize(TextureObject* obj) {
|
2019-09-24 14:47:23 +00:00
|
|
|
/* The mipmap data size is the offset + the size of the
|
|
|
|
* image */
|
2018-08-08 15:50:09 +00:00
|
|
|
|
2019-09-24 20:26:17 +00:00
|
|
|
GLuint imageSize = obj->baseDataSize;
|
2019-09-24 14:47:23 +00:00
|
|
|
GLuint offset = _glGetMipmapDataOffset(obj, 0);
|
2018-08-08 15:50:09 +00:00
|
|
|
|
2019-09-24 14:47:23 +00:00
|
|
|
return imageSize + offset;
|
2018-08-08 15:50:09 +00:00
|
|
|
}
|
|
|
|
|
2022-05-03 13:12:27 +00:00
|
|
|
|
|
|
|
void _glResetSharedPalettes()
|
|
|
|
{
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for (i=0; i < MAX_GLDC_SHARED_PALETTES;i++){
|
|
|
|
|
|
|
|
MEMSET4(SHARED_PALETTES[i], 0x0, sizeof(TexturePalette));
|
|
|
|
SHARED_PALETTES[i]->bank = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset((void*) BANKS_USED, 0x0, sizeof(BANKS_USED));
|
|
|
|
memset((void*) SUBBANKS_USED, 0x0, sizeof(SUBBANKS_USED));
|
|
|
|
|
|
|
|
}
|
2023-05-17 19:36:59 +00:00
|
|
|
|
|
|
|
static void _glInitializeTextureObject(TextureObject* txr, unsigned int id) {
|
|
|
|
txr->index = id;
|
|
|
|
txr->width = txr->height = 0;
|
|
|
|
txr->mipmap = 0;
|
|
|
|
txr->uv_clamp = 0;
|
|
|
|
txr->env = GPU_TXRENV_MODULATEALPHA;
|
|
|
|
txr->data = NULL;
|
|
|
|
txr->mipmapCount = 0;
|
|
|
|
txr->minFilter = GL_NEAREST;
|
|
|
|
txr->magFilter = GL_NEAREST;
|
|
|
|
txr->palette = NULL;
|
|
|
|
txr->isCompressed = GL_FALSE;
|
|
|
|
txr->isPaletted = GL_FALSE;
|
|
|
|
txr->mipmap_bias = GL_KOS_INTERNAL_DEFAULT_MIPMAP_LOD_BIAS;
|
|
|
|
|
|
|
|
/* Not mipmapped by default */
|
|
|
|
txr->baseDataOffset = 0;
|
|
|
|
|
|
|
|
/* Always default to the first shared bank */
|
|
|
|
txr->shared_bank = 0;
|
|
|
|
}
|
|
|
|
|
2019-03-03 19:02:25 +00:00
|
|
|
GLubyte _glInitTextures() {
|
2019-02-25 08:30:02 +00:00
|
|
|
named_array_init(&TEXTURE_OBJECTS, sizeof(TextureObject), MAX_TEXTURE_COUNT);
|
2019-02-21 21:58:31 +00:00
|
|
|
|
2019-02-28 18:33:37 +00:00
|
|
|
// Reserve zero so that it is never given to anyone as an ID!
|
|
|
|
named_array_reserve(&TEXTURE_OBJECTS, 0);
|
|
|
|
|
2023-05-17 19:36:59 +00:00
|
|
|
// Initialize zero as an actual texture object though because apparently it is!
|
2023-05-20 06:47:39 +00:00
|
|
|
TextureObject* default_tex = (TextureObject*) named_array_get(&TEXTURE_OBJECTS, 0);
|
|
|
|
_glInitializeTextureObject(default_tex, 0);
|
|
|
|
TEXTURE_UNITS[0] = default_tex;
|
|
|
|
TEXTURE_UNITS[1] = default_tex;
|
2023-05-17 19:36:59 +00:00
|
|
|
|
2023-05-20 06:47:39 +00:00
|
|
|
for(int i = 0; i < MAX_GLDC_SHARED_PALETTES; i++){
|
2021-12-03 07:32:53 +00:00
|
|
|
SHARED_PALETTES[i] = _initTexturePalette();
|
|
|
|
}
|
2019-03-10 11:18:56 +00:00
|
|
|
|
2022-05-03 13:12:27 +00:00
|
|
|
_glResetSharedPalettes();
|
|
|
|
|
|
|
|
//memset((void*) BANKS_USED, 0x0, sizeof(BANKS_USED));
|
|
|
|
//memset((void*) SUBBANKS_USED, 0x0, sizeof(SUBBANKS_USED));
|
2021-02-19 07:08:58 +00:00
|
|
|
|
2021-04-09 15:24:47 +00:00
|
|
|
size_t vram_free = GPUMemoryAvailable();
|
2023-08-31 20:21:14 +00:00
|
|
|
ALLOC_SIZE = vram_free - PVR_MEM_BUFFER_SIZE; /* Take all but 64kb VRAM */
|
|
|
|
ALLOC_BASE = GPUMemoryAlloc(ALLOC_SIZE);
|
2021-04-18 12:57:00 +00:00
|
|
|
|
2021-04-18 20:33:23 +00:00
|
|
|
#ifdef __DREAMCAST__
|
2021-04-18 12:57:00 +00:00
|
|
|
/* Ensure memory is aligned */
|
2023-09-01 07:34:48 +00:00
|
|
|
gl_assert((uintptr_t) ALLOC_BASE % 32 == 0);
|
2021-04-18 20:33:23 +00:00
|
|
|
#endif
|
2021-04-18 12:57:00 +00:00
|
|
|
|
2023-08-31 20:21:14 +00:00
|
|
|
alloc_init(ALLOC_BASE, ALLOC_SIZE);
|
2023-05-17 19:39:58 +00:00
|
|
|
|
|
|
|
gl_assert(TEXTURE_OBJECTS.element_size > 0);
|
2018-05-11 14:39:28 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-03-03 19:06:01 +00:00
|
|
|
TextureObject* _glGetTexture0() {
|
2018-05-11 14:39:28 +00:00
|
|
|
return TEXTURE_UNITS[0];
|
|
|
|
}
|
|
|
|
|
2019-03-03 19:06:01 +00:00
|
|
|
TextureObject* _glGetTexture1() {
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(1 < MAX_GLDC_TEXTURE_UNITS);
|
2018-05-11 14:39:28 +00:00
|
|
|
return TEXTURE_UNITS[1];
|
|
|
|
}
|
|
|
|
|
2019-03-03 19:06:01 +00:00
|
|
|
TextureObject* _glGetBoundTexture() {
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS);
|
2018-05-11 14:39:28 +00:00
|
|
|
return TEXTURE_UNITS[ACTIVE_TEXTURE];
|
|
|
|
}
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
GLint _glGetTextureInternalFormat() {
|
|
|
|
TextureObject* obj = _glGetBoundTexture();
|
|
|
|
if(!obj) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj->internalFormat;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
void APIENTRY glActiveTextureARB(GLenum texture) {
|
|
|
|
TRACE();
|
|
|
|
|
2023-05-17 19:39:27 +00:00
|
|
|
if(texture < GL_TEXTURE0_ARB || texture >= GL_TEXTURE0_ARB + MAX_GLDC_TEXTURE_UNITS) {
|
2018-05-11 14:39:28 +00:00
|
|
|
_glKosThrowError(GL_INVALID_ENUM, "glActiveTextureARB");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTIVE_TEXTURE = texture & 0xF;
|
2023-05-17 19:39:27 +00:00
|
|
|
gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS);
|
|
|
|
gl_assert(TEXTURE_OBJECTS.element_size > 0);
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2018-05-20 20:28:48 +00:00
|
|
|
GLboolean APIENTRY glIsTexture(GLuint texture) {
|
|
|
|
return (named_array_used(&TEXTURE_OBJECTS, texture)) ? GL_TRUE : GL_FALSE;
|
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
void APIENTRY glGenTextures(GLsizei n, GLuint *textures) {
|
|
|
|
TRACE();
|
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(TEXTURE_OBJECTS.element_size > 0);
|
|
|
|
|
2023-05-20 06:47:39 +00:00
|
|
|
for(GLsizei i = 0; i < n; ++i) {
|
2018-05-11 14:39:28 +00:00
|
|
|
GLuint id = 0;
|
|
|
|
TextureObject* txr = (TextureObject*) named_array_alloc(&TEXTURE_OBJECTS, &id);
|
2023-05-16 12:31:44 +00:00
|
|
|
gl_assert(txr);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(id); // Generated IDs must never be zero
|
2019-02-28 18:33:37 +00:00
|
|
|
|
2019-02-27 20:45:53 +00:00
|
|
|
_glInitializeTextureObject(txr, id);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(txr->index == id);
|
|
|
|
|
2023-05-20 06:47:39 +00:00
|
|
|
textures[i] = id;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2023-05-17 19:39:58 +00:00
|
|
|
|
|
|
|
gl_assert(TEXTURE_OBJECTS.element_size > 0);
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glDeleteTextures(GLsizei n, GLuint *textures) {
|
|
|
|
TRACE();
|
|
|
|
|
2023-05-17 19:39:49 +00:00
|
|
|
gl_assert(TEXTURE_OBJECTS.element_size > 0);
|
|
|
|
|
|
|
|
for(GLsizei i = 0; i < n; ++i) {
|
|
|
|
GLuint id = textures[i];
|
|
|
|
if(id == 0) {
|
|
|
|
/* Zero is the "default texture" and we never allow deletion of it */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureObject* txr = (TextureObject*) named_array_get(&TEXTURE_OBJECTS, id);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2023-05-16 12:31:44 +00:00
|
|
|
if(txr) {
|
2023-05-17 19:39:49 +00:00
|
|
|
gl_assert(txr->index == id);
|
|
|
|
|
2023-05-16 12:31:44 +00:00
|
|
|
/* Make sure we update framebuffer objects that have this texture attached */
|
2023-05-17 19:39:49 +00:00
|
|
|
_glWipeTextureOnFramebuffers(id);
|
2018-05-20 20:28:48 +00:00
|
|
|
|
2023-05-17 19:39:49 +00:00
|
|
|
for(GLuint j = 0; j < MAX_GLDC_TEXTURE_UNITS; ++j) {
|
|
|
|
if(txr == TEXTURE_UNITS[j]) {
|
2023-05-20 06:47:39 +00:00
|
|
|
// Reset to the default texture
|
|
|
|
TEXTURE_UNITS[j] = (TextureObject*) named_array_get(&TEXTURE_OBJECTS, 0);
|
2023-05-17 19:39:49 +00:00
|
|
|
}
|
2023-05-16 12:31:44 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2023-05-16 12:31:44 +00:00
|
|
|
if(txr->data) {
|
2023-08-31 20:21:14 +00:00
|
|
|
alloc_free(ALLOC_BASE, txr->data);
|
2023-05-16 12:31:44 +00:00
|
|
|
txr->data = NULL;
|
|
|
|
}
|
2021-12-03 07:32:53 +00:00
|
|
|
|
2023-05-16 12:31:44 +00:00
|
|
|
if(txr->palette && txr->palette->data) {
|
|
|
|
if (txr->palette->bank > -1) {
|
|
|
|
_glReleasePaletteSlot(txr->palette->bank, txr->palette->size);
|
|
|
|
txr->palette->bank = -1;
|
|
|
|
}
|
|
|
|
free(txr->palette->data);
|
|
|
|
txr->palette->data = NULL;
|
2021-12-03 07:32:53 +00:00
|
|
|
}
|
2018-09-22 19:45:17 +00:00
|
|
|
|
2023-05-16 12:31:44 +00:00
|
|
|
if(txr->palette) {
|
|
|
|
free(txr->palette);
|
|
|
|
txr->palette = NULL;
|
|
|
|
}
|
2018-09-22 19:45:17 +00:00
|
|
|
|
2023-05-17 19:39:49 +00:00
|
|
|
named_array_release(&TEXTURE_OBJECTS, id);
|
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2023-05-17 19:39:49 +00:00
|
|
|
|
|
|
|
gl_assert(TEXTURE_OBJECTS.element_size > 0);
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glBindTexture(GLenum target, GLuint texture) {
|
|
|
|
TRACE();
|
|
|
|
|
2019-03-13 15:14:09 +00:00
|
|
|
GLint target_values [] = {GL_TEXTURE_2D, 0};
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2018-08-22 08:24:49 +00:00
|
|
|
if(_glCheckValidEnum(target, target_values, __func__) != 0) {
|
2018-05-11 14:39:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
TextureObject* txr = (TextureObject*) named_array_get(&TEXTURE_OBJECTS, texture);
|
2019-02-28 18:28:43 +00:00
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
/* If this didn't come from glGenTextures, then we should initialize the
|
|
|
|
* texture the first time it's bound */
|
|
|
|
if(!txr) {
|
|
|
|
TextureObject* txr = named_array_reserve(&TEXTURE_OBJECTS, texture);
|
|
|
|
_glInitializeTextureObject(txr, texture);
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2023-03-17 20:40:45 +00:00
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS);
|
|
|
|
TEXTURE_UNITS[ACTIVE_TEXTURE] = txr;
|
|
|
|
gl_assert(TEXTURE_UNITS[ACTIVE_TEXTURE]->index == texture);
|
|
|
|
|
|
|
|
gl_assert(TEXTURE_OBJECTS.element_size > 0);
|
|
|
|
|
2023-03-17 20:40:45 +00:00
|
|
|
_glGPUStateMarkDirty();
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glTexEnvi(GLenum target, GLenum pname, GLint param) {
|
|
|
|
TRACE();
|
|
|
|
|
|
|
|
GLubyte failures = 0;
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GLint target_values [] = {GL_TEXTURE_ENV, GL_TEXTURE_FILTER_CONTROL_EXT, 0};
|
2018-08-22 08:24:49 +00:00
|
|
|
failures += _glCheckValidEnum(target, target_values, __func__);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS);
|
2018-05-11 14:39:28 +00:00
|
|
|
TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE];
|
2020-05-19 20:27:34 +00:00
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
if(!active) {
|
2023-05-17 19:39:58 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2018-05-11 14:39:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(failures) {
|
|
|
|
return;
|
|
|
|
}
|
2020-03-05 20:09:19 +00:00
|
|
|
switch(target){
|
|
|
|
case GL_TEXTURE_ENV:
|
|
|
|
{
|
|
|
|
GLint pname_values [] = {GL_TEXTURE_ENV_MODE, 0};
|
|
|
|
GLint param_values [] = {GL_MODULATE, GL_DECAL, GL_REPLACE, 0};
|
|
|
|
failures += _glCheckValidEnum(pname, pname_values, __func__);
|
|
|
|
failures += _glCheckValidEnum(param, param_values, __func__);
|
2020-05-19 20:27:34 +00:00
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
if(failures) {
|
|
|
|
return;
|
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
switch(param) {
|
|
|
|
case GL_MODULATE:
|
2021-04-09 15:24:47 +00:00
|
|
|
active->env = GPU_TXRENV_MODULATEALPHA;
|
2020-03-05 20:09:19 +00:00
|
|
|
break;
|
|
|
|
case GL_DECAL:
|
2021-04-09 15:24:47 +00:00
|
|
|
active->env = GPU_TXRENV_DECAL;
|
2020-03-05 20:09:19 +00:00
|
|
|
break;
|
|
|
|
case GL_REPLACE:
|
2021-04-09 15:24:47 +00:00
|
|
|
active->env = GPU_TXRENV_REPLACE;
|
2020-03-05 20:09:19 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_TEXTURE_FILTER_CONTROL_EXT:
|
|
|
|
{
|
|
|
|
GLint pname_values [] = {GL_TEXTURE_LOD_BIAS_EXT, 0};
|
|
|
|
failures += _glCheckValidEnum(pname, pname_values, __func__);
|
2020-05-19 20:27:34 +00:00
|
|
|
failures += (param > GL_MAX_TEXTURE_LOD_BIAS_DEFAULT || param < -GL_MAX_TEXTURE_LOD_BIAS_DEFAULT);
|
2020-03-05 20:09:19 +00:00
|
|
|
if(failures) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
active->mipmap_bias = (GL_MAX_TEXTURE_LOD_BIAS_DEFAULT+1)+param; // bring to 1-15 inclusive
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2023-03-17 20:40:45 +00:00
|
|
|
|
|
|
|
_glGPUStateMarkDirty();
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glTexEnvf(GLenum target, GLenum pname, GLfloat param) {
|
|
|
|
glTexEnvi(target, pname, param);
|
|
|
|
}
|
|
|
|
|
2018-08-07 19:49:10 +00:00
|
|
|
void APIENTRY glCompressedTexImage2DARB(GLenum target,
|
2018-05-11 14:39:28 +00:00
|
|
|
GLint level,
|
2018-08-07 19:22:44 +00:00
|
|
|
GLenum internalFormat,
|
2018-05-11 14:39:28 +00:00
|
|
|
GLsizei width,
|
|
|
|
GLsizei height,
|
|
|
|
GLint border,
|
|
|
|
GLsizei imageSize,
|
|
|
|
const GLvoid *data) {
|
|
|
|
TRACE();
|
|
|
|
|
2018-08-13 08:18:59 +00:00
|
|
|
if(target != GL_TEXTURE_2D) {
|
2018-08-07 19:49:10 +00:00
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
2021-09-13 09:29:04 +00:00
|
|
|
return;
|
2018-08-13 08:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLint w = width;
|
|
|
|
if(w < 8 || (w & -w) != w) {
|
|
|
|
/* Width is not a power of two. Must be!*/
|
2018-09-22 19:45:17 +00:00
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2021-09-13 09:29:04 +00:00
|
|
|
return;
|
2018-08-13 08:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLint h = height;
|
|
|
|
if(h < 8 || (h & -h) != h) {
|
2018-08-14 14:55:03 +00:00
|
|
|
/* Height is not a power of two. Must be!*/
|
2018-09-22 19:45:17 +00:00
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2021-09-13 09:29:04 +00:00
|
|
|
return;
|
2018-08-13 08:18:59 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2018-08-08 08:50:57 +00:00
|
|
|
if(level || border) {
|
|
|
|
/* We don't support setting mipmap levels manually with compressed textures
|
|
|
|
maybe one day */
|
2018-08-07 19:49:10 +00:00
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2021-09-13 09:29:04 +00:00
|
|
|
return;
|
2018-08-08 08:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLboolean mipmapped = GL_FALSE;
|
2021-12-03 07:32:53 +00:00
|
|
|
//GLboolean paletted = GL_FALSE;
|
|
|
|
GLbyte *ptr = (GLbyte*)data;
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2018-08-07 19:22:44 +00:00
|
|
|
switch(internalFormat) {
|
|
|
|
case GL_COMPRESSED_ARGB_1555_VQ_KOS:
|
|
|
|
case GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS:
|
|
|
|
case GL_COMPRESSED_ARGB_4444_VQ_KOS:
|
|
|
|
case GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS:
|
|
|
|
case GL_COMPRESSED_RGB_565_VQ_KOS:
|
|
|
|
case GL_COMPRESSED_RGB_565_VQ_TWID_KOS:
|
|
|
|
break;
|
2018-08-08 08:50:57 +00:00
|
|
|
case GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS:
|
|
|
|
case GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS:
|
|
|
|
case GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS:
|
|
|
|
case GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS:
|
|
|
|
case GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS:
|
|
|
|
case GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS:
|
|
|
|
mipmapped = GL_TRUE;
|
|
|
|
break;
|
2021-12-03 07:32:53 +00:00
|
|
|
case GL_PALETTE4_RGB8_OES:
|
|
|
|
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 16, internalFormat, GL_UNSIGNED_BYTE, data);
|
|
|
|
ptr += 16*3;
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, level, GL_COLOR_INDEX4_EXT, width, height, border, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, ptr);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case GL_PALETTE4_RGBA8_OES:
|
|
|
|
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 16, internalFormat, GL_UNSIGNED_BYTE, data);
|
|
|
|
ptr += 16*4;
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, level, GL_COLOR_INDEX4_EXT, width, height, border, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, ptr);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case GL_PALETTE4_R5_G6_B5_OES:
|
|
|
|
case GL_PALETTE4_RGBA4_OES:
|
|
|
|
case GL_PALETTE4_RGB5_A1_OES:
|
|
|
|
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 16, internalFormat, GL_UNSIGNED_BYTE, data);
|
|
|
|
ptr += 16*2;
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, level, GL_COLOR_INDEX4_EXT, width, height, border, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, ptr);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case GL_PALETTE8_RGB8_OES:
|
|
|
|
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 256, internalFormat, GL_UNSIGNED_BYTE, data);
|
|
|
|
ptr += 256*3;
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, level, GL_COLOR_INDEX8_EXT, width, height, border, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, ptr);
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
case GL_PALETTE8_RGBA8_OES:
|
|
|
|
//
|
|
|
|
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 256, internalFormat, GL_UNSIGNED_BYTE, data);
|
|
|
|
ptr += 256*4;
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, level, GL_COLOR_INDEX8_EXT, width, height, border, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, ptr);
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
case GL_PALETTE8_RGBA4_OES:
|
|
|
|
case GL_PALETTE8_RGB5_A1_OES:
|
|
|
|
case GL_PALETTE8_R5_G6_B5_OES:
|
|
|
|
|
|
|
|
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 256, internalFormat, GL_UNSIGNED_BYTE, data);
|
|
|
|
ptr += 256*2;
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, level, GL_COLOR_INDEX8_EXT, width, height, border, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, ptr);
|
|
|
|
return;
|
|
|
|
|
2021-09-13 09:29:04 +00:00
|
|
|
default: {
|
2022-05-07 11:57:45 +00:00
|
|
|
fprintf(stderr, "Unsupported internalFormat: %d\n", internalFormat);
|
2021-09-13 09:29:04 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
|
|
|
return;
|
|
|
|
}
|
2018-08-07 19:22:44 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS);
|
|
|
|
TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE];
|
|
|
|
GLuint original_id = active->index;
|
|
|
|
|
|
|
|
if(!active) {
|
2018-08-07 19:49:10 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2018-05-11 14:39:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-08 08:50:57 +00:00
|
|
|
/* Set the required mipmap count */
|
2018-05-11 14:39:28 +00:00
|
|
|
active->width = width;
|
|
|
|
active->height = height;
|
2023-08-26 19:34:11 +00:00
|
|
|
active->internalFormat = internalFormat;
|
|
|
|
active->color = _determinePVRFormat(internalFormat);
|
2018-08-20 07:34:54 +00:00
|
|
|
active->mipmapCount = _glGetMipmapLevelCount(active);
|
|
|
|
active->mipmap = (mipmapped) ? ~0 : (1 << level); /* Set only a single bit if this wasn't mipmapped otherwise set all */
|
|
|
|
active->isCompressed = GL_TRUE;
|
2018-05-11 14:39:28 +00:00
|
|
|
|
|
|
|
/* Odds are slim new data is same size as old, so free always */
|
2021-02-19 07:08:58 +00:00
|
|
|
if(active->data) {
|
2023-08-31 20:21:14 +00:00
|
|
|
alloc_free(ALLOC_BASE, active->data);
|
2021-02-19 07:08:58 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2023-08-31 20:21:14 +00:00
|
|
|
active->data = alloc_malloc_and_defrag(imageSize);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(active->data); // Debug assert
|
2021-09-04 11:13:59 +00:00
|
|
|
|
|
|
|
if(!active->data) { // Release, bail out "gracefully"
|
|
|
|
_glKosThrowError(GL_OUT_OF_MEMORY, __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-19 07:08:58 +00:00
|
|
|
if(data) {
|
2021-04-09 15:24:47 +00:00
|
|
|
FASTCPY(active->data, data, imageSize);
|
2021-02-19 07:08:58 +00:00
|
|
|
}
|
2023-05-16 12:31:44 +00:00
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(original_id == active->index);
|
|
|
|
|
2023-05-16 12:31:44 +00:00
|
|
|
_glGPUStateMarkDirty();
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
static GLboolean isTwiddledInternalFormat(GLint internalFormat) {
|
|
|
|
switch(internalFormat) {
|
|
|
|
case GL_RGB565_TWID_KOS:
|
|
|
|
case GL_ARGB4444_TWID_KOS:
|
|
|
|
case GL_ARGB1555_TWID_KOS:
|
|
|
|
case GL_COLOR_INDEX8_TWID_KOS:
|
|
|
|
case GL_COLOR_INDEX4_TWID_KOS:
|
|
|
|
case GL_RGB_TWID_KOS:
|
|
|
|
case GL_RGBA_TWID_KOS:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Takes an internal format, and returns a GL format matching how we'd store
|
|
|
|
* it internally, so it'll return one of the following:
|
|
|
|
*
|
|
|
|
* - GL_RGB565_KOS,
|
|
|
|
* - GL_ARGB4444_KOS
|
|
|
|
* - GL_ARGB1555_KOS
|
|
|
|
* - GL_RGB565_TWID_KOS
|
|
|
|
* - GL_ARGB4444_TWID_KOS
|
|
|
|
* - GL_ARGB1555_TWID_KOS
|
|
|
|
* - GL_COLOR_INDEX8_EXT
|
|
|
|
* - GL_COLOR_INDEX4_EXT
|
|
|
|
* - GL_COLOR_INDEX8_TWID_KOS
|
|
|
|
* - GL_COLOR_INDEX4_TWID_KOS
|
|
|
|
*/
|
2018-05-11 14:39:28 +00:00
|
|
|
static GLint _cleanInternalFormat(GLint internalFormat) {
|
|
|
|
switch (internalFormat) {
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_RGB565_KOS:
|
|
|
|
case GL_ARGB4444_KOS:
|
|
|
|
case GL_ARGB1555_KOS:
|
|
|
|
case GL_RGB565_TWID_KOS:
|
|
|
|
case GL_ARGB4444_TWID_KOS:
|
|
|
|
case GL_ARGB1555_TWID_KOS:
|
|
|
|
case GL_COLOR_INDEX8_TWID_KOS:
|
|
|
|
case GL_COLOR_INDEX4_TWID_KOS:
|
2020-03-05 20:09:19 +00:00
|
|
|
case GL_COLOR_INDEX4_EXT:
|
2018-09-22 19:45:17 +00:00
|
|
|
case GL_COLOR_INDEX8_EXT:
|
2023-08-26 19:34:11 +00:00
|
|
|
/* All of these formats are fine as they are, no conversion needed */
|
|
|
|
return internalFormat;
|
|
|
|
case GL_RGB_TWID_KOS:
|
|
|
|
return GL_RGB565_TWID_KOS;
|
|
|
|
case GL_RGBA_TWID_KOS:
|
|
|
|
return GL_ARGB4444_TWID_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_ALPHA:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_ALPHA4:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_ALPHA8:
|
|
|
|
case GL_ALPHA12:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_ALPHA16:
|
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_ARGB4444_TWID_KOS : GL_ARGB4444_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
case 1:
|
|
|
|
case GL_LUMINANCE:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_LUMINANCE4:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_LUMINANCE8:
|
|
|
|
case GL_LUMINANCE12:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_LUMINANCE16:
|
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_ARGB1555_TWID_KOS : GL_ARGB1555_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
case 2:
|
|
|
|
case GL_LUMINANCE_ALPHA:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_LUMINANCE4_ALPHA4:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_LUMINANCE6_ALPHA2:
|
|
|
|
case GL_LUMINANCE8_ALPHA8:
|
|
|
|
case GL_LUMINANCE12_ALPHA4:
|
|
|
|
case GL_LUMINANCE12_ALPHA12:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_LUMINANCE16_ALPHA16:
|
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_ARGB4444_TWID_KOS : GL_ARGB4444_KOS;
|
|
|
|
case GL_INTENSITY:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_INTENSITY4:
|
|
|
|
case GL_INTENSITY8:
|
|
|
|
case GL_INTENSITY12:
|
|
|
|
case GL_INTENSITY16:
|
2023-08-26 19:34:11 +00:00
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_ARGB4444_TWID_KOS : GL_ARGB4444_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
case 3:
|
2023-08-26 19:34:11 +00:00
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_RGB565_TWID_KOS : GL_RGB565_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_RGB:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_R3_G3_B2:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_RGB4:
|
|
|
|
case GL_RGB5:
|
|
|
|
case GL_RGB8:
|
|
|
|
case GL_RGB10:
|
|
|
|
case GL_RGB12:
|
2018-09-22 19:45:17 +00:00
|
|
|
case GL_RGB16:
|
2023-08-26 19:34:11 +00:00
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_RGB565_TWID_KOS : GL_RGB565_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
case 4:
|
2023-08-26 19:34:11 +00:00
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_ARGB4444_TWID_KOS : GL_ARGB4444_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_RGBA:
|
2018-09-22 19:45:17 +00:00
|
|
|
case GL_RGBA2:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_RGBA4:
|
|
|
|
case GL_RGB5_A1:
|
|
|
|
case GL_RGBA8:
|
|
|
|
case GL_RGB10_A2:
|
|
|
|
case GL_RGBA12:
|
2018-09-22 19:45:17 +00:00
|
|
|
case GL_RGBA16:
|
2023-08-26 19:34:11 +00:00
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_ARGB4444_TWID_KOS : GL_ARGB4444_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
/* Support ARB_texture_rg */
|
|
|
|
case GL_RED:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_R8:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_R16:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_COMPRESSED_RED:
|
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_RGB565_TWID_KOS : GL_RGB565_KOS;
|
|
|
|
case GL_RG:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_RG8:
|
|
|
|
case GL_RG16:
|
|
|
|
case GL_COMPRESSED_RG:
|
2023-08-26 19:34:11 +00:00
|
|
|
return (TEXTURE_TWIDDLE_ENABLED) ? GL_RGB565_TWID_KOS : GL_RGB565_KOS;
|
2018-05-11 14:39:28 +00:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
static GLuint _determinePVRFormat(GLint internalFormat) {
|
2018-05-11 14:39:28 +00:00
|
|
|
/* Given a cleaned internalFormat, return the Dreamcast format
|
|
|
|
* that can hold it
|
|
|
|
*/
|
|
|
|
switch(internalFormat) {
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_RGB565_KOS:
|
|
|
|
return GPU_TXRFMT_RGB565 | GPU_TXRFMT_NONTWIDDLED;
|
|
|
|
case GL_ARGB4444_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB4444 | GPU_TXRFMT_NONTWIDDLED;
|
|
|
|
case GL_ARGB1555_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB1555 | GPU_TXRFMT_NONTWIDDLED;
|
|
|
|
case GL_RGB565_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_RGB565 | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_ARGB4444_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB4444 | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_ARGB1555_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB1555 | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_COLOR_INDEX8_EXT:
|
|
|
|
return GPU_TXRFMT_PAL8BPP | GPU_TXRFMT_NONTWIDDLED;
|
|
|
|
case GL_COLOR_INDEX4_EXT:
|
|
|
|
return GPU_TXRFMT_PAL4BPP | GPU_TXRFMT_NONTWIDDLED;
|
|
|
|
case GL_COLOR_INDEX8_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_PAL8BPP | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_COLOR_INDEX4_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_PAL4BPP | GPU_TXRFMT_TWIDDLED;
|
2023-09-01 19:23:22 +00:00
|
|
|
case GL_COMPRESSED_ARGB_1555_VQ_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB1555 | GPU_TXRFMT_VQ_ENABLE;
|
|
|
|
case GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB1555 | GPU_TXRFMT_VQ_ENABLE | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_COMPRESSED_ARGB_4444_VQ_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB4444 | GPU_TXRFMT_VQ_ENABLE;
|
|
|
|
case GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB4444 | GPU_TXRFMT_VQ_ENABLE | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_COMPRESSED_RGB_565_VQ_KOS:
|
|
|
|
return GPU_TXRFMT_RGB565 | GPU_TXRFMT_VQ_ENABLE;
|
|
|
|
case GL_COMPRESSED_RGB_565_VQ_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_RGB565 | GPU_TXRFMT_VQ_ENABLE | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB1555 | GPU_TXRFMT_VQ_ENABLE;
|
|
|
|
case GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB1555 | GPU_TXRFMT_VQ_ENABLE | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB4444 | GPU_TXRFMT_VQ_ENABLE;
|
|
|
|
case GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_ARGB4444 | GPU_TXRFMT_VQ_ENABLE | GPU_TXRFMT_TWIDDLED;
|
|
|
|
case GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS:
|
|
|
|
return GPU_TXRFMT_RGB565 | GPU_TXRFMT_VQ_ENABLE;
|
|
|
|
case GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS:
|
|
|
|
return GPU_TXRFMT_RGB565 | GPU_TXRFMT_VQ_ENABLE | GPU_TXRFMT_TWIDDLED;
|
2023-08-26 19:34:11 +00:00
|
|
|
default:
|
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
|
|
|
return 0;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-22 19:45:17 +00:00
|
|
|
typedef void (*TextureConversionFunc)(const GLubyte*, GLubyte*);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _rgba8888_to_argb4444(const GLubyte* source, GLubyte* dest) {
|
2022-05-21 19:16:34 +00:00
|
|
|
*((GLushort*) dest) = (source[3] & 0xF0) << 8 | (source[0] & 0xF0) << 4 | (source[1] & 0xF0) | (source[2] & 0xF0) >> 4;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
GL_FORCE_INLINE void _rgba8888_to_rgba4444(const GLubyte* source, GLubyte* dest) {
|
2022-05-21 19:16:34 +00:00
|
|
|
*((GLushort*) dest) = (source[1] & 0xF0) << 8 | (source[2] & 0xF0) << 4 | (source[0] & 0xF0) | (source[3] & 0xF0) >> 4;
|
2021-12-03 07:32:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GL_FORCE_INLINE void _rgb888_to_argb4444(const GLubyte* source, GLubyte* dest) {
|
|
|
|
|
|
|
|
*((GLushort*) dest) = 0xF << 8 | (source[0] & 0xF0) << 4 | (source[1] & 0xF0) | (source[2] & 0xF0) >> 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _rgba8888_to_rgba8888(const GLubyte* source, GLubyte* dest) {
|
2018-09-20 14:08:06 +00:00
|
|
|
/* Noop */
|
|
|
|
GLubyte* dst = (GLubyte*) dest;
|
|
|
|
dst[0] = source[0];
|
|
|
|
dst[1] = source[1];
|
|
|
|
dst[2] = source[2];
|
|
|
|
dst[3] = source[3];
|
|
|
|
}
|
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
GL_FORCE_INLINE void _rgba4444_to_rgba4444(const GLubyte* source, GLubyte* dest) {
|
|
|
|
/* Noop */
|
|
|
|
GLubyte* dst = (GLubyte*) dest;
|
|
|
|
dst[0] = source[0];
|
|
|
|
dst[1] = source[1];
|
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _rgba8888_to_rgb565(const GLubyte* source, GLubyte* dest) {
|
2021-12-03 07:32:53 +00:00
|
|
|
|
2019-02-27 20:11:14 +00:00
|
|
|
*((GLushort*) dest) = ((source[0] & 0b11111000) << 8) | ((source[1] & 0b11111100) << 3) | (source[2] >> 3);
|
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _rgb888_to_rgba8888(const GLubyte* source, GLubyte* dest) {
|
2018-09-20 14:10:08 +00:00
|
|
|
/* Noop */
|
|
|
|
GLubyte* dst = (GLubyte*) dest;
|
|
|
|
dst[0] = source[0];
|
|
|
|
dst[1] = source[1];
|
|
|
|
dst[2] = source[2];
|
|
|
|
dst[3] = 255;
|
|
|
|
}
|
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
GL_FORCE_INLINE void _rgb888_to_rgba4444(const GLubyte* source, GLubyte* dest) {
|
2022-05-04 19:53:18 +00:00
|
|
|
*((GLushort*) dest) = 0xF << 8 | (source[2] & 0xF0) << 4 | (source[1] & 0xF0) | (source[0] & 0xF0) >> 4;
|
2021-12-03 07:32:53 +00:00
|
|
|
}
|
2022-05-04 19:53:18 +00:00
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _rgb888_to_rgb565(const GLubyte* source, GLubyte* dest) {
|
2023-09-01 19:23:22 +00:00
|
|
|
GLushort* d = (GLushort*) dest;
|
|
|
|
|
|
|
|
uint16_t b = (source[2] >> 3) & 0x1f;
|
|
|
|
uint16_t g = ((source[1] >> 2) & 0x3f) << 5;
|
|
|
|
uint16_t r = ((source[0] >> 3) & 0x1f) << 11;
|
|
|
|
|
|
|
|
*d = r | g | b;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
GL_FORCE_INLINE void _rgb565_to_rgb8888(const GLubyte* source, GLubyte* dest) {
|
|
|
|
GLushort src = *((GLushort*) source);
|
|
|
|
|
2022-05-04 19:53:18 +00:00
|
|
|
dest[3] = (src & 0x1f) << 3;
|
|
|
|
dest[2] = ((src >> 5) & 0x3f) <<2;
|
|
|
|
dest[1] = ((src >> 11) & 0x1f) <<3;
|
2021-12-03 07:32:53 +00:00
|
|
|
dest[0] = 0xff;
|
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _rgba8888_to_a000(const GLubyte* source, GLubyte* dest) {
|
2018-09-22 19:45:17 +00:00
|
|
|
*((GLushort*) dest) = ((source[3] & 0b11111000) << 8);
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _r8_to_rgb565(const GLubyte* source, GLubyte* dest) {
|
2018-09-22 19:45:17 +00:00
|
|
|
*((GLushort*) dest) = (source[0] & 0b11111000) << 8;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _rgba4444_to_argb4444(const GLubyte* source, GLubyte* dest) {
|
2018-05-11 14:39:28 +00:00
|
|
|
GLushort* src = (GLushort*) source;
|
2018-09-22 19:45:17 +00:00
|
|
|
*((GLushort*) dest) = ((*src & 0x000F) << 12) | *src >> 4;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _rgba4444_to_rgba8888(const GLubyte* source, GLubyte* dest) {
|
2018-09-20 14:08:06 +00:00
|
|
|
GLushort src = *((GLushort*) source);
|
|
|
|
GLubyte* dst = (GLubyte*) dest;
|
|
|
|
|
2022-05-04 19:53:18 +00:00
|
|
|
dst[0] = (src & 0xf) << 4;
|
|
|
|
dst[1] = ((src >> 4) & 0xf) << 4;
|
|
|
|
dst[2] = ((src >> 8) & 0xf) << 4;
|
|
|
|
dst[3] = (src >> 12) << 4;
|
2018-09-22 19:45:17 +00:00
|
|
|
}
|
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
GL_FORCE_INLINE void _rgba5551_to_rgba8888(const GLubyte* source, GLubyte* dest) {
|
|
|
|
GLushort src = *((GLushort*) source);
|
|
|
|
GLubyte* dst = (GLubyte*) dest;
|
|
|
|
|
2022-05-04 19:53:18 +00:00
|
|
|
dst[0] = (src & 0x1f) << 3;
|
|
|
|
dst[1] = ((src >> 5) & 0x1f) << 3;
|
|
|
|
dst[2] = ((src >> 5) & 0x1f) << 3;
|
|
|
|
dst[3] = (src >> 15) << 7;
|
2018-09-22 19:45:17 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GL_FORCE_INLINE void _i8_to_i8(const GLubyte* source, GLubyte* dest) {
|
2018-09-22 19:45:17 +00:00
|
|
|
/* For indexes */
|
|
|
|
GLubyte* dst = (GLubyte*) dest;
|
|
|
|
*dst = *source;
|
2018-09-20 14:08:06 +00:00
|
|
|
}
|
|
|
|
|
2022-05-04 19:53:18 +00:00
|
|
|
static inline void _a8_to_argb4444(const GLubyte* source, GLubyte* dest) {
|
|
|
|
GLushort color = *source & 0xf0;
|
|
|
|
color |= (color >> 4);
|
|
|
|
*((GLushort*) dest) = (color << 8) | color;
|
2019-09-17 01:48:06 +00:00
|
|
|
}
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
/* Given an cleaned internal format, and the passed format and type, this returns:
|
|
|
|
*
|
|
|
|
* 0 if not conversion is necessary
|
|
|
|
* 1 if a conversion is necessary (func will be set)
|
|
|
|
* 2 if twiddling is necessary
|
|
|
|
* 3 if twiddling and conversion is necessary (func will be set)
|
|
|
|
* -1 if a conversion is unsupported
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static int _determineConversion(GLint internalFormat, GLenum format, GLenum type, TextureConversionFunc* func) {
|
|
|
|
static struct Entry {
|
2023-09-01 19:23:22 +00:00
|
|
|
TextureConversionFunc func;
|
2023-08-26 19:34:11 +00:00
|
|
|
GLint internalFormat;
|
|
|
|
GLenum format;
|
|
|
|
GLenum type;
|
|
|
|
bool twiddle;
|
|
|
|
} conversions [] = {
|
2023-09-01 19:23:22 +00:00
|
|
|
{_a8_to_argb4444, GL_ARGB4444_KOS, GL_ALPHA, GL_UNSIGNED_BYTE, false},
|
|
|
|
{_rgba8888_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false},
|
|
|
|
{_rgba4444_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, false},
|
|
|
|
{NULL, GL_ARGB4444_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false},
|
|
|
|
{NULL, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS, false},
|
|
|
|
{_rgba8888_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_BYTE, true},
|
|
|
|
{NULL, GL_ARGB1555_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false},
|
|
|
|
{NULL, GL_ARGB1555_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS, false},
|
|
|
|
{_rgba8888_to_rgb565, GL_RGB565_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false},
|
|
|
|
{_r8_to_rgb565, GL_RGB565_KOS, GL_RED, GL_UNSIGNED_BYTE, false},
|
|
|
|
{_rgb888_to_rgb565, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_BYTE, false},
|
|
|
|
{_rgba8888_to_rgb565, GL_RGB565_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false},
|
|
|
|
{_r8_to_rgb565, GL_RGB565_KOS, GL_RED, GL_UNSIGNED_BYTE, false},
|
|
|
|
{NULL, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false},
|
|
|
|
{NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_TWID_KOS, false},
|
|
|
|
{_rgb888_to_rgb565, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_BYTE, true},
|
|
|
|
{NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false},
|
|
|
|
{NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_BYTE, false},
|
|
|
|
{NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE_TWID_KOS, false},
|
2023-08-26 19:34:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for(size_t i = 0; i < sizeof(conversions) / sizeof(struct Entry); ++i) {
|
|
|
|
struct Entry* e = conversions + i;
|
|
|
|
if(e->format == format && e->internalFormat == internalFormat && e->type == type) {
|
|
|
|
*func = e->func;
|
|
|
|
int ret = (e->func) ? 1 : 0;
|
|
|
|
ret += (e->twiddle) ? 2 : 0;
|
|
|
|
return ret;
|
2021-12-03 07:32:53 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2023-08-26 19:34:11 +00:00
|
|
|
|
|
|
|
return -1;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static GLboolean _isSupportedFormat(GLenum format) {
|
|
|
|
switch(format) {
|
2019-09-17 01:48:06 +00:00
|
|
|
case GL_ALPHA:
|
2023-08-26 19:34:11 +00:00
|
|
|
case GL_LUMINANCE:
|
|
|
|
case GL_INTENSITY:
|
|
|
|
case GL_LUMINANCE_ALPHA:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_RED:
|
|
|
|
case GL_RGB:
|
|
|
|
case GL_RGBA:
|
|
|
|
case GL_BGRA:
|
2018-09-22 19:45:17 +00:00
|
|
|
case GL_COLOR_INDEX:
|
2018-05-11 14:39:28 +00:00
|
|
|
return GL_TRUE;
|
|
|
|
default:
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-14 08:49:31 +00:00
|
|
|
GLboolean _glIsMipmapComplete(const TextureObject* obj) {
|
2019-09-24 14:47:23 +00:00
|
|
|
|
|
|
|
// Non-square textures can't have mipmaps
|
|
|
|
if(obj->width != obj->height) {
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
|
2018-08-08 08:50:57 +00:00
|
|
|
if(!obj->mipmap || !obj->mipmapCount) {
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLsizei i = 0;
|
2021-02-19 07:08:58 +00:00
|
|
|
for(; i < (GLubyte) obj->mipmapCount; ++i) {
|
2018-08-08 08:50:57 +00:00
|
|
|
if((obj->mipmap & (1 << i)) == 0) {
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return GL_TRUE;
|
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2019-04-17 13:55:30 +00:00
|
|
|
void _glAllocateSpaceForMipmaps(TextureObject* active) {
|
2019-09-24 14:47:23 +00:00
|
|
|
if(active->data && active->baseDataOffset > 0) {
|
|
|
|
/* Already done - mipmaps have a dataOffset */
|
2019-04-17 13:55:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We've allocated level 0 before, but now we're allocating
|
|
|
|
* a level beyond that, we need to reallocate the data, copy level 0
|
|
|
|
* then free the original
|
|
|
|
*/
|
|
|
|
|
2019-09-24 14:47:23 +00:00
|
|
|
GLuint size = active->baseDataSize;
|
2019-04-17 13:55:30 +00:00
|
|
|
|
2019-09-24 14:47:23 +00:00
|
|
|
/* Copy the data out of the pvr and back to ram */
|
2023-03-05 20:26:12 +00:00
|
|
|
GLubyte* temp = NULL;
|
|
|
|
if(active->data) {
|
|
|
|
temp = (GLubyte*) malloc(size);
|
|
|
|
memcpy(temp, active->data, size);
|
2019-04-17 13:55:30 +00:00
|
|
|
|
2023-03-05 20:26:12 +00:00
|
|
|
/* Free the PVR data */
|
2023-08-31 20:21:14 +00:00
|
|
|
alloc_free(ALLOC_BASE, active->data);
|
2023-03-05 20:26:12 +00:00
|
|
|
active->data = NULL;
|
|
|
|
}
|
2019-09-24 14:47:23 +00:00
|
|
|
|
|
|
|
/* Figure out how much room to allocate for mipmaps */
|
|
|
|
GLuint bytes = _glGetMipmapDataSize(active);
|
|
|
|
|
2023-08-31 20:21:14 +00:00
|
|
|
active->data = alloc_malloc_and_defrag(bytes);
|
2019-09-24 14:47:23 +00:00
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(active->data);
|
2021-09-04 11:13:59 +00:00
|
|
|
|
2023-03-05 20:26:12 +00:00
|
|
|
if(temp) {
|
|
|
|
/* If there was existing data, then copy it where it should go */
|
|
|
|
memcpy(_glGetMipmapLocation(active, 0), temp, size);
|
2019-09-24 14:47:23 +00:00
|
|
|
|
2023-03-05 20:26:12 +00:00
|
|
|
/* We no longer need this */
|
|
|
|
free(temp);
|
|
|
|
}
|
2020-03-02 19:20:42 +00:00
|
|
|
|
2019-09-24 14:47:23 +00:00
|
|
|
/* Set the data offset depending on whether or not this is a
|
|
|
|
* paletted texure */
|
|
|
|
active->baseDataOffset = _glGetMipmapDataOffset(active, 0);
|
2019-04-17 13:55:30 +00:00
|
|
|
}
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type) {
|
2018-05-11 14:39:28 +00:00
|
|
|
if(target != GL_TEXTURE_2D) {
|
2020-03-05 20:09:19 +00:00
|
|
|
INFO_MSG("");
|
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2021-11-30 17:23:49 +00:00
|
|
|
if (width > 1024 || height > 1024){
|
|
|
|
INFO_MSG("Invalid texture size");
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2021-11-30 17:23:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-21 20:35:18 +00:00
|
|
|
if(format != GL_COLOR_INDEX) {
|
|
|
|
if(!_isSupportedFormat(format)) {
|
2021-04-13 20:28:59 +00:00
|
|
|
INFO_MSG("Unsupported format");
|
2020-03-05 20:09:19 +00:00
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2019-02-21 20:35:18 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2019-02-21 20:35:18 +00:00
|
|
|
/* Abuse determineStride to see if type is valid */
|
|
|
|
if(_determineStride(GL_RGBA, type) == -1) {
|
2020-03-05 20:09:19 +00:00
|
|
|
INFO_MSG("");
|
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2019-02-21 20:35:18 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2019-02-21 20:35:18 +00:00
|
|
|
internalFormat = _cleanInternalFormat(internalFormat);
|
|
|
|
if(internalFormat == -1) {
|
2020-03-05 20:09:19 +00:00
|
|
|
INFO_MSG("");
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2019-02-21 20:35:18 +00:00
|
|
|
}
|
|
|
|
} else {
|
2021-11-18 10:04:46 +00:00
|
|
|
if(internalFormat != GL_COLOR_INDEX8_EXT && internalFormat != GL_COLOR_INDEX4_EXT) {
|
2020-03-05 20:09:19 +00:00
|
|
|
INFO_MSG("");
|
2019-02-21 20:35:18 +00:00
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2019-02-21 20:35:18 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
GLuint w = width;
|
|
|
|
GLuint h = height;
|
|
|
|
if(level == 0){
|
|
|
|
if((w < 8 || (w & -w) != w)) {
|
|
|
|
/* Width is not a power of two. Must be!*/
|
|
|
|
INFO_MSG("");
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2020-03-05 20:09:19 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2020-05-19 20:27:34 +00:00
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
if((h < 8 || (h & -h) != h)) {
|
|
|
|
/* height is not a power of two. Must be!*/
|
|
|
|
INFO_MSG("");
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2020-03-05 20:09:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Mipmap Errors, kos crashes if 1x1 */
|
|
|
|
if((h < 2) || (w < 2)){
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(TEXTURE_UNITS[ACTIVE_TEXTURE]);
|
2020-03-05 20:09:19 +00:00
|
|
|
TEXTURE_UNITS[ACTIVE_TEXTURE]->mipmap |= (1 << level);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2020-03-05 20:09:19 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 08:18:59 +00:00
|
|
|
if(level < 0) {
|
2020-03-05 20:09:19 +00:00
|
|
|
INFO_MSG("");
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 15:19:03 +00:00
|
|
|
if(level > 0 && width != height) {
|
2021-04-13 20:28:59 +00:00
|
|
|
INFO_MSG("Tried to set non-square texture as a mipmap level");
|
|
|
|
printf("[GL ERROR] Mipmaps cannot be supported on non-square textures\n");
|
2019-04-17 15:19:03 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
2019-04-17 15:19:03 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
if(border) {
|
2020-03-05 20:09:19 +00:00
|
|
|
INFO_MSG("");
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|
|
|
GLsizei width, GLsizei height, GLint border,
|
|
|
|
GLenum format, GLenum type, const GLvoid *data) {
|
|
|
|
|
|
|
|
TRACE();
|
|
|
|
if(!_glTexImage2DValidate(target, level, internalFormat, width, height, border, format, type)) {
|
2021-09-13 09:29:04 +00:00
|
|
|
return;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2023-05-17 19:39:58 +00:00
|
|
|
gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS);
|
|
|
|
TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE];
|
|
|
|
|
|
|
|
if(!active) {
|
2021-04-13 20:28:59 +00:00
|
|
|
INFO_MSG("Called glTexImage2D on unbound texture");
|
2019-03-10 19:38:47 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2021-09-13 09:29:04 +00:00
|
|
|
return;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2021-11-18 10:04:46 +00:00
|
|
|
GLboolean isPaletted = (internalFormat == GL_COLOR_INDEX8_EXT || internalFormat == GL_COLOR_INDEX4_EXT) ? GL_TRUE : GL_FALSE;
|
2023-08-26 19:34:11 +00:00
|
|
|
GLenum cleanInternalFormat = _cleanInternalFormat(internalFormat);
|
|
|
|
GLuint pvrFormat = _determinePVRFormat(cleanInternalFormat);
|
|
|
|
GLuint originalId = active->index;
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2020-03-05 20:09:19 +00:00
|
|
|
if(active->data && (level == 0)) {
|
2018-05-11 14:39:28 +00:00
|
|
|
/* pre-existing texture - check if changed */
|
|
|
|
if(active->width != width ||
|
|
|
|
active->height != height ||
|
2023-08-26 19:34:11 +00:00
|
|
|
active->internalFormat != cleanInternalFormat) {
|
2018-05-11 14:39:28 +00:00
|
|
|
/* changed - free old texture memory */
|
2023-08-31 20:21:14 +00:00
|
|
|
alloc_free(ALLOC_BASE, active->data);
|
2018-05-11 14:39:28 +00:00
|
|
|
active->data = NULL;
|
2018-08-08 08:50:57 +00:00
|
|
|
active->mipmap = 0;
|
2018-08-08 15:50:09 +00:00
|
|
|
active->mipmapCount = 0;
|
2020-03-05 20:09:19 +00:00
|
|
|
active->mipmap_bias = GL_KOS_INTERNAL_DEFAULT_MIPMAP_LOD_BIAS;
|
2018-08-08 15:50:09 +00:00
|
|
|
active->dataStride = 0;
|
2019-09-24 14:47:23 +00:00
|
|
|
active->baseDataOffset = 0;
|
|
|
|
active->baseDataSize = 0;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2018-08-07 19:22:44 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2018-09-22 19:45:17 +00:00
|
|
|
/* All colour formats are represented as shorts internally. Paletted textures
|
|
|
|
* are represented by byte indexes (which look up into a color table)
|
|
|
|
*/
|
|
|
|
GLint destStride = isPaletted ? 1 : 2;
|
|
|
|
GLuint bytes = (width * height * destStride);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2021-11-18 10:04:46 +00:00
|
|
|
//special case 4bpp
|
|
|
|
if(internalFormat == GL_COLOR_INDEX4_EXT){
|
|
|
|
bytes >>= 1;
|
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
if(!active->data) {
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(active);
|
|
|
|
gl_assert(width);
|
|
|
|
gl_assert(height);
|
|
|
|
gl_assert(destStride);
|
2019-02-21 20:35:18 +00:00
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
/* need texture memory */
|
|
|
|
active->width = width;
|
|
|
|
active->height = height;
|
2023-08-26 19:34:11 +00:00
|
|
|
active->color = pvrFormat;
|
|
|
|
active->internalFormat = cleanInternalFormat;
|
2018-08-09 07:56:43 +00:00
|
|
|
/* Set the required mipmap count */
|
|
|
|
active->mipmapCount = _glGetMipmapLevelCount(active);
|
2020-03-05 20:09:19 +00:00
|
|
|
active->mipmap_bias = GL_KOS_INTERNAL_DEFAULT_MIPMAP_LOD_BIAS;
|
2018-09-22 19:45:17 +00:00
|
|
|
active->dataStride = destStride;
|
2019-09-24 14:47:23 +00:00
|
|
|
active->baseDataSize = bytes;
|
2018-08-14 08:49:31 +00:00
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(bytes);
|
2019-04-17 13:55:30 +00:00
|
|
|
|
|
|
|
if(level > 0) {
|
2019-09-24 14:47:23 +00:00
|
|
|
/* If we're uploading a mipmap level, we need to allocate the full amount of space */
|
|
|
|
_glAllocateSpaceForMipmaps(active);
|
|
|
|
} else {
|
2023-08-31 20:21:14 +00:00
|
|
|
active->data = alloc_malloc_and_defrag(active->baseDataSize);
|
2019-04-17 13:55:30 +00:00
|
|
|
}
|
2019-02-21 20:35:18 +00:00
|
|
|
|
2018-08-20 07:34:54 +00:00
|
|
|
active->isCompressed = GL_FALSE;
|
2018-09-22 19:45:17 +00:00
|
|
|
active->isPaletted = isPaletted;
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 13:55:30 +00:00
|
|
|
/* We're supplying a mipmap level, but previously we only had
|
2019-09-24 14:47:23 +00:00
|
|
|
* data for the first level (level 0) */
|
|
|
|
if(level > 0 && active->baseDataOffset == 0) {
|
2019-04-17 13:55:30 +00:00
|
|
|
_glAllocateSpaceForMipmaps(active);
|
|
|
|
}
|
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(active->data);
|
2021-09-04 11:13:59 +00:00
|
|
|
|
|
|
|
/* If we run out of PVR memory just return */
|
|
|
|
if(!active->data) {
|
|
|
|
_glKosThrowError(GL_OUT_OF_MEMORY, __func__);
|
2023-08-26 19:34:11 +00:00
|
|
|
gl_assert(active->index == originalId);
|
2021-09-04 11:13:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-09 07:56:43 +00:00
|
|
|
/* Mark this level as set in the mipmap bitmask */
|
|
|
|
active->mipmap |= (1 << level);
|
|
|
|
|
2019-09-24 14:47:23 +00:00
|
|
|
GLubyte* targetData = (active->baseDataOffset == 0) ? active->data : _glGetMipmapLocation(active, level);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(targetData);
|
2018-08-08 15:50:09 +00:00
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
TextureConversionFunc conversion;
|
|
|
|
int needs_conversion = _determineConversion(cleanInternalFormat, format, type, &conversion);
|
|
|
|
if(needs_conversion < 0) {
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
|
|
|
INFO_MSG("Couldn't find necessary texture conversion\n");
|
2018-05-11 14:39:28 +00:00
|
|
|
return;
|
2023-08-26 19:34:11 +00:00
|
|
|
} else if(needs_conversion > 0) {
|
|
|
|
/* Convert the data */
|
|
|
|
GLint sourceStride = _determineStride(format, type);
|
|
|
|
GLint destStride = _determineStrideInternal(cleanInternalFormat);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
if(sourceStride == -1) {
|
2021-04-13 20:28:59 +00:00
|
|
|
INFO_MSG("Stride was not detected\n");
|
2018-08-08 15:50:09 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2018-05-11 14:39:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-01 19:23:22 +00:00
|
|
|
GLubyte* conversionBuffer = (GLubyte*) memalign(32, bytes);
|
2023-08-26 19:34:11 +00:00
|
|
|
const GLubyte* src = data;
|
|
|
|
GLubyte* dst = conversionBuffer;
|
2023-09-01 19:23:22 +00:00
|
|
|
|
|
|
|
if(needs_conversion == 1) {
|
|
|
|
// Convert
|
|
|
|
for(uint32_t i = 0; i < (width * height); ++i) {
|
|
|
|
conversion(src, dst);
|
|
|
|
dst += destStride;
|
|
|
|
src += sourceStride;
|
|
|
|
}
|
|
|
|
} else if(needs_conversion == 2) {
|
|
|
|
// Twiddle
|
|
|
|
for(uint32_t i = 0; i < (width * height); ++i) {
|
2023-08-26 19:34:11 +00:00
|
|
|
uint32_t newLocation = twid_location(i, width, height);
|
|
|
|
dst = conversionBuffer + (destStride * newLocation);
|
|
|
|
|
2023-09-01 19:23:22 +00:00
|
|
|
for(int j = 0; j < destStride; ++j)
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
|
|
|
src += sourceStride;
|
|
|
|
}
|
|
|
|
} else if(needs_conversion == 3) {
|
|
|
|
// Convert + twiddle
|
|
|
|
for(uint32_t i = 0; i < (width * height); ++i) {
|
|
|
|
uint32_t newLocation = twid_location(i, width, height);
|
|
|
|
dst = conversionBuffer + (destStride * newLocation);
|
2023-08-26 19:34:11 +00:00
|
|
|
conversion(src, dst);
|
2023-09-01 19:23:22 +00:00
|
|
|
src += sourceStride;
|
2021-11-18 10:04:46 +00:00
|
|
|
}
|
2023-08-26 19:34:11 +00:00
|
|
|
}
|
2019-09-24 14:47:23 +00:00
|
|
|
|
2019-09-24 18:39:23 +00:00
|
|
|
FASTCPY(targetData, conversionBuffer, bytes);
|
2019-09-24 14:47:23 +00:00
|
|
|
free(conversionBuffer);
|
2023-08-26 19:34:11 +00:00
|
|
|
} else {
|
|
|
|
/* No conversion necessary, we can just upload data directly */
|
|
|
|
gl_assert(targetData);
|
|
|
|
gl_assert(data);
|
|
|
|
gl_assert(bytes);
|
|
|
|
|
|
|
|
/* No conversion? Just copy the data, and the pvr_format is correct */
|
|
|
|
FASTCPY(targetData, data, bytes);
|
|
|
|
gl_assert(active->index == originalId);
|
2019-09-24 14:47:23 +00:00
|
|
|
}
|
2023-05-16 12:31:44 +00:00
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
gl_assert(active->index == originalId);
|
2023-05-16 12:31:44 +00:00
|
|
|
_glGPUStateMarkDirty();
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param) {
|
|
|
|
TRACE();
|
|
|
|
|
2019-03-03 19:06:01 +00:00
|
|
|
TextureObject* active = _glGetBoundTexture();
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2018-05-28 06:16:40 +00:00
|
|
|
if(!active) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
if(target == GL_TEXTURE_2D) {
|
|
|
|
switch(pname) {
|
|
|
|
case GL_TEXTURE_MAG_FILTER:
|
|
|
|
switch(param) {
|
2018-08-09 08:32:29 +00:00
|
|
|
case GL_NEAREST:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_LINEAR:
|
2018-08-09 08:32:29 +00:00
|
|
|
break;
|
|
|
|
default: {
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
active->magFilter = param;
|
|
|
|
break;
|
|
|
|
case GL_TEXTURE_MIN_FILTER:
|
|
|
|
switch(param) {
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_NEAREST:
|
2018-08-09 08:32:29 +00:00
|
|
|
case GL_LINEAR:
|
|
|
|
case GL_NEAREST_MIPMAP_LINEAR:
|
|
|
|
case GL_NEAREST_MIPMAP_NEAREST:
|
|
|
|
case GL_LINEAR_MIPMAP_LINEAR:
|
|
|
|
case GL_LINEAR_MIPMAP_NEAREST:
|
|
|
|
break;
|
|
|
|
default: {
|
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
|
|
|
return;
|
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2018-08-09 08:32:29 +00:00
|
|
|
active->minFilter = param;
|
|
|
|
break;
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_TEXTURE_WRAP_S:
|
|
|
|
switch(param) {
|
2022-12-09 20:17:46 +00:00
|
|
|
case GL_CLAMP_TO_EDGE:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_CLAMP:
|
|
|
|
active->uv_clamp |= CLAMP_U;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_REPEAT:
|
|
|
|
active->uv_clamp &= ~CLAMP_U;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_TEXTURE_WRAP_T:
|
|
|
|
switch(param) {
|
2022-12-09 20:17:46 +00:00
|
|
|
case GL_CLAMP_TO_EDGE:
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_CLAMP:
|
|
|
|
active->uv_clamp |= CLAMP_V;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_REPEAT:
|
|
|
|
active->uv_clamp &= ~CLAMP_V;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-03-10 11:18:56 +00:00
|
|
|
break;
|
|
|
|
case GL_SHARED_TEXTURE_BANK_KOS:
|
|
|
|
active->shared_bank = param;
|
|
|
|
break;
|
|
|
|
default:
|
2018-05-11 14:39:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-03-17 20:40:45 +00:00
|
|
|
|
|
|
|
_glGPUStateMarkDirty();
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2018-09-20 14:01:13 +00:00
|
|
|
|
2022-01-18 17:23:30 +00:00
|
|
|
void APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param) {
|
2019-02-28 19:21:16 +00:00
|
|
|
glTexParameteri(target, pname, (GLint) param);
|
|
|
|
}
|
|
|
|
|
2018-09-20 14:01:13 +00:00
|
|
|
GLAPI void APIENTRY glColorTableEXT(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *data) {
|
2021-12-03 07:32:53 +00:00
|
|
|
|
2019-03-13 15:14:09 +00:00
|
|
|
GLint validTargets[] = {
|
2019-03-10 11:18:56 +00:00
|
|
|
GL_TEXTURE_2D,
|
|
|
|
GL_SHARED_TEXTURE_PALETTE_EXT,
|
2021-12-03 07:32:53 +00:00
|
|
|
GL_SHARED_TEXTURE_PALETTE_0_KOS,GL_SHARED_TEXTURE_PALETTE_1_KOS,GL_SHARED_TEXTURE_PALETTE_2_KOS,GL_SHARED_TEXTURE_PALETTE_3_KOS,GL_SHARED_TEXTURE_PALETTE_4_KOS,GL_SHARED_TEXTURE_PALETTE_5_KOS,GL_SHARED_TEXTURE_PALETTE_6_KOS,GL_SHARED_TEXTURE_PALETTE_7_KOS,GL_SHARED_TEXTURE_PALETTE_8_KOS,GL_SHARED_TEXTURE_PALETTE_9_KOS,
|
|
|
|
GL_SHARED_TEXTURE_PALETTE_10_KOS,GL_SHARED_TEXTURE_PALETTE_11_KOS,GL_SHARED_TEXTURE_PALETTE_12_KOS,GL_SHARED_TEXTURE_PALETTE_13_KOS,GL_SHARED_TEXTURE_PALETTE_14_KOS,GL_SHARED_TEXTURE_PALETTE_15_KOS,GL_SHARED_TEXTURE_PALETTE_16_KOS,GL_SHARED_TEXTURE_PALETTE_17_KOS,GL_SHARED_TEXTURE_PALETTE_18_KOS,GL_SHARED_TEXTURE_PALETTE_19_KOS,
|
|
|
|
GL_SHARED_TEXTURE_PALETTE_20_KOS,GL_SHARED_TEXTURE_PALETTE_21_KOS,GL_SHARED_TEXTURE_PALETTE_22_KOS,GL_SHARED_TEXTURE_PALETTE_23_KOS,GL_SHARED_TEXTURE_PALETTE_24_KOS,GL_SHARED_TEXTURE_PALETTE_25_KOS,GL_SHARED_TEXTURE_PALETTE_26_KOS,GL_SHARED_TEXTURE_PALETTE_27_KOS,GL_SHARED_TEXTURE_PALETTE_28_KOS,GL_SHARED_TEXTURE_PALETTE_29_KOS,
|
|
|
|
GL_SHARED_TEXTURE_PALETTE_30_KOS,GL_SHARED_TEXTURE_PALETTE_31_KOS,GL_SHARED_TEXTURE_PALETTE_32_KOS,GL_SHARED_TEXTURE_PALETTE_33_KOS,GL_SHARED_TEXTURE_PALETTE_34_KOS,GL_SHARED_TEXTURE_PALETTE_35_KOS,GL_SHARED_TEXTURE_PALETTE_36_KOS,GL_SHARED_TEXTURE_PALETTE_37_KOS,GL_SHARED_TEXTURE_PALETTE_38_KOS,GL_SHARED_TEXTURE_PALETTE_39_KOS,
|
|
|
|
GL_SHARED_TEXTURE_PALETTE_40_KOS,GL_SHARED_TEXTURE_PALETTE_41_KOS,GL_SHARED_TEXTURE_PALETTE_42_KOS,GL_SHARED_TEXTURE_PALETTE_43_KOS,GL_SHARED_TEXTURE_PALETTE_44_KOS,GL_SHARED_TEXTURE_PALETTE_45_KOS,GL_SHARED_TEXTURE_PALETTE_46_KOS,GL_SHARED_TEXTURE_PALETTE_47_KOS,GL_SHARED_TEXTURE_PALETTE_48_KOS,GL_SHARED_TEXTURE_PALETTE_49_KOS,
|
|
|
|
GL_SHARED_TEXTURE_PALETTE_50_KOS,GL_SHARED_TEXTURE_PALETTE_51_KOS,GL_SHARED_TEXTURE_PALETTE_52_KOS,GL_SHARED_TEXTURE_PALETTE_53_KOS,GL_SHARED_TEXTURE_PALETTE_54_KOS,GL_SHARED_TEXTURE_PALETTE_55_KOS,GL_SHARED_TEXTURE_PALETTE_56_KOS,GL_SHARED_TEXTURE_PALETTE_57_KOS,GL_SHARED_TEXTURE_PALETTE_58_KOS,GL_SHARED_TEXTURE_PALETTE_59_KOS,
|
|
|
|
GL_SHARED_TEXTURE_PALETTE_60_KOS,GL_SHARED_TEXTURE_PALETTE_61_KOS,GL_SHARED_TEXTURE_PALETTE_62_KOS,GL_SHARED_TEXTURE_PALETTE_63_KOS,
|
|
|
|
0};
|
|
|
|
|
2022-05-04 20:00:15 +00:00
|
|
|
GLint validInternalFormats[] = {GL_RGB8, GL_RGBA8, GL_RGBA4, 0};
|
|
|
|
GLint validFormats[] = {GL_RGB, GL_RGBA,GL_RGB5_A1, GL_RGB5_A1, GL_RGB565_KOS, GL_RGBA4, 0};
|
2019-03-13 15:14:09 +00:00
|
|
|
GLint validTypes[] = {GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, 0};
|
2018-09-20 14:01:13 +00:00
|
|
|
|
|
|
|
if(_glCheckValidEnum(target, validTargets, __func__) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_glCheckValidEnum(internalFormat, validInternalFormats, __func__) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-03 07:32:53 +00:00
|
|
|
|
|
|
|
switch(format){
|
|
|
|
case GL_PALETTE4_RGBA8_OES:
|
|
|
|
case GL_PALETTE8_RGBA8_OES:
|
|
|
|
format = GL_RGBA;
|
|
|
|
break;
|
|
|
|
case GL_PALETTE4_RGB8_OES:
|
|
|
|
case GL_PALETTE8_RGB8_OES:
|
|
|
|
format = GL_RGB;
|
|
|
|
break;
|
|
|
|
case GL_PALETTE4_R5_G6_B5_OES:
|
|
|
|
case GL_PALETTE8_R5_G6_B5_OES:
|
|
|
|
case GL_UNSIGNED_SHORT_5_6_5:
|
|
|
|
format = GL_RGB565_KOS;
|
|
|
|
break;
|
|
|
|
case GL_PALETTE4_RGB5_A1_OES:
|
|
|
|
case GL_PALETTE8_RGB5_A1_OES:
|
|
|
|
case GL_UNSIGNED_SHORT_5_5_5_1:
|
|
|
|
format = GL_RGB5_A1;
|
|
|
|
break;
|
|
|
|
case GL_PALETTE4_RGBA4_OES:
|
|
|
|
case GL_PALETTE8_RGBA4_OES:
|
|
|
|
case GL_UNSIGNED_SHORT_4_4_4_4:
|
|
|
|
format = GL_RGBA4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-09-20 14:01:13 +00:00
|
|
|
if(_glCheckValidEnum(format, validFormats, __func__) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_glCheckValidEnum(type, validTypes, __func__) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:48:26 +00:00
|
|
|
/* Only allow up to 256 colours in a palette */
|
2019-02-21 20:35:18 +00:00
|
|
|
if(width > 256 || width == 0) {
|
2018-09-20 15:48:26 +00:00
|
|
|
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-03 19:49:28 +00:00
|
|
|
GLint sourceStride = _determineStride(format, type);
|
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(sourceStride > -1);
|
2018-09-20 14:01:13 +00:00
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
TextureConversionFunc convert;
|
|
|
|
int ret = _determineConversion(
|
2022-05-04 20:00:15 +00:00
|
|
|
INTERNAL_PALETTE_FORMAT,
|
2018-09-20 14:01:13 +00:00
|
|
|
format,
|
2023-08-26 19:34:11 +00:00
|
|
|
type,
|
|
|
|
&convert
|
2018-09-20 14:01:13 +00:00
|
|
|
);
|
|
|
|
|
2023-08-26 19:34:11 +00:00
|
|
|
if(ret < 0) {
|
2018-09-20 14:01:13 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-21 21:58:31 +00:00
|
|
|
TexturePalette* palette = NULL;
|
|
|
|
|
2021-12-03 07:32:53 +00:00
|
|
|
GLboolean sharedPaletteUsed = GL_FALSE;
|
|
|
|
|
2019-03-10 11:18:56 +00:00
|
|
|
/* Custom extension - allow uploading to one of 4 custom palettes */
|
|
|
|
if(target == GL_SHARED_TEXTURE_PALETTE_EXT || target == GL_SHARED_TEXTURE_PALETTE_0_KOS) {
|
|
|
|
palette = SHARED_PALETTES[0];
|
2021-12-03 07:32:53 +00:00
|
|
|
sharedPaletteUsed = GL_TRUE;
|
|
|
|
}
|
|
|
|
|
2022-09-14 18:20:24 +00:00
|
|
|
for (GLubyte i = 1; i < MAX_GLDC_SHARED_PALETTES; ++i) {
|
2021-12-03 07:32:53 +00:00
|
|
|
if (target == GL_SHARED_TEXTURE_PALETTE_0_KOS + i) {
|
|
|
|
palette = SHARED_PALETTES[i];
|
|
|
|
sharedPaletteUsed = GL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sharedPaletteUsed == GL_FALSE){
|
2019-03-03 19:06:01 +00:00
|
|
|
TextureObject* active = _glGetBoundTexture();
|
2019-02-21 21:58:31 +00:00
|
|
|
if(!active->palette) {
|
2019-03-09 14:32:50 +00:00
|
|
|
active->palette = _initTexturePalette();
|
2019-02-21 21:58:31 +00:00
|
|
|
}
|
|
|
|
palette = active->palette;
|
2018-09-20 14:01:13 +00:00
|
|
|
}
|
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(palette);
|
2019-03-03 19:49:28 +00:00
|
|
|
|
2019-02-21 21:58:31 +00:00
|
|
|
if(target) {
|
2019-03-08 21:36:48 +00:00
|
|
|
free(palette->data);
|
2019-02-21 21:58:31 +00:00
|
|
|
palette->data = NULL;
|
|
|
|
}
|
|
|
|
|
2019-03-09 14:32:50 +00:00
|
|
|
if(palette->bank > -1) {
|
|
|
|
_glReleasePaletteSlot(palette->bank, palette->size);
|
|
|
|
palette->bank = -1;
|
|
|
|
}
|
|
|
|
|
2019-03-08 21:36:48 +00:00
|
|
|
palette->data = (GLubyte*) malloc(width * 4);
|
2019-02-21 21:58:31 +00:00
|
|
|
palette->format = format;
|
|
|
|
palette->width = width;
|
2019-03-09 14:32:50 +00:00
|
|
|
palette->size = (width > 16) ? 256 : 16;
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(palette->size == 16 || palette->size == 256);
|
2019-03-09 14:32:50 +00:00
|
|
|
|
|
|
|
palette->bank = _glGenPaletteSlot(palette->size);
|
|
|
|
|
|
|
|
if(palette->bank < 0) {
|
|
|
|
/* We ran out of slots! */
|
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
|
|
|
|
|
|
|
free(palette->data);
|
|
|
|
palette->format = palette->width = palette->size = 0;
|
|
|
|
return;
|
|
|
|
}
|
2018-09-20 14:01:13 +00:00
|
|
|
|
|
|
|
GLubyte* src = (GLubyte*) data;
|
2019-02-21 21:58:31 +00:00
|
|
|
GLubyte* dst = (GLubyte*) palette->data;
|
2019-03-03 19:49:28 +00:00
|
|
|
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(src);
|
|
|
|
gl_assert(dst);
|
2018-09-20 14:01:13 +00:00
|
|
|
|
|
|
|
/* Transform and copy the source palette to the texture */
|
|
|
|
GLushort i = 0;
|
|
|
|
for(; i < width; ++i) {
|
2018-09-22 19:45:17 +00:00
|
|
|
convert(src, dst);
|
2018-09-20 14:01:13 +00:00
|
|
|
|
|
|
|
src += sourceStride;
|
|
|
|
dst += 4;
|
|
|
|
}
|
2019-03-03 18:54:25 +00:00
|
|
|
|
2019-03-10 11:18:56 +00:00
|
|
|
_glApplyColorTable(palette);
|
2023-03-17 20:40:45 +00:00
|
|
|
|
|
|
|
_glGPUStateMarkDirty();
|
2018-09-20 14:01:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glColorSubTableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(start);
|
|
|
|
_GL_UNUSED(count);
|
|
|
|
_GL_UNUSED(format);
|
|
|
|
_GL_UNUSED(type);
|
|
|
|
_GL_UNUSED(data);
|
2018-09-20 14:02:22 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2018-09-20 14:01:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *data) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(format);
|
|
|
|
_GL_UNUSED(type);
|
|
|
|
_GL_UNUSED(data);
|
2018-09-20 14:02:22 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2018-09-20 14:01:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glGetColorTableParameterivEXT(GLenum target, GLenum pname, GLint *params) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(pname);
|
|
|
|
_GL_UNUSED(params);
|
2018-09-20 14:02:22 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2018-09-20 14:01:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glGetColorTableParameterfvEXT(GLenum target, GLenum pname, GLfloat *params) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(pname);
|
|
|
|
_GL_UNUSED(params);
|
2018-09-20 14:02:22 +00:00
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
2018-09-20 14:01:13 +00:00
|
|
|
}
|
|
|
|
|
2019-03-10 12:19:41 +00:00
|
|
|
GLAPI void APIENTRY glTexSubImage2D(
|
|
|
|
GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
|
|
|
GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(level);
|
|
|
|
_GL_UNUSED(xoffset);
|
|
|
|
_GL_UNUSED(yoffset);
|
2020-05-19 20:27:34 +00:00
|
|
|
_GL_UNUSED(width);
|
|
|
|
_GL_UNUSED(height);
|
|
|
|
_GL_UNUSED(format);
|
|
|
|
_GL_UNUSED(type);
|
|
|
|
_GL_UNUSED(pixels);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(0 && "Not Implemented");
|
2019-03-10 12:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(level);
|
|
|
|
_GL_UNUSED(xoffset);
|
|
|
|
_GL_UNUSED(yoffset);
|
2020-05-19 20:27:34 +00:00
|
|
|
_GL_UNUSED(x);
|
|
|
|
_GL_UNUSED(y);
|
|
|
|
_GL_UNUSED(width);
|
|
|
|
_GL_UNUSED(height);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(0 && "Not Implemented");
|
2019-03-10 12:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(level);
|
|
|
|
_GL_UNUSED(xoffset);
|
|
|
|
_GL_UNUSED(x);
|
|
|
|
_GL_UNUSED(y);
|
2020-05-19 20:27:34 +00:00
|
|
|
_GL_UNUSED(width);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(0 && "Not Implemented");
|
2019-03-10 12:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(level);
|
|
|
|
_GL_UNUSED(internalformat);
|
2020-05-19 20:27:34 +00:00
|
|
|
_GL_UNUSED(x);
|
|
|
|
_GL_UNUSED(y);
|
|
|
|
_GL_UNUSED(width);
|
|
|
|
_GL_UNUSED(height);
|
|
|
|
_GL_UNUSED(border);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(0 && "Not Implemented");
|
2019-03-10 12:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glCopyTexImage1D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border) {
|
2020-03-05 20:09:19 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(level);
|
|
|
|
_GL_UNUSED(internalformat);
|
2020-05-19 20:27:34 +00:00
|
|
|
_GL_UNUSED(x);
|
|
|
|
_GL_UNUSED(y);
|
|
|
|
_GL_UNUSED(width);
|
|
|
|
_GL_UNUSED(border);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(0 && "Not Implemented");
|
2019-03-10 12:19:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
|
2020-05-19 20:27:34 +00:00
|
|
|
_GL_UNUSED(x);
|
|
|
|
_GL_UNUSED(y);
|
|
|
|
_GL_UNUSED(width);
|
|
|
|
_GL_UNUSED(height);
|
|
|
|
_GL_UNUSED(format);
|
|
|
|
_GL_UNUSED(type);
|
|
|
|
_GL_UNUSED(pixels);
|
2022-08-25 20:24:08 +00:00
|
|
|
gl_assert(0 && "Not Implemented");
|
2019-03-10 12:19:41 +00:00
|
|
|
}
|
2021-11-30 17:23:49 +00:00
|
|
|
GLuint _glMaxTextureMemory() {
|
2023-08-31 20:21:14 +00:00
|
|
|
return ALLOC_SIZE;
|
2021-11-30 17:23:49 +00:00
|
|
|
}
|
2021-02-19 21:28:31 +00:00
|
|
|
|
|
|
|
GLuint _glFreeTextureMemory() {
|
2023-08-31 20:21:14 +00:00
|
|
|
return alloc_count_free(ALLOC_BASE);
|
2021-02-19 21:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLuint _glUsedTextureMemory() {
|
2023-08-31 20:21:14 +00:00
|
|
|
return ALLOC_SIZE - _glFreeTextureMemory();
|
2021-02-19 21:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLuint _glFreeContiguousTextureMemory() {
|
2023-08-31 20:21:14 +00:00
|
|
|
return alloc_count_continuous(ALLOC_BASE);
|
2021-02-19 21:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI GLvoid APIENTRY glDefragmentTextureMemory_KOS(void) {
|
2023-08-31 20:21:14 +00:00
|
|
|
alloc_defrag_start(ALLOC_BASE);
|
2021-02-19 21:28:31 +00:00
|
|
|
|
|
|
|
GLuint id;
|
|
|
|
|
|
|
|
/* Replace all texture pointers */
|
|
|
|
for(id = 0; id < MAX_TEXTURE_COUNT; id++){
|
2023-05-17 19:38:21 +00:00
|
|
|
TextureObject* txr = (TextureObject*) named_array_get(&TEXTURE_OBJECTS, id);
|
|
|
|
if(txr){
|
|
|
|
gl_assert(txr->index == id);
|
2023-08-31 20:21:14 +00:00
|
|
|
txr->data = alloc_defrag_address(ALLOC_BASE, txr->data);
|
2021-02-19 21:28:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-31 20:21:14 +00:00
|
|
|
alloc_defrag_commit(ALLOC_BASE);
|
2021-02-19 21:28:31 +00:00
|
|
|
}
|
2022-01-31 08:29:00 +00:00
|
|
|
|
|
|
|
GLAPI void APIENTRY glGetTexImage(GLenum tex, GLint lod, GLenum format, GLenum type, GLvoid* img) {
|
|
|
|
_GL_UNUSED(tex);
|
|
|
|
_GL_UNUSED(lod);
|
|
|
|
_GL_UNUSED(format);
|
|
|
|
_GL_UNUSED(type);
|
|
|
|
_GL_UNUSED(img);
|
|
|
|
}
|