diff --git a/GL/private.h b/GL/private.h index ad66312..f97a5f5 100644 --- a/GL/private.h +++ b/GL/private.h @@ -383,6 +383,8 @@ GLenum _glGetCullFace(); GLenum _glGetFrontFace(); GLenum _glGetGpuBlendSrcFactor(); GLenum _glGetGpuBlendDstFactor(); +GLint _glGetUnpackRowLength(); +GLint _glGetUnpackAlignment(); extern PolyList OP_LIST; extern PolyList PT_LIST; diff --git a/GL/state.c b/GL/state.c index 03820fd..01ab3f9 100644 --- a/GL/state.c +++ b/GL/state.c @@ -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; } @@ -881,8 +894,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; + } } @@ -1126,6 +1156,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__); diff --git a/GL/texture.c b/GL/texture.c index f8f8109..8f95176 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -1757,6 +1757,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) { @@ -2344,7 +2353,15 @@ void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint y // 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); @@ -2389,6 +2406,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) * texturePitch + xoffset) * destStride; for (uint32_t x = 0; x < width; ++x) { conversion(src, dst); @@ -2402,21 +2420,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]; @@ -2436,10 +2457,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) * texturePitch + xoffset) * destStride; - FASTCPY(destRow, (GLubyte*)data + y * srcRowWidth, srcRowWidth); + FASTCPY(destRow, (GLubyte*)data + y * sourcePitch, sourceRowWidth); } }