Atlas - SDL_render_ps2.c

Home / ext / SDL / src / render / ps2 Lines: 1 | Size: 24729 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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(int reason) 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 gs_rgbaq float_color_to_RGBAQ_tex(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) * 127.0f); 119 uint8_t colorG = (uint8_t)SDL_roundf(SDL_clamp(color->g * color_scale, 0.0f, 1.0f) * 127.0f); 120 uint8_t colorB = (uint8_t)SDL_roundf(SDL_clamp(color->b * color_scale, 0.0f, 1.0f) * 127.0f); 121 uint8_t colorA = (uint8_t)SDL_roundf(SDL_clamp(color->a, 0.0f, 1.0f) * 63.0f); 122 123 return color_to_RGBAQ(colorR, colorG, colorB, colorA, 0x00); 124} 125 126static uint64_t float_GS_SETREG_RGBAQ(const SDL_FColor *color, float color_scale) 127{ 128 uint8_t colorR = (uint8_t)SDL_roundf(SDL_clamp(color->r * color_scale, 0.0f, 1.0f) * 255.0f); 129 uint8_t colorG = (uint8_t)SDL_roundf(SDL_clamp(color->g * color_scale, 0.0f, 1.0f) * 255.0f); 130 uint8_t colorB = (uint8_t)SDL_roundf(SDL_clamp(color->b * color_scale, 0.0f, 1.0f) * 255.0f); 131 uint8_t colorA = (uint8_t)SDL_roundf(SDL_clamp(color->a, 0.0f, 1.0f) * 255.0f); 132 133 return GS_SETREG_RGBAQ(colorR, colorG, colorB, colorA, 0x00); 134} 135 136static void PS2_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) 137{ 138} 139 140static bool PS2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) 141{ 142 GSTEXTURE *ps2_tex = (GSTEXTURE *)SDL_calloc(1, sizeof(GSTEXTURE)); 143 144 if (!ps2_tex) { 145 return false; 146 } 147 148 ps2_tex->Width = texture->w; 149 ps2_tex->Height = texture->h; 150 ps2_tex->PSM = PixelFormatToPS2PSM(texture->format); 151 ps2_tex->Mem = SDL_aligned_alloc(128, gsKit_texture_size_ee(ps2_tex->Width, ps2_tex->Height, ps2_tex->PSM)); 152 153 if (!ps2_tex->Mem) { 154 SDL_free(ps2_tex); 155 return false; 156 } 157 158 texture->internal = ps2_tex; 159 160 return true; 161} 162 163static bool PS2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, 164 const SDL_Rect *rect, void **pixels, int *pitch) 165{ 166 GSTEXTURE *ps2_texture = (GSTEXTURE *)texture->internal; 167 168 *pixels = 169 (void *)((Uint8 *)ps2_texture->Mem + rect->y * ps2_texture->Width * SDL_BYTESPERPIXEL(texture->format) + 170 rect->x * SDL_BYTESPERPIXEL(texture->format)); 171 *pitch = ps2_texture->Width * SDL_BYTESPERPIXEL(texture->format); 172 return true; 173} 174 175static void PS2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) 176{ 177 GSTEXTURE *ps2_texture = (GSTEXTURE *)texture->internal; 178 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 179 180 gsKit_TexManager_invalidate(data->gsGlobal, ps2_texture); 181} 182 183static bool PS2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, 184 const SDL_Rect *rect, const void *pixels, int pitch) 185{ 186 const Uint8 *src; 187 Uint8 *dst; 188 int row, length, dpitch; 189 src = pixels; 190 191 PS2_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch); 192 length = rect->w * SDL_BYTESPERPIXEL(texture->format); 193 if (length == pitch && length == dpitch) { 194 SDL_memcpy(dst, src, length * rect->h); 195 } else { 196 for (row = 0; row < rect->h; ++row) { 197 SDL_memcpy(dst, src, length); 198 src += pitch; 199 dst += dpitch; 200 } 201 } 202 203 PS2_UnlockTexture(renderer, texture); 204 205 return true; 206} 207 208static bool PS2_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) 209{ 210 return true; 211} 212 213static bool PS2_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 214{ 215 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 216 const SDL_Rect *viewport = &cmd->data.viewport.rect; 217 data->viewport = (SDL_Rect *)viewport; 218 219 data->gsGlobal->OffsetX = (int)((2048.0f + (float)viewport->x) * 16.0f); 220 data->gsGlobal->OffsetY = (int)((2048.0f + (float)viewport->y) * 16.0f); 221 gsKit_set_scissor(data->gsGlobal, GS_SETREG_SCISSOR(viewport->x, viewport->x + viewport->w, viewport->y, viewport->y + viewport->h)); 222 223 return true; 224} 225 226static bool PS2_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 227{ 228 return true; // nothing to do in this backend. 229} 230 231static bool PS2_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) 232{ 233 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 234 GSPRIMPOINT *vertices = (GSPRIMPOINT *)SDL_AllocateRenderVertices(renderer, count * sizeof(GSPRIMPOINT), 4, &cmd->data.draw.first); 235 gs_rgbaq rgbaq; 236 int i; 237 238 if (!vertices) { 239 return false; 240 } 241 242 cmd->data.draw.count = count; 243 244 rgbaq = float_color_to_RGBAQ(&cmd->data.draw.color, cmd->data.draw.color_scale); 245 246 for (i = 0; i < count; i++, vertices++, points++) { 247 vertices->xyz2 = vertex_to_XYZ2(data->gsGlobal, points->x, points->y, 0); 248 vertices->rgbaq = rgbaq; 249 } 250 return true; 251} 252 253static bool PS2_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 254 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, 255 int num_vertices, const void *indices, int num_indices, int size_indices, 256 float scale_x, float scale_y) 257{ 258 int i; 259 int count = indices ? num_indices : num_vertices; 260 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 261 const float color_scale = cmd->data.draw.color_scale; 262 263 cmd->data.draw.count = count; 264 size_indices = indices ? size_indices : 0; 265 266 if (texture) { 267 GSPRIMUVPOINT *vertices = (GSPRIMUVPOINT *) SDL_AllocateRenderVertices(renderer, count * sizeof(GSPRIMUVPOINT), 4, &cmd->data.draw.first); 268 GSTEXTURE *ps2_tex = (GSTEXTURE *) texture->internal; 269 270 if (!vertices) { 271 return false; 272 } 273 274 for (i = 0; i < count; i++) { 275 int j; 276 float *xy_; 277 float *uv_; 278 SDL_FColor *col_; 279 if (size_indices == 4) { 280 j = ((const Uint32 *)indices)[i]; 281 } else if (size_indices == 2) { 282 j = ((const Uint16 *)indices)[i]; 283 } else if (size_indices == 1) { 284 j = ((const Uint8 *)indices)[i]; 285 } else { 286 j = i; 287 } 288 289 xy_ = (float *)((char *)xy + j * xy_stride); 290 col_ = (SDL_FColor *)((char *)color + j * color_stride); 291 uv_ = (float *)((char *)uv + j * uv_stride); 292 293 vertices->xyz2 = vertex_to_XYZ2(data->gsGlobal, xy_[0] * scale_x, xy_[1] * scale_y, 0); 294 vertices->rgbaq = float_color_to_RGBAQ_tex(col_, color_scale); 295 vertices->uv = vertex_to_UV(ps2_tex, uv_[0] * ps2_tex->Width, uv_[1] * ps2_tex->Height); 296 297 vertices++; 298 } 299 300 } else { 301 GSPRIMPOINT *vertices = (GSPRIMPOINT *)SDL_AllocateRenderVertices(renderer, count * sizeof(GSPRIMPOINT), 4, &cmd->data.draw.first); 302 303 if (!vertices) { 304 return false; 305 } 306 307 for (i = 0; i < count; i++) { 308 int j; 309 float *xy_; 310 SDL_FColor *col_; 311 if (size_indices == 4) { 312 j = ((const Uint32 *)indices)[i]; 313 } else if (size_indices == 2) { 314 j = ((const Uint16 *)indices)[i]; 315 } else if (size_indices == 1) { 316 j = ((const Uint8 *)indices)[i]; 317 } else { 318 j = i; 319 } 320 321 xy_ = (float *)((char *)xy + j * xy_stride); 322 col_ = (SDL_FColor *)((char *)color + j * color_stride); 323 324 vertices->xyz2 = vertex_to_XYZ2(data->gsGlobal, xy_[0] * scale_x, xy_[1] * scale_y, 0); 325 vertices->rgbaq = float_color_to_RGBAQ(col_, color_scale); 326 327 vertices++; 328 } 329 } 330 331 return true; 332} 333 334static bool PS2_RenderSetViewPort(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 335{ 336 return true; // nothing to do in this backend. 337} 338 339static bool PS2_RenderSetClipRect(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 340{ 341 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 342 SDL_Rect *viewport = data->viewport; 343 344 const SDL_Rect *rect = &cmd->data.cliprect.rect; 345 346 if (cmd->data.cliprect.enabled) { 347 // We need to do it relative to saved viewport 348 viewport->x += rect->x; 349 viewport->y += rect->y; 350 viewport->w = SDL_min(viewport->w, rect->w); 351 viewport->h = SDL_min(viewport->h, rect->h); 352 } 353 gsKit_set_scissor(data->gsGlobal, GS_SETREG_SCISSOR(viewport->x, viewport->x + viewport->w, viewport->y, viewport->y + viewport->h)); 354 355 return true; 356} 357 358static bool PS2_RenderSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 359{ 360 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 361 362 data->drawColor = float_GS_SETREG_RGBAQ(&cmd->data.color.color, cmd->data.color.color_scale); 363 return true; 364} 365 366static bool PS2_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 367{ 368 int offsetX, offsetY; 369 SDL_Rect *viewport; 370 371 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 372 373 // Clear the screen, so let's put default viewport 374 gsKit_set_scissor(data->gsGlobal, GS_SCISSOR_RESET); 375 // Put back original offset 376 offsetX = data->gsGlobal->OffsetX; 377 offsetY = data->gsGlobal->OffsetY; 378 data->gsGlobal->OffsetX = (int)(2048.0f * 16.0f); 379 data->gsGlobal->OffsetY = (int)(2048.0f * 16.0f); 380 gsKit_clear(data->gsGlobal, float_GS_SETREG_RGBAQ(&cmd->data.color.color, cmd->data.color.color_scale)); 381 382 // Put back original offset 383 data->gsGlobal->OffsetX = offsetX; 384 data->gsGlobal->OffsetY = offsetY; 385 386 // // Put back view port 387 viewport = data->viewport; 388 gsKit_set_scissor(data->gsGlobal, GS_SETREG_SCISSOR(viewport->x, viewport->x + viewport->w, viewport->y, viewport->y + viewport->h)); 389 390 return true; 391} 392 393static void PS2_SetBlendMode(PS2_RenderData *data, int blendMode) 394{ 395#define A_COLOR_SOURCE 0 396#define A_COLOR_DEST 1 397#define A_COLOR_NULL 2 398#define A_ALPHA_SOURCE 0 399#define A_ALPHA_DEST 1 400#define A_ALPHA_FIX 2 401 402 switch (blendMode) { 403 case SDL_BLENDMODE_NONE: 404 { 405 data->gsGlobal->PrimAlphaEnable = GS_SETTING_OFF; 406 break; 407 } 408 case SDL_BLENDMODE_BLEND: 409 { 410 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_SOURCE, A_COLOR_DEST, A_ALPHA_SOURCE, A_COLOR_DEST, 0), 0); 411 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON; 412 break; 413 } 414 case SDL_BLENDMODE_BLEND_PREMULTIPLIED: 415 { 416 // FIXME: What are the settings for this? 417 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_SOURCE, A_COLOR_DEST, A_ALPHA_SOURCE, A_COLOR_DEST, 0), 0); 418 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON; 419 break; 420 } 421 case SDL_BLENDMODE_ADD: 422 { 423 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_SOURCE, A_COLOR_NULL, A_ALPHA_FIX, A_COLOR_DEST, 0x80), 0); 424 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON; 425 break; 426 } 427 case SDL_BLENDMODE_ADD_PREMULTIPLIED: 428 { 429 // FIXME: What are the settings for this? 430 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_SOURCE, A_COLOR_NULL, A_ALPHA_FIX, A_COLOR_DEST, 0x80), 0); 431 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON; 432 break; 433 } 434 case SDL_BLENDMODE_MUL: 435 case SDL_BLENDMODE_MOD: 436 { 437 // We don't fully support MOD and MUL, however this is the best we can do 438 gsKit_set_primalpha(data->gsGlobal, GS_SETREG_ALPHA(A_COLOR_DEST, A_COLOR_NULL, A_ALPHA_SOURCE, A_COLOR_SOURCE, 0x80), 0); 439 data->gsGlobal->PrimAlphaEnable = GS_SETTING_ON; 440 break; 441 } 442 } 443} 444 445static bool PS2_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) 446{ 447 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 448 const size_t count = cmd->data.draw.count; 449 450 PS2_SetBlendMode(data, cmd->data.draw.blend); 451 452 if (cmd->data.draw.texture) { 453 const GSPRIMUVPOINT *verts = (GSPRIMUVPOINT *) (vertices + cmd->data.draw.first); 454 GSTEXTURE *ps2_tex = (GSTEXTURE *)cmd->data.draw.texture->internal; 455 456 switch (cmd->data.draw.texture_scale_mode) { 457 case SDL_SCALEMODE_PIXELART: 458 case SDL_SCALEMODE_NEAREST: 459 ps2_tex->Filter = GS_FILTER_NEAREST; 460 break; 461 case SDL_SCALEMODE_LINEAR: 462 ps2_tex->Filter = GS_FILTER_LINEAR; 463 break; 464 default: 465 break; 466 } 467 gsKit_TexManager_bind(data->gsGlobal, ps2_tex); 468 gsKit_prim_list_triangle_goraud_texture_uv_3d(data->gsGlobal, ps2_tex, count, verts); 469 } else { 470 const GSPRIMPOINT *verts = (GSPRIMPOINT *)(vertices + cmd->data.draw.first); 471 gsKit_prim_list_triangle_gouraud_3d(data->gsGlobal, count, verts); 472 } 473 474 return true; 475} 476 477static bool PS2_RenderLines(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) 478{ 479 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 480 const size_t count = cmd->data.draw.count; 481 const GSPRIMPOINT *verts = (GSPRIMPOINT *)(vertices + cmd->data.draw.first); 482 483 PS2_SetBlendMode(data, cmd->data.draw.blend); 484 gsKit_prim_list_line_goraud_3d(data->gsGlobal, count, verts); 485 486 // We're done! 487 return true; 488} 489 490static bool PS2_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd) 491{ 492 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 493 const size_t count = cmd->data.draw.count; 494 const GSPRIMPOINT *verts = (GSPRIMPOINT *)(vertices + cmd->data.draw.first); 495 496 PS2_SetBlendMode(data, cmd->data.draw.blend); 497 gsKit_prim_list_points(data->gsGlobal, count, verts); 498 499 // We're done! 500 return true; 501} 502 503static void PS2_InvalidateCachedState(SDL_Renderer *renderer) 504{ 505 // currently this doesn't do anything. If this needs to do something (and someone is mixing their own rendering calls in!), update this. 506} 507 508static bool PS2_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) 509{ 510 while (cmd) { 511 switch (cmd->command) { 512 case SDL_RENDERCMD_SETVIEWPORT: 513 { 514 PS2_RenderSetViewPort(renderer, cmd); 515 // FIXME: We need to update the clip rect too, see https://github.com/libsdl-org/SDL/issues/9094 516 break; 517 } 518 case SDL_RENDERCMD_SETCLIPRECT: 519 { 520 PS2_RenderSetClipRect(renderer, cmd); 521 break; 522 } 523 case SDL_RENDERCMD_SETDRAWCOLOR: 524 { 525 PS2_RenderSetDrawColor(renderer, cmd); 526 break; 527 } 528 case SDL_RENDERCMD_CLEAR: 529 { 530 PS2_RenderClear(renderer, cmd); 531 break; 532 } 533 case SDL_RENDERCMD_DRAW_POINTS: 534 { 535 PS2_RenderPoints(renderer, vertices, cmd); 536 break; 537 } 538 case SDL_RENDERCMD_DRAW_LINES: 539 { 540 PS2_RenderLines(renderer, vertices, cmd); 541 break; 542 } 543 case SDL_RENDERCMD_FILL_RECTS: // unused 544 break; 545 case SDL_RENDERCMD_COPY: // unused 546 break; 547 case SDL_RENDERCMD_COPY_EX: // unused 548 break; 549 case SDL_RENDERCMD_GEOMETRY: 550 { 551 PS2_RenderGeometry(renderer, vertices, cmd); 552 break; 553 } 554 case SDL_RENDERCMD_NO_OP: 555 break; 556 } 557 cmd = cmd->next; 558 } 559 return true; 560} 561 562static bool PS2_RenderPresent(SDL_Renderer *renderer) 563{ 564 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 565 566 if (data->gsGlobal->DoubleBuffering == GS_SETTING_OFF) { 567 if (data->vsync == -1) { // Dynamic 568 gsKit_sync(data->gsGlobal); 569 } else if (data->vsync == 1) { 570 gsKit_vsync_wait(); 571 } 572 gsKit_queue_exec(data->gsGlobal); 573 } else { 574 gsKit_queue_exec(data->gsGlobal); 575 gsKit_finish(); 576 if (data->vsync == -1) { // Dynamic 577 gsKit_sync(data->gsGlobal); 578 } else if (data->vsync == 1) { 579 gsKit_vsync_wait(); 580 } 581 gsKit_flip(data->gsGlobal); 582 } 583 gsKit_TexManager_nextFrame(data->gsGlobal); 584 gsKit_clear(data->gsGlobal, GS_BLACK); 585 return true; 586} 587 588static void PS2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) 589{ 590 GSTEXTURE *ps2_texture = (GSTEXTURE *)texture->internal; 591 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 592 593 if (!data) { 594 return; 595 } 596 597 if (!ps2_texture) { 598 return; 599 } 600 601 // Free from vram 602 gsKit_TexManager_free(data->gsGlobal, ps2_texture); 603 604 SDL_aligned_free(ps2_texture->Mem); 605 SDL_free(ps2_texture); 606 texture->internal = NULL; 607} 608 609static void PS2_DestroyRenderer(SDL_Renderer *renderer) 610{ 611 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 612 613 if (data) { 614 gsKit_clear(data->gsGlobal, GS_BLACK); 615 gsKit_vram_clear(data->gsGlobal); 616 gsKit_deinit_global(data->gsGlobal); 617 gsKit_remove_vsync_handler(data->vsync_callback_id); 618 619 SDL_free(data); 620 } 621 622 if (vsync_sema_id >= 0) { 623 DeleteSema(vsync_sema_id); 624 } 625} 626 627static bool PS2_SetVSync(SDL_Renderer *renderer, const int vsync) 628{ 629 PS2_RenderData *data = (PS2_RenderData *)renderer->internal; 630 switch (vsync) { 631 case -1: 632 case 0: 633 case 1: 634 // Supported 635 break; 636 default: 637 return SDL_Unsupported(); 638 } 639 data->vsync = vsync; 640 return true; 641} 642 643static bool PS2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) 644{ 645 PS2_RenderData *data; 646 GSGLOBAL *gsGlobal; 647 ee_sema_t sema; 648 649 SDL_SetupRendererColorspace(renderer, create_props); 650 651 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) { 652 return SDL_SetError("Unsupported output colorspace"); 653 } 654 655 data = (PS2_RenderData *)SDL_calloc(1, sizeof(*data)); 656 if (!data) { 657 return false; 658 } 659 660 // Specific gsKit init 661 sema.init_count = 0; 662 sema.max_count = 1; 663 sema.option = 0; 664 vsync_sema_id = CreateSema(&sema); 665 666 gsGlobal = gsKit_init_global_custom(RENDER_QUEUE_OS_POOLSIZE, RENDER_QUEUE_PER_POOLSIZE); 667 668 // GS interlaced/progressive 669 if (SDL_GetHintBoolean(SDL_HINT_PS2_GS_PROGRESSIVE, false)) { 670 gsGlobal->Interlace = GS_NONINTERLACED; 671 } else { 672 gsGlobal->Interlace = GS_INTERLACED; 673 } 674 675 // GS width/height 676 gsGlobal->Width = 0; 677 gsGlobal->Height = 0; 678 const char *hint = SDL_GetHint(SDL_HINT_PS2_GS_WIDTH); 679 if (hint) { 680 gsGlobal->Width = SDL_atoi(hint); 681 } 682 hint = SDL_GetHint(SDL_HINT_PS2_GS_HEIGHT); 683 if (hint) { 684 gsGlobal->Height = SDL_atoi(hint); 685 } 686 if (gsGlobal->Width <= 0) { 687 gsGlobal->Width = 640; 688 } 689 if (gsGlobal->Height <= 0) { 690 gsGlobal->Height = 448; 691 } 692 693 // GS region 694 hint = SDL_GetHint(SDL_HINT_PS2_GS_MODE); 695 if (hint) { 696 if (SDL_strcasecmp(SDL_GetHint(SDL_HINT_PS2_GS_MODE), "NTSC") == 0) { 697 gsGlobal->Mode = GS_MODE_NTSC; 698 } 699 700 if (SDL_strcasecmp(SDL_GetHint(SDL_HINT_PS2_GS_MODE), "PAL") == 0) { 701 gsGlobal->Mode = GS_MODE_PAL; 702 } 703 } 704 705 gsGlobal->PSM = GS_PSM_CT24; 706 gsGlobal->PSMZ = GS_PSMZ_16S; 707 gsGlobal->ZBuffering = GS_SETTING_OFF; 708 gsGlobal->DoubleBuffering = GS_SETTING_ON; 709 gsGlobal->PrimAlphaEnable = GS_SETTING_ON; 710 gsGlobal->Dithering = GS_SETTING_OFF; 711 712 gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0, 1, 0, 1, 0), 0); 713 714 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); 715 dmaKit_chan_init(DMA_CHANNEL_GIF); 716 717 gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT); 718 719 gsKit_vram_clear(gsGlobal); 720 721 gsKit_init_screen(gsGlobal); 722 723 gsKit_TexManager_init(gsGlobal); 724 725 data->vsync_callback_id = gsKit_add_vsync_handler(vsync_handler); 726 727 gsKit_mode_switch(gsGlobal, GS_ONESHOT); 728 729 gsKit_clear(gsGlobal, GS_BLACK); 730 731 data->gsGlobal = gsGlobal; 732 733 renderer->WindowEvent = PS2_WindowEvent; 734 renderer->CreateTexture = PS2_CreateTexture; 735 renderer->UpdateTexture = PS2_UpdateTexture; 736 renderer->LockTexture = PS2_LockTexture; 737 renderer->UnlockTexture = PS2_UnlockTexture; 738 renderer->SetRenderTarget = PS2_SetRenderTarget; 739 renderer->QueueSetViewport = PS2_QueueSetViewport; 740 renderer->QueueSetDrawColor = PS2_QueueNoOp; 741 renderer->QueueDrawPoints = PS2_QueueDrawPoints; 742 renderer->QueueDrawLines = PS2_QueueDrawPoints; 743 renderer->QueueGeometry = PS2_QueueGeometry; 744 renderer->InvalidateCachedState = PS2_InvalidateCachedState; 745 renderer->RunCommandQueue = PS2_RunCommandQueue; 746 renderer->RenderPresent = PS2_RenderPresent; 747 renderer->DestroyTexture = PS2_DestroyTexture; 748 renderer->DestroyRenderer = PS2_DestroyRenderer; 749 renderer->SetVSync = PS2_SetVSync; 750 renderer->internal = data; 751 PS2_InvalidateCachedState(renderer); 752 renderer->window = window; 753 754 renderer->name = PS2_RenderDriver.name; 755 renderer->npot_texture_wrap_unsupported = true; 756 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR1555); 757 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); 758 SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 1024); 759 760 return true; 761} 762 763SDL_RenderDriver PS2_RenderDriver = { 764 PS2_CreateRenderer, "PS2 gsKit" 765}; 766 767#endif // SDL_VIDEO_RENDER_PS2 768
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.