From c4ee32b9dd5e57525e584f916ba06e89800f766d Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 22 Jan 2023 16:38:10 +0100 Subject: [PATCH 01/37] Something already working --- include/SDL_hints.h | 11 + src/render/psp/SDL_render_psp.c | 1292 +++++++------------------------ 2 files changed, 311 insertions(+), 992 deletions(-) diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 6713d01fea204..f603975a1ff57 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -2038,6 +2038,17 @@ extern "C" { */ #define SDL_HINT_PS2_DYNAMIC_VSYNC "SDL_PS2_DYNAMIC_VSYNC" +/** + * \brief A variable controlling if VSYNC is automatically disable if doesn't reach the enough FPS + * + * This variable can be set to the following values: + * "0" - It will be using VSYNC as defined in the main flag. Default + * "1" - If VSYNC was previously enabled, then it will disable VSYNC if doesn't reach enough speed + * + * By default SDL does not enable the automatic VSYNC + */ +#define SDL_HINT_PSP_DYNAMIC_VSYNC "SDL_PSP_DYNAMIC_VSYNC" + /** * A variable to control whether the return key on the soft keyboard should * hide the soft keyboard on Android and iOS. diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 2b85309d81260..7caf450300415 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -22,89 +22,40 @@ #if SDL_VIDEO_RENDER_PSP -#include "SDL_hints.h" #include "../SDL_sysrender.h" +#include "SDL_hints.h" -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include "SDL_render_psp.h" -/* PSP renderer implementation, based on the PGE */ -static unsigned int __attribute__((aligned(16))) DisplayList[262144]; - -#define COL5650(r, g, b, a) ((r >> 3) | ((g >> 2) << 5) | ((b >> 3) << 11)) -#define COL5551(r, g, b, a) ((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10) | (a > 0 ? 0x7000 : 0)) -#define COL4444(r, g, b, a) ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8) | ((a >> 4) << 12)) -#define COL8888(r, g, b, a) ((r) | ((g) << 8) | ((b) << 16) | ((a) << 24)) - -/** - * Holds psp specific texture data - * - * Part of a hot-list of textures that are used as render targets - * When short of vram we spill Least-Recently-Used render targets to system memory - */ -typedef struct PSP_TextureData +static unsigned int __attribute__((aligned(16))) list[262144]; +typedef struct +{ + void *frontbuffer; /**< main screen buffer */ + void *backbuffer; /**< buffer presented to display */ + uint64_t drawColor; + int32_t vsync_callback_id; + uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ +} PSP_RenderData; + +typedef struct PSP_Texture { void *data; /**< Image data. */ - unsigned int size; /**< Size of data in bytes. */ unsigned int width; /**< Image width. */ unsigned int height; /**< Image height. */ unsigned int textureWidth; /**< Texture width (power of two). */ unsigned int textureHeight; /**< Texture height (power of two). */ - unsigned int bits; /**< Image bits per pixel. */ unsigned int format; /**< Image format - one of ::pgePixelFormat. */ + unsigned int filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ unsigned int pitch; - SDL_bool swizzled; /**< Is image swizzled. */ - struct PSP_TextureData *prevhotw; /**< More recently used render target */ - struct PSP_TextureData *nexthotw; /**< Less recently used render target */ -} PSP_TextureData; - -typedef struct -{ - SDL_BlendMode mode; - unsigned int color; - int shadeModel; - SDL_Texture *texture; -} PSP_BlendState; - -typedef struct -{ - void *frontbuffer; /**< main screen buffer */ - void *backbuffer; /**< buffer presented to display */ - SDL_Texture *boundTarget; /**< currently bound rendertarget */ - SDL_bool initialized; /**< is driver initialized */ - SDL_bool displayListAvail; /**< is the display list already initialized for this frame */ - unsigned int psm; /**< format of the display buffers */ - unsigned int bpp; /**< bits per pixel of the main display */ - - SDL_bool vsync; /**< whether we do vsync */ - PSP_BlendState blendState; /**< current blend mode */ - PSP_TextureData *most_recent_target; /**< start of render target LRU double linked list */ - PSP_TextureData *least_recent_target; /**< end of the LRU list */ - - SDL_bool vblank_not_reached; /**< whether vblank wasn't reached */ -} PSP_RenderData; +} PSP_Texture; typedef struct { float x, y, z; } VertV; -typedef struct -{ - float u, v; - float x, y, z; -} VertTV; - typedef struct { SDL_Color col; @@ -136,70 +87,33 @@ int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void* return -1; } -#define PI 3.14159265358979f - -#define radToDeg(x) ((x)*180.f / PI) -#define degToRad(x) ((x)*PI / 180.f) - -static float MathAbs(float x) -{ - float result; - - __asm__ volatile( - "mtv %1, S000\n" - "vabs.s S000, S000\n" - "mfv %0, S000\n" - : "=r"(result) - : "r"(x)); - - return result; -} +static int vsync_sema_id = 0; -static void MathSincos(float r, float *s, float *c) -{ - __asm__ volatile( - "mtv %2, S002\n" - "vcst.s S003, VFPU_2_PI\n" - "vmul.s S002, S002, S003\n" - "vrot.p C000, S002, [s, c]\n" - "mfv %0, S000\n" - "mfv %1, S001\n" - : "=r"(*s), "=r"(*c) - : "r"(r)); -} +/* PRIVATE METHODS */ -static void Swap(float *a, float *b) +static unsigned int getMemorySize(unsigned int width, unsigned int height, unsigned int psm) { - float n = *a; - *a = *b; - *b = n; -} + switch (psm) + { + case GU_PSM_T4: + return (width * height) >> 1; -static inline int InVram(void *data) -{ - return data < (void *)0x04200000; -} + case GU_PSM_T8: + return width * height; -/* Return next power of 2 */ -static int TextureNextPow2(unsigned int w) -{ - unsigned int n = 2; - if (w == 0) { - return 0; - } + case GU_PSM_5650: + case GU_PSM_5551: + case GU_PSM_4444: + case GU_PSM_T16: + return 2 * width * height; - while (w > n) { - n <<= 1; - } + case GU_PSM_8888: + case GU_PSM_T32: + return 4 * width * height; - return n; -} - -static void psp_on_vblank(u32 sub, PSP_RenderData *data) -{ - if (data) { - data->vblank_not_reached = SDL_FALSE; - } + default: + return 0; + } } static int PixelFormatToPSPFMT(Uint32 format) @@ -218,273 +132,19 @@ static int PixelFormatToPSPFMT(Uint32 format) } } -/// SECTION render target LRU management -static void LRUTargetRelink(PSP_TextureData *psp_texture) -{ - if (psp_texture->prevhotw) { - psp_texture->prevhotw->nexthotw = psp_texture->nexthotw; - } - if (psp_texture->nexthotw) { - psp_texture->nexthotw->prevhotw = psp_texture->prevhotw; - } -} - -static void LRUTargetPushFront(PSP_RenderData *data, PSP_TextureData *psp_texture) -{ - psp_texture->nexthotw = data->most_recent_target; - if (data->most_recent_target) { - data->most_recent_target->prevhotw = psp_texture; - } - data->most_recent_target = psp_texture; - if (!data->least_recent_target) { - data->least_recent_target = psp_texture; - } -} - -static void LRUTargetRemove(PSP_RenderData *data, PSP_TextureData *psp_texture) -{ - LRUTargetRelink(psp_texture); - if (data->most_recent_target == psp_texture) { - data->most_recent_target = psp_texture->nexthotw; - } - if (data->least_recent_target == psp_texture) { - data->least_recent_target = psp_texture->prevhotw; - } - psp_texture->prevhotw = NULL; - psp_texture->nexthotw = NULL; -} - -static void LRUTargetBringFront(PSP_RenderData *data, PSP_TextureData *psp_texture) -{ - if (data->most_recent_target == psp_texture) { - return; // nothing to do - } - LRUTargetRemove(data, psp_texture); - LRUTargetPushFront(data, psp_texture); -} - -static void TextureStorageFree(void *storage) -{ - if (InVram(storage)) { - vfree(storage); - } else { - SDL_free(storage); - } -} - -static int TextureSwizzle(PSP_TextureData *psp_texture, void *dst) -{ - int bytewidth, height; - int rowblocks, rowblocksadd; - int i, j; - unsigned int blockaddress = 0; - unsigned int *src = NULL; - unsigned char *data = NULL; - - if (psp_texture->swizzled) { - return 1; - } - - bytewidth = psp_texture->textureWidth * (psp_texture->bits >> 3); - height = psp_texture->size / bytewidth; - - rowblocks = (bytewidth >> 4); - rowblocksadd = (rowblocks - 1) << 7; - - src = (unsigned int *)psp_texture->data; - - data = dst; - if (!data) { - data = SDL_malloc(psp_texture->size); - } - - if (!data) { - return SDL_OutOfMemory(); - } - - for (j = 0; j < height; j++, blockaddress += 16) { - unsigned int *block; - - block = (unsigned int *)&data[blockaddress]; - - for (i = 0; i < rowblocks; i++) { - *block++ = *src++; - *block++ = *src++; - *block++ = *src++; - *block++ = *src++; - block += 28; - } - - if ((j & 0x7) == 0x7) { - blockaddress += rowblocksadd; - } - } - - TextureStorageFree(psp_texture->data); - psp_texture->data = data; - psp_texture->swizzled = SDL_TRUE; - - sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size); - return 1; -} - -static int TextureUnswizzle(PSP_TextureData *psp_texture, void *dst) -{ - int bytewidth, height; - int widthblocks, heightblocks; - int dstpitch, dstrow; - int blockx, blocky; - int j; - unsigned int *src = NULL; - unsigned char *data = NULL; - unsigned char *ydst = NULL; - - if (!psp_texture->swizzled) { - return 1; - } - - bytewidth = psp_texture->textureWidth * (psp_texture->bits >> 3); - height = psp_texture->size / bytewidth; - - widthblocks = bytewidth / 16; - heightblocks = height / 8; - - dstpitch = (bytewidth - 16) / 4; - dstrow = bytewidth * 8; - - src = (unsigned int *)psp_texture->data; - - data = dst; - - if (!data) { - data = SDL_malloc(psp_texture->size); - } - - if (!data) { - return SDL_OutOfMemory(); - } - - ydst = (unsigned char *)data; - - for (blocky = 0; blocky < heightblocks; ++blocky) { - unsigned char *xdst = ydst; - - for (blockx = 0; blockx < widthblocks; ++blockx) { - unsigned int *block; - - block = (unsigned int *)xdst; - - for (j = 0; j < 8; ++j) { - *(block++) = *(src++); - *(block++) = *(src++); - *(block++) = *(src++); - *(block++) = *(src++); - block += dstpitch; - } - - xdst += 16; - } - - ydst += dstrow; - } - - TextureStorageFree(psp_texture->data); - - psp_texture->data = data; - - psp_texture->swizzled = SDL_FALSE; - - sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size); - return 1; -} - -static int TextureSpillToSram(PSP_RenderData *data, PSP_TextureData *psp_texture) -{ - // Assumes the texture is in VRAM - if (psp_texture->swizzled) { - // Texture was swizzled in vram, just copy to system memory - void *sdata = SDL_malloc(psp_texture->size); - if (!sdata) { - return SDL_OutOfMemory(); - } - - SDL_memcpy(sdata, psp_texture->data, psp_texture->size); - vfree(psp_texture->data); - psp_texture->data = sdata; - return 0; - } else { - return TextureSwizzle(psp_texture, NULL); // Will realloc in sysram - } -} - -static int TexturePromoteToVram(PSP_RenderData *data, PSP_TextureData *psp_texture, SDL_bool target) +/* Return next power of 2 */ +static int TextureNextPow2(unsigned int w) { - // Assumes texture in sram and a large enough continuous block in vram - void *tdata = vramalloc(psp_texture->size); - if (psp_texture->swizzled && target) { - return TextureUnswizzle(psp_texture, tdata); - } else { - SDL_memcpy(tdata, psp_texture->data, psp_texture->size); - SDL_free(psp_texture->data); - psp_texture->data = tdata; + unsigned int n = 2; + if (w == 0) { return 0; } -} -static int TextureSpillLRU(PSP_RenderData *data, size_t wanted) -{ - PSP_TextureData *lru = data->least_recent_target; - if (lru) { - if (TextureSpillToSram(data, lru) < 0) { - return -1; - } - LRUTargetRemove(data, lru); - } else { - // Asked to spill but there nothing to spill - return SDL_SetError("Could not spill more VRAM to system memory. VRAM : %dKB,(%dKB), wanted %dKB", vmemavail() / 1024, vlargestblock() / 1024, wanted / 1024); - } - return 0; -} - -static int TextureSpillTargetsForSpace(PSP_RenderData *data, size_t size) -{ - while (vlargestblock() < size) { - if (TextureSpillLRU(data, size) < 0) { - return -1; - } + while (w > n) { + n <<= 1; } - return 0; -} -static int TextureBindAsTarget(PSP_RenderData *data, PSP_TextureData *psp_texture) -{ - unsigned int dstFormat; - - if (!InVram(psp_texture->data)) { - // Bring back the texture in vram - if (TextureSpillTargetsForSpace(data, psp_texture->size) < 0) { - return -1; - } - if (TexturePromoteToVram(data, psp_texture, SDL_TRUE) < 0) { - return -1; - } - } - LRUTargetBringFront(data, psp_texture); - sceGuDrawBufferList(psp_texture->format, vrelptr(psp_texture->data), psp_texture->textureWidth); - - // Stencil alpha dst hack - dstFormat = psp_texture->format; - if (dstFormat == GU_PSM_5551) { - sceGuEnable(GU_STENCIL_TEST); - sceGuStencilOp(GU_REPLACE, GU_REPLACE, GU_REPLACE); - sceGuStencilFunc(GU_GEQUAL, 0xff, 0xff); - sceGuEnable(GU_ALPHA_TEST); - sceGuAlphaFunc(GU_GREATER, 0x00, 0xff); - } else { - sceGuDisable(GU_STENCIL_TEST); - sceGuDisable(GU_ALPHA_TEST); - } - return 0; + return n; } static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) @@ -493,89 +153,52 @@ static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) { - PSP_RenderData *data = renderer->driverdata; - PSP_TextureData *psp_texture = (PSP_TextureData *)SDL_calloc(1, sizeof(*psp_texture)); + PSP_Texture *psp_tex = (PSP_Texture *)SDL_calloc(1, sizeof(PSP_Texture)); - if (!psp_texture) { + if (!psp_tex) { return SDL_OutOfMemory(); } - psp_texture->swizzled = SDL_FALSE; - psp_texture->width = texture->w; - psp_texture->height = texture->h; - psp_texture->textureHeight = TextureNextPow2(texture->h); - psp_texture->textureWidth = TextureNextPow2(texture->w); - psp_texture->format = PixelFormatToPSPFMT(texture->format); - - switch (psp_texture->format) { - case GU_PSM_5650: - case GU_PSM_5551: - case GU_PSM_4444: - psp_texture->bits = 16; - break; - - case GU_PSM_8888: - psp_texture->bits = 32; - break; - - default: - SDL_free(psp_texture); - return -1; - } + psp_tex->width = texture->w; + psp_tex->height = texture->h; + psp_tex->textureWidth = TextureNextPow2(texture->w); + psp_tex->textureHeight = TextureNextPow2(texture->h); + psp_tex->format = PixelFormatToPSPFMT(texture->format); + psp_tex->data = SDL_calloc(1, getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format)); - psp_texture->pitch = psp_texture->textureWidth * SDL_BYTESPERPIXEL(texture->format); - psp_texture->size = psp_texture->textureHeight * psp_texture->pitch; - if (texture->access & SDL_TEXTUREACCESS_TARGET) { - if (TextureSpillTargetsForSpace(renderer->driverdata, psp_texture->size) < 0) { - SDL_free(psp_texture); - return -1; - } - psp_texture->data = vramalloc(psp_texture->size); - if (psp_texture->data) { - LRUTargetPushFront(data, psp_texture); - } - } else { - psp_texture->data = SDL_calloc(1, psp_texture->size); - } - - if (!psp_texture->data) { - SDL_free(psp_texture); + if (!psp_tex->data) { + SDL_free(psp_tex); return SDL_OutOfMemory(); } - texture->driverdata = psp_texture; + + texture->driverdata = psp_tex; return 0; } -static int TextureShouldSwizzle(PSP_TextureData *psp_texture, SDL_Texture *texture) +static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, void **pixels, int *pitch) { - return !((texture->access == SDL_TEXTUREACCESS_TARGET) && InVram(psp_texture->data)) && texture->access != SDL_TEXTUREACCESS_STREAMING && (texture->w >= 16 || texture->h >= 16); + PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + + *pixels = + (void *)((Uint8 *)psp_texture->data + rect->y * psp_texture->width * SDL_BYTESPERPIXEL(texture->format) + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + *pitch = psp_texture->width * SDL_BYTESPERPIXEL(texture->format); + return 0; } -static void TextureActivate(SDL_Texture *texture) +static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) { - PSP_TextureData *psp_texture = (PSP_TextureData *)texture->driverdata; - int scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GU_NEAREST : GU_LINEAR; - - /* Swizzling is useless with small textures. */ - if (TextureShouldSwizzle(psp_texture, texture)) { - TextureSwizzle(psp_texture, NULL); - } + PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - sceGuTexWrap(GU_REPEAT, GU_REPEAT); - sceGuTexMode(psp_texture->format, 0, 0, psp_texture->swizzled); - sceGuTexFilter(scaleMode, scaleMode); /* GU_NEAREST good for tile-map */ - /* GU_LINEAR good for scaling */ - sceGuTexImage(0, psp_texture->textureWidth, psp_texture->textureHeight, psp_texture->textureWidth, psp_texture->data); + // gsKit_TexManager_invalidate(data->gsGlobal, psp_texture); } -static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_Rect *rect, void **pixels, int *pitch); - static int PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch) { - /* PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata; */ const Uint8 *src; Uint8 *dst; int row, length, dpitch; @@ -593,38 +216,24 @@ static int PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, } } - sceKernelDcacheWritebackAll(); - return 0; -} - -static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, - const SDL_Rect *rect, void **pixels, int *pitch) -{ - PSP_TextureData *psp_texture = (PSP_TextureData *)texture->driverdata; + PSP_UnlockTexture(renderer, texture); - *pixels = - (void *)((Uint8 *)psp_texture->data + rect->y * psp_texture->pitch + - rect->x * SDL_BYTESPERPIXEL(texture->format)); - *pitch = psp_texture->pitch; return 0; } -static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) -{ - PSP_TextureData *psp_texture = (PSP_TextureData *)texture->driverdata; - SDL_Rect rect; - - /* We do whole texture updates, at least for now */ - rect.x = 0; - rect.y = 0; - rect.w = texture->w; - rect.h = texture->h; - PSP_UpdateTexture(renderer, texture, &rect, psp_texture->data, psp_texture->pitch); -} - static void PSP_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode) { - /* Nothing to do because TextureActivate takes care of it */ + PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + /* + set texture filtering according to scaleMode + suported hint values are nearest (0, default) or linear (1) + GU scale mode is either GU_NEAREST (good for tile-map) + or GU_LINEAR (good for scaling) + */ + uint32_t guScaleMode = (scaleMode == SDL_ScaleModeNearest + ? GU_NEAREST + : GU_LINEAR); + psp_texture->filter = guScaleMode; } static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) @@ -639,6 +248,7 @@ static int PSP_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd) static int PSP_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) { + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; VertV *verts = (VertV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertV), 4, &cmd->data.draw.first); int i; @@ -653,7 +263,6 @@ static int PSP_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, c verts->y = points->y; verts->z = 0.0f; } - return 0; } @@ -664,20 +273,23 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL { int i; int count = indices ? num_indices : num_vertices; + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; cmd->data.draw.count = count; size_indices = indices ? size_indices : 0; - if (!texture) { - VertCV *verts; - verts = (VertCV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertCV), 4, &cmd->data.draw.first); - if (!verts) { + if (texture) { + VertTCV *vertices = (VertTCV *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertTCV), 4, &cmd->data.draw.first); + PSP_Texture *psp_tex = (PSP_Texture *) texture->driverdata; + + if (!vertices) { return -1; } for (i = 0; i < count; i++) { int j; float *xy_; + float *uv_; SDL_Color col_; if (size_indices == 4) { j = ((const Uint32 *)indices)[i]; @@ -691,20 +303,24 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL xy_ = (float *)((char *)xy + j * xy_stride); col_ = *(SDL_Color *)((char *)color + j * color_stride); + uv_ = (float *)((char *)uv + j * uv_stride); + + vertices->x = xy_[0] * scale_x; + vertices->y = xy_[1] * scale_y; + vertices->z = 0; - verts->x = xy_[0] * scale_x; - verts->y = xy_[1] * scale_y; - verts->z = 0; + vertices->col = col_; - verts->col = col_; + vertices->u = uv_[0] * psp_tex->width; + vertices->v = uv_[1] * psp_tex->height; - verts++; + vertices++; } + } else { - PSP_TextureData *psp_texture = (PSP_TextureData *)texture->driverdata; - VertTCV *verts; - verts = (VertTCV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertTCV), 4, &cmd->data.draw.first); - if (!verts) { + VertCV *vertices = (VertCV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertCV), 4, &cmd->data.draw.first); + + if (!vertices) { return -1; } @@ -712,8 +328,6 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL int j; float *xy_; SDL_Color col_; - float *uv_; - if (size_indices == 4) { j = ((const Uint32 *)indices)[i]; } else if (size_indices == 2) { @@ -726,507 +340,227 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL xy_ = (float *)((char *)xy + j * xy_stride); col_ = *(SDL_Color *)((char *)color + j * color_stride); - uv_ = (float *)((char *)uv + j * uv_stride); - - verts->x = xy_[0] * scale_x; - verts->y = xy_[1] * scale_y; - verts->z = 0; - - verts->col = col_; - verts->u = uv_[0] * psp_texture->textureWidth; - verts->v = uv_[1] * psp_texture->textureHeight; + vertices->x = xy_[0] * scale_x; + vertices->y = xy_[1] * scale_y; + vertices->z = 0; + vertices->col = col_; - verts++; + vertices++; } } return 0; } -static int PSP_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count) +static int PSP_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { - VertV *verts = (VertV *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(VertV), 4, &cmd->data.draw.first); - int i; - - if (!verts) { - return -1; - } - - cmd->data.draw.count = count; - for (i = 0; i < count; i++, rects++) { - verts->x = rects->x; - verts->y = rects->y; - verts->z = 0.0f; - verts++; + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + const SDL_Rect *viewport = &cmd->data.viewport.rect; - verts->x = rects->x + rects->w + 0.5f; - verts->y = rects->y + rects->h + 0.5f; - verts->z = 0.0f; - verts++; - } + sceGuOffset(2048 - (viewport->w >> 1), 2048 - (viewport->h >> 1)); + sceGuViewport(2048, 2048, viewport->w, viewport->h); + sceGuScissor(viewport->x, viewport->y, viewport->w, viewport->h); return 0; } -static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, - const SDL_Rect *srcrect, const SDL_FRect *dstrect) +static int PSP_RenderSetClipRect(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { - VertTV *verts; - const float x = dstrect->x; - const float y = dstrect->y; - const float width = dstrect->w; - const float height = dstrect->h; - - const float u0 = srcrect->x; - const float v0 = srcrect->y; - const float u1 = srcrect->x + srcrect->w; - const float v1 = srcrect->y + srcrect->h; - - if ((MathAbs(u1) - MathAbs(u0)) < 64.0f) { - verts = (VertTV *)SDL_AllocateRenderVertices(renderer, 2 * sizeof(VertTV), 4, &cmd->data.draw.first); - if (!verts) { - return -1; - } - - cmd->data.draw.count = 1; - - verts->u = u0; - verts->v = v0; - verts->x = x; - verts->y = y; - verts->z = 0; - verts++; - - verts->u = u1; - verts->v = v1; - verts->x = x + width; - verts->y = y + height; - verts->z = 0; - verts++; - } else { - float start, end; - float curU = u0; - float curX = x; - const float endX = x + width; - const float slice = 64.0f; - const size_t count = SDL_ceilf(width / slice); - size_t i; - float ustep = (u1 - u0) / width * slice; - - if (ustep < 0.0f) { - ustep = -ustep; - } - - cmd->data.draw.count = count; - - verts = (VertTV *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(VertTV), 4, &cmd->data.draw.first); - if (!verts) { - return -1; - } - - for (i = 0, start = 0, end = width; i < count; i++, start += slice) { - const float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice; - const float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep; - - SDL_assert(start < end); - - verts->u = curU; - verts->v = v0; - verts->x = curX; - verts->y = y; - verts->z = 0; - verts++; + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - curU += sourceWidth; - curX += polyWidth; + const SDL_Rect *rect = &cmd->data.cliprect.rect; - verts->u = curU; - verts->v = v1; - verts->x = curX; - verts->y = (y + height); - verts->z = 0; - verts++; - } + if (cmd->data.cliprect.enabled) { + sceGuEnable(GU_SCISSOR_TEST); + sceGuScissor(rect->x, rect->y, rect->w, rect->h); + } else { + sceGuDisable(GU_SCISSOR_TEST); } return 0; } -static int PSP_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, - const SDL_Rect *srcrect, const SDL_FRect *dstrect, - const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y) +static int PSP_RenderSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { - VertTV *verts = (VertTV *)SDL_AllocateRenderVertices(renderer, 4 * sizeof(VertTV), 4, &cmd->data.draw.first); - const float centerx = center->x; - const float centery = center->y; - const float x = dstrect->x + centerx; - const float y = dstrect->y + centery; - const float width = dstrect->w - centerx; - const float height = dstrect->h - centery; - float s, c; - float cw1, sw1, ch1, sh1, cw2, sw2, ch2, sh2; - - float u0 = srcrect->x; - float v0 = srcrect->y; - float u1 = srcrect->x + srcrect->w; - float v1 = srcrect->y + srcrect->h; - - if (!verts) { - return -1; - } + uint8_t colorR, colorG, colorB, colorA; - cmd->data.draw.count = 1; + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - MathSincos(degToRad(360 - angle), &s, &c); + colorR = cmd->data.color.r; + colorG = cmd->data.color.g; + colorB = cmd->data.color.b; + colorA = cmd->data.color.a; + sceGuColor(GU_RGBA(colorR, colorG, colorB, colorA)); + return 0; +} - cw1 = c * -centerx; - sw1 = s * -centerx; - ch1 = c * -centery; - sh1 = s * -centery; - cw2 = c * width; - sw2 = s * width; - ch2 = c * height; - sh2 = s * height; +static int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +{ + uint8_t colorR, colorG, colorB, colorA; - if (flip & SDL_FLIP_VERTICAL) { - Swap(&v0, &v1); - } + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - if (flip & SDL_FLIP_HORIZONTAL) { - Swap(&u0, &u1); - } + colorR = cmd->data.color.r; + colorG = cmd->data.color.g; + colorB = cmd->data.color.b; + colorA = cmd->data.color.a; - verts->u = u0; - verts->v = v0; - verts->x = x + cw1 + sh1; - verts->y = y - sw1 + ch1; - verts->z = 0; - verts++; - - verts->u = u0; - verts->v = v1; - verts->x = x + cw1 + sh2; - verts->y = y - sw1 + ch2; - verts->z = 0; - verts++; - - verts->u = u1; - verts->v = v1; - verts->x = x + cw2 + sh2; - verts->y = y - sw2 + ch2; - verts->z = 0; - verts++; - - verts->u = u1; - verts->v = v0; - verts->x = x + cw2 + sh1; - verts->y = y - sw2 + ch1; - verts->z = 0; - - if (scale_x != 1.0f || scale_y != 1.0f) { - verts->x *= scale_x; - verts->y *= scale_y; - verts--; - verts->x *= scale_x; - verts->y *= scale_y; - verts--; - verts->x *= scale_x; - verts->y *= scale_y; - verts--; - verts->x *= scale_x; - verts->y *= scale_y; - } + sceGuClearColor(GU_RGBA(colorR, colorG, colorB, colorA)); + sceGuClearStencil(colorA); + sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); return 0; } -static void ResetBlendState(PSP_BlendState *state) +static void PSP_SetBlendMode(PSP_RenderData *data, int blendMode) { - sceGuColor(0xffffffff); - state->color = 0xffffffff; - state->mode = SDL_BLENDMODE_INVALID; - state->texture = NULL; - sceGuDisable(GU_TEXTURE_2D); - sceGuShadeModel(GU_SMOOTH); - state->shadeModel = GU_SMOOTH; + switch (blendMode) { + case SDL_BLENDMODE_NONE: + { + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); + sceGuDisable(GU_BLEND); + break; + } + case SDL_BLENDMODE_BLEND: + { + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuEnable(GU_BLEND); + break; + } + case SDL_BLENDMODE_ADD: + { + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF); + sceGuEnable(GU_BLEND); + break; + } + case SDL_BLENDMODE_MOD: + { + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); + sceGuEnable(GU_BLEND); + break; + } + case SDL_BLENDMODE_MUL: + { + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + /* FIXME SDL_BLENDMODE_MUL is simplified, and dstA is in fact un-changed.*/ + sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuEnable(GU_BLEND); + break; + } + } } -static void StartDrawing(SDL_Renderer *renderer) +static int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + const size_t count = cmd->data.draw.count; - // Check if we need to start GU displaylist - if (!data->displayListAvail) { - sceGuStart(GU_DIRECT, DisplayList); - data->displayListAvail = SDL_TRUE; - // ResetBlendState(&data->blendState); - } + PSP_SetBlendMode(data, cmd->data.draw.blend); - // Check if we need a draw buffer change - if (renderer->target != data->boundTarget) { - SDL_Texture *texture = renderer->target; - if (texture) { - PSP_TextureData *psp_texture = (PSP_TextureData *)texture->driverdata; - // Set target, registering LRU - TextureBindAsTarget(data, psp_texture); - } else { - // Set target back to screen - sceGuDrawBufferList(data->psm, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); - } - data->boundTarget = texture; + if (cmd->data.draw.texture) { + const VertTCV *verts = (VertTCV *)(vertices + cmd->data.draw.first); + PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; + + sceGuEnable(GU_TEXTURE_2D); + sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); + sceGuTexFilter(psp_tex->filter, psp_tex->filter); + sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->textureWidth, psp_tex->data); + sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); + sceGuDisable(GU_TEXTURE_2D); + } else { + const VertCV *verts = (VertCV *)(vertices + cmd->data.draw.first); + sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); } + + return 0; } -static void PSP_SetBlendState(PSP_RenderData *data, PSP_BlendState *state) +int PSP_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { - PSP_BlendState *current = &data->blendState; + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + const size_t count = cmd->data.draw.count; + const VertV *verts = (VertV *)(vertices + cmd->data.draw.first); - if (state->mode != current->mode) { - switch (state->mode) { - case SDL_BLENDMODE_NONE: - sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); - sceGuDisable(GU_BLEND); - break; - case SDL_BLENDMODE_BLEND: - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); - sceGuEnable(GU_BLEND); - break; - case SDL_BLENDMODE_ADD: - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF); - sceGuEnable(GU_BLEND); - break; - case SDL_BLENDMODE_MOD: - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); - sceGuEnable(GU_BLEND); - break; - case SDL_BLENDMODE_MUL: - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - /* FIXME SDL_BLENDMODE_MUL is simplified, and dstA is in fact un-changed.*/ - sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); - sceGuEnable(GU_BLEND); - break; - case SDL_BLENDMODE_INVALID: - break; - } - } + PSP_SetBlendMode(data, cmd->data.draw.blend); + sceGuDrawArray(GU_LINES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); - if (state->color != current->color) { - sceGuColor(state->color); - } + /* We're done! */ + return 0; +} - if (state->shadeModel != current->shadeModel) { - sceGuShadeModel(state->shadeModel); - } +int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) +{ + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + const size_t count = cmd->data.draw.count; + const VertV *verts = (VertV *)(vertices + cmd->data.draw.first); - if (state->texture != current->texture) { - if (state->texture) { - TextureActivate(state->texture); - sceGuEnable(GU_TEXTURE_2D); - } else { - sceGuDisable(GU_TEXTURE_2D); - } - } + PSP_SetBlendMode(data, cmd->data.draw.blend); + sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); - *current = *state; + /* We're done! */ + return 0; } static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) { - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - Uint8 *gpumem = NULL; - StartDrawing(renderer); - - /* note that before the renderer interface change, this would do extrememly small - batches with sceGuGetMemory()--a few vertices at a time--and it's not clear that - this won't fail if you try to push 100,000 draw calls in a single batch. - I don't know what the limits on PSP hardware are. It might be useful to have - rendering backends report a reasonable maximum, so the higher level can flush - if we appear to be exceeding that. */ - gpumem = (Uint8 *)sceGuGetMemory(vertsize); - if (!gpumem) { - return SDL_SetError("Couldn't obtain a %d-byte vertex buffer!", (int)vertsize); - } - SDL_memcpy(gpumem, vertices, vertsize); - while (cmd) { switch (cmd->command) { - case SDL_RENDERCMD_SETDRAWCOLOR: - { - break; /* !!! FIXME: we could cache drawstate like color */ - } - case SDL_RENDERCMD_SETVIEWPORT: { - SDL_Rect *viewport = &cmd->data.viewport.rect; - sceGuOffset(2048 - (viewport->w >> 1), 2048 - (viewport->h >> 1)); - sceGuViewport(2048, 2048, viewport->w, viewport->h); - sceGuScissor(viewport->x, viewport->y, viewport->w, viewport->h); + PSP_RenderSetViewPort(renderer, cmd); /* FIXME: We need to update the clip rect too, see https://github.com/libsdl-org/SDL/issues/9094 */ break; } - case SDL_RENDERCMD_SETCLIPRECT: { - const SDL_Rect *rect = &cmd->data.cliprect.rect; - if (cmd->data.cliprect.enabled) { - sceGuEnable(GU_SCISSOR_TEST); - sceGuScissor(rect->x, rect->y, rect->w, rect->h); - } else { - sceGuDisable(GU_SCISSOR_TEST); - } + PSP_RenderSetClipRect(renderer, cmd); + break; + } + case SDL_RENDERCMD_SETDRAWCOLOR: + { + PSP_RenderSetDrawColor(renderer, cmd); break; } - case SDL_RENDERCMD_CLEAR: { - const Uint8 r = cmd->data.color.r; - const Uint8 g = cmd->data.color.g; - const Uint8 b = cmd->data.color.b; - const Uint8 a = cmd->data.color.a; - sceGuClearColor(GU_RGBA(r, g, b, a)); - sceGuClearStencil(a); - sceGuClear(GU_COLOR_BUFFER_BIT | GU_STENCIL_BUFFER_BIT); + PSP_RenderClear(renderer, cmd); break; } - case SDL_RENDERCMD_DRAW_POINTS: { - const size_t count = cmd->data.draw.count; - const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first); - const Uint8 r = cmd->data.draw.r; - const Uint8 g = cmd->data.draw.g; - const Uint8 b = cmd->data.draw.b; - const Uint8 a = cmd->data.draw.a; - PSP_BlendState state = { - .color = GU_RGBA(r, g, b, a), - .texture = NULL, - .mode = cmd->data.draw.blend, - .shadeModel = GU_FLAT - }; - PSP_SetBlendState(data, &state); - sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); + PSP_RenderPoints(renderer, vertices, cmd); break; } - case SDL_RENDERCMD_DRAW_LINES: { - const size_t count = cmd->data.draw.count; - const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first); - const Uint8 r = cmd->data.draw.r; - const Uint8 g = cmd->data.draw.g; - const Uint8 b = cmd->data.draw.b; - const Uint8 a = cmd->data.draw.a; - PSP_BlendState state = { - .color = GU_RGBA(r, g, b, a), - .texture = NULL, - .mode = cmd->data.draw.blend, - .shadeModel = GU_FLAT - }; - PSP_SetBlendState(data, &state); - sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); + PSP_RenderLines(renderer, vertices, cmd); break; } - - case SDL_RENDERCMD_FILL_RECTS: - { - const size_t count = cmd->data.draw.count; - const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first); - const Uint8 r = cmd->data.draw.r; - const Uint8 g = cmd->data.draw.g; - const Uint8 b = cmd->data.draw.b; - const Uint8 a = cmd->data.draw.a; - PSP_BlendState state = { - .color = GU_RGBA(r, g, b, a), - .texture = NULL, - .mode = cmd->data.draw.blend, - .shadeModel = GU_FLAT - }; - PSP_SetBlendState(data, &state); - sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2 * count, 0, verts); + case SDL_RENDERCMD_FILL_RECTS: /* unused */ break; - } - - case SDL_RENDERCMD_COPY: - { - const size_t count = cmd->data.draw.count; - const VertTV *verts = (VertTV *)(gpumem + cmd->data.draw.first); - const Uint8 a = cmd->data.draw.a; - const Uint8 r = cmd->data.draw.r; - const Uint8 g = cmd->data.draw.g; - const Uint8 b = cmd->data.draw.b; - PSP_BlendState state = { - .color = GU_RGBA(r, g, b, a), - .texture = cmd->data.draw.texture, - .mode = cmd->data.draw.blend, - .shadeModel = GU_SMOOTH - }; - PSP_SetBlendState(data, &state); - sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2 * count, 0, verts); + case SDL_RENDERCMD_COPY: /* unused */ break; - } - - case SDL_RENDERCMD_COPY_EX: - { - const VertTV *verts = (VertTV *)(gpumem + cmd->data.draw.first); - const Uint8 a = cmd->data.draw.a; - const Uint8 r = cmd->data.draw.r; - const Uint8 g = cmd->data.draw.g; - const Uint8 b = cmd->data.draw.b; - PSP_BlendState state = { - .color = GU_RGBA(r, g, b, a), - .texture = cmd->data.draw.texture, - .mode = cmd->data.draw.blend, - .shadeModel = GU_SMOOTH - }; - PSP_SetBlendState(data, &state); - sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 4, 0, verts); + case SDL_RENDERCMD_COPY_EX: /* unused */ break; - } - case SDL_RENDERCMD_GEOMETRY: { - const size_t count = cmd->data.draw.count; - if (!cmd->data.draw.texture) { - const VertCV *verts = (VertCV *)(gpumem + cmd->data.draw.first); - sceGuDisable(GU_TEXTURE_2D); - /* In GU_SMOOTH mode */ - sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); - sceGuEnable(GU_TEXTURE_2D); - } else { - const VertTCV *verts = (VertTCV *)(gpumem + cmd->data.draw.first); - const Uint8 a = cmd->data.draw.a; - const Uint8 r = cmd->data.draw.r; - const Uint8 g = cmd->data.draw.g; - const Uint8 b = cmd->data.draw.b; - PSP_BlendState state = { - .color = GU_RGBA(r, g, b, a), - .texture = NULL, - .mode = cmd->data.draw.blend, - .shadeModel = GU_FLAT - }; - TextureActivate(cmd->data.draw.texture); - PSP_SetBlendState(data, &state); - sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); - } + PSP_RenderGeometry(renderer, vertices, cmd); break; } - case SDL_RENDERCMD_NO_OP: break; } - cmd = cmd->next; } - return 0; } static int PSP_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, - Uint32 pixel_format, void *pixels, int pitch) + Uint32 format, void *pixels, int pitch) { return SDL_Unsupported(); } @@ -1234,31 +568,43 @@ static int PSP_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, static int PSP_RenderPresent(SDL_Renderer *renderer) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - if (!data->displayListAvail) { - return -1; - } - data->displayListAvail = SDL_FALSE; - sceGuFinish(); - sceGuSync(0, 0); + // if (data->gsGlobal->DoubleBuffering == GS_SETTING_OFF) { + // if (data->vsync == 2) { // Dynamic + // gsKit_sync(data->gsGlobal); + // } else if (data->vsync == 1) { + // gsKit_vsync_wait(); + // } + // gsKit_queue_exec(data->gsGlobal); + // } else { + // gsKit_queue_exec(data->gsGlobal); + // gsKit_finish(); + // if (data->vsync == 2) { // Dynamic + // gsKit_sync(data->gsGlobal); + // } else if (data->vsync == 1) { + // gsKit_vsync_wait(); + // } + // gsKit_flip(data->gsGlobal); + // } + // gsKit_TexManager_nextFrame(data->gsGlobal); + // gsKit_clear(data->gsGlobal, GS_BLACK); - if ((data->vsync) && (data->vblank_not_reached)) { - sceDisplayWaitVblankStart(); - } - data->vblank_not_reached = SDL_TRUE; + sceGuFinish(); + sceGuSync(0,0); + sceGuSwapBuffers(); - data->backbuffer = data->frontbuffer; - data->frontbuffer = vabsptr(sceGuSwapBuffers()); + // Starting a new frame + sceGuStart(GU_DIRECT,list); return 0; } static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) { - PSP_RenderData *renderdata = (PSP_RenderData *)renderer->driverdata; - PSP_TextureData *psp_texture = (PSP_TextureData *)texture->driverdata; + PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - if (!renderdata) { + if (!data) { return; } @@ -1266,8 +612,7 @@ static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) return; } - LRUTargetRemove(renderdata, psp_texture); - TextureStorageFree(psp_texture->data); + SDL_free(psp_texture->data); SDL_free(psp_texture); texture->driverdata = NULL; } @@ -1276,36 +621,38 @@ static void PSP_DestroyRenderer(SDL_Renderer *renderer) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; if (data) { - if (!data->initialized) { - return; - } - sceKernelDisableSubIntr(PSP_VBLANK_INT, 0); sceKernelReleaseSubIntrHandler(PSP_VBLANK_INT, 0); sceDisplayWaitVblankStart(); sceGuDisplay(GU_FALSE); + sceGuTerm(); vfree(data->backbuffer); vfree(data->frontbuffer); - data->initialized = SDL_FALSE; - data->displayListAvail = SDL_FALSE; SDL_free(data); } + + if (vsync_sema_id >= 0) { + // DeleteSema(vsync_sema_id); + } + } static int PSP_SetVSync(SDL_Renderer *renderer, const int vsync) { - PSP_RenderData *data = renderer->driverdata; - data->vsync = vsync; + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + SDL_bool dynamicVsync = SDL_GetHintBoolean(SDL_HINT_PSP_DYNAMIC_VSYNC, SDL_FALSE); + data->vsync = vsync ? (dynamicVsync ? 2 : 1) : 0; return 0; } -int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 flags) +static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 flags) { PSP_RenderData *data; - int pixelformat; void *doublebuffer = NULL; + uint32_t bufferSize = 0; + SDL_bool dynamicVsync; data = (PSP_RenderData *)SDL_calloc(1, sizeof(*data)); if (!data) { @@ -1313,6 +660,34 @@ int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 flags) return SDL_OutOfMemory(); } + /* Specific GU init */ + bufferSize = getMemorySize(PSP_FRAME_BUFFER_WIDTH, PSP_SCREEN_HEIGHT, GU_PSM_8888); + doublebuffer = vramalloc(bufferSize * 2); + data->backbuffer = doublebuffer; + data->frontbuffer = ((uint8_t *)doublebuffer) + bufferSize; + + sceGuInit(); + sceGuStart(GU_DIRECT, list); + sceGuDrawBuffer(GU_PSM_8888, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); + sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); + + sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1)); + sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); + + sceGuDisable(GU_DEPTH_TEST); + + sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); + sceGuEnable(GU_SCISSOR_TEST); + + sceGuFinish(); + sceGuSync(0,0); + + sceDisplayWaitVblankStart(); + sceGuDisplay(GU_TRUE); + + dynamicVsync = SDL_GetHintBoolean(SDL_HINT_PSP_DYNAMIC_VSYNC, SDL_FALSE); + data->vsync = flags & SDL_RENDERER_PRESENTVSYNC ? (dynamicVsync ? 2 : 1) : 0; + renderer->WindowEvent = PSP_WindowEvent; renderer->CreateTexture = PSP_CreateTexture; renderer->UpdateTexture = PSP_UpdateTexture; @@ -1321,13 +696,10 @@ int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 flags) renderer->SetTextureScaleMode = PSP_SetTextureScaleMode; renderer->SetRenderTarget = PSP_SetRenderTarget; renderer->QueueSetViewport = PSP_QueueSetViewport; - renderer->QueueSetDrawColor = PSP_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ + renderer->QueueSetDrawColor = PSP_QueueSetViewport; renderer->QueueDrawPoints = PSP_QueueDrawPoints; - renderer->QueueDrawLines = PSP_QueueDrawPoints; /* lines and points queue vertices the same way. */ + renderer->QueueDrawLines = PSP_QueueDrawPoints; renderer->QueueGeometry = PSP_QueueGeometry; - renderer->QueueFillRects = PSP_QueueFillRects; - renderer->QueueCopy = PSP_QueueCopy; - renderer->QueueCopyEx = PSP_QueueCopyEx; renderer->RunCommandQueue = PSP_RunCommandQueue; renderer->RenderReadPixels = PSP_RenderReadPixels; renderer->RenderPresent = PSP_RenderPresent; @@ -1335,80 +707,16 @@ int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 flags) renderer->DestroyRenderer = PSP_DestroyRenderer; renderer->SetVSync = PSP_SetVSync; renderer->info = PSP_RenderDriver.info; - renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); renderer->driverdata = data; renderer->window = window; - data->initialized = SDL_TRUE; - data->most_recent_target = NULL; - data->least_recent_target = NULL; - - if (flags & SDL_RENDERER_PRESENTVSYNC) { - data->vsync = SDL_TRUE; - } else { - data->vsync = SDL_FALSE; - } - - pixelformat = PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window)); - switch (pixelformat) { - case GU_PSM_4444: - case GU_PSM_5650: - case GU_PSM_5551: - data->bpp = 2; - data->psm = pixelformat; - break; - default: - data->bpp = 4; - data->psm = GU_PSM_8888; - break; - } - - doublebuffer = vramalloc(PSP_FRAME_BUFFER_SIZE * data->bpp * 2); - data->backbuffer = doublebuffer; - data->frontbuffer = ((uint8_t *)doublebuffer) + PSP_FRAME_BUFFER_SIZE * data->bpp; - - sceGuInit(); - /* setup GU */ - sceGuStart(GU_DIRECT, DisplayList); - sceGuDrawBuffer(data->psm, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); - sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); - - sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1)); - sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); - - sceGuDisable(GU_DEPTH_TEST); - - /* Scissoring */ - sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); - sceGuEnable(GU_SCISSOR_TEST); - - /* Backface culling */ - /* - FIXME: Culling probably un-needed ? It can conflict with SDL_RENDERCMD_GEOMETRY - sceGuFrontFace(GU_CCW); - sceGuEnable(GU_CULL_FACE); - */ - - // Setup initial blend state - ResetBlendState(&data->blendState); - - sceGuFinish(); - sceGuSync(0, 0); - sceDisplayWaitVblankStartCB(); - sceGuDisplay(GU_TRUE); - - /* Improve performance when VSYC is enabled and it is not reaching the 60 FPS */ - data->vblank_not_reached = SDL_TRUE; - sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, psp_on_vblank, data); - sceKernelEnableSubIntr(PSP_VBLANK_INT, 0); - return 0; } SDL_RenderDriver PSP_RenderDriver = { .CreateRenderer = PSP_CreateRenderer, .info = { - .name = "PSP", + .name = "PSP GU", .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, .num_texture_formats = 4, .texture_formats = { From 6e831bc7a27cbb52dadfe894d94b6c7d177fcae6 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 22 Jan 2023 22:15:46 +0100 Subject: [PATCH 02/37] Fixed some textures not being renderer properly --- src/render/psp/SDL_render_psp.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 7caf450300415..2e1273e8bdf07 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -132,6 +132,20 @@ static int PixelFormatToPSPFMT(Uint32 format) } } +static int calculatePitchForTextureFormat(int width, int format) +{ + switch (format) { + case GU_PSM_5650: + case GU_PSM_5551: + case GU_PSM_4444: + return (width + 7) & ~7; + case GU_PSM_8888: + return (width + 3) & ~3; + default: + return width; + } +} + /* Return next power of 2 */ static int TextureNextPow2(unsigned int w) { @@ -159,11 +173,11 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return SDL_OutOfMemory(); } - psp_tex->width = texture->w; + psp_tex->format = PixelFormatToPSPFMT(texture->format); + psp_tex->width = calculatePitchForTextureFormat(texture->w, psp_tex->format); psp_tex->height = texture->h; psp_tex->textureWidth = TextureNextPow2(texture->w); psp_tex->textureHeight = TextureNextPow2(texture->h); - psp_tex->format = PixelFormatToPSPFMT(texture->format); psp_tex->data = SDL_calloc(1, getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format)); if (!psp_tex->data) { @@ -468,7 +482,7 @@ static int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_Render sceGuEnable(GU_TEXTURE_2D); sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); sceGuTexFilter(psp_tex->filter, psp_tex->filter); - sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->textureWidth, psp_tex->data); + sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data); sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); } else { From 1ea5d8a7be2534786627e2abe1020cd63447383e Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 22 Jan 2023 22:42:32 +0100 Subject: [PATCH 03/37] Dinamic vsync implementation --- src/render/psp/SDL_render_psp.c | 69 +++++++++++++++------------------ 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 2e1273e8bdf07..e4c4286e5125f 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -35,8 +35,8 @@ typedef struct void *frontbuffer; /**< main screen buffer */ void *backbuffer; /**< buffer presented to display */ uint64_t drawColor; - int32_t vsync_callback_id; uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ + SDL_bool vblank_not_reached; /**< whether vblank wasn't reached */ } PSP_RenderData; typedef struct PSP_Texture @@ -90,6 +90,12 @@ int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void* static int vsync_sema_id = 0; /* PRIVATE METHODS */ +static void psp_on_vblank(u32 sub, PSP_RenderData *data) +{ + if (data) { + data->vblank_not_reached = SDL_FALSE; + } +} static unsigned int getMemorySize(unsigned int width, unsigned int height, unsigned int psm) { @@ -116,7 +122,7 @@ static unsigned int getMemorySize(unsigned int width, unsigned int height, unsig } } -static int PixelFormatToPSPFMT(Uint32 format) +static int pixelFormatToPSPFMT(Uint32 format) { switch (format) { case SDL_PIXELFORMAT_BGR565: @@ -147,18 +153,13 @@ static int calculatePitchForTextureFormat(int width, int format) } /* Return next power of 2 */ -static int TextureNextPow2(unsigned int w) +static int calculateNextPow2(int value) { - unsigned int n = 2; - if (w == 0) { - return 0; + int i = 1; + while (i < value) { + i <<= 1; } - - while (w > n) { - n <<= 1; - } - - return n; + return i; } static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) @@ -173,11 +174,11 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return SDL_OutOfMemory(); } - psp_tex->format = PixelFormatToPSPFMT(texture->format); + psp_tex->format = pixelFormatToPSPFMT(texture->format); psp_tex->width = calculatePitchForTextureFormat(texture->w, psp_tex->format); psp_tex->height = texture->h; - psp_tex->textureWidth = TextureNextPow2(texture->w); - psp_tex->textureHeight = TextureNextPow2(texture->h); + psp_tex->textureWidth = calculateNextPow2(texture->w); + psp_tex->textureHeight = calculateNextPow2(texture->h); psp_tex->data = SDL_calloc(1, getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format)); if (!psp_tex->data) { @@ -199,6 +200,7 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, (void *)((Uint8 *)psp_texture->data + rect->y * psp_texture->width * SDL_BYTESPERPIXEL(texture->format) + rect->x * SDL_BYTESPERPIXEL(texture->format)); *pitch = psp_texture->width * SDL_BYTESPERPIXEL(texture->format); + return 0; } @@ -277,6 +279,7 @@ static int PSP_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, c verts->y = points->y; verts->z = 0.0f; } + return 0; } @@ -406,6 +409,7 @@ static int PSP_RenderSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd colorB = cmd->data.color.b; colorA = cmd->data.color.a; sceGuColor(GU_RGBA(colorR, colorG, colorB, colorA)); + return 0; } @@ -502,7 +506,6 @@ int PSP_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *c PSP_SetBlendMode(data, cmd->data.draw.blend); sceGuDrawArray(GU_LINES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); - /* We're done! */ return 0; } @@ -515,7 +518,6 @@ int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand * PSP_SetBlendMode(data, cmd->data.draw.blend); sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); - /* We're done! */ return 0; } @@ -583,29 +585,16 @@ static int PSP_RenderPresent(SDL_Renderer *renderer) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - // if (data->gsGlobal->DoubleBuffering == GS_SETTING_OFF) { - // if (data->vsync == 2) { // Dynamic - // gsKit_sync(data->gsGlobal); - // } else if (data->vsync == 1) { - // gsKit_vsync_wait(); - // } - // gsKit_queue_exec(data->gsGlobal); - // } else { - // gsKit_queue_exec(data->gsGlobal); - // gsKit_finish(); - // if (data->vsync == 2) { // Dynamic - // gsKit_sync(data->gsGlobal); - // } else if (data->vsync == 1) { - // gsKit_vsync_wait(); - // } - // gsKit_flip(data->gsGlobal); - // } - // gsKit_TexManager_nextFrame(data->gsGlobal); - // gsKit_clear(data->gsGlobal, GS_BLACK); + if (((data->vsync == 2) && (data->vblank_not_reached)) || // Dynamic + (data->vsync == 1)) { // Normal VSync + sceDisplayWaitVblankStart(); + } + data->vblank_not_reached = SDL_TRUE; sceGuFinish(); sceGuSync(0,0); - sceGuSwapBuffers(); + data->backbuffer = data->frontbuffer; + data->frontbuffer = vabsptr(sceGuSwapBuffers()); // Starting a new frame sceGuStart(GU_DIRECT,list); @@ -699,8 +688,14 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 sceDisplayWaitVblankStart(); sceGuDisplay(GU_TRUE); + /* Improve performance when VSYC is enabled and it is not reaching the 60 FPS */ dynamicVsync = SDL_GetHintBoolean(SDL_HINT_PSP_DYNAMIC_VSYNC, SDL_FALSE); data->vsync = flags & SDL_RENDERER_PRESENTVSYNC ? (dynamicVsync ? 2 : 1) : 0; + if (data->vsync == 2) { + sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, psp_on_vblank, data); + sceKernelEnableSubIntr(PSP_VBLANK_INT, 0); + } + data->vblank_not_reached = SDL_TRUE; renderer->WindowEvent = PSP_WindowEvent; renderer->CreateTexture = PSP_CreateTexture; From 70d1b7adf2654876a690aab1ce6682d82a82fe56 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 22 Jan 2023 22:58:12 +0100 Subject: [PATCH 04/37] PSP doesn't support render target --- src/render/psp/SDL_render_psp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index e4c4286e5125f..efeb5d6d9945c 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -252,11 +252,6 @@ static void PSP_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture psp_texture->filter = guScaleMode; } -static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) -{ - return 0; -} - static int PSP_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { return 0; /* nothing to do in this backend. */ @@ -703,7 +698,6 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 renderer->LockTexture = PSP_LockTexture; renderer->UnlockTexture = PSP_UnlockTexture; renderer->SetTextureScaleMode = PSP_SetTextureScaleMode; - renderer->SetRenderTarget = PSP_SetRenderTarget; renderer->QueueSetViewport = PSP_QueueSetViewport; renderer->QueueSetDrawColor = PSP_QueueSetViewport; renderer->QueueDrawPoints = PSP_QueueDrawPoints; From da1081846d723aa738d8b461352e0c1c7f7c7b96 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Tue, 24 Jan 2023 00:56:27 +0100 Subject: [PATCH 05/37] Some others improvements --- CMakeLists.txt | 2 +- src/render/psp/SDL_render_psp.c | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea2368cdfe9aa..9fdd1a4cbbab0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2727,9 +2727,9 @@ elseif(PSP) pspvram pspaudio pspvfpu - pspdisplay pspgu pspge + pspdisplay psphprm pspctrl psppower diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index efeb5d6d9945c..cec6f8317a70e 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -209,7 +209,7 @@ static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - // gsKit_TexManager_invalidate(data->gsGlobal, psp_texture); + sceKernelDcacheWritebackAll(); } static int PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, @@ -420,7 +420,7 @@ static int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd) colorA = cmd->data.color.a; sceGuClearColor(GU_RGBA(colorR, colorG, colorB, colorA)); - sceGuClearStencil(colorA); + sceGuClearDepth(0); sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); return 0; @@ -580,14 +580,15 @@ static int PSP_RenderPresent(SDL_Renderer *renderer) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + sceGuFinish(); + sceGuSync(0,0); + if (((data->vsync == 2) && (data->vblank_not_reached)) || // Dynamic (data->vsync == 1)) { // Normal VSync sceDisplayWaitVblankStart(); } data->vblank_not_reached = SDL_TRUE; - sceGuFinish(); - sceGuSync(0,0); data->backbuffer = data->frontbuffer; data->frontbuffer = vabsptr(sceGuSwapBuffers()); @@ -658,6 +659,9 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 return SDL_OutOfMemory(); } + // flush cache so that no stray data remains + sceKernelDcacheWritebackAll(); + /* Specific GU init */ bufferSize = getMemorySize(PSP_FRAME_BUFFER_WIDTH, PSP_SCREEN_HEIGHT, GU_PSM_8888); doublebuffer = vramalloc(bufferSize * 2); @@ -683,6 +687,12 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 sceDisplayWaitVblankStart(); sceGuDisplay(GU_TRUE); + sceGuStart(GU_DIRECT,list); + + // Clear the screen + sceGuClearColor(0); + sceGuClear(GU_COLOR_BUFFER_BIT); + /* Improve performance when VSYC is enabled and it is not reaching the 60 FPS */ dynamicVsync = SDL_GetHintBoolean(SDL_HINT_PSP_DYNAMIC_VSYNC, SDL_FALSE); data->vsync = flags & SDL_RENDERER_PRESENTVSYNC ? (dynamicVsync ? 2 : 1) : 0; From 252061b9f2b56208752ba6291e32bcf088e83367 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Tue, 24 Jan 2023 17:02:27 +0100 Subject: [PATCH 06/37] Fix weird texture issues --- CMakeLists.txt | 2 +- src/render/psp/SDL_render_psp.c | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fdd1a4cbbab0..ea2368cdfe9aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2727,9 +2727,9 @@ elseif(PSP) pspvram pspaudio pspvfpu + pspdisplay pspgu pspge - pspdisplay psphprm pspctrl psppower diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index cec6f8317a70e..d50a96f36b930 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -47,6 +47,7 @@ typedef struct PSP_Texture unsigned int textureWidth; /**< Texture width (power of two). */ unsigned int textureHeight; /**< Texture height (power of two). */ unsigned int format; /**< Image format - one of ::pgePixelFormat. */ + unsigned int size; /**< Image size in bytes. */ unsigned int filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ unsigned int pitch; } PSP_Texture; @@ -179,7 +180,8 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) psp_tex->height = texture->h; psp_tex->textureWidth = calculateNextPow2(texture->w); psp_tex->textureHeight = calculateNextPow2(texture->h); - psp_tex->data = SDL_calloc(1, getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format)); + psp_tex->size = getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format); + psp_tex->data = SDL_calloc(1, psp_tex->size); if (!psp_tex->data) { SDL_free(psp_tex); @@ -209,7 +211,7 @@ static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - sceKernelDcacheWritebackAll(); + sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size); } static int PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, @@ -478,10 +480,10 @@ static int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_Render const VertTCV *verts = (VertTCV *)(vertices + cmd->data.draw.first); PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; - sceGuEnable(GU_TEXTURE_2D); sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); - sceGuTexFilter(psp_tex->filter, psp_tex->filter); sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data); + sceGuTexFilter(psp_tex->filter, psp_tex->filter); + sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); } else { @@ -518,6 +520,18 @@ int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand * static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) { + /* note that before the renderer interface change, this would do extrememly small + batches with sceGuGetMemory()--a few vertices at a time--and it's not clear that + this won't fail if you try to push 100,000 draw calls in a single batch. + I don't know what the limits on PSP hardware are. It might be useful to have + rendering backends report a reasonable maximum, so the higher level can flush + if we appear to be exceeding that. */ + Uint8 *gpumem = (Uint8 *)sceGuGetMemory(vertsize); + if (gpumem == NULL) { + return SDL_SetError("Couldn't obtain a %d-byte vertex buffer!", (int)vertsize); + } + SDL_memcpy(gpumem, vertices, vertsize); + while (cmd) { switch (cmd->command) { case SDL_RENDERCMD_SETVIEWPORT: @@ -543,12 +557,12 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v } case SDL_RENDERCMD_DRAW_POINTS: { - PSP_RenderPoints(renderer, vertices, cmd); + PSP_RenderPoints(renderer, gpumem, cmd); break; } case SDL_RENDERCMD_DRAW_LINES: { - PSP_RenderLines(renderer, vertices, cmd); + PSP_RenderLines(renderer, gpumem, cmd); break; } case SDL_RENDERCMD_FILL_RECTS: /* unused */ @@ -559,7 +573,7 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v break; case SDL_RENDERCMD_GEOMETRY: { - PSP_RenderGeometry(renderer, vertices, cmd); + PSP_RenderGeometry(renderer, gpumem, cmd); break; } case SDL_RENDERCMD_NO_OP: From aeac20feaf3e152e2d31883ae74a77467ef37999 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Wed, 25 Jan 2023 19:49:27 +0100 Subject: [PATCH 07/37] Fixing colored triangles support --- src/render/psp/SDL_render_psp.c | 110 +++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 39 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index d50a96f36b930..9a954b185cb72 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -30,16 +30,24 @@ #include "SDL_render_psp.h" static unsigned int __attribute__((aligned(16))) list[262144]; + +typedef struct +{ + uint8_t shade; /**< GU_FLAT or GU_SMOOTH */ + uint8_t mode; /**< GU_ADD, GU_SUBTRACT, GU_REVERSE_SUBTRACT, GU_MIN, GU_MAX */ +} PSP_BlendInfo; + typedef struct { void *frontbuffer; /**< main screen buffer */ void *backbuffer; /**< buffer presented to display */ uint64_t drawColor; + PSP_BlendInfo blendInfo; /**< current blend info */ uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ SDL_bool vblank_not_reached; /**< whether vblank wasn't reached */ } PSP_RenderData; -typedef struct PSP_Texture +typedef struct { void *data; /**< Image data. */ unsigned int width; /**< Image width. */ @@ -428,44 +436,56 @@ static int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd) return 0; } -static void PSP_SetBlendMode(PSP_RenderData *data, int blendMode) +static void PSP_SetBlendMode(PSP_RenderData *data, PSP_BlendInfo blendInfo) { - switch (blendMode) { - case SDL_BLENDMODE_NONE: - { - sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); - sceGuDisable(GU_BLEND); - break; - } - case SDL_BLENDMODE_BLEND: - { - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); - sceGuEnable(GU_BLEND); - break; - } - case SDL_BLENDMODE_ADD: - { - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF); - sceGuEnable(GU_BLEND); - break; - } - case SDL_BLENDMODE_MOD: - { - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); - sceGuEnable(GU_BLEND); - break; - } - case SDL_BLENDMODE_MUL: - { - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + // Update the blend mode if necessary + if (data->blendInfo.mode != blendInfo.mode) { + switch (blendInfo.mode) { + case SDL_BLENDMODE_NONE: + { + sceGuShadeModel(GU_SMOOTH); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); + sceGuDisable(GU_BLEND); + break; + } + case SDL_BLENDMODE_BLEND: + { + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuEnable(GU_BLEND); + break; + } + case SDL_BLENDMODE_ADD: + { + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF); + sceGuEnable(GU_BLEND); + break; + } + case SDL_BLENDMODE_MOD: + { + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); + sceGuEnable(GU_BLEND); + break; + } + case SDL_BLENDMODE_MUL: + { + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); /* FIXME SDL_BLENDMODE_MUL is simplified, and dstA is in fact un-changed.*/ - sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); - sceGuEnable(GU_BLEND); - break; + sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuEnable(GU_BLEND); + break; + } + } + + data->blendInfo.mode = blendInfo.mode; } + + // Update shade model if needed + if (data->blendInfo.shade != blendInfo.shade) { + sceGuShadeModel(blendInfo.shade); + data->blendInfo.shade = blendInfo.shade; } } @@ -473,8 +493,12 @@ static int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_Render { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const size_t count = cmd->data.draw.count; + PSP_BlendInfo blendInfo = { + .mode = cmd->data.draw.blend, + .shade = GU_SMOOTH + }; - PSP_SetBlendMode(data, cmd->data.draw.blend); + PSP_SetBlendMode(data, blendInfo); if (cmd->data.draw.texture) { const VertTCV *verts = (VertTCV *)(vertices + cmd->data.draw.first); @@ -499,8 +523,12 @@ int PSP_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *c PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const size_t count = cmd->data.draw.count; const VertV *verts = (VertV *)(vertices + cmd->data.draw.first); + const PSP_BlendInfo blendInfo = { + .mode = cmd->data.draw.blend, + .shade = GU_FLAT + }; - PSP_SetBlendMode(data, cmd->data.draw.blend); + PSP_SetBlendMode(data, blendInfo); sceGuDrawArray(GU_LINES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); return 0; @@ -511,8 +539,12 @@ int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand * PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const size_t count = cmd->data.draw.count; const VertV *verts = (VertV *)(vertices + cmd->data.draw.first); + const PSP_BlendInfo blendInfo = { + .mode = cmd->data.draw.blend, + .shade = GU_FLAT + }; - PSP_SetBlendMode(data, cmd->data.draw.blend); + PSP_SetBlendMode(data, blendInfo); sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); return 0; From 62746888683b44d932109f04b6a0b110fe8ce8e5 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sat, 28 Jan 2023 01:36:15 +0100 Subject: [PATCH 08/37] Create function for calculate the proper slice size --- src/render/psp/SDL_render_psp.c | 92 +++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 9a954b185cb72..1ae37f918f99c 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -63,20 +63,52 @@ typedef struct typedef struct { float x, y, z; -} VertV; +} __attribute__ ((packed)) VertV; typedef struct { SDL_Color col; float x, y, z; -} VertCV; +} __attribute__ ((packed)) VertCV; typedef struct { float u, v; SDL_Color col; float x, y, z; -} VertTCV; +} __attribute__ ((packed)) VertTCV; + +typedef struct +{ + float u, v; + float x, y, z; +} __attribute__ ((packed)) VertTV; + +typedef struct +{ + int width; + int height; +} SliceSize; + +typedef enum +{ + SLICE_PIXEL_BITS_32, + SLICE_PIXEL_BITS_16, + SLICE_PIXEL_BITS_COUNT +} SlicePixelBits; + +#define SLICE_VALUES_COUNT 3 +typedef struct +{ + SlicePixelBits pixelBits; + SliceSize sizes[SLICE_VALUES_COUNT]; + SliceSize condition; +} SliceInfo; + +static SliceInfo sliceInfo[SLICE_PIXEL_BITS_COUNT] = { + { SLICE_PIXEL_BITS_32, { { 128, 16 }, { 64, 32 }, { 32, 64 } }, { 32, 16 } }, + { SLICE_PIXEL_BITS_16, { { 128, 32 }, { 64, 64 }, { 32, 128 } }, { 32, 32 } } +}; int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void** out) { @@ -171,6 +203,60 @@ static int calculateNextPow2(int value) return i; } +static int calculateBestSliceSizeForTexture(SDL_Texture *texture, SliceSize *uvSize, SliceSize *sliceSize, SliceSize *sliceDimension) { + int i; + uint8_t horizontalSlices, verticalSlices; + int pixelBits = 0; + int pixelSize = SDL_BYTESPERPIXEL(texture->format); + SliceInfo *sliceInfoPtr = NULL; + SliceSize *foundSlizeSize = NULL; + + switch (pixelSize) { + case 4: + sliceInfoPtr = &sliceInfo[SLICE_PIXEL_BITS_32]; + break; + case 2: + sliceInfoPtr = &sliceInfo[SLICE_PIXEL_BITS_16]; + break; + default: + return -1; + } + + if (sliceInfoPtr->condition.width > uvSize->width && sliceInfoPtr->condition.height > uvSize->height) { + sliceSize->width = uvSize->width; + sliceSize->height = uvSize->height; + sliceDimension->width = 1; + sliceDimension->height = 1; + return 0; + } + + if (uvSize->width >= uvSize->height) { + for (i = 0; i < SLICE_VALUES_COUNT; i++) { + if (uvSize->width >= sliceInfoPtr->sizes[i].width) { + foundSlizeSize = &sliceInfoPtr->sizes[i]; + break; + } + } + } else { + for (i = SLICE_VALUES_COUNT - 1; i >= 0; i--) { + if (uvSize->height >= sliceInfoPtr->sizes[i].height) { + foundSlizeSize = &sliceInfoPtr->sizes[i]; + break; + } + } + } + + if (foundSlizeSize == NULL) + return -1; + + sliceSize->width = foundSlizeSize->width; + sliceSize->height = foundSlizeSize->height; + sliceDimension->width = ((texture->w % foundSlizeSize->width == 0) ? 0 : 1) + (texture->w / foundSlizeSize->width); + sliceDimension->height = ((texture->h % foundSlizeSize->height == 0) ? 0 : 1) + (texture->h / foundSlizeSize->height); + + return 0; +} + static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) { } From f2df1b230b16479d274793266ea6c0ef00b2deff Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sat, 28 Jan 2023 13:34:33 +0100 Subject: [PATCH 09/37] Implementation looks to be almost right --- src/render/psp/SDL_render_psp.c | 131 +++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 1ae37f918f99c..c9a03dbe1e9c1 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -251,12 +251,51 @@ static int calculateBestSliceSizeForTexture(SDL_Texture *texture, SliceSize *uvS sliceSize->width = foundSlizeSize->width; sliceSize->height = foundSlizeSize->height; - sliceDimension->width = ((texture->w % foundSlizeSize->width == 0) ? 0 : 1) + (texture->w / foundSlizeSize->width); - sliceDimension->height = ((texture->h % foundSlizeSize->height == 0) ? 0 : 1) + (texture->h / foundSlizeSize->height); + sliceDimension->width = ((uvSize->width % foundSlizeSize->width == 0) ? 0 : 1) + (uvSize->width / foundSlizeSize->width); + sliceDimension->height = ((uvSize->height % foundSlizeSize->height == 0) ? 0 : 1) + (uvSize->height / foundSlizeSize->height); return 0; } +static void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, + const SDL_Rect *srcrect, const SDL_FRect *dstrect) { + int i, j; + float dstrectSlizeWidth = dstrect->w / dimensions->width; + float dstrectSlizeHeight = dstrect->h / dimensions->height; + int remainingWidth = srcrect->w % sliceSize->width; + int remainingHeight = srcrect->h % sliceSize->height; + int hasRemainingWidth = remainingWidth > 0; + int hasRemainingHeight = remainingHeight > 0; + + int verticesCount = dimensions->width * dimensions->height * 2; + for (i = 0; i < dimensions->width; i++) { + for (j = 0; j < dimensions->height; j++) { + uint8_t currentIndex = (i * dimensions->height + j) * 2; + vertices[currentIndex].u = srcrect->x + i * sliceSize->width; + vertices[currentIndex].v = srcrect->y + j * sliceSize->height; + vertices[currentIndex].x = dstrect->x + i * dstrectSlizeWidth; + vertices[currentIndex].y = dstrect->y + j * dstrectSlizeHeight; + vertices[currentIndex].z = 0; + + if (i == dimensions->width - 1 && hasRemainingWidth) { + vertices[currentIndex + 1].u = srcrect->x + i * sliceSize->width + remainingWidth; + } else { + vertices[currentIndex + 1].u = (srcrect->x + (i +1) * sliceSize->width); + } + + if (j == dimensions->height - 1 && hasRemainingHeight) { + vertices[currentIndex + 1].v = srcrect->y + j * sliceSize->height + remainingHeight; + } else { + vertices[currentIndex + 1].v = (srcrect->y + (j + 1) * sliceSize->height); + } + + vertices[currentIndex + 1].x = dstrect->x + (i + 1) * dstrectSlizeWidth; + vertices[currentIndex + 1].y = dstrect->y + (j + 1) * dstrectSlizeHeight; + vertices[currentIndex + 1].z = 0; + } + } +} + static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) { } @@ -461,6 +500,60 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL return 0; } +static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const SDL_Rect *srcrect, const SDL_FRect *dstrect) +{ + VertTV *verts; + uint8_t verticesCount; + const float x = dstrect->x; + const float y = dstrect->y; + const float width = dstrect->w; + const float height = dstrect->h; + + const float u0 = srcrect->x; + const float v0 = srcrect->y; + const float u1 = srcrect->x + srcrect->w; + const float v1 = srcrect->y + srcrect->h; + + // We need to split in slices because we have a texture bigger than 64 pixel width + if (texture) { + SliceSize sliceSize, sliceDimension, uvSize; + uvSize.width = abs(u1) - abs(u0); + uvSize.height = abs(v1) - abs(v0); + if (calculateBestSliceSizeForTexture(texture, &uvSize, &sliceSize, &sliceDimension)) + return -1; + + verticesCount = sliceDimension.width * sliceDimension.height * 2; + verts = (VertTV *)SDL_AllocateRenderVertices(renderer, verticesCount * sizeof(VertTV), 4, &cmd->data.draw.first); + if (verts == NULL) + return -1; + + fillSpriteVertices(verts, &sliceDimension, &sliceSize, srcrect, dstrect); + } else { + // We don't need to split in slices because we don't have a texture + verticesCount = 2; + verts = (VertTV *)SDL_AllocateRenderVertices(renderer, verticesCount * sizeof(VertTV), 4, &cmd->data.draw.first); + if (verts == NULL) + return -1; + + verts[0].u = u0; + verts[0].v = v0; + verts[0].x = x; + verts[0].y = y; + verts[0].z = 0; + + verts[1].u = u1; + verts[1].v = v1; + verts[1].x = x + width; + verts[1].y = y + height; + verts[1].z = 0; + } + + cmd->data.draw.count = verticesCount; + + return 0; +} + static int PSP_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; @@ -636,6 +729,34 @@ int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand * return 0; } +int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) +{ + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + const size_t count = cmd->data.draw.count; + const VertTV *verts = (VertTV *)(vertices + cmd->data.draw.first); + PSP_BlendInfo blendInfo = { + .mode = cmd->data.draw.blend, + .shade = GU_FLAT + }; + + PSP_SetBlendMode(data, blendInfo); + + if (cmd->data.draw.texture) { + PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; + + sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); + sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data); + sceGuTexFilter(psp_tex->filter, psp_tex->filter); + sceGuEnable(GU_TEXTURE_2D); + sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); + sceGuDisable(GU_TEXTURE_2D); + } else { + sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); + } + + return 0; +} + static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) { /* note that before the renderer interface change, this would do extrememly small @@ -685,8 +806,11 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v } case SDL_RENDERCMD_FILL_RECTS: /* unused */ break; - case SDL_RENDERCMD_COPY: /* unused */ + case SDL_RENDERCMD_COPY: + { + PSP_RenderCopy(renderer, gpumem, cmd); break; + } case SDL_RENDERCMD_COPY_EX: /* unused */ break; case SDL_RENDERCMD_GEOMETRY: @@ -845,6 +969,7 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 renderer->QueueDrawPoints = PSP_QueueDrawPoints; renderer->QueueDrawLines = PSP_QueueDrawPoints; renderer->QueueGeometry = PSP_QueueGeometry; + renderer->QueueCopy = PSP_QueueCopy; renderer->RunCommandQueue = PSP_RunCommandQueue; renderer->RenderReadPixels = PSP_RenderReadPixels; renderer->RenderPresent = PSP_RenderPresent; From b31b288f9f23eb5202d122b14bb51781a95ffc7f Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 29 Jan 2023 00:02:20 +0100 Subject: [PATCH 10/37] Fix the slice calculation --- src/render/psp/SDL_render_psp.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index c9a03dbe1e9c1..eb5fc34acf4c9 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -260,12 +260,12 @@ static int calculateBestSliceSizeForTexture(SDL_Texture *texture, SliceSize *uvS static void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, const SDL_Rect *srcrect, const SDL_FRect *dstrect) { int i, j; - float dstrectSlizeWidth = dstrect->w / dimensions->width; - float dstrectSlizeHeight = dstrect->h / dimensions->height; int remainingWidth = srcrect->w % sliceSize->width; int remainingHeight = srcrect->h % sliceSize->height; int hasRemainingWidth = remainingWidth > 0; int hasRemainingHeight = remainingHeight > 0; + float dstrectRateWidth = (float)(abs(dstrect->w - dimensions->width)) / (float)(abs(srcrect->w - dimensions->width)); + float dstrectRateHeight = (float)(abs(dstrect->h - dimensions->height)) / (float)(abs(srcrect->h - dimensions->height)); int verticesCount = dimensions->width * dimensions->height * 2; for (i = 0; i < dimensions->width; i++) { @@ -273,24 +273,26 @@ static void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSiz uint8_t currentIndex = (i * dimensions->height + j) * 2; vertices[currentIndex].u = srcrect->x + i * sliceSize->width; vertices[currentIndex].v = srcrect->y + j * sliceSize->height; - vertices[currentIndex].x = dstrect->x + i * dstrectSlizeWidth; - vertices[currentIndex].y = dstrect->y + j * dstrectSlizeHeight; + vertices[currentIndex].x = dstrect->x + i * sliceSize->width * dstrectRateWidth; + vertices[currentIndex].y = dstrect->y + j * sliceSize->height * dstrectRateHeight; vertices[currentIndex].z = 0; if (i == dimensions->width - 1 && hasRemainingWidth) { vertices[currentIndex + 1].u = srcrect->x + i * sliceSize->width + remainingWidth; + vertices[currentIndex + 1].x = dstrect->x + i * (sliceSize->width * dstrectRateWidth) + remainingWidth * dstrectRateWidth; } else { vertices[currentIndex + 1].u = (srcrect->x + (i +1) * sliceSize->width); + vertices[currentIndex + 1].x = dstrect->x + (i + 1) * sliceSize->width * dstrectRateWidth; } if (j == dimensions->height - 1 && hasRemainingHeight) { vertices[currentIndex + 1].v = srcrect->y + j * sliceSize->height + remainingHeight; + vertices[currentIndex + 1].y = dstrect->y + j * sliceSize->height * dstrectRateHeight + remainingHeight * dstrectRateHeight; } else { vertices[currentIndex + 1].v = (srcrect->y + (j + 1) * sliceSize->height); + vertices[currentIndex + 1].y = dstrect->y + (j + 1) * sliceSize->height * dstrectRateHeight; } - vertices[currentIndex + 1].x = dstrect->x + (i + 1) * dstrectSlizeWidth; - vertices[currentIndex + 1].y = dstrect->y + (j + 1) * dstrectSlizeHeight; vertices[currentIndex + 1].z = 0; } } @@ -518,8 +520,8 @@ static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Tex // We need to split in slices because we have a texture bigger than 64 pixel width if (texture) { SliceSize sliceSize, sliceDimension, uvSize; - uvSize.width = abs(u1) - abs(u0); - uvSize.height = abs(v1) - abs(v0); + uvSize.width = abs(u1 - u0); + uvSize.height = abs(v1 - v0); if (calculateBestSliceSizeForTexture(texture, &uvSize, &sliceSize, &sliceDimension)) return -1; From 741cedb7460a0b5259ea72fa2977452f07d414a3 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 29 Jan 2023 01:11:18 +0100 Subject: [PATCH 11/37] Move textures to VRAM --- src/render/psp/SDL_render_psp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index eb5fc34acf4c9..214822d559ea0 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -316,10 +316,10 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) psp_tex->textureWidth = calculateNextPow2(texture->w); psp_tex->textureHeight = calculateNextPow2(texture->h); psp_tex->size = getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format); - psp_tex->data = SDL_calloc(1, psp_tex->size); + psp_tex->data = vramalloc(psp_tex->size); if (!psp_tex->data) { - SDL_free(psp_tex); + vfree(psp_tex); return SDL_OutOfMemory(); } @@ -869,7 +869,7 @@ static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) return; } - SDL_free(psp_texture->data); + vfree(psp_texture->data); SDL_free(psp_texture); texture->driverdata = NULL; } From b128bb69e2f737821819c220125faf3cc37a3f6e Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 29 Jan 2023 01:11:40 +0100 Subject: [PATCH 12/37] Change draw buffer to GU_PSM_4444 --- src/render/psp/SDL_render_psp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 214822d559ea0..a9bbcf4da5fad 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -921,14 +921,14 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 sceKernelDcacheWritebackAll(); /* Specific GU init */ - bufferSize = getMemorySize(PSP_FRAME_BUFFER_WIDTH, PSP_SCREEN_HEIGHT, GU_PSM_8888); + bufferSize = getMemorySize(PSP_FRAME_BUFFER_WIDTH, PSP_SCREEN_HEIGHT, GU_PSM_4444); doublebuffer = vramalloc(bufferSize * 2); data->backbuffer = doublebuffer; data->frontbuffer = ((uint8_t *)doublebuffer) + bufferSize; sceGuInit(); sceGuStart(GU_DIRECT, list); - sceGuDrawBuffer(GU_PSM_8888, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); + sceGuDrawBuffer(GU_PSM_4444, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1)); From a2b52034fefa51515d02f3614f8925931ceca542 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 30 Jan 2023 17:54:24 +0100 Subject: [PATCH 13/37] Implement FIllRects --- src/render/psp/SDL_render_psp.c | 51 ++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index a9bbcf4da5fad..efffb22fbe0d7 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -502,6 +502,34 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL return 0; } +static int PSP_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count) +{ + VertV *verts = (VertV *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(VertV), 4, &cmd->data.draw.first); + int i; + + if (verts == NULL) { + return -1; + } + + cmd->data.draw.count = count; + for (i = 0; i < count; i++, rects++) { + verts->x = rects->x; + verts->y = rects->y; + verts->z = 0.0f; + verts++; + + verts->x = rects->x + rects->w; + verts->y = rects->y + rects->h; + verts->z = 0.0f; + verts++; + } + + // Update the vertex count + cmd->data.draw.count = count * 2; + + return 0; +} + static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect) { @@ -715,6 +743,23 @@ int PSP_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *c return 0; } +int PSP_RenderFillRects(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) +{ + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + const size_t count = cmd->data.draw.count; + const VertV *verts = (VertV *)(vertices + cmd->data.draw.first); + const PSP_BlendInfo blendInfo = { + .mode = cmd->data.draw.blend, + .shade = GU_FLAT + }; + + PSP_SetBlendMode(data, blendInfo); + sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); + + return 0; +} + + int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; @@ -806,8 +851,11 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v PSP_RenderLines(renderer, gpumem, cmd); break; } - case SDL_RENDERCMD_FILL_RECTS: /* unused */ + case SDL_RENDERCMD_FILL_RECTS: + { + PSP_RenderFillRects(renderer, gpumem, cmd); break; + } case SDL_RENDERCMD_COPY: { PSP_RenderCopy(renderer, gpumem, cmd); @@ -971,6 +1019,7 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 renderer->QueueDrawPoints = PSP_QueueDrawPoints; renderer->QueueDrawLines = PSP_QueueDrawPoints; renderer->QueueGeometry = PSP_QueueGeometry; + renderer->QueueFillRects = PSP_QueueFillRects; renderer->QueueCopy = PSP_QueueCopy; renderer->RunCommandQueue = PSP_RunCommandQueue; renderer->RenderReadPixels = PSP_RenderReadPixels; From 0560f719119eb895507220fd1b1a5b8d489093cb Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 30 Jan 2023 17:55:31 +0100 Subject: [PATCH 14/37] Disable texture check in the Copy method --- src/render/psp/SDL_render_psp.c | 66 ++++++++++++--------------------- 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index efffb22fbe0d7..1f54841a50196 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -545,39 +545,23 @@ static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Tex const float u1 = srcrect->x + srcrect->w; const float v1 = srcrect->y + srcrect->h; - // We need to split in slices because we have a texture bigger than 64 pixel width - if (texture) { - SliceSize sliceSize, sliceDimension, uvSize; - uvSize.width = abs(u1 - u0); - uvSize.height = abs(v1 - v0); - if (calculateBestSliceSizeForTexture(texture, &uvSize, &sliceSize, &sliceDimension)) - return -1; - - verticesCount = sliceDimension.width * sliceDimension.height * 2; - verts = (VertTV *)SDL_AllocateRenderVertices(renderer, verticesCount * sizeof(VertTV), 4, &cmd->data.draw.first); - if (verts == NULL) - return -1; - - fillSpriteVertices(verts, &sliceDimension, &sliceSize, srcrect, dstrect); - } else { - // We don't need to split in slices because we don't have a texture - verticesCount = 2; - verts = (VertTV *)SDL_AllocateRenderVertices(renderer, verticesCount * sizeof(VertTV), 4, &cmd->data.draw.first); - if (verts == NULL) - return -1; + SliceSize sliceSize, sliceDimension, uvSize; - verts[0].u = u0; - verts[0].v = v0; - verts[0].x = x; - verts[0].y = y; - verts[0].z = 0; - - verts[1].u = u1; - verts[1].v = v1; - verts[1].x = x + width; - verts[1].y = y + height; - verts[1].z = 0; - } + // In this function texture must be created + if (!texture) + return -1; + + uvSize.width = abs(u1 - u0); + uvSize.height = abs(v1 - v0); + if (calculateBestSliceSizeForTexture(texture, &uvSize, &sliceSize, &sliceDimension)) + return -1; + + verticesCount = sliceDimension.width * sliceDimension.height * 2; + verts = (VertTV *)SDL_AllocateRenderVertices(renderer, verticesCount * sizeof(VertTV), 4, &cmd->data.draw.first); + if (verts == NULL) + return -1; + + fillSpriteVertices(verts, &sliceDimension, &sliceSize, srcrect, dstrect); cmd->data.draw.count = verticesCount; @@ -788,18 +772,14 @@ int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cm PSP_SetBlendMode(data, blendInfo); - if (cmd->data.draw.texture) { - PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; + PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; - sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); - sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data); - sceGuTexFilter(psp_tex->filter, psp_tex->filter); - sceGuEnable(GU_TEXTURE_2D); - sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); - sceGuDisable(GU_TEXTURE_2D); - } else { - sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); - } + sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); + sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data); + sceGuTexFilter(psp_tex->filter, psp_tex->filter); + sceGuEnable(GU_TEXTURE_2D); + sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); + sceGuDisable(GU_TEXTURE_2D); return 0; } From 31832812dd5537eca5a989810ba9596dc837f2d5 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 30 Jan 2023 18:00:53 +0100 Subject: [PATCH 15/37] Use inline for trying to improve performance --- src/render/psp/SDL_render_psp.c | 120 ++++++++++++++++---------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 1f54841a50196..7604c2b7285dd 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -138,7 +138,7 @@ static void psp_on_vblank(u32 sub, PSP_RenderData *data) } } -static unsigned int getMemorySize(unsigned int width, unsigned int height, unsigned int psm) +static inline unsigned int getMemorySize(unsigned int width, unsigned int height, unsigned int psm) { switch (psm) { @@ -163,7 +163,7 @@ static unsigned int getMemorySize(unsigned int width, unsigned int height, unsig } } -static int pixelFormatToPSPFMT(Uint32 format) +static inline int pixelFormatToPSPFMT(Uint32 format) { switch (format) { case SDL_PIXELFORMAT_BGR565: @@ -179,7 +179,7 @@ static int pixelFormatToPSPFMT(Uint32 format) } } -static int calculatePitchForTextureFormat(int width, int format) +static inline int calculatePitchForTextureFormat(int width, int format) { switch (format) { case GU_PSM_5650: @@ -194,7 +194,7 @@ static int calculatePitchForTextureFormat(int width, int format) } /* Return next power of 2 */ -static int calculateNextPow2(int value) +static inline int calculateNextPow2(int value) { int i = 1; while (i < value) { @@ -203,7 +203,7 @@ static int calculateNextPow2(int value) return i; } -static int calculateBestSliceSizeForTexture(SDL_Texture *texture, SliceSize *uvSize, SliceSize *sliceSize, SliceSize *sliceDimension) { +static inline int calculateBestSliceSizeForTexture(SDL_Texture *texture, SliceSize *uvSize, SliceSize *sliceSize, SliceSize *sliceDimension) { int i; uint8_t horizontalSlices, verticalSlices; int pixelBits = 0; @@ -257,7 +257,7 @@ static int calculateBestSliceSizeForTexture(SDL_Texture *texture, SliceSize *uvS return 0; } -static void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, +static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, const SDL_Rect *srcrect, const SDL_FRect *dstrect) { int i, j; int remainingWidth = srcrect->w % sliceSize->width; @@ -580,55 +580,6 @@ static int PSP_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd) return 0; } -static int PSP_RenderSetClipRect(SDL_Renderer *renderer, SDL_RenderCommand *cmd) -{ - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - - const SDL_Rect *rect = &cmd->data.cliprect.rect; - - if (cmd->data.cliprect.enabled) { - sceGuEnable(GU_SCISSOR_TEST); - sceGuScissor(rect->x, rect->y, rect->w, rect->h); - } else { - sceGuDisable(GU_SCISSOR_TEST); - } - - return 0; -} - -static int PSP_RenderSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd) -{ - uint8_t colorR, colorG, colorB, colorA; - - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - - colorR = cmd->data.color.r; - colorG = cmd->data.color.g; - colorB = cmd->data.color.b; - colorA = cmd->data.color.a; - sceGuColor(GU_RGBA(colorR, colorG, colorB, colorA)); - - return 0; -} - -static int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd) -{ - uint8_t colorR, colorG, colorB, colorA; - - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - - colorR = cmd->data.color.r; - colorG = cmd->data.color.g; - colorB = cmd->data.color.b; - colorA = cmd->data.color.a; - - sceGuClearColor(GU_RGBA(colorR, colorG, colorB, colorA)); - sceGuClearDepth(0); - sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); - - return 0; -} - static void PSP_SetBlendMode(PSP_RenderData *data, PSP_BlendInfo blendInfo) { // Update the blend mode if necessary @@ -682,7 +633,56 @@ static void PSP_SetBlendMode(PSP_RenderData *data, PSP_BlendInfo blendInfo) } } -static int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) +static inline int PSP_RenderSetClipRect(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +{ + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + + const SDL_Rect *rect = &cmd->data.cliprect.rect; + + if (cmd->data.cliprect.enabled) { + sceGuEnable(GU_SCISSOR_TEST); + sceGuScissor(rect->x, rect->y, rect->w, rect->h); + } else { + sceGuDisable(GU_SCISSOR_TEST); + } + + return 0; +} + +static inline int PSP_RenderSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +{ + uint8_t colorR, colorG, colorB, colorA; + + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + + colorR = cmd->data.color.r; + colorG = cmd->data.color.g; + colorB = cmd->data.color.b; + colorA = cmd->data.color.a; + sceGuColor(GU_RGBA(colorR, colorG, colorB, colorA)); + + return 0; +} + +static inline int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +{ + uint8_t colorR, colorG, colorB, colorA; + + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + + colorR = cmd->data.color.r; + colorG = cmd->data.color.g; + colorB = cmd->data.color.b; + colorA = cmd->data.color.a; + + sceGuClearColor(GU_RGBA(colorR, colorG, colorB, colorA)); + sceGuClearDepth(0); + sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); + + return 0; +} + +static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const size_t count = cmd->data.draw.count; @@ -711,7 +711,7 @@ static int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_Render return 0; } -int PSP_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) +static inline int PSP_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const size_t count = cmd->data.draw.count; @@ -727,7 +727,7 @@ int PSP_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *c return 0; } -int PSP_RenderFillRects(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) +static inline int PSP_RenderFillRects(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const size_t count = cmd->data.draw.count; @@ -744,7 +744,7 @@ int PSP_RenderFillRects(SDL_Renderer *renderer, void *vertices, SDL_RenderComman } -int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) +static inline int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const size_t count = cmd->data.draw.count; @@ -760,7 +760,7 @@ int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand * return 0; } -int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) +static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const size_t count = cmd->data.draw.count; From f4e4d58fd5951df05c57c32a42fb7a8d141d9eba Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Tue, 31 Jan 2023 17:06:01 +0100 Subject: [PATCH 16/37] Use destiny to create the different slices --- src/render/psp/SDL_render_psp.c | 162 ++++++++++---------------------- 1 file changed, 51 insertions(+), 111 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 7604c2b7285dd..8399a5d09eb2e 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -24,10 +24,13 @@ #include "../SDL_sysrender.h" #include "SDL_hints.h" +#include "SDL_render_psp.h" #include #include -#include "SDL_render_psp.h" +#include +#include +#include static unsigned int __attribute__((aligned(16))) list[262144]; @@ -41,6 +44,7 @@ typedef struct { void *frontbuffer; /**< main screen buffer */ void *backbuffer; /**< buffer presented to display */ + uint8_t drawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ uint64_t drawColor; PSP_BlendInfo blendInfo; /**< current blend info */ uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ @@ -90,25 +94,6 @@ typedef struct int height; } SliceSize; -typedef enum -{ - SLICE_PIXEL_BITS_32, - SLICE_PIXEL_BITS_16, - SLICE_PIXEL_BITS_COUNT -} SlicePixelBits; - -#define SLICE_VALUES_COUNT 3 -typedef struct -{ - SlicePixelBits pixelBits; - SliceSize sizes[SLICE_VALUES_COUNT]; - SliceSize condition; -} SliceInfo; - -static SliceInfo sliceInfo[SLICE_PIXEL_BITS_COUNT] = { - { SLICE_PIXEL_BITS_32, { { 128, 16 }, { 64, 32 }, { 32, 64 } }, { 32, 16 } }, - { SLICE_PIXEL_BITS_16, { { 128, 32 }, { 64, 64 }, { 32, 128 } }, { 32, 32 } } -}; int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void** out) { @@ -127,7 +112,6 @@ int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void* } return -1; } - static int vsync_sema_id = 0; /* PRIVATE METHODS */ @@ -203,56 +187,28 @@ static inline int calculateNextPow2(int value) return i; } -static inline int calculateBestSliceSizeForTexture(SDL_Texture *texture, SliceSize *uvSize, SliceSize *sliceSize, SliceSize *sliceDimension) { - int i; - uint8_t horizontalSlices, verticalSlices; - int pixelBits = 0; - int pixelSize = SDL_BYTESPERPIXEL(texture->format); - SliceInfo *sliceInfoPtr = NULL; - SliceSize *foundSlizeSize = NULL; - - switch (pixelSize) { - case 4: - sliceInfoPtr = &sliceInfo[SLICE_PIXEL_BITS_32]; - break; - case 2: - sliceInfoPtr = &sliceInfo[SLICE_PIXEL_BITS_16]; - break; - default: - return -1; - } - - if (sliceInfoPtr->condition.width > uvSize->width && sliceInfoPtr->condition.height > uvSize->height) { - sliceSize->width = uvSize->width; - sliceSize->height = uvSize->height; - sliceDimension->width = 1; - sliceDimension->height = 1; - return 0; - } +static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const SDL_FRect *dstrect, SliceSize *sliceSize, SliceSize *sliceDimension) { + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - if (uvSize->width >= uvSize->height) { - for (i = 0; i < SLICE_VALUES_COUNT; i++) { - if (uvSize->width >= sliceInfoPtr->sizes[i].width) { - foundSlizeSize = &sliceInfoPtr->sizes[i]; - break; - } - } - } else { - for (i = SLICE_VALUES_COUNT - 1; i >= 0; i--) { - if (uvSize->height >= sliceInfoPtr->sizes[i].height) { - foundSlizeSize = &sliceInfoPtr->sizes[i]; - break; - } - } - } + // We split in blocks of (64 x destiny height) when 16 bits per color + // or (32 x destiny height) when 32 bits per color - if (foundSlizeSize == NULL) + switch (data->drawBufferFormat) { + case GU_PSM_5650: + case GU_PSM_5551: + case GU_PSM_4444: + sliceSize->width = 64; + break; + case GU_PSM_8888: + sliceSize->width = 32; + break; + default: return -1; + } + sliceSize->height = dstrect->h; - sliceSize->width = foundSlizeSize->width; - sliceSize->height = foundSlizeSize->height; - sliceDimension->width = ((uvSize->width % foundSlizeSize->width == 0) ? 0 : 1) + (uvSize->width / foundSlizeSize->width); - sliceDimension->height = ((uvSize->height % foundSlizeSize->height == 0) ? 0 : 1) + (uvSize->height / foundSlizeSize->height); + sliceDimension->width = SDL_ceilf(dstrect->w / sliceSize->width); + sliceDimension->height = SDL_ceilf(dstrect->h / sliceSize->height); return 0; } @@ -260,37 +216,40 @@ static inline int calculateBestSliceSizeForTexture(SDL_Texture *texture, SliceSi static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, const SDL_Rect *srcrect, const SDL_FRect *dstrect) { int i, j; - int remainingWidth = srcrect->w % sliceSize->width; - int remainingHeight = srcrect->h % sliceSize->height; + int remainingWidth = (int)dstrect->w % sliceSize->width; + int remainingHeight = (int)dstrect->h % sliceSize->height; int hasRemainingWidth = remainingWidth > 0; int hasRemainingHeight = remainingHeight > 0; - float dstrectRateWidth = (float)(abs(dstrect->w - dimensions->width)) / (float)(abs(srcrect->w - dimensions->width)); - float dstrectRateHeight = (float)(abs(dstrect->h - dimensions->height)) / (float)(abs(srcrect->h - dimensions->height)); + float srcrectRateWidth = (float)(abs(srcrect->w - dimensions->width)) / (float)(abs(dstrect->w - dimensions->width)); + float srcrectRateHeight = (float)(abs(srcrect->h - dimensions->height)) / (float)(abs(dstrect->h - dimensions->height)); + float srcWidth = sliceSize->width * srcrectRateWidth; + float srcHeight = sliceSize->height * srcrectRateHeight; + float remainingSrcWidth = remainingWidth * srcrectRateWidth; + float remainingSrcHeight = remainingHeight * srcrectRateHeight; - int verticesCount = dimensions->width * dimensions->height * 2; for (i = 0; i < dimensions->width; i++) { for (j = 0; j < dimensions->height; j++) { uint8_t currentIndex = (i * dimensions->height + j) * 2; - vertices[currentIndex].u = srcrect->x + i * sliceSize->width; - vertices[currentIndex].v = srcrect->y + j * sliceSize->height; - vertices[currentIndex].x = dstrect->x + i * sliceSize->width * dstrectRateWidth; - vertices[currentIndex].y = dstrect->y + j * sliceSize->height * dstrectRateHeight; + vertices[currentIndex].u = srcrect->x + i * srcWidth; + vertices[currentIndex].v = srcrect->y + j * srcHeight; + vertices[currentIndex].x = dstrect->x + i * sliceSize->width; + vertices[currentIndex].y = dstrect->y + j * sliceSize->height; vertices[currentIndex].z = 0; if (i == dimensions->width - 1 && hasRemainingWidth) { - vertices[currentIndex + 1].u = srcrect->x + i * sliceSize->width + remainingWidth; - vertices[currentIndex + 1].x = dstrect->x + i * (sliceSize->width * dstrectRateWidth) + remainingWidth * dstrectRateWidth; + vertices[currentIndex + 1].u = vertices[currentIndex].u + remainingSrcWidth; + vertices[currentIndex + 1].x = vertices[currentIndex].x + remainingWidth; } else { - vertices[currentIndex + 1].u = (srcrect->x + (i +1) * sliceSize->width); - vertices[currentIndex + 1].x = dstrect->x + (i + 1) * sliceSize->width * dstrectRateWidth; + vertices[currentIndex + 1].u = vertices[currentIndex].u + srcWidth; + vertices[currentIndex + 1].x = vertices[currentIndex].x + sliceSize->width; } if (j == dimensions->height - 1 && hasRemainingHeight) { - vertices[currentIndex + 1].v = srcrect->y + j * sliceSize->height + remainingHeight; - vertices[currentIndex + 1].y = dstrect->y + j * sliceSize->height * dstrectRateHeight + remainingHeight * dstrectRateHeight; + vertices[currentIndex + 1].v = vertices[currentIndex].v + remainingSrcHeight; + vertices[currentIndex + 1].y = vertices[currentIndex].y + remainingHeight; } else { - vertices[currentIndex + 1].v = (srcrect->y + (j + 1) * sliceSize->height); - vertices[currentIndex + 1].y = dstrect->y + (j + 1) * sliceSize->height * dstrectRateHeight; + vertices[currentIndex + 1].v = vertices[currentIndex].v + srcHeight; + vertices[currentIndex + 1].y = vertices[currentIndex].y + sliceSize->height; } vertices[currentIndex + 1].z = 0; @@ -344,7 +303,6 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) { PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size); } @@ -396,7 +354,6 @@ static int PSP_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd) static int PSP_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) { - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; VertV *verts = (VertV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertV), 4, &cmd->data.draw.first); int i; @@ -422,7 +379,6 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL { int i; int count = indices ? num_indices : num_vertices; - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; cmd->data.draw.count = count; size_indices = indices ? size_indices : 0; @@ -535,25 +491,14 @@ static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Tex { VertTV *verts; uint8_t verticesCount; - const float x = dstrect->x; - const float y = dstrect->y; - const float width = dstrect->w; - const float height = dstrect->h; - const float u0 = srcrect->x; - const float v0 = srcrect->y; - const float u1 = srcrect->x + srcrect->w; - const float v1 = srcrect->y + srcrect->h; - - SliceSize sliceSize, sliceDimension, uvSize; + SliceSize sliceSize, sliceDimension; // In this function texture must be created if (!texture) return -1; - uvSize.width = abs(u1 - u0); - uvSize.height = abs(v1 - v0); - if (calculateBestSliceSizeForTexture(texture, &uvSize, &sliceSize, &sliceDimension)) + if (calculateBestSliceSizeForSprite(renderer, dstrect, &sliceSize, &sliceDimension)) return -1; verticesCount = sliceDimension.width * sliceDimension.height * 2; @@ -570,7 +515,6 @@ static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Tex static int PSP_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; const SDL_Rect *viewport = &cmd->data.viewport.rect; sceGuOffset(2048 - (viewport->w >> 1), 2048 - (viewport->h >> 1)); @@ -635,8 +579,6 @@ static void PSP_SetBlendMode(PSP_RenderData *data, PSP_BlendInfo blendInfo) static inline int PSP_RenderSetClipRect(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - const SDL_Rect *rect = &cmd->data.cliprect.rect; if (cmd->data.cliprect.enabled) { @@ -653,8 +595,6 @@ static inline int PSP_RenderSetDrawColor(SDL_Renderer *renderer, SDL_RenderComma { uint8_t colorR, colorG, colorB, colorA; - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - colorR = cmd->data.color.r; colorG = cmd->data.color.g; colorB = cmd->data.color.b; @@ -668,8 +608,6 @@ static inline int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd { uint8_t colorR, colorG, colorB, colorA; - PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - colorR = cmd->data.color.r; colorG = cmd->data.color.g; colorB = cmd->data.color.b; @@ -763,6 +701,7 @@ static inline int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_R static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; const size_t count = cmd->data.draw.count; const VertTV *verts = (VertTV *)(vertices + cmd->data.draw.first); PSP_BlendInfo blendInfo = { @@ -772,8 +711,6 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren PSP_SetBlendMode(data, blendInfo); - PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; - sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data); sceGuTexFilter(psp_tex->filter, psp_tex->filter); @@ -948,15 +885,18 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 // flush cache so that no stray data remains sceKernelDcacheWritebackAll(); + // Forcing for now using GU_PSM_4444 + data->drawBufferFormat = GU_PSM_4444; + /* Specific GU init */ - bufferSize = getMemorySize(PSP_FRAME_BUFFER_WIDTH, PSP_SCREEN_HEIGHT, GU_PSM_4444); + bufferSize = getMemorySize(PSP_FRAME_BUFFER_WIDTH, PSP_SCREEN_HEIGHT, data->drawBufferFormat); doublebuffer = vramalloc(bufferSize * 2); data->backbuffer = doublebuffer; data->frontbuffer = ((uint8_t *)doublebuffer) + bufferSize; sceGuInit(); sceGuStart(GU_DIRECT, list); - sceGuDrawBuffer(GU_PSM_4444, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); + sceGuDrawBuffer(data->drawBufferFormat, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1)); From 31d94856e24c1512bda2213bbb8b39dccd6d70cf Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Tue, 31 Jan 2023 20:09:37 +0100 Subject: [PATCH 17/37] Skip small textures --- src/render/psp/SDL_render_psp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 8399a5d09eb2e..64d478f81e759 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -197,10 +197,10 @@ static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const case GU_PSM_5650: case GU_PSM_5551: case GU_PSM_4444: - sliceSize->width = 64; + sliceSize->width = dstrect->w > 64 ? 64: dstrect->w; break; case GU_PSM_8888: - sliceSize->width = 32; + sliceSize->width = dstrect->w > 32 ? 32: dstrect->w; break; default: return -1; From eaf781f62b8053e7867d62f2612bc37b5b3a9db9 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Wed, 1 Feb 2023 19:58:33 +0100 Subject: [PATCH 18/37] Implementing swizzling --- src/render/psp/SDL_render_psp.c | 171 ++++++++++++++++++++++++++++---- 1 file changed, 151 insertions(+), 20 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 64d478f81e759..ba2ea2b58e452 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -54,14 +54,21 @@ typedef struct typedef struct { void *data; /**< Image data. */ - unsigned int width; /**< Image width. */ - unsigned int height; /**< Image height. */ - unsigned int textureWidth; /**< Texture width (power of two). */ - unsigned int textureHeight; /**< Texture height (power of two). */ - unsigned int format; /**< Image format - one of ::pgePixelFormat. */ - unsigned int size; /**< Image size in bytes. */ - unsigned int filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ - unsigned int pitch; + void *swizzledData; /**< Swizzled image data. */ + uint32_t textureWidth; /**< Texture width (power of two). */ + uint32_t textureHeight; /**< Texture height (power of two). */ + uint32_t width; /**< Image width. */ + uint32_t height; /**< Image height. */ + uint32_t pitch; /**< Image pitch. */ + uint32_t swizzledWidth; /**< Swizzled image width. */ + uint32_t swizzledHeight;/**< Swizzled image height. */ + uint32_t swizzledPitch; /**< Swizzled image pitch. */ + uint32_t size; /**< Image size in bytes. */ + uint32_t swizzledSize; /**< Swizzled image size in bytes. */ + uint8_t format; /**< Image format - one of ::pgePixelFormat. */ + uint8_t filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ + uint8_t swizzled; /**< Whether the image is swizzled or not. */ + } PSP_Texture; typedef struct @@ -177,6 +184,20 @@ static inline int calculatePitchForTextureFormat(int width, int format) } } +static inline int calculateHeightForSwizzledTexture(int height, int format) +{ + switch (format) { + case GU_PSM_5650: + case GU_PSM_5551: + case GU_PSM_4444: + return (height + 15) & ~15; + case GU_PSM_8888: + return (height + 7) & ~7; + default: + return height; + } +} + /* Return next power of 2 */ static inline int calculateNextPow2(int value) { @@ -187,7 +208,8 @@ static inline int calculateNextPow2(int value) return i; } -static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const SDL_FRect *dstrect, SliceSize *sliceSize, SliceSize *sliceDimension) { +static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const SDL_FRect *dstrect, SliceSize *sliceSize, SliceSize *sliceDimension) +{ PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; // We split in blocks of (64 x destiny height) when 16 bits per color @@ -214,7 +236,8 @@ static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const } static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, - const SDL_Rect *srcrect, const SDL_FRect *dstrect) { + const SDL_Rect *srcrect, const SDL_FRect *dstrect) +{ int i, j; int remainingWidth = (int)dstrect->w % sliceSize->width; int remainingHeight = (int)dstrect->h % sliceSize->height; @@ -257,6 +280,92 @@ static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, S } } +// The slize when swizzling is always 16x32 bytes, no matter the texture format +// so the algorithm is the same for all formats +static inline int swizzle(PSP_Texture *psp_texture) +{ + uint32_t i, j, verticalSlice, dstOffset; + uint32_t *src, *dst, *srcBlock, *dstBlock; + uint32_t srcWidth = psp_texture->pitch >> 2; + uint32_t dstWidth = psp_texture->swizzledPitch >> 2; + uint32_t srcWidthBlocks = srcWidth >> 2; + uint8_t blockSizeBytes = 16; // 4 pixels of 32 bits + + dst = (uint32_t *)psp_texture->swizzledData; + for (j = 0; j < psp_texture->height; j++) { + src = (uint32_t *)psp_texture->data + j * srcWidth; + verticalSlice = (((j >> 3) << 3) * dstWidth) + ((j % 8) << 2); + for (i = 0; i < srcWidthBlocks; i++) { + srcBlock = src + (i << 2); + dstOffset = verticalSlice + (i << 5); + dstBlock = dst + dstOffset; + memcpy(dstBlock, srcBlock, blockSizeBytes); + } + } + + return 1; +} + +static inline int unswizzle(PSP_Texture *psp_texture) +{ + uint32_t i, j, verticalSlice, srcOffset; + uint32_t *src, *dst, *srcBlock, *dstBlock; + uint32_t srcWidth = psp_texture->swizzledPitch >> 2; + uint32_t dstWidth = psp_texture->pitch >> 2; + uint32_t dstWidthBlocks = dstWidth >> 2; + uint8_t blockSizeBytes = 16; // 4 pixels of 32 bits + + src = (uint32_t *)psp_texture->swizzledData; + for (j = 0; j < psp_texture->height; j++) { + dst = (uint32_t *)psp_texture->data + j * dstWidth; + verticalSlice = (((j >> 3) << 3) * srcWidth) + ((j % 8) << 2); + for (i = 0; i < dstWidthBlocks; i++) { + dstBlock = dst + (i << 2); + srcOffset = verticalSlice + (i << 5); + srcBlock = src + srcOffset; + memcpy(dstBlock, srcBlock, blockSizeBytes); + } + } + + return 1; +} + +static inline void prepareTextureForUpload(PSP_Texture *psp_tex) +{ + if (psp_tex->swizzled) + return; + + psp_tex->swizzledData = vramalloc(psp_tex->swizzledSize); + if (!psp_tex->swizzledData) { + sceKernelDcacheWritebackRange(psp_tex->data, psp_tex->size); + return; + } + + swizzle(psp_tex); + SDL_free(psp_tex->data); + psp_tex->swizzled = GU_TRUE; + + sceKernelDcacheWritebackRange(psp_tex->swizzledData, psp_tex->swizzledSize); +} + +static inline void prepareTextureForDownload(PSP_Texture *psp_tex) +{ + if (!psp_tex->swizzled) + return; + + psp_tex->data = SDL_malloc(psp_tex->size); + if (!psp_tex->data) { + sceKernelDcacheInvalidateRange(psp_tex->swizzledData, psp_tex->swizzledSize); + return; + } + + unswizzle(psp_tex); + vfree(psp_tex->swizzledData); + psp_tex->swizzled = GU_FALSE; + + sceKernelDcacheInvalidateRange(psp_tex->data, psp_tex->size); +} + static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) { } @@ -270,15 +379,21 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) } psp_tex->format = pixelFormatToPSPFMT(texture->format); - psp_tex->width = calculatePitchForTextureFormat(texture->w, psp_tex->format); - psp_tex->height = texture->h; psp_tex->textureWidth = calculateNextPow2(texture->w); psp_tex->textureHeight = calculateNextPow2(texture->h); + psp_tex->width = calculatePitchForTextureFormat(texture->w, psp_tex->format); + psp_tex->height = texture->h; + psp_tex->pitch = psp_tex->width * SDL_BYTESPERPIXEL(texture->format); + psp_tex->swizzledWidth = psp_tex->textureWidth; + psp_tex->swizzledHeight = calculateHeightForSwizzledTexture(texture->h, psp_tex->format); + psp_tex->swizzledPitch = psp_tex->swizzledWidth * SDL_BYTESPERPIXEL(texture->format); psp_tex->size = getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format); - psp_tex->data = vramalloc(psp_tex->size); + psp_tex->swizzledSize = getMemorySize(psp_tex->swizzledWidth, psp_tex->swizzledHeight, psp_tex->format); + psp_tex->data = SDL_calloc(1, psp_tex->size); + psp_tex->swizzled = GU_FALSE; if (!psp_tex->data) { - vfree(psp_tex); + SDL_free(psp_tex); return SDL_OutOfMemory(); } @@ -292,6 +407,9 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, { PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + // How a pointer to the texture data is returned it need to be unswizzled before it can be used + prepareTextureForDownload(psp_texture); + *pixels = (void *)((Uint8 *)psp_texture->data + rect->y * psp_texture->width * SDL_BYTESPERPIXEL(texture->format) + rect->x * SDL_BYTESPERPIXEL(texture->format)); @@ -632,11 +750,17 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL PSP_SetBlendMode(data, blendInfo); if (cmd->data.draw.texture) { + uint32_t tbw, twp; const VertTCV *verts = (VertTCV *)(vertices + cmd->data.draw.first); PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; - sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); - sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data); + prepareTextureForUpload(psp_tex); + + tbw = psp_tex->swizzled ? psp_tex->swizzledWidth : psp_tex->width; + twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data; + + sceGuTexMode(psp_tex->format, 0, 0, psp_tex->swizzled); + sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, tbw, twp); sceGuTexFilter(psp_tex->filter, psp_tex->filter); sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); @@ -700,19 +824,25 @@ static inline int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_R static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { + uint32_t tbw, twp; PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; const size_t count = cmd->data.draw.count; const VertTV *verts = (VertTV *)(vertices + cmd->data.draw.first); - PSP_BlendInfo blendInfo = { + const PSP_BlendInfo blendInfo = { .mode = cmd->data.draw.blend, .shade = GU_FLAT }; PSP_SetBlendMode(data, blendInfo); - sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE); - sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data); + prepareTextureForUpload(psp_tex); + + tbw = psp_tex->swizzled ? psp_tex->textureWidth : psp_tex->width; + twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data; + + sceGuTexMode(psp_tex->format, 0, 0, psp_tex->swizzled); + sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, tbw, twp); sceGuTexFilter(psp_tex->filter, psp_tex->filter); sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); @@ -834,7 +964,8 @@ static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) return; } - vfree(psp_texture->data); + vfree(psp_texture->swizzledData); + SDL_free(psp_texture->data); SDL_free(psp_texture); texture->driverdata = NULL; } From 67adbe8d7f122b48ae2ce9129931f36e6bafe4ad Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Wed, 8 Feb 2023 23:44:00 +0100 Subject: [PATCH 19/37] Some cleaning --- src/render/psp/SDL_render_psp.c | 50 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index ba2ea2b58e452..d210f0ed99cca 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -282,18 +282,18 @@ static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, S // The slize when swizzling is always 16x32 bytes, no matter the texture format // so the algorithm is the same for all formats -static inline int swizzle(PSP_Texture *psp_texture) +static inline int swizzle(PSP_Texture *psp_tex) { uint32_t i, j, verticalSlice, dstOffset; uint32_t *src, *dst, *srcBlock, *dstBlock; - uint32_t srcWidth = psp_texture->pitch >> 2; - uint32_t dstWidth = psp_texture->swizzledPitch >> 2; + uint32_t srcWidth = psp_tex->pitch >> 2; + uint32_t dstWidth = psp_tex->swizzledPitch >> 2; uint32_t srcWidthBlocks = srcWidth >> 2; uint8_t blockSizeBytes = 16; // 4 pixels of 32 bits - dst = (uint32_t *)psp_texture->swizzledData; - for (j = 0; j < psp_texture->height; j++) { - src = (uint32_t *)psp_texture->data + j * srcWidth; + dst = (uint32_t *)psp_tex->swizzledData; + for (j = 0; j < psp_tex->height; j++) { + src = (uint32_t *)psp_tex->data + j * srcWidth; verticalSlice = (((j >> 3) << 3) * dstWidth) + ((j % 8) << 2); for (i = 0; i < srcWidthBlocks; i++) { srcBlock = src + (i << 2); @@ -306,18 +306,18 @@ static inline int swizzle(PSP_Texture *psp_texture) return 1; } -static inline int unswizzle(PSP_Texture *psp_texture) +static inline int unswizzle(PSP_Texture *psp_tex) { uint32_t i, j, verticalSlice, srcOffset; uint32_t *src, *dst, *srcBlock, *dstBlock; - uint32_t srcWidth = psp_texture->swizzledPitch >> 2; - uint32_t dstWidth = psp_texture->pitch >> 2; + uint32_t srcWidth = psp_tex->swizzledPitch >> 2; + uint32_t dstWidth = psp_tex->pitch >> 2; uint32_t dstWidthBlocks = dstWidth >> 2; uint8_t blockSizeBytes = 16; // 4 pixels of 32 bits - src = (uint32_t *)psp_texture->swizzledData; - for (j = 0; j < psp_texture->height; j++) { - dst = (uint32_t *)psp_texture->data + j * dstWidth; + src = (uint32_t *)psp_tex->swizzledData; + for (j = 0; j < psp_tex->height; j++) { + dst = (uint32_t *)psp_tex->data + j * dstWidth; verticalSlice = (((j >> 3) << 3) * srcWidth) + ((j % 8) << 2); for (i = 0; i < dstWidthBlocks; i++) { dstBlock = dst + (i << 2); @@ -405,24 +405,24 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch) { - PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; // How a pointer to the texture data is returned it need to be unswizzled before it can be used - prepareTextureForDownload(psp_texture); + prepareTextureForDownload(psp_tex); *pixels = - (void *)((Uint8 *)psp_texture->data + rect->y * psp_texture->width * SDL_BYTESPERPIXEL(texture->format) + + (void *)((Uint8 *)psp_tex->data + rect->y * psp_tex->width * SDL_BYTESPERPIXEL(texture->format) + rect->x * SDL_BYTESPERPIXEL(texture->format)); - *pitch = psp_texture->width * SDL_BYTESPERPIXEL(texture->format); + *pitch = psp_tex->width * SDL_BYTESPERPIXEL(texture->format); return 0; } static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) { - PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; - sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size); + sceKernelDcacheWritebackRange(psp_tex->data, psp_tex->size); } static int PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, @@ -452,7 +452,7 @@ static int PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, static void PSP_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode) { - PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; /* set texture filtering according to scaleMode suported hint values are nearest (0, default) or linear (1) @@ -462,7 +462,7 @@ static void PSP_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture uint32_t guScaleMode = (scaleMode == SDL_ScaleModeNearest ? GU_NEAREST : GU_LINEAR); - psp_texture->filter = guScaleMode; + psp_tex->filter = guScaleMode; } static int PSP_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd) @@ -953,20 +953,20 @@ static int PSP_RenderPresent(SDL_Renderer *renderer) static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) { - PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata; + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; if (!data) { return; } - if (!psp_texture) { + if (!psp_tex) { return; } - vfree(psp_texture->swizzledData); - SDL_free(psp_texture->data); - SDL_free(psp_texture); + vfree(psp_tex->swizzledData); + SDL_free(psp_tex->data); + SDL_free(psp_tex); texture->driverdata = NULL; } From af3372c701eb93c512401807441132e4672bde0c Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Thu, 9 Feb 2023 00:19:01 +0100 Subject: [PATCH 20/37] Swizzle just static textures --- src/render/psp/SDL_render_psp.c | 50 ++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index d210f0ed99cca..3847388e971c3 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -330,9 +330,10 @@ static inline int unswizzle(PSP_Texture *psp_tex) return 1; } -static inline void prepareTextureForUpload(PSP_Texture *psp_tex) +static inline void prepareTextureForUpload(SDL_Texture *texture) { - if (psp_tex->swizzled) + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; + if (texture->access != SDL_TEXTUREACCESS_STATIC || psp_tex->swizzled ) return; psp_tex->swizzledData = vramalloc(psp_tex->swizzledSize); @@ -348,9 +349,11 @@ static inline void prepareTextureForUpload(PSP_Texture *psp_tex) sceKernelDcacheWritebackRange(psp_tex->swizzledData, psp_tex->swizzledSize); } -static inline void prepareTextureForDownload(PSP_Texture *psp_tex) +static inline void prepareTextureForDownload(SDL_Texture *texture) { - if (!psp_tex->swizzled) + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; + + if (texture->access != SDL_TEXTUREACCESS_STATIC || !psp_tex->swizzled) return; psp_tex->data = SDL_malloc(psp_tex->size); @@ -389,13 +392,21 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) psp_tex->swizzledPitch = psp_tex->swizzledWidth * SDL_BYTESPERPIXEL(texture->format); psp_tex->size = getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format); psp_tex->swizzledSize = getMemorySize(psp_tex->swizzledWidth, psp_tex->swizzledHeight, psp_tex->format); - psp_tex->data = SDL_calloc(1, psp_tex->size); - psp_tex->swizzled = GU_FALSE; - if (!psp_tex->data) { - SDL_free(psp_tex); - return SDL_OutOfMemory(); + if (texture->access != SDL_TEXTUREACCESS_STATIC) { + psp_tex->data = vramalloc(psp_tex->size); + if (!psp_tex->data) { + vfree(psp_tex); + return SDL_OutOfMemory(); + } + } else { + psp_tex->data = SDL_calloc(1, psp_tex->size); + if (!psp_tex->data) { + SDL_free(psp_tex); + return SDL_OutOfMemory(); + } } + psp_tex->swizzled = GU_FALSE; texture->driverdata = psp_tex; @@ -408,7 +419,7 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; // How a pointer to the texture data is returned it need to be unswizzled before it can be used - prepareTextureForDownload(psp_tex); + prepareTextureForDownload(texture); *pixels = (void *)((Uint8 *)psp_tex->data + rect->y * psp_tex->width * SDL_BYTESPERPIXEL(texture->format) + @@ -741,6 +752,7 @@ static inline int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + SDL_Texture *texture = cmd->data.draw.texture; const size_t count = cmd->data.draw.count; PSP_BlendInfo blendInfo = { .mode = cmd->data.draw.blend, @@ -749,12 +761,13 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL PSP_SetBlendMode(data, blendInfo); - if (cmd->data.draw.texture) { + if (texture) { uint32_t tbw, twp; const VertTCV *verts = (VertTCV *)(vertices + cmd->data.draw.first); - PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; + + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; - prepareTextureForUpload(psp_tex); + prepareTextureForUpload(texture); tbw = psp_tex->swizzled ? psp_tex->swizzledWidth : psp_tex->width; twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data; @@ -826,7 +839,8 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren { uint32_t tbw, twp; PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata; + SDL_Texture *texture = cmd->data.draw.texture; + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; const size_t count = cmd->data.draw.count; const VertTV *verts = (VertTV *)(vertices + cmd->data.draw.first); const PSP_BlendInfo blendInfo = { @@ -836,7 +850,7 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren PSP_SetBlendMode(data, blendInfo); - prepareTextureForUpload(psp_tex); + prepareTextureForUpload(texture); tbw = psp_tex->swizzled ? psp_tex->textureWidth : psp_tex->width; twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data; @@ -965,7 +979,11 @@ static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) } vfree(psp_tex->swizzledData); - SDL_free(psp_tex->data); + if (texture->access != SDL_TEXTUREACCESS_STATIC) { + vfree(psp_tex->data); + } else { + SDL_free(psp_tex->data); + } SDL_free(psp_tex); texture->driverdata = NULL; } From fd95e72c6778739623244a505b3e80780f0cc680 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sun, 27 Apr 2025 21:40:30 +0200 Subject: [PATCH 21/37] Fix deallocation textures --- src/render/psp/SDL_render_psp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 3847388e971c3..dc1e44826543f 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -978,8 +978,9 @@ static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) return; } - vfree(psp_tex->swizzledData); - if (texture->access != SDL_TEXTUREACCESS_STATIC) { + if (psp_tex->swizzledData) { + vfree(psp_tex->swizzledData); + } else if (texture->access != SDL_TEXTUREACCESS_STATIC) { vfree(psp_tex->data); } else { SDL_free(psp_tex->data); From f8f5c8abeedc6b6169497733bf6cc2f4b18b6317 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Sat, 11 Feb 2023 12:37:59 +0100 Subject: [PATCH 22/37] Render to target looks to work fine now --- src/render/psp/SDL_render_psp.c | 34 +++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index dc1e44826543f..a41109d03f70a 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -45,6 +45,7 @@ typedef struct void *frontbuffer; /**< main screen buffer */ void *backbuffer; /**< buffer presented to display */ uint8_t drawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ + uint8_t currentDrawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ uint64_t drawColor; PSP_BlendInfo blendInfo; /**< current blend info */ uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ @@ -184,6 +185,16 @@ static inline int calculatePitchForTextureFormat(int width, int format) } } +static inline int calculatePitchForTextureFormatAndAccess(int width, int format, int access) +{ + if (access == SDL_TEXTUREACCESS_TARGET) { + // Round up to 64 bytes because it is required to be used by sceGuDrawBufferList + return (width + 63) & ~63; + } else { + return calculatePitchForTextureFormat(width, format); + } +} + static inline int calculateHeightForSwizzledTexture(int height, int format) { switch (format) { @@ -215,7 +226,7 @@ static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const // We split in blocks of (64 x destiny height) when 16 bits per color // or (32 x destiny height) when 32 bits per color - switch (data->drawBufferFormat) { + switch (data->currentDrawBufferFormat) { case GU_PSM_5650: case GU_PSM_5551: case GU_PSM_4444: @@ -384,7 +395,7 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) psp_tex->format = pixelFormatToPSPFMT(texture->format); psp_tex->textureWidth = calculateNextPow2(texture->w); psp_tex->textureHeight = calculateNextPow2(texture->h); - psp_tex->width = calculatePitchForTextureFormat(texture->w, psp_tex->format); + psp_tex->width = calculatePitchForTextureFormatAndAccess(texture->w, psp_tex->format, texture->access); psp_tex->height = texture->h; psp_tex->pitch = psp_tex->width * SDL_BYTESPERPIXEL(texture->format); psp_tex->swizzledWidth = psp_tex->textureWidth; @@ -476,6 +487,22 @@ static void PSP_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture psp_tex->filter = guScaleMode; } +static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) +{ + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + + if (texture) { + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; + sceGuDrawBufferList(psp_tex->format, vrelptr(psp_tex->data), psp_tex->width); + data->currentDrawBufferFormat = psp_tex->format; + } else { + sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); + data->currentDrawBufferFormat = data->drawBufferFormat; + } + + return 0; +} + static int PSP_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { return 0; /* nothing to do in this backend. */ @@ -1037,6 +1064,7 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 // Forcing for now using GU_PSM_4444 data->drawBufferFormat = GU_PSM_4444; + data->currentDrawBufferFormat = data->drawBufferFormat; /* Specific GU init */ bufferSize = getMemorySize(PSP_FRAME_BUFFER_WIDTH, PSP_SCREEN_HEIGHT, data->drawBufferFormat); @@ -1048,6 +1076,7 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 sceGuStart(GU_DIRECT, list); sceGuDrawBuffer(data->drawBufferFormat, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); + sceGuDepthBuffer(vrelptr(data->backbuffer), 0); // Set the depth buffer to the same space as the framebuffer sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1)); sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); @@ -1084,6 +1113,7 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 renderer->LockTexture = PSP_LockTexture; renderer->UnlockTexture = PSP_UnlockTexture; renderer->SetTextureScaleMode = PSP_SetTextureScaleMode; + renderer->SetRenderTarget = PSP_SetRenderTarget; renderer->QueueSetViewport = PSP_QueueSetViewport; renderer->QueueSetDrawColor = PSP_QueueSetViewport; renderer->QueueDrawPoints = PSP_QueueDrawPoints; From 8f236337445b3308adc9c290890adcf7ed7d4e70 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Tue, 21 Feb 2023 00:06:47 +0100 Subject: [PATCH 23/37] Make screen buffer format based on windows pixel format --- src/render/psp/SDL_render_psp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index a41109d03f70a..5fd4eef9748b9 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -1062,8 +1062,7 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 // flush cache so that no stray data remains sceKernelDcacheWritebackAll(); - // Forcing for now using GU_PSM_4444 - data->drawBufferFormat = GU_PSM_4444; + data->drawBufferFormat = pixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window));; data->currentDrawBufferFormat = data->drawBufferFormat; /* Specific GU init */ From 74e76efe1cd898fc279bf56ee23d47bf16824c2c Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Tue, 21 Feb 2023 00:13:55 +0100 Subject: [PATCH 24/37] Improving logic when a single slice is needed --- src/render/psp/SDL_render_psp.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 5fd4eef9748b9..faaa0c727ab50 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -246,9 +246,28 @@ static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const return 0; } +static inline void fillSingleSliceVertices(VertTV *vertices, const SDL_Rect *srcrect, const SDL_FRect *dstrect) { + vertices[0].x = dstrect->x; + vertices[0].y = dstrect->y; + vertices[0].z = 0.0f; + vertices[0].u = srcrect->x; + vertices[0].v = srcrect->y; + + vertices[1].x = dstrect->x + dstrect->w; + vertices[1].y = dstrect->y + dstrect->h; + vertices[1].z = 0.0f; + vertices[1].u = srcrect->x + srcrect->w; + vertices[1].v = srcrect->y + srcrect->h; +} + static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, const SDL_Rect *srcrect, const SDL_FRect *dstrect) { + // For avoiding division by zero + if (dimensions->width == 1 && dimensions->height == 1) { + fillSingleSliceVertices((VertV *)vertices, srcrect, dstrect); + return; + } int i, j; int remainingWidth = (int)dstrect->w % sliceSize->width; int remainingHeight = (int)dstrect->h % sliceSize->height; From e8d7fad1d7261b3c50133224500f4d6b44f1b06c Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Tue, 21 Feb 2023 00:16:18 +0100 Subject: [PATCH 25/37] Applying trick for Alpha in 5551 --- src/render/psp/SDL_render_psp.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index faaa0c727ab50..973bb1de76d90 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -514,6 +514,22 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; sceGuDrawBufferList(psp_tex->format, vrelptr(psp_tex->data), psp_tex->width); data->currentDrawBufferFormat = psp_tex->format; + + if(psp_tex->format == GU_PSM_5551) { + sceGuEnable(GU_STENCIL_TEST); + sceGuStencilOp(GU_REPLACE, GU_REPLACE, GU_REPLACE); + sceGuStencilFunc(GU_GEQUAL, 0xff, 0xff); + sceGuEnable(GU_ALPHA_TEST); + sceGuAlphaFunc(GU_GREATER, 0x00, 0xff); + } else { + sceGuDisable(GU_STENCIL_TEST); + sceGuDisable(GU_ALPHA_TEST); + } + + //Enable scissor to avoid drawing outside viewport + sceGuEnable(GU_SCISSOR_TEST); + sceGuScissor(0,0,psp_tex->width, psp_tex->height); + } else { sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); data->currentDrawBufferFormat = data->drawBufferFormat; From 0aefe48de1a90663f00656b7960e08fc7fd0048e Mon Sep 17 00:00:00 2001 From: Wouter Wijsman Date: Fri, 14 Jun 2024 17:15:33 +0200 Subject: [PATCH 26/37] Fix build errors and warnings --- src/render/psp/SDL_render_psp.c | 48 ++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 973bb1de76d90..4fdb4a109342c 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -54,8 +54,8 @@ typedef struct typedef struct { - void *data; /**< Image data. */ - void *swizzledData; /**< Swizzled image data. */ + void *data; /**< Image data. */ + void *swizzledData; /**< Swizzled image data. */ uint32_t textureWidth; /**< Texture width (power of two). */ uint32_t textureHeight; /**< Texture height (power of two). */ uint32_t width; /**< Image width. */ @@ -66,9 +66,9 @@ typedef struct uint32_t swizzledPitch; /**< Swizzled image pitch. */ uint32_t size; /**< Image size in bytes. */ uint32_t swizzledSize; /**< Swizzled image size in bytes. */ - uint8_t format; /**< Image format - one of ::pgePixelFormat. */ - uint8_t filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ - uint8_t swizzled; /**< Whether the image is swizzled or not. */ + uint8_t format; /**< Image format - one of ::pgePixelFormat. */ + uint8_t filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ + uint8_t swizzled; /**< Whether the image is swizzled or not. */ } PSP_Texture; @@ -263,22 +263,30 @@ static inline void fillSingleSliceVertices(VertTV *vertices, const SDL_Rect *src static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, const SDL_Rect *srcrect, const SDL_FRect *dstrect) { + + int i, j; + int remainingWidth, remainingHeight; + int hasRemainingWidth, hasRemainingHeight; + float srcrectRateWidth, srcrectRateHeight; + float srcWidth, srcHeight; + float remainingSrcWidth, remainingSrcHeight; + // For avoiding division by zero if (dimensions->width == 1 && dimensions->height == 1) { - fillSingleSliceVertices((VertV *)vertices, srcrect, dstrect); + fillSingleSliceVertices(vertices, srcrect, dstrect); return; } - int i, j; - int remainingWidth = (int)dstrect->w % sliceSize->width; - int remainingHeight = (int)dstrect->h % sliceSize->height; - int hasRemainingWidth = remainingWidth > 0; - int hasRemainingHeight = remainingHeight > 0; - float srcrectRateWidth = (float)(abs(srcrect->w - dimensions->width)) / (float)(abs(dstrect->w - dimensions->width)); - float srcrectRateHeight = (float)(abs(srcrect->h - dimensions->height)) / (float)(abs(dstrect->h - dimensions->height)); - float srcWidth = sliceSize->width * srcrectRateWidth; - float srcHeight = sliceSize->height * srcrectRateHeight; - float remainingSrcWidth = remainingWidth * srcrectRateWidth; - float remainingSrcHeight = remainingHeight * srcrectRateHeight; + + remainingWidth = (int)dstrect->w % sliceSize->width; + remainingHeight = (int)dstrect->h % sliceSize->height; + hasRemainingWidth = remainingWidth > 0; + hasRemainingHeight = remainingHeight > 0; + srcrectRateWidth = (float)(abs(srcrect->w - dimensions->width)) / (float)(abs(dstrect->w - dimensions->width)); + srcrectRateHeight = (float)(abs(srcrect->h - dimensions->height)) / (float)(abs(dstrect->h - dimensions->height)); + srcWidth = sliceSize->width * srcrectRateWidth; + srcHeight = sliceSize->height * srcrectRateHeight; + remainingSrcWidth = remainingWidth * srcrectRateWidth; + remainingSrcHeight = remainingHeight * srcrectRateHeight; for (i = 0; i < dimensions->width; i++) { for (j = 0; j < dimensions->height; j++) { @@ -824,7 +832,8 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL PSP_SetBlendMode(data, blendInfo); if (texture) { - uint32_t tbw, twp; + uint32_t tbw; + void *twp; const VertTCV *verts = (VertTCV *)(vertices + cmd->data.draw.first); PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; @@ -899,7 +908,8 @@ static inline int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_R static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { - uint32_t tbw, twp; + uint32_t tbw; + void *twp; PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; SDL_Texture *texture = cmd->data.draw.texture; PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; From 22e9495b364a860a9c53a044025ecd4c6da8981e Mon Sep 17 00:00:00 2001 From: Wouter Wijsman Date: Fri, 14 Jun 2024 16:58:42 +0200 Subject: [PATCH 27/37] Do less calculations in PSP_LockTexture --- src/render/psp/SDL_render_psp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 4fdb4a109342c..e7ac003379563 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -460,9 +460,9 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, prepareTextureForDownload(texture); *pixels = - (void *)((Uint8 *)psp_tex->data + rect->y * psp_tex->width * SDL_BYTESPERPIXEL(texture->format) + + (void *)((Uint8 *)psp_tex->data + rect->y * psp_tex->pitch + rect->x * SDL_BYTESPERPIXEL(texture->format)); - *pitch = psp_tex->width * SDL_BYTESPERPIXEL(texture->format); + *pitch = psp_tex->pitch; return 0; } From 16810a16a183cb8ad5af42cc1a7a4fb9a7b56dd9 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 28 Apr 2025 16:45:27 +0200 Subject: [PATCH 28/37] Fast clear --- src/render/psp/SDL_render_psp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index e7ac003379563..a19a3b297f9aa 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -813,8 +813,7 @@ static inline int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd colorA = cmd->data.color.a; sceGuClearColor(GU_RGBA(colorR, colorG, colorB, colorA)); - sceGuClearDepth(0); - sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); + sceGuClear(GU_FAST_CLEAR_BIT|GU_COLOR_BUFFER_BIT); return 0; } From b958d67a8c211c2e041d160962ca5a7a2e69f89d Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Mon, 19 Aug 2024 16:26:35 +0200 Subject: [PATCH 29/37] Improve CPU&GPU parallelization --- src/render/psp/SDL_render_psp.c | 43 +++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index a19a3b297f9aa..5ec6cb0415e55 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -32,7 +32,7 @@ #include #include -static unsigned int __attribute__((aligned(16))) list[262144]; +#define GPU_LIST_SIZE 256 * 1024 typedef struct { @@ -42,13 +42,14 @@ typedef struct typedef struct { + uint32_t __attribute__((aligned(16))) guList[2][GPU_LIST_SIZE]; void *frontbuffer; /**< main screen buffer */ void *backbuffer; /**< buffer presented to display */ + PSP_BlendInfo blendInfo; /**< current blend info */ uint8_t drawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ uint8_t currentDrawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ - uint64_t drawColor; - PSP_BlendInfo blendInfo; /**< current blend info */ uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ + uint8_t list_idx; SDL_bool vblank_not_reached; /**< whether vblank wasn't reached */ } PSP_RenderData; @@ -69,7 +70,6 @@ typedef struct uint8_t format; /**< Image format - one of ::pgePixelFormat. */ uint8_t filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ uint8_t swizzled; /**< Whether the image is swizzled or not. */ - } PSP_Texture; typedef struct @@ -539,7 +539,7 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) sceGuScissor(0,0,psp_tex->width, psp_tex->height); } else { - sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); + sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); data->currentDrawBufferFormat = data->drawBufferFormat; } @@ -1018,8 +1018,12 @@ static int PSP_RenderPresent(SDL_Renderer *renderer) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - sceGuFinish(); - sceGuSync(0,0); + int g_packet_size = sceGuFinish(); + void *pkt = data->guList[data->list_idx]; + SDL_assert(g_packet_size < GPU_LIST_SIZE); + sceKernelDcacheWritebackRange(pkt, g_packet_size) ; + + sceGuSync(GU_SYNC_FINISH, GU_SYNC_WHAT_DONE); if (((data->vsync == 2) && (data->vblank_not_reached)) || // Dynamic (data->vsync == 1)) { // Normal VSync @@ -1030,8 +1034,14 @@ static int PSP_RenderPresent(SDL_Renderer *renderer) data->backbuffer = data->frontbuffer; data->frontbuffer = vabsptr(sceGuSwapBuffers()); + // Send the packet to the GPU + sceGuSendList(GU_TAIL, data->guList[data->list_idx], NULL); + // Starting a new frame - sceGuStart(GU_DIRECT,list); + data->list_idx = (data->list_idx != 0) ? 0 : 1; + + sceGuStart(GU_SEND, data->guList[data->list_idx]); + sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); return 0; } @@ -1093,7 +1103,6 @@ static int PSP_SetVSync(SDL_Renderer *renderer, const int vsync) static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 flags) { PSP_RenderData *data; - void *doublebuffer = NULL; uint32_t bufferSize = 0; SDL_bool dynamicVsync; @@ -1111,15 +1120,13 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 /* Specific GU init */ bufferSize = getMemorySize(PSP_FRAME_BUFFER_WIDTH, PSP_SCREEN_HEIGHT, data->drawBufferFormat); - doublebuffer = vramalloc(bufferSize * 2); - data->backbuffer = doublebuffer; - data->frontbuffer = ((uint8_t *)doublebuffer) + bufferSize; + data->frontbuffer = vramalloc(bufferSize); + data->backbuffer = vramalloc(bufferSize); sceGuInit(); - sceGuStart(GU_DIRECT, list); + sceGuStart(GU_DIRECT, data->guList[0]); sceGuDrawBuffer(data->drawBufferFormat, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); - sceGuDepthBuffer(vrelptr(data->backbuffer), 0); // Set the depth buffer to the same space as the framebuffer sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1)); sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); @@ -1130,12 +1137,16 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 sceGuEnable(GU_SCISSOR_TEST); sceGuFinish(); - sceGuSync(0,0); + sceGuSync(GU_SYNC_FINISH, GU_SYNC_WHAT_DONE); sceDisplayWaitVblankStart(); sceGuDisplay(GU_TRUE); - sceGuStart(GU_DIRECT,list); + // Starting the first frame + data->list_idx = 0; + + sceGuStart(GU_SEND, data->guList[data->list_idx]); + sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); // Clear the screen sceGuClearColor(0); From 0ee1c2b903f25d5569015dc3c2b2362cdc9a4aba Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Wed, 2 Jul 2025 16:40:15 +0200 Subject: [PATCH 30/37] Applying formatter --- src/render/psp/SDL_render_psp.c | 204 +++++++++++++++----------------- 1 file changed, 98 insertions(+), 106 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 5ec6cb0415e55..b1c3c2b9a8f67 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -26,75 +26,75 @@ #include "SDL_hints.h" #include "SDL_render_psp.h" +#include #include #include -#include #include -#include +#include #define GPU_LIST_SIZE 256 * 1024 typedef struct { - uint8_t shade; /**< GU_FLAT or GU_SMOOTH */ - uint8_t mode; /**< GU_ADD, GU_SUBTRACT, GU_REVERSE_SUBTRACT, GU_MIN, GU_MAX */ + uint8_t shade; /**< GU_FLAT or GU_SMOOTH */ + uint8_t mode; /**< GU_ADD, GU_SUBTRACT, GU_REVERSE_SUBTRACT, GU_MIN, GU_MAX */ } PSP_BlendInfo; typedef struct { uint32_t __attribute__((aligned(16))) guList[2][GPU_LIST_SIZE]; - void *frontbuffer; /**< main screen buffer */ - void *backbuffer; /**< buffer presented to display */ - PSP_BlendInfo blendInfo; /**< current blend info */ - uint8_t drawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ - uint8_t currentDrawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ - uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ + void *frontbuffer; /**< main screen buffer */ + void *backbuffer; /**< buffer presented to display */ + PSP_BlendInfo blendInfo; /**< current blend info */ + uint8_t drawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ + uint8_t currentDrawBufferFormat; /**< GU_PSM_8888 or GU_PSM_5650 or GU_PSM_4444 */ + uint8_t vsync; /* 0 (Disabled), 1 (Enabled), 2 (Dynamic) */ uint8_t list_idx; SDL_bool vblank_not_reached; /**< whether vblank wasn't reached */ } PSP_RenderData; typedef struct { - void *data; /**< Image data. */ - void *swizzledData; /**< Swizzled image data. */ - uint32_t textureWidth; /**< Texture width (power of two). */ - uint32_t textureHeight; /**< Texture height (power of two). */ - uint32_t width; /**< Image width. */ - uint32_t height; /**< Image height. */ - uint32_t pitch; /**< Image pitch. */ - uint32_t swizzledWidth; /**< Swizzled image width. */ - uint32_t swizzledHeight;/**< Swizzled image height. */ - uint32_t swizzledPitch; /**< Swizzled image pitch. */ - uint32_t size; /**< Image size in bytes. */ - uint32_t swizzledSize; /**< Swizzled image size in bytes. */ - uint8_t format; /**< Image format - one of ::pgePixelFormat. */ - uint8_t filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ - uint8_t swizzled; /**< Whether the image is swizzled or not. */ + void *data; /**< Image data. */ + void *swizzledData; /**< Swizzled image data. */ + uint32_t textureWidth; /**< Texture width (power of two). */ + uint32_t textureHeight; /**< Texture height (power of two). */ + uint32_t width; /**< Image width. */ + uint32_t height; /**< Image height. */ + uint32_t pitch; /**< Image pitch. */ + uint32_t swizzledWidth; /**< Swizzled image width. */ + uint32_t swizzledHeight; /**< Swizzled image height. */ + uint32_t swizzledPitch; /**< Swizzled image pitch. */ + uint32_t size; /**< Image size in bytes. */ + uint32_t swizzledSize; /**< Swizzled image size in bytes. */ + uint8_t format; /**< Image format - one of ::pgePixelFormat. */ + uint8_t filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */ + uint8_t swizzled; /**< Whether the image is swizzled or not. */ } PSP_Texture; typedef struct { float x, y, z; -} __attribute__ ((packed)) VertV; +} __attribute__((packed)) VertV; typedef struct { SDL_Color col; float x, y, z; -} __attribute__ ((packed)) VertCV; +} __attribute__((packed)) VertCV; typedef struct { float u, v; SDL_Color col; float x, y, z; -} __attribute__ ((packed)) VertTCV; +} __attribute__((packed)) VertTCV; typedef struct { float u, v; float x, y, z; -} __attribute__ ((packed)) VertTV; +} __attribute__((packed)) VertTV; typedef struct { @@ -102,8 +102,7 @@ typedef struct int height; } SliceSize; - -int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void** out) +int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void **out) { PSP_RenderData *rd; if (r == NULL) { @@ -111,16 +110,15 @@ int SDL_PSP_RenderGetProp(SDL_Renderer *r, enum SDL_PSP_RenderProps which, void* } 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; + case SDL_PSP_RENDERPROPS_FRONTBUFFER: + *out = rd->frontbuffer; + return 0; + case SDL_PSP_RENDERPROPS_BACKBUFFER: + *out = rd->backbuffer; + return 0; } return -1; } -static int vsync_sema_id = 0; /* PRIVATE METHODS */ static void psp_on_vblank(u32 sub, PSP_RenderData *data) @@ -132,27 +130,26 @@ static void psp_on_vblank(u32 sub, PSP_RenderData *data) static inline unsigned int getMemorySize(unsigned int width, unsigned int height, unsigned int psm) { - switch (psm) - { - case GU_PSM_T4: - return (width * height) >> 1; - - case GU_PSM_T8: - return width * height; - - case GU_PSM_5650: - case GU_PSM_5551: - case GU_PSM_4444: - case GU_PSM_T16: - return 2 * width * height; - - case GU_PSM_8888: - case GU_PSM_T32: - return 4 * width * height; - - default: - return 0; - } + switch (psm) { + case GU_PSM_T4: + return (width * height) >> 1; + + case GU_PSM_T8: + return width * height; + + case GU_PSM_5650: + case GU_PSM_5551: + case GU_PSM_4444: + case GU_PSM_T16: + return 2 * width * height; + + case GU_PSM_8888: + case GU_PSM_T32: + return 4 * width * height; + + default: + return 0; + } } static inline int pixelFormatToPSPFMT(Uint32 format) @@ -219,7 +216,7 @@ static inline int calculateNextPow2(int value) return i; } -static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const SDL_FRect *dstrect, SliceSize *sliceSize, SliceSize *sliceDimension) +static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const SDL_FRect *dstrect, SliceSize *sliceSize, SliceSize *sliceDimension) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; @@ -230,23 +227,24 @@ static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const case GU_PSM_5650: case GU_PSM_5551: case GU_PSM_4444: - sliceSize->width = dstrect->w > 64 ? 64: dstrect->w; + sliceSize->width = dstrect->w > 64 ? 64 : dstrect->w; break; case GU_PSM_8888: - sliceSize->width = dstrect->w > 32 ? 32: dstrect->w; + sliceSize->width = dstrect->w > 32 ? 32 : dstrect->w; break; default: return -1; } sliceSize->height = dstrect->h; - + sliceDimension->width = SDL_ceilf(dstrect->w / sliceSize->width); sliceDimension->height = SDL_ceilf(dstrect->h / sliceSize->height); return 0; } -static inline void fillSingleSliceVertices(VertTV *vertices, const SDL_Rect *srcrect, const SDL_FRect *dstrect) { +static inline void fillSingleSliceVertices(VertTV *vertices, const SDL_Rect *srcrect, const SDL_FRect *dstrect) +{ vertices[0].x = dstrect->x; vertices[0].y = dstrect->y; vertices[0].z = 0.0f; @@ -261,7 +259,7 @@ static inline void fillSingleSliceVertices(VertTV *vertices, const SDL_Rect *src } static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize, - const SDL_Rect *srcrect, const SDL_FRect *dstrect) + const SDL_Rect *srcrect, const SDL_FRect *dstrect) { int i, j; @@ -281,7 +279,7 @@ static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, S remainingHeight = (int)dstrect->h % sliceSize->height; hasRemainingWidth = remainingWidth > 0; hasRemainingHeight = remainingHeight > 0; - srcrectRateWidth = (float)(abs(srcrect->w - dimensions->width)) / (float)(abs(dstrect->w - dimensions->width)); + srcrectRateWidth = (float)(abs(srcrect->w - dimensions->width)) / (float)(abs(dstrect->w - dimensions->width)); srcrectRateHeight = (float)(abs(srcrect->h - dimensions->height)) / (float)(abs(dstrect->h - dimensions->height)); srcWidth = sliceSize->width * srcrectRateWidth; srcHeight = sliceSize->height * srcrectRateHeight; @@ -304,7 +302,7 @@ static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, S vertices[currentIndex + 1].u = vertices[currentIndex].u + srcWidth; vertices[currentIndex + 1].x = vertices[currentIndex].x + sliceSize->width; } - + if (j == dimensions->height - 1 && hasRemainingHeight) { vertices[currentIndex + 1].v = vertices[currentIndex].v + remainingSrcHeight; vertices[currentIndex + 1].y = vertices[currentIndex].y + remainingHeight; @@ -340,7 +338,7 @@ static inline int swizzle(PSP_Texture *psp_tex) memcpy(dstBlock, srcBlock, blockSizeBytes); } } - + return 1; } @@ -364,16 +362,16 @@ static inline int unswizzle(PSP_Texture *psp_tex) memcpy(dstBlock, srcBlock, blockSizeBytes); } } - + return 1; } static inline void prepareTextureForUpload(SDL_Texture *texture) { PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; - if (texture->access != SDL_TEXTUREACCESS_STATIC || psp_tex->swizzled ) + if (texture->access != SDL_TEXTUREACCESS_STATIC || psp_tex->swizzled) return; - + psp_tex->swizzledData = vramalloc(psp_tex->swizzledSize); if (!psp_tex->swizzledData) { sceKernelDcacheWritebackRange(psp_tex->data, psp_tex->size); @@ -393,7 +391,7 @@ static inline void prepareTextureForDownload(SDL_Texture *texture) if (texture->access != SDL_TEXTUREACCESS_STATIC || !psp_tex->swizzled) return; - + psp_tex->data = SDL_malloc(psp_tex->size); if (!psp_tex->data) { sceKernelDcacheInvalidateRange(psp_tex->swizzledData, psp_tex->swizzledSize); @@ -509,8 +507,8 @@ static void PSP_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture or GU_LINEAR (good for scaling) */ uint32_t guScaleMode = (scaleMode == SDL_ScaleModeNearest - ? GU_NEAREST - : GU_LINEAR); + ? GU_NEAREST + : GU_LINEAR); psp_tex->filter = guScaleMode; } @@ -523,7 +521,7 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) sceGuDrawBufferList(psp_tex->format, vrelptr(psp_tex->data), psp_tex->width); data->currentDrawBufferFormat = psp_tex->format; - if(psp_tex->format == GU_PSM_5551) { + if (psp_tex->format == GU_PSM_5551) { sceGuEnable(GU_STENCIL_TEST); sceGuStencilOp(GU_REPLACE, GU_REPLACE, GU_REPLACE); sceGuStencilFunc(GU_GEQUAL, 0xff, 0xff); @@ -534,9 +532,9 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) sceGuDisable(GU_ALPHA_TEST); } - //Enable scissor to avoid drawing outside viewport + // Enable scissor to avoid drawing outside viewport sceGuEnable(GU_SCISSOR_TEST); - sceGuScissor(0,0,psp_tex->width, psp_tex->height); + sceGuScissor(0, 0, psp_tex->width, psp_tex->height); } else { sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); @@ -583,8 +581,8 @@ static int PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL size_indices = indices ? size_indices : 0; if (texture) { - VertTCV *vertices = (VertTCV *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertTCV), 4, &cmd->data.draw.first); - PSP_Texture *psp_tex = (PSP_Texture *) texture->driverdata; + VertTCV *vertices = (VertTCV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertTCV), 4, &cmd->data.draw.first); + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; if (!vertices) { return -1; @@ -699,12 +697,12 @@ static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Tex if (calculateBestSliceSizeForSprite(renderer, dstrect, &sliceSize, &sliceDimension)) return -1; - + verticesCount = sliceDimension.width * sliceDimension.height * 2; verts = (VertTV *)SDL_AllocateRenderVertices(renderer, verticesCount * sizeof(VertTV), 4, &cmd->data.draw.first); if (verts == NULL) return -1; - + fillSpriteVertices(verts, &sliceDimension, &sliceSize, srcrect, dstrect); cmd->data.draw.count = verticesCount; @@ -765,7 +763,7 @@ static void PSP_SetBlendMode(PSP_RenderData *data, PSP_BlendInfo blendInfo) break; } } - + data->blendInfo.mode = blendInfo.mode; } @@ -813,7 +811,7 @@ static inline int PSP_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd colorA = cmd->data.color.a; sceGuClearColor(GU_RGBA(colorR, colorG, colorB, colorA)); - sceGuClear(GU_FAST_CLEAR_BIT|GU_COLOR_BUFFER_BIT); + sceGuClear(GU_FAST_CLEAR_BIT | GU_COLOR_BUFFER_BIT); return 0; } @@ -834,7 +832,7 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL uint32_t tbw; void *twp; const VertTCV *verts = (VertTCV *)(vertices + cmd->data.draw.first); - + PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; prepareTextureForUpload(texture); @@ -888,7 +886,6 @@ static inline int PSP_RenderFillRects(SDL_Renderer *renderer, void *vertices, SD return 0; } - static inline int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; @@ -933,7 +930,7 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); - return 0; + return 0; } static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) @@ -955,7 +952,6 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v case SDL_RENDERCMD_SETVIEWPORT: { PSP_RenderSetViewPort(renderer, cmd); - /* FIXME: We need to update the clip rect too, see https://github.com/libsdl-org/SDL/issues/9094 */ break; } case SDL_RENDERCMD_SETCLIPRECT: @@ -1021,12 +1017,12 @@ static int PSP_RenderPresent(SDL_Renderer *renderer) int g_packet_size = sceGuFinish(); void *pkt = data->guList[data->list_idx]; SDL_assert(g_packet_size < GPU_LIST_SIZE); - sceKernelDcacheWritebackRange(pkt, g_packet_size) ; + sceKernelDcacheWritebackRange(pkt, g_packet_size); sceGuSync(GU_SYNC_FINISH, GU_SYNC_WHAT_DONE); if (((data->vsync == 2) && (data->vblank_not_reached)) || // Dynamic - (data->vsync == 1)) { // Normal VSync + (data->vsync == 1)) { // Normal VSync sceDisplayWaitVblankStart(); } data->vblank_not_reached = SDL_TRUE; @@ -1085,11 +1081,6 @@ static void PSP_DestroyRenderer(SDL_Renderer *renderer) SDL_free(data); } - - if (vsync_sema_id >= 0) { - // DeleteSema(vsync_sema_id); - } - } static int PSP_SetVSync(SDL_Renderer *renderer, const int vsync) @@ -1115,7 +1106,8 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 // flush cache so that no stray data remains sceKernelDcacheWritebackAll(); - data->drawBufferFormat = pixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window));; + data->drawBufferFormat = pixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window)); + ; data->currentDrawBufferFormat = data->drawBufferFormat; /* Specific GU init */ @@ -1127,27 +1119,27 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 sceGuStart(GU_DIRECT, data->guList[0]); sceGuDrawBuffer(data->drawBufferFormat, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); - + sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1)); sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); - + sceGuDisable(GU_DEPTH_TEST); - sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); - sceGuEnable(GU_SCISSOR_TEST); - - sceGuFinish(); - sceGuSync(GU_SYNC_FINISH, GU_SYNC_WHAT_DONE); + sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); + sceGuEnable(GU_SCISSOR_TEST); + + sceGuFinish(); + sceGuSync(GU_SYNC_FINISH, GU_SYNC_WHAT_DONE); - sceDisplayWaitVblankStart(); - sceGuDisplay(GU_TRUE); + sceDisplayWaitVblankStart(); + sceGuDisplay(GU_TRUE); // Starting the first frame data->list_idx = 0; sceGuStart(GU_SEND, data->guList[data->list_idx]); sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); - + // Clear the screen sceGuClearColor(0); sceGuClear(GU_COLOR_BUFFER_BIT); @@ -1191,7 +1183,7 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 SDL_RenderDriver PSP_RenderDriver = { .CreateRenderer = PSP_CreateRenderer, .info = { - .name = "PSP GU", + .name = "PSP_GU", .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, .num_texture_formats = 4, .texture_formats = { From 3ac816ab085005b1aadc279181da43790f03dc8b Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Wed, 2 Jul 2025 17:14:24 +0200 Subject: [PATCH 31/37] forcing fast-math in the Cmake --- CMakeLists.txt | 1 + src/render/psp/SDL_render_psp.c | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea2368cdfe9aa..ebf15d6b8bf70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2666,6 +2666,7 @@ elseif(VITA) # CheckPTHREAD() elseif(PSP) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsingle-precision-constant -ffast-math") file(GLOB PSP_MAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/psp/*.c) list(APPEND SDLMAIN_SOURCES ${PSP_MAIN_SOURCES}) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index b1c3c2b9a8f67..c3fe565f285a5 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -727,42 +727,32 @@ static void PSP_SetBlendMode(PSP_RenderData *data, PSP_BlendInfo blendInfo) if (data->blendInfo.mode != blendInfo.mode) { switch (blendInfo.mode) { case SDL_BLENDMODE_NONE: - { sceGuShadeModel(GU_SMOOTH); sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); sceGuDisable(GU_BLEND); break; - } case SDL_BLENDMODE_BLEND: - { sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); sceGuEnable(GU_BLEND); break; - } case SDL_BLENDMODE_ADD: - { sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF); sceGuEnable(GU_BLEND); break; - } case SDL_BLENDMODE_MOD: - { sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); sceGuEnable(GU_BLEND); break; - } case SDL_BLENDMODE_MUL: - { sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); /* FIXME SDL_BLENDMODE_MUL is simplified, and dstA is in fact un-changed.*/ sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); sceGuEnable(GU_BLEND); break; } - } data->blendInfo.mode = blendInfo.mode; } From 72cb8391e35b4d8028b1694bcd408c145a647cc1 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Wed, 2 Jul 2025 17:58:34 +0200 Subject: [PATCH 32/37] Inline blendmode --- src/render/psp/SDL_render_psp.c | 88 ++++++++++++++++----------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index c3fe565f285a5..ee122facc0279 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -405,6 +405,49 @@ static inline void prepareTextureForDownload(SDL_Texture *texture) sceKernelDcacheInvalidateRange(psp_tex->data, psp_tex->size); } +static inline void PSP_SetBlendMode(PSP_RenderData *data, PSP_BlendInfo blendInfo) +{ + // Update the blend mode if necessary + if (data->blendInfo.mode != blendInfo.mode) { + switch (blendInfo.mode) { + case SDL_BLENDMODE_NONE: + sceGuShadeModel(GU_SMOOTH); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); + sceGuDisable(GU_BLEND); + break; + case SDL_BLENDMODE_BLEND: + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuEnable(GU_BLEND); + break; + case SDL_BLENDMODE_ADD: + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF); + sceGuEnable(GU_BLEND); + break; + case SDL_BLENDMODE_MOD: + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); + sceGuEnable(GU_BLEND); + break; + case SDL_BLENDMODE_MUL: + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + /* FIXME SDL_BLENDMODE_MUL is simplified, and dstA is in fact un-changed.*/ + sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuEnable(GU_BLEND); + break; + } + + data->blendInfo.mode = blendInfo.mode; + } + + // Update shade model if needed + if (data->blendInfo.shade != blendInfo.shade) { + sceGuShadeModel(blendInfo.shade); + data->blendInfo.shade = blendInfo.shade; + } +} + static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) { } @@ -710,7 +753,7 @@ static int PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Tex return 0; } -static int PSP_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +static inline int PSP_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { const SDL_Rect *viewport = &cmd->data.viewport.rect; @@ -721,49 +764,6 @@ static int PSP_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd) return 0; } -static void PSP_SetBlendMode(PSP_RenderData *data, PSP_BlendInfo blendInfo) -{ - // Update the blend mode if necessary - if (data->blendInfo.mode != blendInfo.mode) { - switch (blendInfo.mode) { - case SDL_BLENDMODE_NONE: - sceGuShadeModel(GU_SMOOTH); - sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); - sceGuDisable(GU_BLEND); - break; - case SDL_BLENDMODE_BLEND: - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); - sceGuEnable(GU_BLEND); - break; - case SDL_BLENDMODE_ADD: - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF); - sceGuEnable(GU_BLEND); - break; - case SDL_BLENDMODE_MOD: - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); - sceGuEnable(GU_BLEND); - break; - case SDL_BLENDMODE_MUL: - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - /* FIXME SDL_BLENDMODE_MUL is simplified, and dstA is in fact un-changed.*/ - sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); - sceGuEnable(GU_BLEND); - break; - } - - data->blendInfo.mode = blendInfo.mode; - } - - // Update shade model if needed - if (data->blendInfo.shade != blendInfo.shade) { - sceGuShadeModel(blendInfo.shade); - data->blendInfo.shade = blendInfo.shade; - } -} - static inline int PSP_RenderSetClipRect(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { const SDL_Rect *rect = &cmd->data.cliprect.rect; From ae3f7648007080c5cbf1bba5969e604de4906209 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Thu, 3 Jul 2025 13:22:24 +0200 Subject: [PATCH 33/37] Improving flushing --- src/render/psp/SDL_render_psp.c | 36 ++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index ee122facc0279..8f2d8cac4dcfd 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -923,6 +923,25 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren return 0; } +static inline void PSP_SendQueueToGPU(SDL_Renderer *renderer) { + PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; + + int g_packet_size = sceGuFinish(); + void *pkt = data->guList[data->list_idx]; + SDL_assert(g_packet_size < GPU_LIST_SIZE); + sceKernelDcacheWritebackRange(pkt, g_packet_size); + + sceGuSync(GU_SYNC_SEND, GU_SYNC_WHAT_DONE); + + // Send the packet to the GPU + sceGuSendList(GU_TAIL, data->guList[data->list_idx], NULL); + + // Starting a new list + data->list_idx = (data->list_idx != 0) ? 0 : 1; + + sceGuStart(GU_SEND, data->guList[data->list_idx]); +} + static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) { /* note that before the renderer interface change, this would do extrememly small @@ -991,6 +1010,9 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v } cmd = cmd->next; } + + PSP_SendQueueToGPU(renderer); + return 0; } @@ -1004,13 +1026,6 @@ static int PSP_RenderPresent(SDL_Renderer *renderer) { PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata; - int g_packet_size = sceGuFinish(); - void *pkt = data->guList[data->list_idx]; - SDL_assert(g_packet_size < GPU_LIST_SIZE); - sceKernelDcacheWritebackRange(pkt, g_packet_size); - - sceGuSync(GU_SYNC_FINISH, GU_SYNC_WHAT_DONE); - if (((data->vsync == 2) && (data->vblank_not_reached)) || // Dynamic (data->vsync == 1)) { // Normal VSync sceDisplayWaitVblankStart(); @@ -1020,13 +1035,6 @@ static int PSP_RenderPresent(SDL_Renderer *renderer) data->backbuffer = data->frontbuffer; data->frontbuffer = vabsptr(sceGuSwapBuffers()); - // Send the packet to the GPU - sceGuSendList(GU_TAIL, data->guList[data->list_idx], NULL); - - // Starting a new frame - data->list_idx = (data->list_idx != 0) ? 0 : 1; - - sceGuStart(GU_SEND, data->guList[data->list_idx]); sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); return 0; From 4c4cd67d8acf4b7e0a0b798d551902bbd70d8eb0 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Thu, 3 Jul 2025 13:35:28 +0200 Subject: [PATCH 34/37] use sceGuSignal for assuring thread-safe (CPU & GPU) --- src/render/psp/SDL_render_psp.c | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 8f2d8cac4dcfd..0d8ff556c80d9 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -57,6 +58,7 @@ typedef struct { void *data; /**< Image data. */ void *swizzledData; /**< Swizzled image data. */ + uint32_t semaphore; /**< Semaphore for the texture. */ uint32_t textureWidth; /**< Texture width (power of two). */ uint32_t textureHeight; /**< Texture height (power of two). */ uint32_t width; /**< Image width. */ @@ -128,6 +130,34 @@ static void psp_on_vblank(u32 sub, PSP_RenderData *data) } } +static void psp_on_signal(int id) +{ + sceKernelSignalSema(id, 1); +} + +static inline uint32_t createSemaphore(SDL_Texture *texture) +{ + uint32_t semaphore; + char semaphoreName[31]; + snprintf(semaphoreName, sizeof(semaphoreName), "PSP_Tex_Sem_%p", texture); + semaphore = sceKernelCreateSema(semaphoreName, 0, 1, 1, NULL); + if (semaphore < 0) { + SDL_SetError("Failed to create texture semaphore"); + return -1; + } + return semaphore; +} + +static inline void destroySemaphore(uint32_t semaphore) +{ + if (semaphore != -1) { + // Wait for all threads to finish using the semaphore + sceKernelWaitSema(semaphore, 1, NULL); + sceKernelDeleteSema(semaphore); + semaphore = -1; + } +} + static inline unsigned int getMemorySize(unsigned int width, unsigned int height, unsigned int psm) { switch (psm) { @@ -460,6 +490,10 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return SDL_OutOfMemory(); } + psp_tex->semaphore = createSemaphore(texture); + if (psp_tex->semaphore == -1) { + return SDL_OutOfMemory(); + } psp_tex->format = pixelFormatToPSPFMT(texture->format); psp_tex->textureWidth = calculateNextPow2(texture->w); psp_tex->textureHeight = calculateNextPow2(texture->h); @@ -475,12 +509,14 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) if (texture->access != SDL_TEXTUREACCESS_STATIC) { psp_tex->data = vramalloc(psp_tex->size); if (!psp_tex->data) { + destroySemaphore(psp_tex->semaphore); vfree(psp_tex); return SDL_OutOfMemory(); } } else { psp_tex->data = SDL_calloc(1, psp_tex->size); if (!psp_tex->data) { + destroySemaphore(psp_tex->semaphore); SDL_free(psp_tex); return SDL_OutOfMemory(); } @@ -500,6 +536,7 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, // How a pointer to the texture data is returned it need to be unswizzled before it can be used prepareTextureForDownload(texture); + sceKernelWaitSema(psp_tex->semaphore, 1, NULL); *pixels = (void *)((Uint8 *)psp_tex->data + rect->y * psp_tex->pitch + rect->x * SDL_BYTESPERPIXEL(texture->format)); @@ -513,6 +550,7 @@ static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; sceKernelDcacheWritebackRange(psp_tex->data, psp_tex->size); + sceKernelSignalSema(psp_tex->semaphore, 1); } static int PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, @@ -561,6 +599,7 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) if (texture) { PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata; + sceKernelWaitSema(psp_tex->semaphore, 1, NULL); sceGuDrawBufferList(psp_tex->format, vrelptr(psp_tex->data), psp_tex->width); data->currentDrawBufferFormat = psp_tex->format; @@ -579,6 +618,7 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) sceGuEnable(GU_SCISSOR_TEST); sceGuScissor(0, 0, psp_tex->width, psp_tex->height); + sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore); } else { sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); data->currentDrawBufferFormat = data->drawBufferFormat; @@ -830,12 +870,14 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL tbw = psp_tex->swizzled ? psp_tex->swizzledWidth : psp_tex->width; twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data; + sceKernelWaitSema(psp_tex->semaphore, 1, NULL); sceGuTexMode(psp_tex->format, 0, 0, psp_tex->swizzled); sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, tbw, twp); sceGuTexFilter(psp_tex->filter, psp_tex->filter); sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); + sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore); } else { const VertCV *verts = (VertCV *)(vertices + cmd->data.draw.first); sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); @@ -909,6 +951,9 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren PSP_SetBlendMode(data, blendInfo); prepareTextureForUpload(texture); + // We can't use sceKernelWaitSema here because several consecutive SDL_RenderCopy calls + // could be performed by the user. + sceKernelPollSema(psp_tex->semaphore, 1); tbw = psp_tex->swizzled ? psp_tex->textureWidth : psp_tex->width; twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data; @@ -919,6 +964,7 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); + sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore); return 0; } @@ -1053,6 +1099,8 @@ static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) return; } + destroySemaphore(psp_tex->semaphore); + if (psp_tex->swizzledData) { vfree(psp_tex->swizzledData); } else if (texture->access != SDL_TEXTUREACCESS_STATIC) { @@ -1151,6 +1199,9 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 } data->vblank_not_reached = SDL_TRUE; + // Set the callback for the texture semaphores + sceGuSetCallback(GU_CALLBACK_SIGNAL, psp_on_signal); + renderer->WindowEvent = PSP_WindowEvent; renderer->CreateTexture = PSP_CreateTexture; renderer->UpdateTexture = PSP_UpdateTexture; From f83f2262260557a7bd53dae685268ba5508f0e1d Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Thu, 3 Jul 2025 13:41:51 +0200 Subject: [PATCH 35/37] Using now 3 GPU lists --- src/render/psp/SDL_render_psp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 0d8ff556c80d9..2739500f3e4f0 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -43,7 +43,7 @@ typedef struct typedef struct { - uint32_t __attribute__((aligned(16))) guList[2][GPU_LIST_SIZE]; + uint32_t __attribute__((aligned(16))) guList[3][GPU_LIST_SIZE]; void *frontbuffer; /**< main screen buffer */ void *backbuffer; /**< buffer presented to display */ PSP_BlendInfo blendInfo; /**< current blend info */ @@ -983,7 +983,7 @@ static inline void PSP_SendQueueToGPU(SDL_Renderer *renderer) { sceGuSendList(GU_TAIL, data->guList[data->list_idx], NULL); // Starting a new list - data->list_idx = (data->list_idx != 0) ? 0 : 1; + data->list_idx = (data->list_idx + 1) % 3; sceGuStart(GU_SEND, data->guList[data->list_idx]); } From 5cf2015fff974f58471e5182cc5a4e84ce0285b0 Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Thu, 3 Jul 2025 14:45:44 +0200 Subject: [PATCH 36/37] Use NOWait for scegusignal --- src/render/psp/SDL_render_psp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 2739500f3e4f0..f6113951b0871 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -618,7 +618,7 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) sceGuEnable(GU_SCISSOR_TEST); sceGuScissor(0, 0, psp_tex->width, psp_tex->height); - sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore); + sceGuSignal(GU_SIGNAL_NOWAIT, psp_tex->semaphore); } else { sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); data->currentDrawBufferFormat = data->drawBufferFormat; @@ -877,7 +877,7 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); - sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore); + sceGuSignal(GU_SIGNAL_NOWAIT, psp_tex->semaphore); } else { const VertCV *verts = (VertCV *)(vertices + cmd->data.draw.first); sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); @@ -964,7 +964,7 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); - sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore); + sceGuSignal(GU_SIGNAL_NOWAIT, psp_tex->semaphore); return 0; } From 70bc7b072349f6d415b401f32c77e2abeb8d293e Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Fri, 4 Jul 2025 01:07:32 +0200 Subject: [PATCH 37/37] Read semID from sceGuSignalCallback - Combine 2 consecutive sceGuSignal for sending the semID in 2 calls (higher & lower) bits --- src/render/psp/SDL_render_psp.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index f6113951b0871..38ab727bf9d19 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -130,9 +130,33 @@ static void psp_on_vblank(u32 sub, PSP_RenderData *data) } } +// This is a trick to be able of getting the semaphore ID from the signal callback +// From the value received on the signal callback, we can just use the lower 16 bits +// So in order to get the semaphore ID (which is 32 bits), we have done this trick. +// Where on the sceGuSignalSemaphore we send 2 consecutive signals, one with the high 16 bits +// and the other with the low 16 bits. +// Then on the psp_on_signal we identify if we are reading the high or the low 16 bits +// by using the psp_on_signal_read_high variable. +// So we can get the semaphore ID by combining the high and low 16 bits. +static uint8_t psp_on_signal_read_high = 0; +static uint16_t psp_on_signal_high = 0; static void psp_on_signal(int id) +{ + uint16_t value = id & 0xFFFF; + if (psp_on_signal_read_high) { + uint32_t semaphore = (psp_on_signal_high << 16) | value; + sceKernelSignalSema(semaphore, 1); + psp_on_signal_read_high = 0; + } else { + psp_on_signal_high = value; + psp_on_signal_read_high = 1; + } +} + +static inline void sceGuSignalSemaphore(uint32_t semaphore) { - sceKernelSignalSema(id, 1); + sceGuSignal(GU_SIGNAL_NOWAIT, (semaphore >> 16) & 0xFFFF); + sceGuSignal(GU_SIGNAL_NOWAIT, (semaphore & 0xFFFF)); } static inline uint32_t createSemaphore(SDL_Texture *texture) @@ -618,7 +642,7 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) sceGuEnable(GU_SCISSOR_TEST); sceGuScissor(0, 0, psp_tex->width, psp_tex->height); - sceGuSignal(GU_SIGNAL_NOWAIT, psp_tex->semaphore); + sceGuSignalSemaphore(psp_tex->semaphore); } else { sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); data->currentDrawBufferFormat = data->drawBufferFormat; @@ -877,7 +901,7 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); - sceGuSignal(GU_SIGNAL_NOWAIT, psp_tex->semaphore); + sceGuSignalSemaphore(psp_tex->semaphore); } else { const VertCV *verts = (VertCV *)(vertices + cmd->data.draw.first); sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); @@ -964,7 +988,7 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren sceGuEnable(GU_TEXTURE_2D); sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); sceGuDisable(GU_TEXTURE_2D); - sceGuSignal(GU_SIGNAL_NOWAIT, psp_tex->semaphore); + sceGuSignalSemaphore(psp_tex->semaphore); return 0; }