SDL: Add SDL_RenderReadPixels

From a86ba3916e4db020efc2a0b1f34edaf368e73b89 Mon Sep 17 00:00:00 2001
From: Ivan Epifanov <[EMAIL REDACTED]>
Date: Sat, 28 Nov 2020 00:32:32 +0300
Subject: [PATCH] Add SDL_RenderReadPixels

---
 src/render/vitagxm/SDL_render_vita_gxm.c | 78 ++++++++++++++++++++++--
 1 file changed, 72 insertions(+), 6 deletions(-)

diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c
index d27174357..88ecf704f 100644
--- a/src/render/vitagxm/SDL_render_vita_gxm.c
+++ b/src/render/vitagxm/SDL_render_vita_gxm.c
@@ -959,19 +959,85 @@ VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *
     return 0;
 }
 
+void read_pixels(int x, int y, size_t width, size_t height, void *data) {
+    SceDisplayFrameBuf pParam;
+    pParam.size = sizeof(SceDisplayFrameBuf);
+
+    sceDisplayGetFrameBuf(&pParam, SCE_DISPLAY_SETBUF_NEXTFRAME);
+
+    int i, j;
+    Uint32 *out32 = (Uint32 *)data;
+    Uint32 *in32 = (Uint32 *)pParam.base;
+
+    in32 += (x + y * pParam.pitch);
+
+    for (i = 0; i < height; i++) {
+        for (j = 0; j < width; j++) {
+            out32[(height - (i + 1)) * width + j] = in32[j];
+        }
+        in32 += pParam.pitch;
+    }
+}
+
+
 static int
 VITA_GXM_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
     Uint32 pixel_format, void *pixels, int pitch)
 {
-    SceDisplayFrameBuf framebuf;
-    SDL_memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf));
-    sceDisplayGetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_IMMEDIATE);
+    // TODO: read from texture rendertarget. Although no-one sane should do it.
+    if (render->target) {
+        return SDL_Unsupported();
+    }
+
+    Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
+    size_t buflen;
+    void *temp_pixels;
+    int temp_pitch;
+    Uint8 *src, *dst, *tmp;
+    int w, h, length, rows;
+    int status;
+
+    temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
+    buflen = rect->h * temp_pitch;
+    if (buflen == 0) {
+        return 0;  /* nothing to do. */
+    }
+
+    temp_pixels = SDL_malloc(buflen);
+    if (!temp_pixels) {
+        return SDL_OutOfMemory();
+    }
 
-    // TODO
-    //pixels = framebuf.base;
+    SDL_GetRendererOutputSize(renderer, &w, &h);
 
-    return 0;
+    read_pixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
+                       rect->w, rect->h, temp_pixels);
+
+    /* Flip the rows to be top-down if necessary */
+
+    if (!renderer->target) {
+        SDL_bool isstack;
+        length = rect->w * SDL_BYTESPERPIXEL(temp_format);
+        src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
+        dst = (Uint8*)temp_pixels;
+        tmp = SDL_small_alloc(Uint8, length, &isstack);
+        rows = rect->h / 2;
+        while (rows--) {
+            SDL_memcpy(tmp, dst, length);
+            SDL_memcpy(dst, src, length);
+            SDL_memcpy(src, tmp, length);
+            dst += temp_pitch;
+            src -= temp_pitch;
+        }
+        SDL_small_free(tmp, isstack);
+    }
+
+    status = SDL_ConvertPixels(rect->w, rect->h,
+                               temp_format, temp_pixels, temp_pitch,
+                               pixel_format, pixels, pitch);
+    SDL_free(temp_pixels);
 
+    return status;
 }