Fix a PSP-specific crash in the Kelp Forest. psp
authorachurch
Mon, 10 Jan 2011 10:35:28 +0900
branchpsp
changeset 643 a739a295ee78
parent 642 8b202aba3a13
child 646 ea845f99c211
Fix a PSP-specific crash in the Kelp Forest. This patch corrects a bug in PSP-specific texture management code which frequently results in a crash when entering the Kelp Forest area, as reported by Tom Lu.
PSP/src/fakegl.c
--- a/PSP/src/fakegl.c	Mon Jan 10 09:50:53 2011 +0900
+++ b/PSP/src/fakegl.c	Mon Jan 10 10:35:28 2011 +0900
@@ -2338,20 +2338,41 @@
 
     const Texture * const texture = texture_array[bound_texture].texture;
 
-    if (texture->swizzled && (texture->height & 7) != 0) {
+    /* These combinations should be impossible, but check anyway to avoid
+     * overrunning the source buffer. */
+    if (texture->swizzled
+     && ((texture->height & 7) != 0
+         || (texture->indexed
+             ? (texture->stride & 15) != 0
+             : (texture->stride & 3) != 0))
+    ) {
         DMSG("Can't handle getting swizzled textures with unaligned height"
-             " (%p, %dx%d, stride=%d)", texture, texture->width,
+             "or stride (%p, %dx%d, stride=%d)", texture, texture->width,
              texture->height, texture->stride);
         SET_ERROR(GL_INVALID_OPERATION);
         return;
     }
 
-    uint32_t *dest = (uint32_t *)pixels;
-    const uint32_t width       = texture->width;
-    const uint32_t height      = texture->height;
-    const uint32_t src_stride  = texture->stride;
-    const uint32_t dest_stride = texture->width;
-    const uint32_t *palette    = texture->palette;
+    /* If the width is unaligned for a swizzled texture, we'll overflow
+     * the destination buffer, so allocate a temporary, aligned-width
+     * buffer for unswizzling. */
+    uint32_t *temp_buffer = NULL;
+    if (texture->width != texture->stride) {
+        const uint32_t size = texture->stride * texture->height * 4;
+        temp_buffer = mem_alloc(size, 64, MEM_ALLOC_TEMP);
+        if (UNLIKELY(!temp_buffer)) {
+            DMSG("Can't allocate temporary buffer for unswizzling (%u bytes)",
+                 size);
+            SET_ERROR(GL_OUT_OF_MEMORY);
+            return;
+        }
+    }
+
+    uint32_t *dest = temp_buffer ? temp_buffer : (uint32_t *)pixels;
+    const unsigned int width       = texture->width;
+    const unsigned int height      = texture->height;
+    const unsigned int stride      = texture->stride;
+    const uint32_t * const palette = texture->palette;
 
     if (texture->swizzled) {
 
@@ -2359,12 +2380,12 @@
 
             const uint8_t *src = texture->pixels;
             unsigned int y;
-            for (y = 0; y < height; y += 8, dest += dest_stride*7) {
+            for (y = 0; y < height; y += 8, dest += stride*7) {
                 unsigned int x;
                 for (x = 0; x < width; x += 16, dest += 16) {
                     uint32_t *destline = dest;
                     unsigned int line;
-                    for (line = 0; line < 8; line++, destline += dest_stride) {
+                    for (line = 0; line < 8; line++, destline += stride) {
                         unsigned int i;
                         for (i = 0; i < 16; i += 4, src += 4) {
                             const uint8_t pixel0 = src[0];
@@ -2384,12 +2405,12 @@
 
             const uint32_t *src = (const uint32_t *)texture->pixels;
             unsigned int y;
-            for (y = 0; y < height; y += 8, dest += dest_stride*7) {
+            for (y = 0; y < height; y += 8, dest += stride*7) {
                 unsigned int x;
                 for (x = 0; x < width; x += 16, dest += 16) {
                     uint32_t *destline = dest;
                     unsigned int line;
-                    for (line = 0; line < 8; line++, destline += dest_stride) {
+                    for (line = 0; line < 8; line++, destline += stride) {
                         const uint32_t pixel0 = src[0];
                         const uint32_t pixel1 = src[1];
                         const uint32_t pixel2 = src[2];
@@ -2410,7 +2431,7 @@
 
             const uint8_t *src = texture->pixels;
             unsigned int y;
-            for (y = 0; y < height; y++, src += src_stride, dest += dest_stride) {
+            for (y = 0; y < height; y++, src += stride, dest += stride) {
                 unsigned int x;
                 for (x = 0; x < width; x++) {
                     dest[x] = palette[src[x]];
@@ -2422,13 +2443,23 @@
             const uint32_t *src =
                 (const uint32_t *)texture->pixels;
             unsigned int y;
-            for (y = 0; y < height; y++, src += src_stride, dest += dest_stride) {
+            for (y = 0; y < height; y++, src += stride, dest += stride) {
                 memcpy(dest, src, width*4);
             }
 
         }  // if (indexed)
 
     }  // if (swizzled)
+
+    if (temp_buffer) {
+        const uint32_t *copy_src = temp_buffer;
+        uint32_t *copy_dest = (uint32_t *)pixels;
+        unsigned int y;
+        for (y = 0; y < height; y++, copy_src += stride, copy_dest += width) {
+            memcpy(copy_dest, copy_src, width*4);
+        }
+        mem_free(temp_buffer);
+    }
 }
 
 /*************************************************************************/