summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c')
-rw-r--r--contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c727
1 files changed, 727 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c b/contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c
new file mode 100644
index 0000000..ddcab9e
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c
@@ -0,0 +1,727 @@
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_PS2
24
25#include "../SDL_sysrender.h"
26
27#include <kernel.h>
28#include <malloc.h>
29#include <gsKit.h>
30#include <dmaKit.h>
31#include <gsToolkit.h>
32
33#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
34#pragma GCC diagnostic push
35#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
36#endif
37
38#include <gsInline.h>
39
40#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
41#pragma GCC diagnostic pop
42#endif
43
44// turn black GS Screen
45#define GS_BLACK GS_SETREG_RGBA(0x00, 0x00, 0x00, 0x80)
46// Size of Persistent drawbuffer (Single Buffered)
47#define RENDER_QUEUE_PER_POOLSIZE 1024 * 256 // 256K of persistent renderqueue
48/* Size of Oneshot drawbuffer (Double Buffered, so it uses this size * 2) */
49#define RENDER_QUEUE_OS_POOLSIZE 1024 * 1024 * 2 // 2048K of oneshot renderqueue
50
51typedef struct
52{
53 GSGLOBAL *gsGlobal;
54 uint64_t drawColor;
55 SDL_Rect *viewport;
56 int32_t vsync_callback_id;
57 int vsync; // 0 (Disabled), 1 (Enabled), -1 (Dynamic)
58} PS2_RenderData;
59
60static int vsync_sema_id = 0;
61
62// PRIVATE METHODS
63static int vsync_handler(void)
64{
65 iSignalSema(vsync_sema_id);
66
67 ExitHandler();
68 return 0;
69}
70
71// Copy of gsKit_sync_flip, but without the 'flip'
72static void gsKit_sync(GSGLOBAL *gsGlobal)
73{
74 if (!gsGlobal->FirstFrame) {
75 WaitSema(vsync_sema_id);
76 }
77 while (PollSema(vsync_sema_id) >= 0)
78 ;
79}
80
81// Copy of gsKit_sync_flip, but without the 'sync'
82static void gsKit_flip(GSGLOBAL *gsGlobal)
83{
84 if (!gsGlobal->FirstFrame) {
85 if (gsGlobal->DoubleBuffering == GS_SETTING_ON) {
86 GS_SET_DISPFB2(gsGlobal->ScreenBuffer[gsGlobal->ActiveBuffer & 1] / 8192,
87 gsGlobal->Width / 64, gsGlobal->PSM, 0, 0);
88
89 gsGlobal->ActiveBuffer ^= 1;
90 }
91 }
92
93 gsKit_setactive(gsGlobal);
94}
95
96static int PixelFormatToPS2PSM(Uint32 format)
97{
98 switch (format) {
99 case SDL_PIXELFORMAT_ABGR1555:
100 return GS_PSM_CT16;
101 default:
102 return GS_PSM_CT32;
103 }
104}
105
106static gs_rgbaq float_color_to_RGBAQ(const SDL_FColor *color, float color_scale)
107{
108 uint8_t colorR = (uint8_t)SDL_roundf(SDL_clamp(color->r * color_scale, 0.0f, 1.0f) * 255.0f);
109 uint8_t colorG = (uint8_t)SDL_roundf(SDL_clamp(color->g * color_scale, 0.0f, 1.0f) * 255.0f);
110 uint8_t colorB = (uint8_t)SDL_roundf(SDL_clamp(color->b * color_scale, 0.0f, 1.0f) * 255.0f);
111 uint8_t colorA = (uint8_t)SDL_roundf(SDL_clamp(color->a, 0.0f, 1.0f) * 255.0f);
112
113 return color_to_RGBAQ(colorR, colorG, colorB, colorA, 0x00);
114}
115
116static uint64_t float_GS_SETREG_RGBAQ(const SDL_FColor *color, float color_scale)
117{
118 uint8_t colorR = (uint8_t)SDL_roundf(SDL_clamp(color->r * color_scale, 0.0f, 1.0f) * 255.0f);
119 uint8_t colorG = (uint8_t)SDL_roundf(SDL_clamp(color->g * color_scale, 0.0f, 1.0f) * 255.0f);
120 uint8_t colorB = (uint8_t)SDL_roundf(SDL_clamp(color->b * color_scale, 0.0f, 1.0f) * 255.0f);
121 uint8_t colorA = (uint8_t)SDL_roundf(SDL_clamp(color->a, 0.0f, 1.0f) * 255.0f);
122
123 return GS_SETREG_RGBAQ(colorR, colorG, colorB, colorA, 0x00);
124}
125
126static void PS2_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
127{
128}
129
130static bool PS2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
131{
132 GSTEXTURE *ps2_tex = (GSTEXTURE *)SDL_calloc(1, sizeof(GSTEXTURE));
133
134 if (!ps2_tex) {
135 return false;
136 }
137
138 ps2_tex->Width = texture->w;
139 ps2_tex->Height = texture->h;
140 ps2_tex->PSM = PixelFormatToPS2PSM(texture->format);
141 ps2_tex->Mem = SDL_aligned_alloc(128, gsKit_texture_size_ee(ps2_tex->Width, ps2_tex->Height, ps2_tex->PSM));
142
143 if (!ps2_tex->Mem) {
144 SDL_free(ps2_tex);
145 return false;
146 }
147
148 texture->internal = ps2_tex;
149
150 return true;
151}
152
153static bool PS2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
154 const SDL_Rect *rect, void **pixels, int *pitch)
155{
156 GSTEXTURE *ps2_texture = (GSTEXTURE *)texture->internal;
157
158 *pixels =
159 (void *)((Uint8 *)ps2_texture->Mem + rect->y * ps2_texture->Width * SDL_BYTESPERPIXEL(texture->format) +
160 rect->x * SDL_BYTESPERPIXEL(texture->format));
161 *pitch = ps2_texture->Width * SDL_BYTESPERPIXEL(texture->format);
162 return true;
163}
164
165static void PS2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
166{
167 GSTEXTURE *ps2_texture = (GSTEXTURE *)texture->internal;
168 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
169
170 gsKit_TexManager_invalidate(data->gsGlobal, ps2_texture);
171}
172
173static bool PS2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
174 const SDL_Rect *rect, const void *pixels, int pitch)
175{
176 const Uint8 *src;
177 Uint8 *dst;
178 int row, length, dpitch;
179 src = pixels;
180
181 PS2_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch);
182 length = rect->w * SDL_BYTESPERPIXEL(texture->format);
183 if (length == pitch && length == dpitch) {
184 SDL_memcpy(dst, src, length * rect->h);
185 } else {
186 for (row = 0; row < rect->h; ++row) {
187 SDL_memcpy(dst, src, length);
188 src += pitch;
189 dst += dpitch;
190 }
191 }
192
193 PS2_UnlockTexture(renderer, texture);
194
195 return true;
196}
197
198static void PS2_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
199{
200 GSTEXTURE *ps2_texture = (GSTEXTURE *)texture->internal;
201 /*
202 set texture filtering according to scaleMode
203 supported hint values are nearest (0, default) or linear (1)
204 gskit scale mode is either GS_FILTER_NEAREST (good for tile-map)
205 or GS_FILTER_LINEAR (good for scaling)
206 */
207 uint32_t gsKitScaleMode = (scaleMode == SDL_SCALEMODE_NEAREST
208 ? GS_FILTER_NEAREST
209 : GS_FILTER_LINEAR);
210 ps2_texture->Filter = gsKitScaleMode;
211}
212
213static bool PS2_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
214{
215 return true;
216}
217
218static bool PS2_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
219{
220 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
221 const SDL_Rect *viewport = &cmd->data.viewport.rect;
222 data->viewport = (SDL_Rect *)viewport;
223
224 data->gsGlobal->OffsetX = (int)((2048.0f + (float)viewport->x) * 16.0f);
225 data->gsGlobal->OffsetY = (int)((2048.0f + (float)viewport->y) * 16.0f);
226 gsKit_set_scissor(data->gsGlobal, GS_SETREG_SCISSOR(viewport->x, viewport->x + viewport->w, viewport->y, viewport->y + viewport->h));
227
228 return true;
229}
230
231static bool PS2_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
232{
233 return true; // nothing to do in this backend.
234}
235
236static bool PS2_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
237{
238 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
239 GSPRIMPOINT *vertices = (GSPRIMPOINT *)SDL_AllocateRenderVertices(renderer, count * sizeof(GSPRIMPOINT), 4, &cmd->data.draw.first);
240 gs_rgbaq rgbaq;
241 int i;
242
243 if (!vertices) {
244 return false;
245 }
246
247 cmd->data.draw.count = count;
248
249 rgbaq = float_color_to_RGBAQ(&cmd->data.draw.color, cmd->data.draw.color_scale);
250
251 for (i = 0; i < count; i++, vertices++, points++) {
252 vertices->xyz2 = vertex_to_XYZ2(data->gsGlobal, points->x, points->y, 0);
253 vertices->rgbaq = rgbaq;
254 }
255 return true;
256}
257
258static bool PS2_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
259 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride,
260 int num_vertices, const void *indices, int num_indices, int size_indices,
261 float scale_x, float scale_y)
262{
263 int i;
264 int count = indices ? num_indices : num_vertices;
265 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
266 const float color_scale = cmd->data.draw.color_scale;
267
268 cmd->data.draw.count = count;
269 size_indices = indices ? size_indices : 0;
270
271 if (texture) {
272 GSPRIMUVPOINT *vertices = (GSPRIMUVPOINT *) SDL_AllocateRenderVertices(renderer, count * sizeof(GSPRIMUVPOINT), 4, &cmd->data.draw.first);
273 GSTEXTURE *ps2_tex = (GSTEXTURE *) texture->internal;
274
275 if (!vertices) {
276 return false;
277 }
278
279 for (i = 0; i < count; i++) {
280 int j;
281 float *xy_;
282 float *uv_;
283 SDL_FColor *col_;
284 if (size_indices == 4) {
285 j = ((const Uint32 *)indices)[i];
286 } else if (size_indices == 2) {
287 j = ((const Uint16 *)indices)[i];
288 } else if (size_indices == 1) {
289 j = ((const Uint8 *)indices)[i];
290 } else {
291 j = i;
292 }
293
294 xy_ = (float *)((char *)xy + j * xy_stride);
295 col_ = (SDL_FColor *)((char *)color + j * color_stride);
296 uv_ = (float *)((char *)uv + j * uv_stride);
297
298 vertices->xyz2 = vertex_to_XYZ2(data->gsGlobal, xy_[0] * scale_x, xy_[1] * scale_y, 0);
299 vertices->rgbaq = float_color_to_RGBAQ(col_, color_scale);
300 vertices->uv = vertex_to_UV(ps2_tex, uv_[0] * ps2_tex->Width, uv_[1] * ps2_tex->Height);
301
302 vertices++;
303 }
304
305 } else {
306 GSPRIMPOINT *vertices = (GSPRIMPOINT *)SDL_AllocateRenderVertices(renderer, count * sizeof(GSPRIMPOINT), 4, &cmd->data.draw.first);
307
308 if (!vertices) {
309 return false;
310 }
311
312 for (i = 0; i < count; i++) {
313 int j;
314 float *xy_;
315 SDL_FColor *col_;
316 if (size_indices == 4) {
317 j = ((const Uint32 *)indices)[i];
318 } else if (size_indices == 2) {
319 j = ((const Uint16 *)indices)[i];
320 } else if (size_indices == 1) {
321 j = ((const Uint8 *)indices)[i];
322 } else {
323 j = i;
324 }
325
326 xy_ = (float *)((char *)xy + j * xy_stride);
327 col_ = (SDL_FColor *)((char *)color + j * color_stride);
328
329 vertices->xyz2 = vertex_to_XYZ2(data->gsGlobal, xy_[0] * scale_x, xy_[1] * scale_y, 0);
330 vertices->rgbaq = float_color_to_RGBAQ(col_, color_scale);
331
332 vertices++;
333 }
334 }
335
336 return true;
337}
338
339static bool PS2_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
340{
341 return true; // nothing to do in this backend.
342}
343
344static bool PS2_RenderSetClipRect(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
345{
346 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
347 SDL_Rect *viewport = data->viewport;
348
349 const SDL_Rect *rect = &cmd->data.cliprect.rect;
350
351 if (cmd->data.cliprect.enabled) {
352 // We need to do it relative to saved viewport
353 viewport->x += rect->x;
354 viewport->y += rect->y;
355 viewport->w = SDL_min(viewport->w, rect->w);
356 viewport->h = SDL_min(viewport->h, rect->h);
357 }
358 gsKit_set_scissor(data->gsGlobal, GS_SETREG_SCISSOR(viewport->x, viewport->x + viewport->w, viewport->y, viewport->y + viewport->h));
359
360 return true;
361}
362
363static bool PS2_RenderSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
364{
365 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
366
367 data->drawColor = float_GS_SETREG_RGBAQ(&cmd->data.color.color, cmd->data.color.color_scale);
368 return true;
369}
370
371static bool PS2_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
372{
373 int offsetX, offsetY;
374 SDL_Rect *viewport;
375
376 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
377
378 // Clear the screen, so let's put default viewport
379 gsKit_set_scissor(data->gsGlobal, GS_SCISSOR_RESET);
380 // Put back original offset
381 offsetX = data->gsGlobal->OffsetX;
382 offsetY = data->gsGlobal->OffsetY;
383 data->gsGlobal->OffsetX = (int)(2048.0f * 16.0f);
384 data->gsGlobal->OffsetY = (int)(2048.0f * 16.0f);
385 gsKit_clear(data->gsGlobal, float_GS_SETREG_RGBAQ(&cmd->data.color.color, cmd->data.color.color_scale));
386
387 // Put back original offset
388 data->gsGlobal->OffsetX = offsetX;
389 data->gsGlobal->OffsetY = offsetY;
390
391 // // Put back view port
392 viewport = data->viewport;
393 gsKit_set_scissor(data->gsGlobal, GS_SETREG_SCISSOR(viewport->x, viewport->x + viewport->w, viewport->y, viewport->y + viewport->h));
394
395 return true;
396}
397
398static void PS2_SetBlendMode(PS2_RenderData *data, int blendMode)
399{
400#define A_COLOR_SOURCE 0
401#define A_COLOR_DEST 1
402#define A_COLOR_NULL 2
403#define A_ALPHA_SOURCE 0
404#define A_ALPHA_DEST 1
405#define A_ALPHA_FIX 2
406
407 switch (blendMode) {
408 case SDL_BLENDMODE_NONE:
409 {
410 data->gsGlobal->PrimAlphaEnable = GS_SETTING_OFF;
411 break;
412 }
413 case SDL_BLENDMODE_BLEND:
414 {
415 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_SOURCE, A_COLOR_DEST, A_ALPHA_SOURCE, A_COLOR_DEST, 0), 0);
416 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
417 break;
418 }
419 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
420 {
421 // FIXME: What are the settings for this?
422 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_SOURCE, A_COLOR_DEST, A_ALPHA_SOURCE, A_COLOR_DEST, 0), 0);
423 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
424 break;
425 }
426 case SDL_BLENDMODE_ADD:
427 {
428 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_SOURCE, A_COLOR_NULL, A_ALPHA_FIX, A_COLOR_DEST, 0x80), 0);
429 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
430 break;
431 }
432 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
433 {
434 // FIXME: What are the settings for this?
435 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_SOURCE, A_COLOR_NULL, A_ALPHA_FIX, A_COLOR_DEST, 0x80), 0);
436 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
437 break;
438 }
439 case SDL_BLENDMODE_MUL:
440 case SDL_BLENDMODE_MOD:
441 {
442 // We don't fully support MOD and MUL, however this is the best we can do
443 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_DEST, A_COLOR_NULL, A_ALPHA_SOURCE, A_COLOR_SOURCE, 0x80), 0);
444 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
445 break;
446 }
447 }
448}
449
450static bool PS2_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd)
451{
452 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
453 const size_t count = cmd->data.draw.count;
454
455 PS2_SetBlendMode(data, cmd->data.draw.blend);
456
457 if (cmd->data.draw.texture) {
458 const GSPRIMUVPOINT *verts = (GSPRIMUVPOINT *) (vertices + cmd->data.draw.first);
459 GSTEXTURE *ps2_tex = (GSTEXTURE *)cmd->data.draw.texture->internal;
460
461 gsKit_TexManager_bind(data->gsGlobal, ps2_tex);
462 gsKit_prim_list_triangle_goraud_texture_uv_3d(data->gsGlobal, ps2_tex, count, verts);
463 } else {
464 const GSPRIMPOINT *verts = (GSPRIMPOINT *)(vertices + cmd->data.draw.first);
465 gsKit_prim_list_triangle_gouraud_3d(data->gsGlobal, count, verts);
466 }
467
468 return true;
469}
470
471static bool PS2_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd)
472{
473 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
474 const size_t count = cmd->data.draw.count;
475 const GSPRIMPOINT *verts = (GSPRIMPOINT *)(vertices + cmd->data.draw.first);
476
477 PS2_SetBlendMode(data, cmd->data.draw.blend);
478 gsKit_prim_list_line_goraud_3d(data->gsGlobal, count, verts);
479
480 // We're done!
481 return true;
482}
483
484static bool PS2_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd)
485{
486 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
487 const size_t count = cmd->data.draw.count;
488 const GSPRIMPOINT *verts = (GSPRIMPOINT *)(vertices + cmd->data.draw.first);
489
490 PS2_SetBlendMode(data, cmd->data.draw.blend);
491 gsKit_prim_list_points(data->gsGlobal, count, verts);
492
493 // We're done!
494 return true;
495}
496
497static void PS2_InvalidateCachedState(SDL_Renderer *renderer)
498{
499 // currently this doesn't do anything. If this needs to do something (and someone is mixing their own rendering calls in!), update this.
500}
501
502static bool PS2_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
503{
504 while (cmd) {
505 switch (cmd->command) {
506 case SDL_RENDERCMD_SETVIEWPORT:
507 {
508 PS2_RenderSetViewPort(renderer, cmd);
509 // FIXME: We need to update the clip rect too, see https://github.com/libsdl-org/SDL/issues/9094
510 break;
511 }
512 case SDL_RENDERCMD_SETCLIPRECT:
513 {
514 PS2_RenderSetClipRect(renderer, cmd);
515 break;
516 }
517 case SDL_RENDERCMD_SETDRAWCOLOR:
518 {
519 PS2_RenderSetDrawColor(renderer, cmd);
520 break;
521 }
522 case SDL_RENDERCMD_CLEAR:
523 {
524 PS2_RenderClear(renderer, cmd);
525 break;
526 }
527 case SDL_RENDERCMD_DRAW_POINTS:
528 {
529 PS2_RenderPoints(renderer, vertices, cmd);
530 break;
531 }
532 case SDL_RENDERCMD_DRAW_LINES:
533 {
534 PS2_RenderLines(renderer, vertices, cmd);
535 break;
536 }
537 case SDL_RENDERCMD_FILL_RECTS: // unused
538 break;
539 case SDL_RENDERCMD_COPY: // unused
540 break;
541 case SDL_RENDERCMD_COPY_EX: // unused
542 break;
543 case SDL_RENDERCMD_GEOMETRY:
544 {
545 PS2_RenderGeometry(renderer, vertices, cmd);
546 break;
547 }
548 case SDL_RENDERCMD_NO_OP:
549 break;
550 }
551 cmd = cmd->next;
552 }
553 return true;
554}
555
556static bool PS2_RenderPresent(SDL_Renderer *renderer)
557{
558 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
559
560 if (data->gsGlobal->DoubleBuffering == GS_SETTING_OFF) {
561 if (data->vsync == -1) { // Dynamic
562 gsKit_sync(data->gsGlobal);
563 } else if (data->vsync == 1) {
564 gsKit_vsync_wait();
565 }
566 gsKit_queue_exec(data->gsGlobal);
567 } else {
568 gsKit_queue_exec(data->gsGlobal);
569 gsKit_finish();
570 if (data->vsync == -1) { // Dynamic
571 gsKit_sync(data->gsGlobal);
572 } else if (data->vsync == 1) {
573 gsKit_vsync_wait();
574 }
575 gsKit_flip(data->gsGlobal);
576 }
577 gsKit_TexManager_nextFrame(data->gsGlobal);
578 gsKit_clear(data->gsGlobal, GS_BLACK);
579 return true;
580}
581
582static void PS2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
583{
584 GSTEXTURE *ps2_texture = (GSTEXTURE *)texture->internal;
585 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
586
587 if (!data) {
588 return;
589 }
590
591 if (!ps2_texture) {
592 return;
593 }
594
595 // Free from vram
596 gsKit_TexManager_free(data->gsGlobal, ps2_texture);
597
598 SDL_aligned_free(ps2_texture->Mem);
599 SDL_free(ps2_texture);
600 texture->internal = NULL;
601}
602
603static void PS2_DestroyRenderer(SDL_Renderer *renderer)
604{
605 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
606
607 if (data) {
608 gsKit_clear(data->gsGlobal, GS_BLACK);
609 gsKit_vram_clear(data->gsGlobal);
610 gsKit_deinit_global(data->gsGlobal);
611 gsKit_remove_vsync_handler(data->vsync_callback_id);
612
613 SDL_free(data);
614 }
615
616 if (vsync_sema_id >= 0) {
617 DeleteSema(vsync_sema_id);
618 }
619}
620
621static bool PS2_SetVSync(SDL_Renderer *renderer, const int vsync)
622{
623 PS2_RenderData *data = (PS2_RenderData *)renderer->internal;
624 switch (vsync) {
625 case -1:
626 case 0:
627 case 1:
628 // Supported
629 break;
630 default:
631 return SDL_Unsupported();
632 }
633 data->vsync = vsync;
634 return true;
635}
636
637static bool PS2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
638{
639 PS2_RenderData *data;
640 GSGLOBAL *gsGlobal;
641 ee_sema_t sema;
642
643 SDL_SetupRendererColorspace(renderer, create_props);
644
645 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
646 return SDL_SetError("Unsupported output colorspace");
647 }
648
649 data = (PS2_RenderData *)SDL_calloc(1, sizeof(*data));
650 if (!data) {
651 return false;
652 }
653
654 // Specific gsKit init
655 sema.init_count = 0;
656 sema.max_count = 1;
657 sema.option = 0;
658 vsync_sema_id = CreateSema(&sema);
659
660 gsGlobal = gsKit_init_global_custom(RENDER_QUEUE_OS_POOLSIZE, RENDER_QUEUE_PER_POOLSIZE);
661
662 gsGlobal->Mode = GS_MODE_NTSC;
663 gsGlobal->Height = 448;
664
665 gsGlobal->PSM = GS_PSM_CT24;
666 gsGlobal->PSMZ = GS_PSMZ_16S;
667 gsGlobal->ZBuffering = GS_SETTING_OFF;
668 gsGlobal->DoubleBuffering = GS_SETTING_ON;
669 gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
670 gsGlobal->Dithering = GS_SETTING_OFF;
671
672 gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0, 1, 0, 1, 0), 0);
673
674 dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF);
675 dmaKit_chan_init(DMA_CHANNEL_GIF);
676
677 gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT);
678
679 gsKit_vram_clear(gsGlobal);
680
681 gsKit_init_screen(gsGlobal);
682
683 gsKit_TexManager_init(gsGlobal);
684
685 data->vsync_callback_id = gsKit_add_vsync_handler(vsync_handler);
686
687 gsKit_mode_switch(gsGlobal, GS_ONESHOT);
688
689 gsKit_clear(gsGlobal, GS_BLACK);
690
691 data->gsGlobal = gsGlobal;
692
693 renderer->WindowEvent = PS2_WindowEvent;
694 renderer->CreateTexture = PS2_CreateTexture;
695 renderer->UpdateTexture = PS2_UpdateTexture;
696 renderer->LockTexture = PS2_LockTexture;
697 renderer->UnlockTexture = PS2_UnlockTexture;
698 renderer->SetTextureScaleMode = PS2_SetTextureScaleMode;
699 renderer->SetRenderTarget = PS2_SetRenderTarget;
700 renderer->QueueSetViewport = PS2_QueueSetViewport;
701 renderer->QueueSetDrawColor = PS2_QueueNoOp;
702 renderer->QueueDrawPoints = PS2_QueueDrawPoints;
703 renderer->QueueDrawLines = PS2_QueueDrawPoints;
704 renderer->QueueGeometry = PS2_QueueGeometry;
705 renderer->InvalidateCachedState = PS2_InvalidateCachedState;
706 renderer->RunCommandQueue = PS2_RunCommandQueue;
707 renderer->RenderPresent = PS2_RenderPresent;
708 renderer->DestroyTexture = PS2_DestroyTexture;
709 renderer->DestroyRenderer = PS2_DestroyRenderer;
710 renderer->SetVSync = PS2_SetVSync;
711 renderer->internal = data;
712 PS2_InvalidateCachedState(renderer);
713 renderer->window = window;
714
715 renderer->name = PS2_RenderDriver.name;
716 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR1555);
717 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888);
718 SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 1024);
719
720 return true;
721}
722
723SDL_RenderDriver PS2_RenderDriver = {
724 PS2_CreateRenderer, "PS2 gsKit"
725};
726
727#endif // SDL_VIDEO_RENDER_PS2