From 7b6695f4d4be2032b8ec90b20b58809fe24c6a34 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Thu, 14 Mar 2024 02:58:44 +0000 Subject: [PATCH] PSP: zero-copy WindowSurface API for direct VRAM access if all one needs is a raw framebuffer to the PSP's vram, instead of dealing with renderers and textures, that need to be copied hence and forth, this method allows one to create a window, set the pixel format using SDL_SetWindowDisplayMode() - preferably BGR565 for optimal speed (the other possible natively supported option is ABGR8888) - and then request SDL_GetWindowSurface(), which provides one with a surface with direct framebuffer access. note that the pixels pointer inside the surface will be switched after each call because of double-buffering. it's advisable to overwrite all pixels of the PSP visible area (480x272) to not encounter old data. after writing the pixels, a call to SDL_UpdateWindowSurface() sends the changes to the graphics chip. the result is a raw framerate of 250 fps with BGR565 mode, under optimal circumstances - i.e. nothing else is done than drawing, and the drawing loop is as simple as possible. that leaves about 12 ms per frame for other tasks and still allow a fluent 60 fps. --- src/render/psp/SDL_render_psp.c | 19 +++++ src/render/psp/SDL_render_psp.h | 32 +++++++++ src/video/psp/SDL_pspvideo.c | 121 ++++++++++++++++++++++++++++++++ src/video/psp/SDL_pspvideo.h | 8 +++ 4 files changed, 180 insertions(+) create mode 100644 src/render/psp/SDL_render_psp.h diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 47fab82c15..4a446ad42c 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -36,6 +36,7 @@ #include #include #include +#include "SDL_render_psp.h" /* PSP renderer implementation, based on the PGE */ @@ -124,6 +125,24 @@ typedef struct float x, y, z; } VertTCV; +int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void** out) +{ + PSP_RenderData *rd; + if (r == NULL) { + return -1; + } + rd = r->driverdata; + switch (which) { + case SDL_PSP_RENDERPROPS_FRONTBUFFER: + *out = rd->frontbuffer; + return 0; + case SDL_PSP_RENDERPROPS_BACKBUFFER: + *out = rd->backbuffer; + return 0; + } + return -1; +} + #define PI 3.14159265358979f #define radToDeg(x) ((x)*180.f / PI) diff --git a/src/render/psp/SDL_render_psp.h b/src/render/psp/SDL_render_psp.h new file mode 100644 index 0000000000..f952886c04 --- /dev/null +++ b/src/render/psp/SDL_render_psp.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + 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. +*/ + +/* this header is meant to be included after the other related internal SDL + headers. it's the interface between psp renderer and video driver code. */ + +enum SDL_PSP_RenderProps +{ + SDL_PSP_RENDERPROPS_FRONTBUFFER, + SDL_PSP_RENDERPROPS_BACKBUFFER, +}; + +int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void** out); + diff --git a/src/video/psp/SDL_pspvideo.c b/src/video/psp/SDL_pspvideo.c index 9631904bd1..46837b6ac7 100644 --- a/src/video/psp/SDL_pspvideo.c +++ b/src/video/psp/SDL_pspvideo.c @@ -29,14 +29,128 @@ #include "SDL_syswm.h" #include "SDL_loadso.h" #include "SDL_events.h" +#include "SDL_render.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_keyboard_c.h" +#include "../../render/SDL_sysrender.h" /* PSP declarations */ #include "SDL_pspvideo.h" #include "SDL_pspevents_c.h" #include "SDL_pspgl_c.h" +#include "../../render/psp/SDL_render_psp.h" + +#define SDL_WINDOWTEXTUREDATA "_SDL_WindowTextureData" + +typedef struct +{ + SDL_Renderer *renderer; + SDL_Texture *texture; + void *pixels; + int pitch; + int bytes_per_pixel; +} SDL_WindowTextureData; + +int PSP_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format, void **pixels, int *pitch) +{ + SDL_RendererInfo info; + SDL_WindowTextureData *data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); + int i, w, h; + + SDL_GetWindowSizeInPixels(window, &w, &h); + + if (w != 480) { + return SDL_SetError("Unexpected window size"); + } + + if (!data) { + SDL_Renderer *renderer = NULL; + for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { + SDL_GetRenderDriverInfo(i, &info); + if (SDL_strcmp(info.name, "software") != 0) { + renderer = SDL_CreateRenderer(window, i, 0); + if (renderer && (SDL_GetRendererInfo(renderer, &info) == 0) && (info.flags & SDL_RENDERER_ACCELERATED)) { + break; /* this will work. */ + } + if (renderer) { /* wasn't accelerated, etc, skip it. */ + SDL_DestroyRenderer(renderer); + renderer = NULL; + } + } + } + if (!renderer) { + return SDL_SetError("No hardware accelerated renderers available"); + } + + SDL_assert(renderer != NULL); /* should have explicitly checked this above. */ + + /* Create the data after we successfully create the renderer (bug #1116) */ + data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data)); + + if (!data) { + SDL_DestroyRenderer(renderer); + return SDL_OutOfMemory(); + } + + SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data); + data->renderer = renderer; + } else { + if (SDL_GetRendererInfo(data->renderer, &info) == -1) { + return -1; + } + } + + /* Find the first format without an alpha channel */ + *format = info.texture_formats[0]; + + for (i = 0; i < (int)info.num_texture_formats; ++i) { + if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) && + !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) { + *format = info.texture_formats[i]; + break; + } + } + + /* get the PSP renderer's "private" data */ + SDL_PSP_RenderGetProp(data->renderer, SDL_PSP_RENDERPROPS_FRONTBUFFER, &data->pixels); + + /* Create framebuffer data */ + data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format); + /* since we point directly to VRAM's frontbuffer, we have to use + the upscaled pitch of 512 width - since PSP requires all textures to be + powers of 2. */ + data->pitch = 512 * data->bytes_per_pixel; + *pixels = data->pixels; + *pitch = data->pitch; + + /* Make sure we're not double-scaling the viewport */ + SDL_RenderSetViewport(data->renderer, NULL); + + return 0; +} + +int PSP_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects) +{ + SDL_WindowTextureData *data; + data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); + if (!data || !data->renderer || !window->surface) { + return -1; + } + data->renderer->RenderPresent(data->renderer); + SDL_PSP_RenderGetProp(data->renderer, SDL_PSP_RENDERPROPS_BACKBUFFER, &window->surface->pixels); + return 0; +} + +void PSP_DestroyWindowFramebuffer(_THIS, SDL_Window *window) +{ + SDL_WindowTextureData *data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); + if (!data || !data->renderer) { + return; + } + SDL_DestroyRenderer(data->renderer); + data->renderer = NULL; +} /* unused static SDL_bool PSP_initialized = SDL_FALSE; @@ -128,6 +242,13 @@ static SDL_VideoDevice *PSP_Create() device->PumpEvents = PSP_PumpEvents; + /* backend to use VRAM directly as a framebuffer using + SDL_GetWindowSurface() API. */ + device->checked_texture_framebuffer = 1; + device->CreateWindowFramebuffer = PSP_CreateWindowFramebuffer; + device->UpdateWindowFramebuffer = PSP_UpdateWindowFramebuffer; + device->DestroyWindowFramebuffer = PSP_DestroyWindowFramebuffer; + return device; } diff --git a/src/video/psp/SDL_pspvideo.h b/src/video/psp/SDL_pspvideo.h index 442d3eae03..44413e788f 100644 --- a/src/video/psp/SDL_pspvideo.h +++ b/src/video/psp/SDL_pspvideo.h @@ -68,6 +68,14 @@ void PSP_MinimizeWindow(_THIS, SDL_Window *window); void PSP_RestoreWindow(_THIS, SDL_Window *window); void PSP_DestroyWindow(_THIS, SDL_Window *window); +/* "methods" aka callbacks for SDL_WindowSurface API */ +int PSP_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, + void **pixels, int *pitch); +int PSP_UpdateWindowFramebuffer(_THIS, SDL_Window *window, +const SDL_Rect *rects, int numrects); +void PSP_DestroyWindowFramebuffer(_THIS, SDL_Window *window); + + /* Window manager function */ SDL_bool PSP_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info);