2018-05-20 15:44:16 +00:00
|
|
|
#include <stdio.h>
|
2019-09-24 20:26:17 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
2018-05-20 15:16:53 +00:00
|
|
|
#include "private.h"
|
2018-05-20 15:44:16 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
GLuint index;
|
|
|
|
GLuint texture_id;
|
|
|
|
GLboolean is_complete;
|
2018-05-20 20:28:48 +00:00
|
|
|
|
|
|
|
/* FIXME: Add OP, TR and PT lists per framebuffer */
|
|
|
|
|
2018-05-20 15:44:16 +00:00
|
|
|
} FrameBuffer;
|
|
|
|
|
|
|
|
static FrameBuffer* ACTIVE_FRAMEBUFFER = NULL;
|
2018-05-20 15:16:53 +00:00
|
|
|
static NamedArray FRAMEBUFFERS;
|
|
|
|
|
|
|
|
|
2019-03-03 19:02:25 +00:00
|
|
|
void _glInitFramebuffers() {
|
2018-05-20 15:44:16 +00:00
|
|
|
named_array_init(&FRAMEBUFFERS, sizeof(FrameBuffer), 32);
|
2019-03-11 19:24:08 +00:00
|
|
|
|
|
|
|
// Reserve zero so that it is never given to anyone as an ID!
|
|
|
|
named_array_reserve(&FRAMEBUFFERS, 0);
|
2018-05-20 15:44:16 +00:00
|
|
|
}
|
2018-05-20 15:16:53 +00:00
|
|
|
|
2019-03-03 19:06:01 +00:00
|
|
|
void _glWipeTextureOnFramebuffers(GLuint texture) {
|
2018-05-20 20:28:48 +00:00
|
|
|
/* Spec says we don't update inactive framebuffers, they'll presumably just cause
|
|
|
|
* a GL_INVALID_OPERATION if we try to render to them */
|
|
|
|
if(ACTIVE_FRAMEBUFFER && ACTIVE_FRAMEBUFFER->texture_id == texture) {
|
|
|
|
ACTIVE_FRAMEBUFFER->texture_id = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-20 15:44:16 +00:00
|
|
|
void APIENTRY glGenFramebuffersEXT(GLsizei n, GLuint* framebuffers) {
|
|
|
|
TRACE();
|
|
|
|
|
|
|
|
while(n--) {
|
|
|
|
GLuint id = 0;
|
|
|
|
FrameBuffer* fb = (FrameBuffer*) named_array_alloc(&FRAMEBUFFERS, &id);
|
|
|
|
fb->index = id;
|
|
|
|
fb->is_complete = GL_FALSE;
|
|
|
|
fb->texture_id = 0;
|
|
|
|
|
|
|
|
*framebuffers = id;
|
|
|
|
framebuffers++;
|
|
|
|
}
|
2018-05-20 15:16:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glDeleteFramebuffersEXT(GLsizei n, const GLuint* framebuffers) {
|
2018-05-20 15:44:16 +00:00
|
|
|
TRACE();
|
|
|
|
|
|
|
|
while(n--) {
|
|
|
|
FrameBuffer* fb = (FrameBuffer*) named_array_get(&FRAMEBUFFERS, *framebuffers);
|
|
|
|
|
|
|
|
if(fb == ACTIVE_FRAMEBUFFER) {
|
|
|
|
ACTIVE_FRAMEBUFFER = NULL;
|
|
|
|
}
|
2018-05-20 15:16:53 +00:00
|
|
|
|
2018-05-20 15:44:16 +00:00
|
|
|
named_array_release(&FRAMEBUFFERS, *framebuffers++);
|
|
|
|
}
|
2018-05-20 15:16:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glBindFramebufferEXT(GLenum target, GLuint framebuffer) {
|
2020-03-05 19:49:23 +00:00
|
|
|
_GL_UNUSED(target);
|
2018-05-20 15:44:16 +00:00
|
|
|
TRACE();
|
2018-05-20 15:16:53 +00:00
|
|
|
|
2018-05-20 15:44:16 +00:00
|
|
|
if(framebuffer) {
|
|
|
|
ACTIVE_FRAMEBUFFER = (FrameBuffer*) named_array_get(&FRAMEBUFFERS, framebuffer);
|
|
|
|
} else {
|
|
|
|
ACTIVE_FRAMEBUFFER = NULL;
|
2018-05-20 20:28:48 +00:00
|
|
|
|
|
|
|
/* FIXME: This is where we need to submit the lists and then clear them. Binding zero means returning to the
|
|
|
|
* default framebuffer so we need to render a frame to the texture at that point */
|
2018-05-20 15:44:16 +00:00
|
|
|
}
|
2018-05-20 15:16:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void APIENTRY glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
|
2020-03-05 19:49:23 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(attachment);
|
|
|
|
_GL_UNUSED(textarget);
|
|
|
|
_GL_UNUSED(level);
|
2018-05-20 20:28:48 +00:00
|
|
|
if(texture != 0 && !glIsTexture(texture)) {
|
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
|
|
|
return;
|
|
|
|
}
|
2018-05-20 15:16:53 +00:00
|
|
|
|
2018-05-20 20:28:48 +00:00
|
|
|
if(!ACTIVE_FRAMEBUFFER) {
|
|
|
|
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTIVE_FRAMEBUFFER->texture_id = texture;
|
2018-05-20 15:16:53 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint A1555(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (1 << 15);
|
2019-09-25 12:10:34 +00:00
|
|
|
return (v & MASK) >> 8;
|
2018-08-09 07:56:43 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint R1555(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (31 << 10);
|
2019-09-25 12:10:34 +00:00
|
|
|
return (v & MASK) >> 7;
|
2018-08-09 07:56:43 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint G1555(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (31 << 5);
|
2019-09-25 12:10:34 +00:00
|
|
|
return (v & MASK) >> 2;
|
2018-08-09 07:56:43 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint B1555(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (31 << 0);
|
2019-09-25 12:10:34 +00:00
|
|
|
return (v & MASK) << 3;
|
2018-08-09 07:56:43 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint A4444(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (0xF << 12);
|
|
|
|
return (v & MASK) >> 12;
|
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint R4444(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (0xF << 8);
|
|
|
|
return (v & MASK) >> 8;
|
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint G4444(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (0xF << 4);
|
|
|
|
return (v & MASK) >> 4;
|
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint B4444(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (0xF << 0);
|
|
|
|
return (v & MASK) >> 0;
|
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint R565(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (31 << 11);
|
2019-09-25 12:32:13 +00:00
|
|
|
return (v & MASK) >> 8;
|
2018-08-09 07:56:43 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint G565(GLuint v) {
|
2019-09-25 12:45:08 +00:00
|
|
|
const GLuint MASK = (63 << 5);
|
2019-09-25 12:32:13 +00:00
|
|
|
return (v & MASK) >> 3;
|
2018-08-09 07:56:43 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
GL_FORCE_INLINE GLuint B565(GLuint v) {
|
2018-08-09 07:56:43 +00:00
|
|
|
const GLuint MASK = (31 << 0);
|
2019-09-25 12:45:08 +00:00
|
|
|
return (v & MASK) << 3;
|
2018-08-09 07:56:43 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 19:49:23 +00:00
|
|
|
static GL_NO_INSTRUMENT GLboolean _glCalculateAverageTexel(GLuint pvrFormat, const GLubyte* src1, const GLubyte* src2, const GLubyte* src3, const GLubyte* src4, GLubyte* t) {
|
2018-08-09 07:56:43 +00:00
|
|
|
GLuint a, r, g, b;
|
|
|
|
|
2019-09-26 08:17:07 +00:00
|
|
|
GLubyte format = ((pvrFormat & (1 << 27)) | (pvrFormat & (1 << 26))) >> 26;
|
|
|
|
|
|
|
|
const GLubyte ARGB1555 = 0;
|
|
|
|
const GLubyte ARGB4444 = 1;
|
|
|
|
const GLubyte RGB565 = 2;
|
|
|
|
|
2021-04-09 15:24:47 +00:00
|
|
|
if((pvrFormat & GPU_TXRFMT_PAL8BPP) == GPU_TXRFMT_PAL8BPP) {
|
2019-09-26 08:17:07 +00:00
|
|
|
/* Paletted... all we can do really is just pick one of the
|
|
|
|
* 4 texels.. unless we want to change the palette (bad) or
|
|
|
|
* pick the closest available colour (slow, and probably bad)
|
|
|
|
*/
|
|
|
|
*t = *src1;
|
|
|
|
} else if(format == RGB565) {
|
2019-09-25 12:10:34 +00:00
|
|
|
GLushort* s1 = (GLushort*) src1;
|
|
|
|
GLushort* s2 = (GLushort*) src2;
|
|
|
|
GLushort* s3 = (GLushort*) src3;
|
|
|
|
GLushort* s4 = (GLushort*) src4;
|
|
|
|
GLushort* d1 = (GLushort*) t;
|
|
|
|
|
2018-08-09 07:56:43 +00:00
|
|
|
r = R565(*s1) + R565(*s2) + R565(*s3) + R565(*s4);
|
2019-09-24 20:26:17 +00:00
|
|
|
g = G565(*s1) + G565(*s2) + G565(*s3) + G565(*s4);
|
|
|
|
b = B565(*s1) + B565(*s2) + B565(*s3) + B565(*s4);
|
2018-08-09 07:56:43 +00:00
|
|
|
|
|
|
|
r /= 4;
|
|
|
|
g /= 4;
|
|
|
|
b /= 4;
|
|
|
|
|
2019-09-24 20:26:17 +00:00
|
|
|
*d1 = PACK_RGB565(r, g, b);
|
2019-09-26 08:17:07 +00:00
|
|
|
} else if(format == ARGB4444) {
|
|
|
|
GLushort* s1 = (GLushort*) src1;
|
|
|
|
GLushort* s2 = (GLushort*) src2;
|
|
|
|
GLushort* s3 = (GLushort*) src3;
|
|
|
|
GLushort* s4 = (GLushort*) src4;
|
|
|
|
GLushort* d1 = (GLushort*) t;
|
|
|
|
|
|
|
|
a = A4444(*s1) + A4444(*s2) + A4444(*s3) + A4444(*s4);
|
|
|
|
r = R4444(*s1) + R4444(*s2) + R4444(*s3) + R4444(*s4);
|
|
|
|
g = G4444(*s1) + G4444(*s2) + G4444(*s3) + G4444(*s4);
|
|
|
|
b = B4444(*s1) + B4444(*s2) + B4444(*s3) + B4444(*s4);
|
|
|
|
|
|
|
|
a /= 4;
|
|
|
|
r /= 4;
|
|
|
|
g /= 4;
|
|
|
|
b /= 4;
|
|
|
|
|
|
|
|
*d1 = PACK_ARGB4444(a, r, g, b);
|
2018-08-09 07:56:43 +00:00
|
|
|
} else {
|
2019-09-26 08:17:07 +00:00
|
|