Simple Directmedia Layer
at main 727 lines 24 kB view raw
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2024 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