Merge branch 'optimize-sdl-texture-streaming' into 'master'

Improve unpack handling for streaming texture uploads

See merge request simulant/GLdc!171
This commit is contained in:
Luke Benstead 2026-06-06 06:01:04 +00:00
commit 2da4f94b9a
3 changed files with 83 additions and 16 deletions

View File

@ -379,6 +379,8 @@ GLenum _glGetCullFace();
GLenum _glGetFrontFace();
GLenum _glGetGpuBlendSrcFactor();
GLenum _glGetGpuBlendDstFactor();
GLint _glGetUnpackRowLength();
GLint _glGetUnpackAlignment();
extern PolyList OP_LIST;
extern PolyList PT_LIST;

View File

@ -66,6 +66,9 @@ static struct {
GLfloat half_point_size;
GLfloat half_line_width;
GLint unpack_row_length;
GLint unpack_alignment;
} GPUState = {
.is_dirty = GL_TRUE,
.depth_func = GL_LESS,
@ -102,6 +105,8 @@ static struct {
.current_tex_coord1 = {0.0f, 0.0f},
.half_point_size = 0.5f,
.half_line_width = 0.5f,
.unpack_row_length = 0,
.unpack_alignment = 4,
};
float* _glCurrentColor() {
@ -141,6 +146,14 @@ GLboolean _glGPUStateIsDirty() {
return GPUState.is_dirty;
}
GLint _glGetUnpackRowLength() {
return GPUState.unpack_row_length;
}
GLint _glGetUnpackAlignment() {
return GPUState.unpack_alignment;
}
Material* _glActiveMaterial() {
return &GPUState.material;
}
@ -873,8 +886,25 @@ void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha
}
void glPixelStorei(GLenum pname, GLint param) {
_GL_UNUSED(pname);
_GL_UNUSED(param);
switch(pname) {
case GL_UNPACK_ROW_LENGTH:
if(param < 0) {
_glKosThrowError(GL_INVALID_VALUE, __func__);
return;
}
GPUState.unpack_row_length = param;
break;
case GL_UNPACK_ALIGNMENT:
if(param != 1 && param != 2 && param != 4 && param != 8) {
_glKosThrowError(GL_INVALID_VALUE, __func__);
return;
}
GPUState.unpack_alignment = param;
break;
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);
break;
}
}
@ -1118,6 +1148,12 @@ void APIENTRY glGetIntegerv(GLenum pname, GLint *params) {
case GL_TEXTURE_INTERNAL_FORMAT_KOS:
*params = _glGetTextureInternalFormat();
break;
case GL_UNPACK_ROW_LENGTH:
*params = GPUState.unpack_row_length;
break;
case GL_UNPACK_ALIGNMENT:
*params = GPUState.unpack_alignment;
break;
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);

View File

