SDL: Native framebuffer for software renderer

From 1e2eed1a018c2070157d6104aa473f744e5bf860 Mon Sep 17 00:00:00 2001
From: Ivan Epifanov <[EMAIL REDACTED]>
Date: Mon, 28 Dec 2020 15:32:52 +0300
Subject: [PATCH] Native framebuffer for software renderer

---
 src/video/vita/SDL_vitaframebuffer.c | 121 +++++++++++++++++++++++++++
 src/video/vita/SDL_vitaframebuffer.h |  27 ++++++
 src/video/vita/SDL_vitavideo.c       |   5 ++
 src/video/vita/SDL_vitavideo.h       |   5 ++
 4 files changed, 158 insertions(+)
 create mode 100644 src/video/vita/SDL_vitaframebuffer.c
 create mode 100644 src/video/vita/SDL_vitaframebuffer.h

diff --git a/src/video/vita/SDL_vitaframebuffer.c b/src/video/vita/SDL_vitaframebuffer.c
new file mode 100644
index 000000000..ab6323654
--- /dev/null
+++ b/src/video/vita/SDL_vitaframebuffer.c
@@ -0,0 +1,121 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_VITA
+
+#include "SDL_vitavideo.h"
+
+#include <psp2/kernel/sysmem.h>
+
+#define SCREEN_W 960
+#define SCREEN_H 544
+#define ALIGN(x, a)     (((x) + ((a) - 1)) & ~((a) - 1))
+#define DISPLAY_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8
+
+void *vita_gpu_alloc(SceKernelMemBlockType type, unsigned int size, SceUID *uid)
+{
+    void *mem;
+
+    if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW) {
+        size = ALIGN(size, 256*1024);
+    } else {
+        size = ALIGN(size, 4*1024);
+    }
+
+    *uid = sceKernelAllocMemBlock("gpu_mem", type, size, NULL);
+
+    if (*uid < 0)
+        return NULL;
+
+    if (sceKernelGetMemBlockBase(*uid, &mem) < 0)
+        return NULL;
+
+    return mem;
+}
+
+void vita_gpu_free(SceUID uid)
+{
+    void *mem = NULL;
+    if (sceKernelGetMemBlockBase(uid, &mem) < 0)
+        return;
+    sceKernelFreeMemBlock(uid);
+}
+
+int VITA_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
+{
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+    SceDisplayFrameBuf framebuf;
+
+    *format = SDL_PIXELFORMAT_ABGR8888;
+    *pitch = SCREEN_W * 4;
+
+    data->buffer = vita_gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
+        4 * SCREEN_W * SCREEN_H,
+        &data->buffer_uid
+    );
+
+    // memset the buffer to black
+    for (int y = 0; y < SCREEN_H; y++) {
+        unsigned int *row = (unsigned int *)data->buffer + y * SCREEN_W;
+        for (int x = 0; x < SCREEN_W; x++) {
+            row[x] = 0xff0000FF;
+        }
+    }
+
+    SDL_memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf));
+    framebuf.size        = sizeof(SceDisplayFrameBuf);
+    framebuf.base        = data->buffer;
+    framebuf.pitch       = SCREEN_W;
+    framebuf.pixelformat = DISPLAY_PIXEL_FORMAT;
+    framebuf.width       = SCREEN_W;
+    framebuf.height      = SCREEN_H;
+    sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME);
+
+    *pixels = data->buffer;
+
+    return 0;
+}
+
+int VITA_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects)
+{
+    // do nothing
+    return 0;
+}
+
+void VITA_DestroyWindowFramebuffer(_THIS, SDL_Window * window)
+{
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+
+    if (!data) {
+        /* The window wasn't fully initialized */
+        return;
+    }
+
+    vita_gpu_free(data->buffer_uid);
+    data->buffer = NULL;
+    return;
+}
+
+#endif /* SDL_VIDEO_DRIVER_VITA */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/vita/SDL_vitaframebuffer.h b/src/video/vita/SDL_vitaframebuffer.h
new file mode 100644
index 000000000..b2e6b6ae3
--- /dev/null
+++ b/src/video/vita/SDL_vitaframebuffer.h
@@ -0,0 +1,27 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+extern int VITA_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch);
+extern int VITA_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects);
+extern void VITA_DestroyWindowFramebuffer(_THIS, SDL_Window * window);
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/vita/SDL_vitavideo.c b/src/video/vita/SDL_vitavideo.c
index 54063148b..b2c5c96b2 100644
--- a/src/video/vita/SDL_vitavideo.c
+++ b/src/video/vita/SDL_vitavideo.c
@@ -37,6 +37,7 @@
 #include "SDL_vitatouch.h"
 #include "SDL_vitakeyboard.h"
 #include "SDL_vitamouse_c.h"
+#include "SDL_vitaframebuffer.h"
 #if SDLVIDEO_OPENGL_ES2
 #include "SDL_vitagl_c.h"
 #endif
@@ -121,6 +122,10 @@ VITA_Create()
     device->DestroyWindow = VITA_DestroyWindow;
     device->GetWindowWMInfo = VITA_GetWindowWMInfo;
 
+    device->CreateWindowFramebuffer = VITA_CreateWindowFramebuffer;
+    device->UpdateWindowFramebuffer = VITA_UpdateWindowFramebuffer;
+    device->DestroyWindowFramebuffer = VITA_DestroyWindowFramebuffer;
+
 #if SDL_VIDEO_OPENGL_ES2
     device->GL_LoadLibrary = VITA_GL_LoadLibrary;
     device->GL_GetProcAddress = VITA_GL_GetProcAddress;
diff --git a/src/video/vita/SDL_vitavideo.h b/src/video/vita/SDL_vitavideo.h
index 8f02e9680..f92182728 100644
--- a/src/video/vita/SDL_vitavideo.h
+++ b/src/video/vita/SDL_vitavideo.h
@@ -25,6 +25,8 @@
 #include "../../SDL_internal.h"
 #include "../SDL_sysvideo.h"
 
+#include <psp2/types.h>
+#include <psp2/display.h>
 #include <psp2/ime_dialog.h>
 
 typedef struct SDL_VideoData
@@ -34,6 +36,7 @@ typedef struct SDL_VideoData
 
 	wchar_t ime_buffer[SCE_IME_DIALOG_MAX_TEXT_LENGTH];
 	SDL_bool ime_active;
+
 } SDL_VideoData;
 
 
@@ -46,6 +49,8 @@ typedef struct SDL_DisplayData
 typedef struct SDL_WindowData
 {
     SDL_bool uses_gles;
+    SceUID buffer_uid;
+    void* buffer;
 
 } SDL_WindowData;