summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/render/psp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/render/psp')
-rw-r--r--contrib/SDL-3.2.8/src/render/psp/SDL_render_psp.c1400
-rw-r--r--contrib/SDL-3.2.8/src/render/psp/SDL_render_psp_c.h30
2 files changed, 1430 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/render/psp/SDL_render_psp.c b/contrib/SDL-3.2.8/src/render/psp/SDL_render_psp.c
new file mode 100644
index 0000000..3ce5036
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/psp/SDL_render_psp.c
@@ -0,0 +1,1400 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_RENDER_PSP
24
25#include "../SDL_sysrender.h"
26
27#include "SDL_render_psp_c.h"
28
29#include <pspkernel.h>
30#include <pspdisplay.h>
31#include <pspgu.h>
32#include <pspgum.h>
33#include <stdio.h>
34#include <string.h>
35#include <math.h>
36#include <pspge.h>
37#include <stdarg.h>
38#include <stdlib.h>
39#include <vram.h>
40
41// PSP renderer implementation, based on the PGE
42
43static unsigned int __attribute__((aligned(16))) DisplayList[262144];
44
45#define COL5650(r, g, b, a) ((r >> 3) | ((g >> 2) << 5) | ((b >> 3) << 11))
46#define COL5551(r, g, b, a) ((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10) | (a > 0 ? 0x7000 : 0))
47#define COL4444(r, g, b, a) ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8) | ((a >> 4) << 12))
48#define COL8888(r, g, b, a) ((r) | ((g) << 8) | ((b) << 16) | ((a) << 24))
49
50/**
51 * Holds psp specific texture data
52 *
53 * Part of a hot-list of textures that are used as render targets
54 * When short of vram we spill Least-Recently-Used render targets to system memory
55 */
56typedef struct PSP_TextureData
57{
58 void *data; /**< Image data. */
59 unsigned int size; /**< Size of data in bytes. */
60 unsigned int width; /**< Image width. */
61 unsigned int height; /**< Image height. */
62 unsigned int textureWidth; /**< Texture width (power of two). */
63 unsigned int textureHeight; /**< Texture height (power of two). */
64 unsigned int bits; /**< Image bits per pixel. */
65 unsigned int format; /**< Image format - one of ::pgePixelFormat. */
66 unsigned int pitch;
67 bool swizzled; /**< Is image swizzled. */
68 struct PSP_TextureData *prevhotw; /**< More recently used render target */
69 struct PSP_TextureData *nexthotw; /**< Less recently used render target */
70} PSP_TextureData;
71
72typedef struct
73{
74 SDL_BlendMode mode;
75 unsigned int color;
76 int shadeModel;
77 SDL_Texture *texture;
78} PSP_BlendState;
79
80typedef struct
81{
82 unsigned int color;
83} PSP_DrawStateCache;
84
85typedef struct
86{
87 void *frontbuffer; /**< main screen buffer */
88 void *backbuffer; /**< buffer presented to display */
89 SDL_Texture *boundTarget; /**< currently bound rendertarget */
90 bool initialized; /**< is driver initialized */
91 bool displayListAvail; /**< is the display list already initialized for this frame */
92 unsigned int psm; /**< format of the display buffers */
93 unsigned int bpp; /**< bits per pixel of the main display */
94
95 bool vsync; /**< whether we do vsync */
96 PSP_BlendState blendState; /**< current blend mode */
97 PSP_TextureData *most_recent_target; /**< start of render target LRU double linked list */
98 PSP_TextureData *least_recent_target; /**< end of the LRU list */
99
100 bool vblank_not_reached; /**< whether vblank wasn't reached */
101} PSP_RenderData;
102
103typedef struct
104{
105 float x, y, z;
106} VertV;
107
108typedef struct
109{
110 float u, v;
111 float x, y, z;
112} VertTV;
113
114typedef struct
115{
116 SDL_Color col;
117 float x, y, z;
118} VertCV;
119
120typedef struct
121{
122 float u, v;
123 SDL_Color col;
124 float x, y, z;
125} VertTCV;
126
127#define radToDeg(x) ((x)*180.f / SDL_PI_F)
128#define degToRad(x) ((x)*SDL_PI_F / 180.f)
129
130static float MathAbs(float x)
131{
132 float result;
133
134 __asm__ volatile(
135 "mtv %1, S000\n"
136 "vabs.s S000, S000\n"
137 "mfv %0, S000\n"
138 : "=r"(result)
139 : "r"(x));
140
141 return result;
142}
143
144static void MathSincos(float r, float *s, float *c)
145{
146 __asm__ volatile(
147 "mtv %2, S002\n"
148 "vcst.s S003, VFPU_2_PI\n"
149 "vmul.s S002, S002, S003\n"
150 "vrot.p C000, S002, [s, c]\n"
151 "mfv %0, S000\n"
152 "mfv %1, S001\n"
153 : "=r"(*s), "=r"(*c)
154 : "r"(r));
155}
156
157static void Swap(float *a, float *b)
158{
159 float n = *a;
160 *a = *b;
161 *b = n;
162}
163
164static inline int InVram(void *data)
165{
166 return data < (void *)0x04200000;
167}
168
169// Return next power of 2
170static int TextureNextPow2(unsigned int w)
171{
172 unsigned int n = 2;
173 if (w == 0) {
174 return 0;
175 }
176
177 while (w > n) {
178 n <<= 1;
179 }
180
181 return n;
182}
183
184static void psp_on_vblank(u32 sub, PSP_RenderData *data)
185{
186 if (data) {
187 data->vblank_not_reached = false;
188 }
189}
190
191static int PixelFormatToPSPFMT(SDL_PixelFormat format)
192{
193 switch (format) {
194 case SDL_PIXELFORMAT_BGR565:
195 return GU_PSM_5650;
196 case SDL_PIXELFORMAT_ABGR1555:
197 return GU_PSM_5551;
198 case SDL_PIXELFORMAT_ABGR4444:
199 return GU_PSM_4444;
200 case SDL_PIXELFORMAT_ABGR8888:
201 return GU_PSM_8888;
202 default:
203 return GU_PSM_8888;
204 }
205}
206
207/// SECTION render target LRU management
208static void LRUTargetRelink(PSP_TextureData *psp_texture)
209{
210 if (psp_texture->prevhotw) {
211 psp_texture->prevhotw->nexthotw = psp_texture->nexthotw;
212 }
213 if (psp_texture->nexthotw) {
214 psp_texture->nexthotw->prevhotw = psp_texture->prevhotw;
215 }
216}
217
218static void LRUTargetPushFront(PSP_RenderData *data, PSP_TextureData *psp_texture)
219{
220 psp_texture->nexthotw = data->most_recent_target;
221 if (data->most_recent_target) {
222 data->most_recent_target->prevhotw = psp_texture;
223 }
224 data->most_recent_target = psp_texture;
225 if (!data->least_recent_target) {
226 data->least_recent_target = psp_texture;
227 }
228}
229
230static void LRUTargetRemove(PSP_RenderData *data, PSP_TextureData *psp_texture)
231{
232 LRUTargetRelink(psp_texture);
233 if (data->most_recent_target == psp_texture) {
234 data->most_recent_target = psp_texture->nexthotw;
235 }
236 if (data->least_recent_target == psp_texture) {
237 data->least_recent_target = psp_texture->prevhotw;
238 }
239 psp_texture->prevhotw = NULL;
240 psp_texture->nexthotw = NULL;
241}
242
243static void LRUTargetBringFront(PSP_RenderData *data, PSP_TextureData *psp_texture)
244{
245 if (data->most_recent_target == psp_texture) {
246 return; // nothing to do
247 }
248 LRUTargetRemove(data, psp_texture);
249 LRUTargetPushFront(data, psp_texture);
250}
251
252static void TextureStorageFree(void *storage)
253{
254 if (InVram(storage)) {
255 vfree(storage);
256 } else {
257 SDL_free(storage);
258 }
259}
260
261static bool TextureSwizzle(PSP_TextureData *psp_texture, void *dst)
262{
263 int bytewidth, height;
264 int rowblocks, rowblocksadd;
265 int i, j;
266 unsigned int blockaddress = 0;
267 unsigned int *src = NULL;
268 unsigned char *data = NULL;
269
270 if (psp_texture->swizzled) {
271 return true;
272 }
273
274 bytewidth = psp_texture->textureWidth * (psp_texture->bits >> 3);
275 height = psp_texture->size / bytewidth;
276
277 rowblocks = (bytewidth >> 4);
278 rowblocksadd = (rowblocks - 1) << 7;
279
280 src = (unsigned int *)psp_texture->data;
281
282 data = dst;
283 if (!data) {
284 data = SDL_malloc(psp_texture->size);
285 }
286
287 if (!data) {
288 return false;
289 }
290
291 for (j = 0; j < height; j++, blockaddress += 16) {
292 unsigned int *block;
293
294 block = (unsigned int *)&data[blockaddress];
295
296 for (i = 0; i < rowblocks; i++) {
297 *block++ = *src++;
298 *block++ = *src++;
299 *block++ = *src++;
300 *block++ = *src++;
301 block += 28;
302 }
303
304 if ((j & 0x7) == 0x7) {
305 blockaddress += rowblocksadd;
306 }
307 }
308
309 TextureStorageFree(psp_texture->data);
310 psp_texture->data = data;
311 psp_texture->swizzled = true;
312
313 sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size);
314 return true;
315}
316
317static bool TextureUnswizzle(PSP_TextureData *psp_texture, void *dst)
318{
319 int bytewidth, height;
320 int widthblocks, heightblocks;
321 int dstpitch, dstrow;
322 int blockx, blocky;
323 int j;
324 unsigned int *src = NULL;
325 unsigned char *data = NULL;
326 unsigned char *ydst = NULL;
327
328 if (!psp_texture->swizzled) {
329 return true;
330 }
331
332 bytewidth = psp_texture->textureWidth * (psp_texture->bits >> 3);
333 height = psp_texture->size / bytewidth;
334
335 widthblocks = bytewidth / 16;
336 heightblocks = height / 8;
337
338 dstpitch = (bytewidth - 16) / 4;
339 dstrow = bytewidth * 8;
340
341 src = (unsigned int *)psp_texture->data;
342
343 data = dst;
344
345 if (!data) {
346 data = SDL_malloc(psp_texture->size);
347 }
348
349 if (!data) {
350 return false;
351 }
352
353 ydst = (unsigned char *)data;
354
355 for (blocky = 0; blocky < heightblocks; ++blocky) {
356 unsigned char *xdst = ydst;
357
358 for (blockx = 0; blockx < widthblocks; ++blockx) {
359 unsigned int *block;
360
361 block = (unsigned int *)xdst;
362
363 for (j = 0; j < 8; ++j) {
364 *(block++) = *(src++);
365 *(block++) = *(src++);
366 *(block++) = *(src++);
367 *(block++) = *(src++);
368 block += dstpitch;
369 }
370
371 xdst += 16;
372 }
373
374 ydst += dstrow;
375 }
376
377 TextureStorageFree(psp_texture->data);
378
379 psp_texture->data = data;
380
381 psp_texture->swizzled = false;
382
383 sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size);
384 return true;
385}
386
387static bool TextureSpillToSram(PSP_RenderData *data, PSP_TextureData *psp_texture)
388{
389 // Assumes the texture is in VRAM
390 if (psp_texture->swizzled) {
391 // Texture was swizzled in vram, just copy to system memory
392 void *sdata = SDL_malloc(psp_texture->size);
393 if (!sdata) {
394 return false;
395 }
396
397 SDL_memcpy(sdata, psp_texture->data, psp_texture->size);
398 vfree(psp_texture->data);
399 psp_texture->data = sdata;
400 return true;
401 } else {
402 return TextureSwizzle(psp_texture, NULL); // Will realloc in sysram
403 }
404}
405
406static bool TexturePromoteToVram(PSP_RenderData *data, PSP_TextureData *psp_texture, bool target)
407{
408 // Assumes texture in sram and a large enough continuous block in vram
409 void *tdata = vramalloc(psp_texture->size);
410 if (psp_texture->swizzled && target) {
411 return TextureUnswizzle(psp_texture, tdata);
412 } else {
413 SDL_memcpy(tdata, psp_texture->data, psp_texture->size);
414 SDL_free(psp_texture->data);
415 psp_texture->data = tdata;
416 return true;
417 }
418}
419
420static bool TextureSpillLRU(PSP_RenderData *data, size_t wanted)
421{
422 PSP_TextureData *lru = data->least_recent_target;
423 if (lru) {
424 if (!TextureSpillToSram(data, lru)) {
425 return false;
426 }
427 LRUTargetRemove(data, lru);
428 } else {
429 // Asked to spill but there nothing to spill
430 return SDL_SetError("Could not spill more VRAM to system memory. VRAM : %dKB,(%dKB), wanted %dKB", vmemavail() / 1024, vlargestblock() / 1024, wanted / 1024);
431 }
432 return true;
433}
434
435static bool TextureSpillTargetsForSpace(PSP_RenderData *data, size_t size)
436{
437 while (vlargestblock() < size) {
438 if (!TextureSpillLRU(data, size)) {
439 return false;
440 }
441 }
442 return true;
443}
444
445static bool TextureBindAsTarget(PSP_RenderData *data, PSP_TextureData *psp_texture)
446{
447 unsigned int dstFormat;
448
449 if (!InVram(psp_texture->data)) {
450 // Bring back the texture in vram
451 if (!TextureSpillTargetsForSpace(data, psp_texture->size)) {
452 return false;
453 }
454 if (!TexturePromoteToVram(data, psp_texture, true)) {
455 return false;
456 }
457 }
458 LRUTargetBringFront(data, psp_texture);
459 sceGuDrawBufferList(psp_texture->format, vrelptr(psp_texture->data), psp_texture->textureWidth);
460
461 // Stencil alpha dst hack
462 dstFormat = psp_texture->format;
463 if (dstFormat == GU_PSM_5551) {
464 sceGuEnable(GU_STENCIL_TEST);
465 sceGuStencilOp(GU_REPLACE, GU_REPLACE, GU_REPLACE);
466 sceGuStencilFunc(GU_GEQUAL, 0xff, 0xff);
467 sceGuEnable(GU_ALPHA_TEST);
468 sceGuAlphaFunc(GU_GREATER, 0x00, 0xff);
469 } else {
470 sceGuDisable(GU_STENCIL_TEST);
471 sceGuDisable(GU_ALPHA_TEST);
472 }
473 return true;
474}
475
476static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
477{
478}
479
480static bool PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
481{
482 PSP_RenderData *data = renderer->internal;
483 PSP_TextureData *psp_texture = (PSP_TextureData *)SDL_calloc(1, sizeof(*psp_texture));
484
485 if (!psp_texture) {
486 return false;
487 }
488
489 psp_texture->swizzled = false;
490 psp_texture->width = texture->w;
491 psp_texture->height = texture->h;
492 psp_texture->textureHeight = TextureNextPow2(texture->h);
493 psp_texture->textureWidth = TextureNextPow2(texture->w);
494 psp_texture->format = PixelFormatToPSPFMT(texture->format);
495
496 switch (psp_texture->format) {
497 case GU_PSM_5650:
498 case GU_PSM_5551:
499 case GU_PSM_4444:
500 psp_texture->bits = 16;
501 break;
502
503 case GU_PSM_8888:
504 psp_texture->bits = 32;
505 break;
506
507 default:
508 SDL_free(psp_texture);
509 return false;
510 }
511
512 psp_texture->pitch = psp_texture->textureWidth * SDL_BYTESPERPIXEL(texture->format);
513 psp_texture->size = psp_texture->textureHeight * psp_texture->pitch;
514 if (texture->access == SDL_TEXTUREACCESS_TARGET) {
515 if (!TextureSpillTargetsForSpace(renderer->internal, psp_texture->size)) {
516 SDL_free(psp_texture);
517 return false;
518 }
519 psp_texture->data = vramalloc(psp_texture->size);
520 if (psp_texture->data) {
521 LRUTargetPushFront(data, psp_texture);
522 }
523 } else {
524 psp_texture->data = SDL_calloc(1, psp_texture->size);
525 }
526
527 if (!psp_texture->data) {
528 SDL_free(psp_texture);
529 return false;
530 }
531 texture->internal = psp_texture;
532
533 return true;
534}
535
536static bool TextureShouldSwizzle(PSP_TextureData *psp_texture, SDL_Texture *texture)
537{
538 return !((texture->access == SDL_TEXTUREACCESS_TARGET) && InVram(psp_texture->data)) && texture->access != SDL_TEXTUREACCESS_STREAMING && (texture->w >= 16 || texture->h >= 16);
539}
540
541static void TextureActivate(SDL_Texture *texture)
542{
543 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal;
544 int scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? GU_NEAREST : GU_LINEAR;
545
546 // Swizzling is useless with small textures.
547 if (TextureShouldSwizzle(psp_texture, texture)) {
548 TextureSwizzle(psp_texture, NULL);
549 }
550
551 sceGuTexWrap(GU_REPEAT, GU_REPEAT);
552 sceGuTexMode(psp_texture->format, 0, 0, psp_texture->swizzled);
553 sceGuTexFilter(scaleMode, scaleMode); // GU_NEAREST good for tile-map
554 // GU_LINEAR good for scaling
555 sceGuTexImage(0, psp_texture->textureWidth, psp_texture->textureHeight, psp_texture->textureWidth, psp_texture->data);
556}
557
558static bool PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
559 const SDL_Rect *rect, void **pixels, int *pitch);
560
561static bool PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
562 const SDL_Rect *rect, const void *pixels, int pitch)
563{
564 /* PSP_TextureData *psp_texture = (PSP_TextureData *) texture->internal; */
565 const Uint8 *src;
566 Uint8 *dst;
567 int row, length, dpitch;
568 src = pixels;
569
570 PSP_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch);
571 length = rect->w * SDL_BYTESPERPIXEL(texture->format);
572 if (length == pitch && length == dpitch) {
573 SDL_memcpy(dst, src, length * rect->h);
574 } else {
575 for (row = 0; row < rect->h; ++row) {
576 SDL_memcpy(dst, src, length);
577 src += pitch;
578 dst += dpitch;
579 }
580 }
581
582 sceKernelDcacheWritebackAll();
583 return true;
584}
585
586static bool PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
587 const SDL_Rect *rect, void **pixels, int *pitch)
588{
589 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal;
590
591 *pixels =
592 (void *)((Uint8 *)psp_texture->data + rect->y * psp_texture->pitch +
593 rect->x * SDL_BYTESPERPIXEL(texture->format));
594 *pitch = psp_texture->pitch;
595 return true;
596}
597
598static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
599{
600 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal;
601 SDL_Rect rect;
602
603 // We do whole texture updates, at least for now
604 rect.x = 0;
605 rect.y = 0;
606 rect.w = texture->w;
607 rect.h = texture->h;
608 PSP_UpdateTexture(renderer, texture, &rect, psp_texture->data, psp_texture->pitch);
609}
610
611static void PSP_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
612{
613 // Nothing to do because TextureActivate takes care of it
614}
615
616static bool PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
617{
618 return true;
619}
620
621static bool PSP_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
622{
623 return true; // nothing to do in this backend.
624}
625
626static bool PSP_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
627{
628 VertV *verts = (VertV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertV), 4, &cmd->data.draw.first);
629 int i;
630
631 if (!verts) {
632 return false;
633 }
634
635 cmd->data.draw.count = count;
636
637 for (i = 0; i < count; i++, verts++, points++) {
638 verts->x = points->x;
639 verts->y = points->y;
640 verts->z = 0.0f;
641 }
642
643 return true;
644}
645
646static bool PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
647 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride,
648 int num_vertices, const void *indices, int num_indices, int size_indices,
649 float scale_x, float scale_y)
650{
651 int i;
652 int count = indices ? num_indices : num_vertices;
653 const float color_scale = cmd->data.draw.color_scale;
654
655 cmd->data.draw.count = count;
656 size_indices = indices ? size_indices : 0;
657
658 if (!texture) {
659 VertCV *verts;
660 verts = (VertCV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertCV), 4, &cmd->data.draw.first);
661 if (!verts) {
662 return false;
663 }
664
665 for (i = 0; i < count; i++) {
666 int j;
667 float *xy_;
668 SDL_FColor *col_;
669 if (size_indices == 4) {
670 j = ((const Uint32 *)indices)[i];
671 } else if (size_indices == 2) {
672 j = ((const Uint16 *)indices)[i];
673 } else if (size_indices == 1) {
674 j = ((const Uint8 *)indices)[i];
675 } else {
676 j = i;
677 }
678
679 xy_ = (float *)((char *)xy + j * xy_stride);
680 col_ = (SDL_FColor *)((char *)color + j * color_stride);
681
682 verts->x = xy_[0] * scale_x;
683 verts->y = xy_[1] * scale_y;
684 verts->z = 0;
685
686 verts->col.r = (Uint8)SDL_roundf(SDL_clamp(col_->r * color_scale, 0.0f, 1.0f) * 255.0f);
687 verts->col.g = (Uint8)SDL_roundf(SDL_clamp(col_->g * color_scale, 0.0f, 1.0f) * 255.0f);
688 verts->col.b = (Uint8)SDL_roundf(SDL_clamp(col_->b * color_scale, 0.0f, 1.0f) * 255.0f);
689 verts->col.a = (Uint8)SDL_roundf(SDL_clamp(col_->a, 0.0f, 1.0f) * 255.0f);
690
691 verts++;
692 }
693 } else {
694 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal;
695 VertTCV *verts;
696 verts = (VertTCV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertTCV), 4, &cmd->data.draw.first);
697 if (!verts) {
698 return false;
699 }
700
701 for (i = 0; i < count; i++) {
702 int j;
703 float *xy_;
704 SDL_FColor *col_;
705 float *uv_;
706
707 if (size_indices == 4) {
708 j = ((const Uint32 *)indices)[i];
709 } else if (size_indices == 2) {
710 j = ((const Uint16 *)indices)[i];
711 } else if (size_indices == 1) {
712 j = ((const Uint8 *)indices)[i];
713 } else {
714 j = i;
715 }
716
717 xy_ = (float *)((char *)xy + j * xy_stride);
718 col_ = (SDL_FColor *)((char *)color + j * color_stride);
719 uv_ = (float *)((char *)uv + j * uv_stride);
720
721 verts->x = xy_[0] * scale_x;
722 verts->y = xy_[1] * scale_y;
723 verts->z = 0;
724
725 verts->col.r = (Uint8)SDL_roundf(SDL_clamp(col_->r * color_scale, 0.0f, 1.0f) * 255.0f);
726 verts->col.g = (Uint8)SDL_roundf(SDL_clamp(col_->g * color_scale, 0.0f, 1.0f) * 255.0f);
727 verts->col.b = (Uint8)SDL_roundf(SDL_clamp(col_->b * color_scale, 0.0f, 1.0f) * 255.0f);
728 verts->col.a = (Uint8)SDL_roundf(SDL_clamp(col_->a, 0.0f, 1.0f) * 255.0f);
729
730 verts->u = uv_[0] * psp_texture->textureWidth;
731 verts->v = uv_[1] * psp_texture->textureHeight;
732
733 verts++;
734 }
735 }
736
737 return true;
738}
739
740static bool PSP_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count)
741{
742 VertV *verts = (VertV *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(VertV), 4, &cmd->data.draw.first);
743 int i;
744
745 if (!verts) {
746 return false;
747 }
748
749 cmd->data.draw.count = count;
750 for (i = 0; i < count; i++, rects++) {
751 verts->x = rects->x;
752 verts->y = rects->y;
753 verts->z = 0.0f;
754 verts++;
755
756 verts->x = rects->x + rects->w + 0.5f;
757 verts->y = rects->y + rects->h + 0.5f;
758 verts->z = 0.0f;
759 verts++;
760 }
761
762 return true;
763}
764
765static bool PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
766 const SDL_FRect *srcrect, const SDL_FRect *dstrect)
767{
768 VertTV *verts;
769 const float x = dstrect->x;
770 const float y = dstrect->y;
771 const float width = dstrect->w;
772 const float height = dstrect->h;
773
774 const float u0 = srcrect->x;
775 const float v0 = srcrect->y;
776 const float u1 = srcrect->x + srcrect->w;
777 const float v1 = srcrect->y + srcrect->h;
778
779 if ((MathAbs(u1) - MathAbs(u0)) < 64.0f) {
780 verts = (VertTV *)SDL_AllocateRenderVertices(renderer, 2 * sizeof(VertTV), 4, &cmd->data.draw.first);
781 if (!verts) {
782 return false;
783 }
784
785 cmd->data.draw.count = 1;
786
787 verts->u = u0;
788 verts->v = v0;
789 verts->x = x;
790 verts->y = y;
791 verts->z = 0;
792 verts++;
793
794 verts->u = u1;
795 verts->v = v1;
796 verts->x = x + width;
797 verts->y = y + height;
798 verts->z = 0;
799 verts++;
800 } else {
801 float start, end;
802 float curU = u0;
803 float curX = x;
804 const float endX = x + width;
805 const float slice = 64.0f;
806 const size_t count = (size_t)SDL_ceilf(width / slice);
807 size_t i;
808 float ustep = (u1 - u0) / width * slice;
809
810 if (ustep < 0.0f) {
811 ustep = -ustep;
812 }
813
814 cmd->data.draw.count = count;
815
816 verts = (VertTV *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(VertTV), 4, &cmd->data.draw.first);
817 if (!verts) {
818 return false;
819 }
820
821 for (i = 0, start = 0, end = width; i < count; i++, start += slice) {
822 const float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice;
823 const float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep;
824
825 SDL_assert(start < end);
826
827 verts->u = curU;
828 verts->v = v0;
829 verts->x = curX;
830 verts->y = y;
831 verts->z = 0;
832 verts++;
833
834 curU += sourceWidth;
835 curX += polyWidth;
836
837 verts->u = curU;
838 verts->v = v1;
839 verts->x = curX;
840 verts->y = (y + height);
841 verts->z = 0;
842 verts++;
843 }
844 }
845
846 return true;
847}
848
849static bool PSP_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
850 const SDL_FRect *srcrect, const SDL_FRect *dstrect,
851 const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
852{
853 VertTV *verts = (VertTV *)SDL_AllocateRenderVertices(renderer, 4 * sizeof(VertTV), 4, &cmd->data.draw.first);
854 const float centerx = center->x;
855 const float centery = center->y;
856 const float x = dstrect->x + centerx;
857 const float y = dstrect->y + centery;
858 const float width = dstrect->w - centerx;
859 const float height = dstrect->h - centery;
860 float s, c;
861 float cw1, sw1, ch1, sh1, cw2, sw2, ch2, sh2;
862
863 float u0 = srcrect->x;
864 float v0 = srcrect->y;
865 float u1 = srcrect->x + srcrect->w;
866 float v1 = srcrect->y + srcrect->h;
867
868 if (!verts) {
869 return false;
870 }
871
872 cmd->data.draw.count = 1;
873
874 MathSincos(degToRad((float)(360 - angle)), &s, &c);
875
876 cw1 = c * -centerx;
877 sw1 = s * -centerx;
878 ch1 = c * -centery;
879 sh1 = s * -centery;
880 cw2 = c * width;
881 sw2 = s * width;
882 ch2 = c * height;
883 sh2 = s * height;
884
885 if (flip & SDL_FLIP_VERTICAL) {
886 Swap(&v0, &v1);
887 }
888
889 if (flip & SDL_FLIP_HORIZONTAL) {
890 Swap(&u0, &u1);
891 }
892
893 verts->u = u0;
894 verts->v = v0;
895 verts->x = x + cw1 + sh1;
896 verts->y = y - sw1 + ch1;
897 verts->z = 0;
898 verts++;
899
900 verts->u = u0;
901 verts->v = v1;
902 verts->x = x + cw1 + sh2;
903 verts->y = y - sw1 + ch2;
904 verts->z = 0;
905 verts++;
906
907 verts->u = u1;
908 verts->v = v1;
909 verts->x = x + cw2 + sh2;
910 verts->y = y - sw2 + ch2;
911 verts->z = 0;
912 verts++;
913
914 verts->u = u1;
915 verts->v = v0;
916 verts->x = x + cw2 + sh1;
917 verts->y = y - sw2 + ch1;
918 verts->z = 0;
919
920 if (scale_x != 1.0f || scale_y != 1.0f) {
921 verts->x *= scale_x;
922 verts->y *= scale_y;
923 verts--;
924 verts->x *= scale_x;
925 verts->y *= scale_y;
926 verts--;
927 verts->x *= scale_x;
928 verts->y *= scale_y;
929 verts--;
930 verts->x *= scale_x;
931 verts->y *= scale_y;
932 }
933
934 return true;
935}
936
937static void ResetBlendState(PSP_BlendState *state)
938{
939 sceGuColor(0xffffffff);
940 state->color = 0xffffffff;
941 state->mode = SDL_BLENDMODE_INVALID;
942 state->texture = NULL;
943 sceGuDisable(GU_TEXTURE_2D);
944 sceGuShadeModel(GU_SMOOTH);
945 state->shadeModel = GU_SMOOTH;
946}
947
948static void StartDrawing(SDL_Renderer *renderer)
949{
950 PSP_RenderData *data = (PSP_RenderData *)renderer->internal;
951
952 // Check if we need to start GU displaylist
953 if (!data->displayListAvail) {
954 sceGuStart(GU_DIRECT, DisplayList);
955 data->displayListAvail = true;
956 // ResetBlendState(&data->blendState);
957 }
958
959 // Check if we need a draw buffer change
960 if (renderer->target != data->boundTarget) {
961 SDL_Texture *texture = renderer->target;
962 if (texture) {
963 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal;
964 // Set target, registering LRU
965 TextureBindAsTarget(data, psp_texture);
966 } else {
967 // Set target back to screen
968 sceGuDrawBufferList(data->psm, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH);
969 }
970 data->boundTarget = texture;
971 }
972}
973
974static void PSP_SetBlendState(PSP_RenderData *data, PSP_BlendState *state)
975{
976 PSP_BlendState *current = &data->blendState;
977
978 if (state->mode != current->mode) {
979 switch (state->mode) {
980 case SDL_BLENDMODE_NONE:
981 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
982 sceGuDisable(GU_BLEND);
983 break;
984 case SDL_BLENDMODE_BLEND:
985 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
986 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
987 sceGuEnable(GU_BLEND);
988 break;
989 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
990 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
991 sceGuBlendFunc(GU_ADD, GU_FIX, GU_ONE_MINUS_SRC_ALPHA, 0x00FFFFFF, 0 );
992 sceGuEnable(GU_BLEND);
993 break;
994 case SDL_BLENDMODE_ADD:
995 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
996 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF);
997 sceGuEnable(GU_BLEND);
998 break;
999 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
1000 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
1001 sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0, 0x00FFFFFF);
1002 sceGuEnable(GU_BLEND);
1003 break;
1004 case SDL_BLENDMODE_MOD:
1005 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
1006 sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0);
1007 sceGuEnable(GU_BLEND);
1008 break;
1009 case SDL_BLENDMODE_MUL:
1010 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
1011 // FIXME SDL_BLENDMODE_MUL is simplified, and dstA is in fact un-changed.
1012 sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
1013 sceGuEnable(GU_BLEND);
1014 break;
1015 case SDL_BLENDMODE_INVALID:
1016 break;
1017 }
1018 }
1019
1020 if (state->color != current->color) {
1021 sceGuColor(state->color);
1022 }
1023
1024 if (state->shadeModel != current->shadeModel) {
1025 sceGuShadeModel(state->shadeModel);
1026 }
1027
1028 if (state->texture != current->texture) {
1029 if (state->texture) {
1030 TextureActivate(state->texture);
1031 sceGuEnable(GU_TEXTURE_2D);
1032 } else {
1033 sceGuDisable(GU_TEXTURE_2D);
1034 }
1035 }
1036
1037 *current = *state;
1038}
1039
1040static void PSP_InvalidateCachedState(SDL_Renderer *renderer)
1041{
1042 // currently this doesn't do anything. If this needs to do something (and someone is mixing their own rendering calls in!), update this.
1043}
1044
1045static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
1046{
1047 PSP_RenderData *data = (PSP_RenderData *)renderer->internal;
1048 Uint8 *gpumem = NULL;
1049 PSP_DrawStateCache drawstate;
1050
1051 drawstate.color = 0;
1052
1053 StartDrawing(renderer);
1054
1055 /* note that before the renderer interface change, this would do extremely small
1056 batches with sceGuGetMemory()--a few vertices at a time--and it's not clear that
1057 this won't fail if you try to push 100,000 draw calls in a single batch.
1058 I don't know what the limits on PSP hardware are. It might be useful to have
1059 rendering backends report a reasonable maximum, so the higher level can flush
1060 if we appear to be exceeding that. */
1061 gpumem = (Uint8 *)sceGuGetMemory(vertsize);
1062 if (!gpumem) {
1063 return SDL_SetError("Couldn't obtain a %d-byte vertex buffer!", (int)vertsize);
1064 }
1065 SDL_memcpy(gpumem, vertices, vertsize);
1066
1067 while (cmd) {
1068 switch (cmd->command) {
1069 case SDL_RENDERCMD_SETDRAWCOLOR:
1070 {
1071 const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
1072 const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
1073 const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
1074 const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f);
1075 drawstate.color = GU_RGBA(r, g, b, a);
1076 break;
1077 }
1078
1079 case SDL_RENDERCMD_SETVIEWPORT:
1080 {
1081 SDL_Rect *viewport = &cmd->data.viewport.rect;
1082 sceGuOffset(2048 - (viewport->w >> 1), 2048 - (viewport->h >> 1));
1083 sceGuViewport(2048, 2048, viewport->w, viewport->h);
1084 sceGuScissor(viewport->x, viewport->y, viewport->w, viewport->h);
1085 // FIXME: We need to update the clip rect too, see https://github.com/libsdl-org/SDL/issues/9094
1086 break;
1087 }
1088
1089 case SDL_RENDERCMD_SETCLIPRECT:
1090 {
1091 const SDL_Rect *rect = &cmd->data.cliprect.rect;
1092 if (cmd->data.cliprect.enabled) {
1093 sceGuEnable(GU_SCISSOR_TEST);
1094 sceGuScissor(rect->x, rect->y, rect->w, rect->h);
1095 } else {
1096 sceGuDisable(GU_SCISSOR_TEST);
1097 }
1098 break;
1099 }
1100
1101 case SDL_RENDERCMD_CLEAR:
1102 {
1103 const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
1104 const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
1105 const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
1106 const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f);
1107 sceGuClearColor(GU_RGBA(r, g, b, a));
1108 sceGuClearStencil(a);
1109 sceGuClear(GU_COLOR_BUFFER_BIT | GU_STENCIL_BUFFER_BIT);
1110 break;
1111 }
1112
1113 case SDL_RENDERCMD_DRAW_POINTS:
1114 {
1115 const size_t count = cmd->data.draw.count;
1116 const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
1117 PSP_BlendState state = {
1118 .color = drawstate.color,
1119 .texture = NULL,
1120 .mode = cmd->data.draw.blend,
1121 .shadeModel = GU_FLAT
1122 };
1123 PSP_SetBlendState(data, &state);
1124 sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
1125 break;
1126 }
1127
1128 case SDL_RENDERCMD_DRAW_LINES:
1129 {
1130 const size_t count = cmd->data.draw.count;
1131 const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
1132 PSP_BlendState state = {
1133 .color = drawstate.color,
1134 .texture = NULL,
1135 .mode = cmd->data.draw.blend,
1136 .shadeModel = GU_FLAT
1137 };
1138 PSP_SetBlendState(data, &state);
1139 sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
1140 break;
1141 }
1142
1143 case SDL_RENDERCMD_FILL_RECTS:
1144 {
1145 const size_t count = cmd->data.draw.count;
1146 const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
1147 PSP_BlendState state = {
1148 .color = drawstate.color,
1149 .texture = NULL,
1150 .mode = cmd->data.draw.blend,
1151 .shadeModel = GU_FLAT
1152 };
1153 PSP_SetBlendState(data, &state);
1154 sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2 * count, 0, verts);
1155 break;
1156 }
1157
1158 case SDL_RENDERCMD_COPY:
1159 {
1160 const size_t count = cmd->data.draw.count;
1161 const VertTV *verts = (VertTV *)(gpumem + cmd->data.draw.first);
1162 PSP_BlendState state = {
1163 .color = drawstate.color,
1164 .texture = cmd->data.draw.texture,
1165 .mode = cmd->data.draw.blend,
1166 .shadeModel = GU_SMOOTH
1167 };
1168 PSP_SetBlendState(data, &state);
1169 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2 * count, 0, verts);
1170 break;
1171 }
1172
1173 case SDL_RENDERCMD_COPY_EX:
1174 {
1175 const VertTV *verts = (VertTV *)(gpumem + cmd->data.draw.first);
1176 PSP_BlendState state = {
1177 .color = drawstate.color,
1178 .texture = cmd->data.draw.texture,
1179 .mode = cmd->data.draw.blend,
1180 .shadeModel = GU_SMOOTH
1181 };
1182 PSP_SetBlendState(data, &state);
1183 sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 4, 0, verts);
1184 break;
1185 }
1186
1187 case SDL_RENDERCMD_GEOMETRY:
1188 {
1189 const size_t count = cmd->data.draw.count;
1190 if (!cmd->data.draw.texture) {
1191 const VertCV *verts = (VertCV *)(gpumem + cmd->data.draw.first);
1192 sceGuDisable(GU_TEXTURE_2D);
1193 // In GU_SMOOTH mode
1194 sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
1195 sceGuEnable(GU_TEXTURE_2D);
1196 } else {
1197 const VertTCV *verts = (VertTCV *)(gpumem + cmd->data.draw.first);
1198 PSP_BlendState state = {
1199 .color = drawstate.color,
1200 .texture = NULL,
1201 .mode = cmd->data.draw.blend,
1202 .shadeModel = GU_FLAT
1203 };
1204 TextureActivate(cmd->data.draw.texture);
1205 PSP_SetBlendState(data, &state);
1206 sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
1207 }
1208 break;
1209 }
1210
1211 case SDL_RENDERCMD_NO_OP:
1212 break;
1213 }
1214
1215 cmd = cmd->next;
1216 }
1217
1218 return true;
1219}
1220
1221static bool PSP_RenderPresent(SDL_Renderer *renderer)
1222{
1223 PSP_RenderData *data = (PSP_RenderData *)renderer->internal;
1224 if (!data->displayListAvail) {
1225 return false;
1226 }
1227
1228 data->displayListAvail = false;
1229 sceGuFinish();
1230 sceGuSync(0, 0);
1231
1232 if ((data->vsync) && (data->vblank_not_reached)) {
1233 sceDisplayWaitVblankStart();
1234 }
1235 data->vblank_not_reached = true;
1236
1237 data->backbuffer = data->frontbuffer;
1238 data->frontbuffer = vabsptr(sceGuSwapBuffers());
1239
1240 return true;
1241}
1242
1243static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1244{
1245 PSP_RenderData *renderdata = (PSP_RenderData *)renderer->internal;
1246 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal;
1247
1248 if (!renderdata) {
1249 return;
1250 }
1251
1252 if (!psp_texture) {
1253 return;
1254 }
1255
1256 LRUTargetRemove(renderdata, psp_texture);
1257 TextureStorageFree(psp_texture->data);
1258 SDL_free(psp_texture);
1259 texture->internal = NULL;
1260}
1261
1262static void PSP_DestroyRenderer(SDL_Renderer *renderer)
1263{
1264 PSP_RenderData *data = (PSP_RenderData *)renderer->internal;
1265 if (data) {
1266 if (!data->initialized) {
1267 return;
1268 }
1269
1270 sceKernelDisableSubIntr(PSP_VBLANK_INT, 0);
1271 sceKernelReleaseSubIntrHandler(PSP_VBLANK_INT, 0);
1272 sceDisplayWaitVblankStart();
1273 sceGuDisplay(GU_FALSE);
1274 sceGuTerm();
1275 vfree(data->backbuffer);
1276 vfree(data->frontbuffer);
1277
1278 data->initialized = false;
1279 data->displayListAvail = false;
1280 SDL_free(data);
1281 }
1282}
1283
1284static bool PSP_SetVSync(SDL_Renderer *renderer, const int vsync)
1285{
1286 PSP_RenderData *data = renderer->internal;
1287 data->vsync = vsync;
1288 return true;
1289}
1290
1291static bool PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
1292{
1293 PSP_RenderData *data;
1294 int pixelformat;
1295 void *doublebuffer = NULL;
1296
1297 SDL_SetupRendererColorspace(renderer, create_props);
1298
1299 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
1300 return SDL_SetError("Unsupported output colorspace");
1301 }
1302
1303 data = (PSP_RenderData *)SDL_calloc(1, sizeof(*data));
1304 if (!data) {
1305 return false;
1306 }
1307
1308 renderer->WindowEvent = PSP_WindowEvent;
1309 renderer->CreateTexture = PSP_CreateTexture;
1310 renderer->UpdateTexture = PSP_UpdateTexture;
1311 renderer->LockTexture = PSP_LockTexture;
1312 renderer->UnlockTexture = PSP_UnlockTexture;
1313 renderer->SetTextureScaleMode = PSP_SetTextureScaleMode;
1314 renderer->SetRenderTarget = PSP_SetRenderTarget;
1315 renderer->QueueSetViewport = PSP_QueueNoOp;
1316 renderer->QueueSetDrawColor = PSP_QueueNoOp;
1317 renderer->QueueDrawPoints = PSP_QueueDrawPoints;
1318 renderer->QueueDrawLines = PSP_QueueDrawPoints; // lines and points queue vertices the same way.
1319 renderer->QueueGeometry = PSP_QueueGeometry;
1320 renderer->QueueFillRects = PSP_QueueFillRects;
1321 renderer->QueueCopy = PSP_QueueCopy;
1322 renderer->QueueCopyEx = PSP_QueueCopyEx;
1323 renderer->InvalidateCachedState = PSP_InvalidateCachedState;
1324 renderer->RunCommandQueue = PSP_RunCommandQueue;
1325 renderer->RenderPresent = PSP_RenderPresent;
1326 renderer->DestroyTexture = PSP_DestroyTexture;
1327 renderer->DestroyRenderer = PSP_DestroyRenderer;
1328 renderer->SetVSync = PSP_SetVSync;
1329 renderer->internal = data;
1330 PSP_InvalidateCachedState(renderer);
1331 renderer->window = window;
1332
1333 renderer->name = PSP_RenderDriver.name;
1334 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGR565);
1335 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR1555);
1336 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR4444);
1337 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888);
1338 SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 512);
1339
1340 data->initialized = true;
1341 data->most_recent_target = NULL;
1342 data->least_recent_target = NULL;
1343
1344 pixelformat = PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window));
1345 switch (pixelformat) {
1346 case GU_PSM_4444:
1347 case GU_PSM_5650:
1348 case GU_PSM_5551:
1349 data->bpp = 2;
1350 data->psm = pixelformat;
1351 break;
1352 default:
1353 data->bpp = 4;
1354 data->psm = GU_PSM_8888;
1355 break;
1356 }
1357
1358 doublebuffer = vramalloc(PSP_FRAME_BUFFER_SIZE * data->bpp * 2);
1359 data->backbuffer = doublebuffer;
1360 data->frontbuffer = ((uint8_t *)doublebuffer) + PSP_FRAME_BUFFER_SIZE * data->bpp;
1361
1362 sceGuInit();
1363 // setup GU
1364 sceGuStart(GU_DIRECT, DisplayList);
1365 sceGuDrawBuffer(data->psm, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH);
1366 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH);
1367
1368 sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1));
1369 sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
1370
1371 sceGuDisable(GU_DEPTH_TEST);
1372
1373 // Scissoring
1374 sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
1375 sceGuEnable(GU_SCISSOR_TEST);
1376
1377 // Backface culling
1378 sceGuDisable(GU_CULL_FACE);
1379
1380 // Setup initial blend state
1381 ResetBlendState(&data->blendState);
1382
1383 sceGuFinish();
1384 sceGuSync(0, 0);
1385 sceDisplayWaitVblankStartCB();
1386 sceGuDisplay(GU_TRUE);
1387
1388 // Improve performance when VSYC is enabled and it is not reaching the 60 FPS
1389 data->vblank_not_reached = true;
1390 sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, psp_on_vblank, data);
1391 sceKernelEnableSubIntr(PSP_VBLANK_INT, 0);
1392
1393 return true;
1394}
1395
1396SDL_RenderDriver PSP_RenderDriver = {
1397 PSP_CreateRenderer, "PSP"
1398};
1399
1400#endif // SDL_VIDEO_RENDER_PSP
diff --git a/contrib/SDL-3.2.8/src/render/psp/SDL_render_psp_c.h b/contrib/SDL-3.2.8/src/render/psp/SDL_render_psp_c.h
new file mode 100644
index 0000000..4d60847
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/psp/SDL_render_psp_c.h
@@ -0,0 +1,30 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#ifndef SDL_VIDEO_RENDER_PSP_C_H
22#define SDL_VIDEO_RENDER_PSP_C_H
23
24#define PSP_SCREEN_WIDTH 480
25#define PSP_SCREEN_HEIGHT 272
26
27#define PSP_FRAME_BUFFER_WIDTH 512
28#define PSP_FRAME_BUFFER_SIZE (PSP_FRAME_BUFFER_WIDTH * PSP_SCREEN_HEIGHT)
29
30#endif // SDL_VIDEO_RENDER_PSP_C_H