@ -1625,6 +1625,15 @@ static inline GLboolean is4BPPFormat(GLenum format) {
return format == GL_COLOR_INDEX4_EXT || format == GL_COLOR_INDEX4_TWID_KOS;
}
static GLuint _glGetUnpackRowPitch(GLsizei width, GLint sourceStride, GLenum format) {
GLint rowLength = _glGetUnpackRowLength();
GLint unpackAlignment = _glGetUnpackAlignment();
GLuint rowPixels = (rowLength > 0) ? (GLuint) rowLength : (GLuint) width;
GLuint rowBytes = is4BPPFormat(format) ? ((rowPixels + 1) / 2) : (rowPixels * (GLuint) sourceStride);
return (rowBytes + (GLuint) unpackAlignment - 1) & ~((GLuint) unpackAlignment - 1);
}
void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type, const GLvoid *data) {
@ -1745,6 +1754,12 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
GLubyte* targetData = (active->baseDataOffset == 0) ? active->data : _glGetMipmapLocation(active, level);
gl_assert(targetData);
if(!data) {
gl_assert(active->index == originalId);
_glGPUStateMarkDirty();
return;
}
if(needs_conversion < 0) {
_glKosThrowError(GL_INVALID_VALUE, __func__);
INFO_MSG("Couldn't find necessary texture conversion\n");
@ -2164,18 +2179,19 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y
return;
}
GLboolean isPaletted = (
active->internalFormat == GL_COLOR_INDEX8_EXT ||
active->internalFormat == GL_COLOR_INDEX4_EXT ||
active->internalFormat == GL_COLOR_INDEX4_TWID_KOS ||
active->internalFormat == GL_COLOR_INDEX8_TWID_KOS
) ? GL_TRUE : GL_FALSE;
GLenum cleanInternalFormat = _cleanInternalFormat(active->internalFormat);
// Determine source stride
GLint sourceStride = _determineStride(format, type);
GLuint srcBytes = (width * height * sourceStride);
if (sourceStride < 0) {
INFO_MSG("Stride was not detected\n");
_glKosThrowError(GL_INVALID_OPERATION, __func__);
return;
}
GLuint sourceRowWidth = is4BPPFormat(format) ? (((GLuint) width + 1) / 2) : ((GLuint) width * (GLuint) sourceStride);
GLuint sourcePitch = _glGetUnpackRowPitch(width, sourceStride, format);
GLuint srcBytes = height ? (sourcePitch * ((GLuint) height - 1) + sourceRowWidth) : 0;
// Calculate destination stride (this accounts for both POT and NPOT)
GLint destStride = _determineStrideInternal(cleanInternalFormat);
@ -2220,6 +2236,7 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y
}
if (needs_conversion == CONVERSION_TYPE_CONVERT) {
for (uint32_t y = 0; y < height; ++y) {
src = (const GLubyte*) data + (y * sourcePitch);
dst = conversionBuffer + ((y + yoffset) * textureWidth + xoffset) * destStride;
for (uint32_t x = 0; x < width; ++x) {
conversion(src, dst);
@ -2233,21 +2250,24 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y
for (uint32_t y = yoffset; y < yoffset + height; ++y) {
for (uint32_t x = xoffset; x < xoffset + width; ++x) {
uint32_t srcIndex = (y - yoffset) * width + (x - xoffset);
uint32_t newLocation = twid_compute_index(x, y, maskX, maskY);
dst = conversionBuffer + (destStride * newLocation);
src = (const GLubyte*) data + ((y - yoffset) * sourcePitch) + ((x - xoffset) * sourceStride);
if (needs_conversion == 3) {
conversion(src + srcIndex * sourceStride, dst);
conversion(src, dst);
} else {
memcpy(dst, src + srcIndex * sourceStride, destStride);
memcpy(dst, src, destStride);
}
}
}
}
if (pack) {
assert(isPaletted);
assert(active->internalFormat == GL_COLOR_INDEX8_EXT ||
active->internalFormat == GL_COLOR_INDEX4_EXT ||
active->internalFormat == GL_COLOR_INDEX4_TWID_KOS ||
active->internalFormat == GL_COLOR_INDEX8_TWID_KOS);
size_t dst_byte = 0;
for (size_t src_byte = 0; src_byte < destBytes; ++src_byte) {
uint8_t v = conversionBuffer[src_byte];
@ -2267,10 +2287,19 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y
free(conversionBuffer);
} else {
// No conversion necessary, we can update data directly
if (xoffset == 0 &&
yoffset == 0 &&
width == textureWidth &&
sourceStride == destStride &&
sourcePitch == textureWidth * destStride) {
FASTCPY(targetData, data, height * sourcePitch);
_glGPUStateMarkDirty();
return;
}
for (GLsizei y = 0; y < height; ++y) {
GLsizei srcRowWidth = width * sourceStride;
GLubyte* destRow = targetData + ((y + yoffset) * textureWidth + xoffset) * destStride;
FASTCPY(destRow, (GLubyte*)data + y * srcRowWidth, srcRowWidth);
FASTCPY(destRow, (GLubyte*)data + y * sourcePitch, sourceRowWidth);
}
}