Atlas - SDL_render_psp.c

Home / ext / SDL / src / render / psp Lines: 10 | Size: 50992 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_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 SDL_ScaleMode texture_scale_mode; 79 SDL_TextureAddressMode texture_address_mode_u; 80 SDL_TextureAddressMode texture_address_mode_v; 81} PSP_BlendState; 82 83typedef struct 84{ 85 SDL_Rect viewport; 86 bool viewport_dirty; 87 bool viewport_is_set; 88 89 bool cliprect_enabled_dirty; 90 bool cliprect_enabled; 91 bool cliprect_dirty; 92 SDL_Rect cliprect; 93 94 float draw_offset_x; 95 float draw_offset_y; 96 97 int drawablew; 98 int drawableh; 99 unsigned int color; 100} PSP_DrawStateCache; 101 102typedef struct 103{ 104 void *frontbuffer; /**< main screen buffer */ 105 void *backbuffer; /**< buffer presented to display */ 106 SDL_Texture *boundTarget; /**< currently bound rendertarget */ 107 bool initialized; /**< is driver initialized */ 108 bool displayListAvail; /**< is the display list already initialized for this frame */ 109 unsigned int psm; /**< format of the display buffers */ 110 unsigned int bpp; /**< bits per pixel of the main display */ 111 112 bool vsync; /**< whether we do vsync */ 113 PSP_BlendState blendState; /**< current blend mode */ 114 PSP_TextureData *most_recent_target; /**< start of render target LRU double linked list */ 115 PSP_TextureData *least_recent_target; /**< end of the LRU list */ 116 117 PSP_DrawStateCache drawstate; 118 bool vblank_not_reached; /**< whether vblank wasn't reached */ 119} PSP_RenderData; 120 121typedef struct 122{ 123 float x, y, z; 124} VertV; 125 126typedef struct 127{ 128 float u, v; 129 float x, y, z; 130} VertTV; 131 132typedef struct 133{ 134 SDL_Color col; 135 float x, y, z; 136} VertCV; 137 138typedef struct 139{ 140 float u, v; 141 SDL_Color col; 142 float x, y, z; 143} VertTCV; 144 145#define radToDeg(x) ((x)*180.f / SDL_PI_F) 146#define degToRad(x) ((x)*SDL_PI_F / 180.f) 147 148static float MathAbs(float x) 149{ 150 float result; 151 152 __asm__ volatile( 153 "mtv %1, S000\n" 154 "vabs.s S000, S000\n" 155 "mfv %0, S000\n" 156 : "=r"(result) 157 : "r"(x)); 158 159 return result; 160} 161 162static void MathSincos(float r, float *s, float *c) 163{ 164 __asm__ volatile( 165 "mtv %2, S002\n" 166 "vcst.s S003, VFPU_2_PI\n" 167 "vmul.s S002, S002, S003\n" 168 "vrot.p C000, S002, [s, c]\n" 169 "mfv %0, S000\n" 170 "mfv %1, S001\n" 171 : "=r"(*s), "=r"(*c) 172 : "r"(r)); 173} 174 175static void Swap(float *a, float *b) 176{ 177 float n = *a; 178 *a = *b; 179 *b = n; 180} 181 182static inline int InVram(void *data) 183{ 184 return data < (void *)0x04200000; 185} 186 187// Return next power of 2 188static int TextureNextPow2(unsigned int w) 189{ 190 unsigned int n = 2; 191 if (w == 0) { 192 return 0; 193 } 194 195 while (w > n) { 196 n <<= 1; 197 } 198 199 return n; 200} 201 202static void psp_on_vblank(u32 sub, PSP_RenderData *data) 203{ 204 if (data) { 205 data->vblank_not_reached = false; 206 } 207} 208 209static int PixelFormatToPSPFMT(SDL_PixelFormat format) 210{ 211 switch (format) { 212 case SDL_PIXELFORMAT_BGR565: 213 return GU_PSM_5650; 214 case SDL_PIXELFORMAT_ABGR1555: 215 return GU_PSM_5551; 216 case SDL_PIXELFORMAT_ABGR4444: 217 return GU_PSM_4444; 218 case SDL_PIXELFORMAT_ABGR8888: 219 return GU_PSM_8888; 220 default: 221 return GU_PSM_8888; 222 } 223} 224 225/// SECTION render target LRU management 226static void LRUTargetRelink(PSP_TextureData *psp_texture) 227{ 228 if (psp_texture->prevhotw) { 229 psp_texture->prevhotw->nexthotw = psp_texture->nexthotw; 230 } 231 if (psp_texture->nexthotw) { 232 psp_texture->nexthotw->prevhotw = psp_texture->prevhotw; 233 } 234} 235 236static void LRUTargetPushFront(PSP_RenderData *data, PSP_TextureData *psp_texture) 237{ 238 psp_texture->nexthotw = data->most_recent_target; 239 if (data->most_recent_target) { 240 data->most_recent_target->prevhotw = psp_texture; 241 } 242 data->most_recent_target = psp_texture; 243 if (!data->least_recent_target) { 244 data->least_recent_target = psp_texture; 245 } 246} 247 248static void LRUTargetRemove(PSP_RenderData *data, PSP_TextureData *psp_texture) 249{ 250 LRUTargetRelink(psp_texture); 251 if (data->most_recent_target == psp_texture) { 252 data->most_recent_target = psp_texture->nexthotw; 253 } 254 if (data->least_recent_target == psp_texture) { 255 data->least_recent_target = psp_texture->prevhotw; 256 } 257 psp_texture->prevhotw = NULL; 258 psp_texture->nexthotw = NULL; 259} 260 261static void LRUTargetBringFront(PSP_RenderData *data, PSP_TextureData *psp_texture) 262{ 263 if (data->most_recent_target == psp_texture) { 264 return; // nothing to do 265 } 266 LRUTargetRemove(data, psp_texture); 267 LRUTargetPushFront(data, psp_texture); 268} 269 270static void TextureStorageFree(void *storage) 271{ 272 if (InVram(storage)) { 273 vfree(storage); 274 } else { 275 SDL_free(storage); 276 } 277} 278 279static bool TextureSwizzle(PSP_TextureData *psp_texture, void *dst) 280{ 281 int bytewidth, height; 282 int rowblocks, rowblocksadd; 283 int i, j; 284 unsigned int blockaddress = 0; 285 unsigned int *src = NULL; 286 unsigned char *data = NULL; 287 288 if (psp_texture->swizzled) { 289 return true; 290 } 291 292 bytewidth = psp_texture->textureWidth * (psp_texture->bits >> 3); 293 height = psp_texture->size / bytewidth; 294 295 rowblocks = (bytewidth >> 4); 296 rowblocksadd = (rowblocks - 1) << 7; 297 298 src = (unsigned int *)psp_texture->data; 299 300 data = dst; 301 if (!data) { 302 data = SDL_malloc(psp_texture->size); 303 } 304 305 if (!data) { 306 return false; 307 } 308 309 for (j = 0; j < height; j++, blockaddress += 16) { 310 unsigned int *block; 311 312 block = (unsigned int *)&data[blockaddress]; 313 314 for (i = 0; i < rowblocks; i++) { 315 *block++ = *src++; 316 *block++ = *src++; 317 *block++ = *src++; 318 *block++ = *src++; 319 block += 28; 320 } 321 322 if ((j & 0x7) == 0x7) { 323 blockaddress += rowblocksadd; 324 } 325 } 326 327 TextureStorageFree(psp_texture->data); 328 psp_texture->data = data; 329 psp_texture->swizzled = true; 330 331 sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size); 332 return true; 333} 334 335static bool TextureUnswizzle(PSP_TextureData *psp_texture, void *dst) 336{ 337 int bytewidth, height; 338 int widthblocks, heightblocks; 339 int dstpitch, dstrow; 340 int blockx, blocky; 341 int j; 342 unsigned int *src = NULL; 343 unsigned char *data = NULL; 344 unsigned char *ydst = NULL; 345 346 if (!psp_texture->swizzled) { 347 return true; 348 } 349 350 bytewidth = psp_texture->textureWidth * (psp_texture->bits >> 3); 351 height = psp_texture->size / bytewidth; 352 353 widthblocks = bytewidth / 16; 354 heightblocks = height / 8; 355 356 dstpitch = (bytewidth - 16) / 4; 357 dstrow = bytewidth * 8; 358 359 src = (unsigned int *)psp_texture->data; 360 361 data = dst; 362 363 if (!data) { 364 data = SDL_malloc(psp_texture->size); 365 } 366 367 if (!data) { 368 return false; 369 } 370 371 ydst = (unsigned char *)data; 372 373 for (blocky = 0; blocky < heightblocks; ++blocky) { 374 unsigned char *xdst = ydst; 375 376 for (blockx = 0; blockx < widthblocks; ++blockx) { 377 unsigned int *block; 378 379 block = (unsigned int *)xdst; 380 381 for (j = 0; j < 8; ++j) { 382 *(block++) = *(src++); 383 *(block++) = *(src++); 384 *(block++) = *(src++); 385 *(block++) = *(src++); 386 block += dstpitch; 387 } 388 389 xdst += 16; 390 } 391 392 ydst += dstrow; 393 } 394 395 TextureStorageFree(psp_texture->data); 396 397 psp_texture->data = data; 398 399 psp_texture->swizzled = false; 400 401 sceKernelDcacheWritebackRange(psp_texture->data, psp_texture->size); 402 return true; 403} 404 405static bool TextureSpillToSram(PSP_RenderData *data, PSP_TextureData *psp_texture) 406{ 407 // Assumes the texture is in VRAM 408 if (psp_texture->swizzled) { 409 // Texture was swizzled in vram, just copy to system memory 410 void *sdata = SDL_malloc(psp_texture->size); 411 if (!sdata) { 412 return false; 413 } 414 415 SDL_memcpy(sdata, psp_texture->data, psp_texture->size); 416 vfree(psp_texture->data); 417 psp_texture->data = sdata; 418 return true; 419 } else { 420 return TextureSwizzle(psp_texture, NULL); // Will realloc in sysram 421 } 422} 423 424static bool TexturePromoteToVram(PSP_RenderData *data, PSP_TextureData *psp_texture, bool target) 425{ 426 // Assumes texture in sram and a large enough continuous block in vram 427 void *tdata = vramalloc(psp_texture->size); 428 if (psp_texture->swizzled && target) { 429 return TextureUnswizzle(psp_texture, tdata); 430 } else { 431 SDL_memcpy(tdata, psp_texture->data, psp_texture->size); 432 SDL_free(psp_texture->data); 433 psp_texture->data = tdata; 434 return true; 435 } 436} 437 438static bool TextureSpillLRU(PSP_RenderData *data, size_t wanted) 439{ 440 PSP_TextureData *lru = data->least_recent_target; 441 if (lru) { 442 if (!TextureSpillToSram(data, lru)) { 443 return false; 444 } 445 LRUTargetRemove(data, lru); 446 } else { 447 // Asked to spill but there nothing to spill 448 return SDL_SetError("Could not spill more VRAM to system memory. VRAM : %dKB,(%dKB), wanted %dKB", vmemavail() / 1024, vlargestblock() / 1024, wanted / 1024); 449 } 450 return true; 451} 452 453static bool TextureSpillTargetsForSpace(PSP_RenderData *data, size_t size) 454{ 455 while (vlargestblock() < size) { 456 if (!TextureSpillLRU(data, size)) { 457 return false; 458 } 459 } 460 return true; 461} 462 463static bool TextureBindAsTarget(PSP_RenderData *data, PSP_TextureData *psp_texture) 464{ 465 unsigned int dstFormat; 466 467 if (!InVram(psp_texture->data)) { 468 // Bring back the texture in vram 469 if (!TextureSpillTargetsForSpace(data, psp_texture->size)) { 470 return false; 471 } 472 if (!TexturePromoteToVram(data, psp_texture, true)) { 473 return false; 474 } 475 } 476 LRUTargetBringFront(data, psp_texture); 477 sceGuDrawBufferList(psp_texture->format, vrelptr(psp_texture->data), psp_texture->textureWidth); 478 479 // Stencil alpha dst hack 480 dstFormat = psp_texture->format; 481 if (dstFormat == GU_PSM_5551) { 482 sceGuEnable(GU_STENCIL_TEST); 483 sceGuStencilOp(GU_REPLACE, GU_REPLACE, GU_REPLACE); 484 sceGuStencilFunc(GU_GEQUAL, 0xff, 0xff); 485 sceGuEnable(GU_ALPHA_TEST); 486 sceGuAlphaFunc(GU_GREATER, 0x00, 0xff); 487 } else { 488 sceGuDisable(GU_STENCIL_TEST); 489 sceGuDisable(GU_ALPHA_TEST); 490 } 491 return true; 492} 493 494static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) 495{ 496} 497 498static bool PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) 499{ 500 PSP_RenderData *data = renderer->internal; 501 PSP_TextureData *psp_texture = (PSP_TextureData *)SDL_calloc(1, sizeof(*psp_texture)); 502 503 if (!psp_texture) { 504 return false; 505 } 506 507 psp_texture->swizzled = false; 508 psp_texture->width = texture->w; 509 psp_texture->height = texture->h; 510 psp_texture->textureHeight = TextureNextPow2(texture->h); 511 psp_texture->textureWidth = TextureNextPow2(texture->w); 512 psp_texture->format = PixelFormatToPSPFMT(texture->format); 513 514 switch (psp_texture->format) { 515 case GU_PSM_5650: 516 case GU_PSM_5551: 517 case GU_PSM_4444: 518 psp_texture->bits = 16; 519 break; 520 521 case GU_PSM_8888: 522 psp_texture->bits = 32; 523 break; 524 525 default: 526 SDL_free(psp_texture); 527 return false; 528 } 529 530 psp_texture->pitch = psp_texture->textureWidth * SDL_BYTESPERPIXEL(texture->format); 531 psp_texture->size = psp_texture->textureHeight * psp_texture->pitch; 532 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 533 if (!TextureSpillTargetsForSpace(renderer->internal, psp_texture->size)) { 534 SDL_free(psp_texture); 535 return false; 536 } 537 psp_texture->data = vramalloc(psp_texture->size); 538 if (psp_texture->data) { 539 LRUTargetPushFront(data, psp_texture); 540 } 541 } else { 542 psp_texture->data = SDL_calloc(1, psp_texture->size); 543 } 544 545 if (!psp_texture->data) { 546 SDL_free(psp_texture); 547 return false; 548 } 549 texture->internal = psp_texture; 550 551 return true; 552} 553 554static bool TextureShouldSwizzle(PSP_TextureData *psp_texture, SDL_Texture *texture) 555{ 556 return !((texture->access == SDL_TEXTUREACCESS_TARGET) && InVram(psp_texture->data)) && texture->access != SDL_TEXTUREACCESS_STREAMING && (texture->w >= 16 || texture->h >= 16); 557} 558 559static void SetTextureScaleMode(SDL_ScaleMode scaleMode) 560{ 561 switch (scaleMode) { 562 case SDL_SCALEMODE_PIXELART: 563 case SDL_SCALEMODE_NEAREST: 564 sceGuTexFilter(GU_NEAREST, GU_NEAREST); 565 break; 566 case SDL_SCALEMODE_LINEAR: 567 sceGuTexFilter(GU_LINEAR, GU_LINEAR); 568 break; 569 default: 570 break; 571 } 572} 573 574static int TranslateAddressMode(SDL_TextureAddressMode mode) 575{ 576 switch (mode) { 577 case SDL_TEXTURE_ADDRESS_CLAMP: 578 return GU_CLAMP; 579 case SDL_TEXTURE_ADDRESS_WRAP: 580 return GU_REPEAT; 581 default: 582 SDL_assert(!"Unknown texture address mode"); 583 return GU_CLAMP; 584 } 585} 586 587static void SetTextureAddressMode(SDL_TextureAddressMode addressModeU, SDL_TextureAddressMode addressModeV) 588{ 589 sceGuTexWrap(TranslateAddressMode(addressModeU), TranslateAddressMode(addressModeV)); 590} 591 592static void TextureActivate(SDL_Texture *texture) 593{ 594 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal; 595 596 // Swizzling is useless with small textures. 597 if (TextureShouldSwizzle(psp_texture, texture)) { 598 TextureSwizzle(psp_texture, NULL); 599 } 600 601 sceGuTexMode(psp_texture->format, 0, 0, psp_texture->swizzled); 602 sceGuTexImage(0, psp_texture->textureWidth, psp_texture->textureHeight, psp_texture->textureWidth, psp_texture->data); 603} 604 605static bool PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, 606 const SDL_Rect *rect, void **pixels, int *pitch); 607 608static bool PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, 609 const SDL_Rect *rect, const void *pixels, int pitch) 610{ 611 /* PSP_TextureData *psp_texture = (PSP_TextureData *) texture->internal; */ 612 const Uint8 *src; 613 Uint8 *dst; 614 int row, length, dpitch; 615 src = pixels; 616 617 PSP_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch); 618 length = rect->w * SDL_BYTESPERPIXEL(texture->format); 619 if (length == pitch && length == dpitch) { 620 SDL_memcpy(dst, src, length * rect->h); 621 } else { 622 for (row = 0; row < rect->h; ++row) { 623 SDL_memcpy(dst, src, length); 624 src += pitch; 625 dst += dpitch; 626 } 627 } 628 629 sceKernelDcacheWritebackAll(); 630 return true; 631} 632 633static bool PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, 634 const SDL_Rect *rect, void **pixels, int *pitch) 635{ 636 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal; 637 638 *pixels = 639 (void *)((Uint8 *)psp_texture->data + rect->y * psp_texture->pitch + 640 rect->x * SDL_BYTESPERPIXEL(texture->format)); 641 *pitch = psp_texture->pitch; 642 return true; 643} 644 645static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) 646{ 647 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal; 648 SDL_Rect rect; 649 650 // We do whole texture updates, at least for now 651 rect.x = 0; 652 rect.y = 0; 653 rect.w = texture->w; 654 rect.h = texture->h; 655 PSP_UpdateTexture(renderer, texture, &rect, psp_texture->data, psp_texture->pitch); 656} 657 658static bool PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) 659{ 660 return true; 661} 662 663static bool PSP_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 664{ 665 return true; // nothing to do in this backend. 666} 667 668static bool PSP_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) 669{ 670 VertV *verts = (VertV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertV), 4, &cmd->data.draw.first); 671 int i; 672 673 if (!verts) { 674 return false; 675 } 676 677 cmd->data.draw.count = count; 678 679 for (i = 0; i < count; i++, verts++, points++) { 680 verts->x = points->x; 681 verts->y = points->y; 682 verts->z = 0.0f; 683 } 684 685 return true; 686} 687 688static bool PSP_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 689 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, 690 int num_vertices, const void *indices, int num_indices, int size_indices, 691 float scale_x, float scale_y) 692{ 693 int i; 694 int count = indices ? num_indices : num_vertices; 695 const float color_scale = cmd->data.draw.color_scale; 696 697 cmd->data.draw.count = count; 698 size_indices = indices ? size_indices : 0; 699 700 if (!texture) { 701 VertCV *verts; 702 verts = (VertCV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertCV), 4, &cmd->data.draw.first); 703 if (!verts) { 704 return false; 705 } 706 707 for (i = 0; i < count; i++) { 708 int j; 709 float *xy_; 710 SDL_FColor *col_; 711 if (size_indices == 4) { 712 j = ((const Uint32 *)indices)[i]; 713 } else if (size_indices == 2) { 714 j = ((const Uint16 *)indices)[i]; 715 } else if (size_indices == 1) { 716 j = ((const Uint8 *)indices)[i]; 717 } else { 718 j = i; 719 } 720 721 xy_ = (float *)((char *)xy + j * xy_stride); 722 col_ = (SDL_FColor *)((char *)color + j * color_stride); 723 724 verts->x = xy_[0] * scale_x; 725 verts->y = xy_[1] * scale_y; 726 verts->z = 0; 727 728 verts->col.r = (Uint8)SDL_roundf(SDL_clamp(col_->r * color_scale, 0.0f, 1.0f) * 255.0f); 729 verts->col.g = (Uint8)SDL_roundf(SDL_clamp(col_->g * color_scale, 0.0f, 1.0f) * 255.0f); 730 verts->col.b = (Uint8)SDL_roundf(SDL_clamp(col_->b * color_scale, 0.0f, 1.0f) * 255.0f); 731 verts->col.a = (Uint8)SDL_roundf(SDL_clamp(col_->a, 0.0f, 1.0f) * 255.0f); 732 733 verts++; 734 } 735 } else { 736 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal; 737 VertTCV *verts; 738 verts = (VertTCV *)SDL_AllocateRenderVertices(renderer, count * sizeof(VertTCV), 4, &cmd->data.draw.first); 739 if (!verts) { 740 return false; 741 } 742 743 for (i = 0; i < count; i++) { 744 int j; 745 float *xy_; 746 SDL_FColor *col_; 747 float *uv_; 748 749 if (size_indices == 4) { 750 j = ((const Uint32 *)indices)[i]; 751 } else if (size_indices == 2) { 752 j = ((const Uint16 *)indices)[i]; 753 } else if (size_indices == 1) { 754 j = ((const Uint8 *)indices)[i]; 755 } else { 756 j = i; 757 } 758 759 xy_ = (float *)((char *)xy + j * xy_stride); 760 col_ = (SDL_FColor *)((char *)color + j * color_stride); 761 uv_ = (float *)((char *)uv + j * uv_stride); 762 763 verts->x = xy_[0] * scale_x; 764 verts->y = xy_[1] * scale_y; 765 verts->z = 0; 766 767 verts->col.r = (Uint8)SDL_roundf(SDL_clamp(col_->r * color_scale, 0.0f, 1.0f) * 255.0f); 768 verts->col.g = (Uint8)SDL_roundf(SDL_clamp(col_->g * color_scale, 0.0f, 1.0f) * 255.0f); 769 verts->col.b = (Uint8)SDL_roundf(SDL_clamp(col_->b * color_scale, 0.0f, 1.0f) * 255.0f); 770 verts->col.a = (Uint8)SDL_roundf(SDL_clamp(col_->a, 0.0f, 1.0f) * 255.0f); 771 772 verts->u = uv_[0] * psp_texture->textureWidth; 773 verts->v = uv_[1] * psp_texture->textureHeight; 774 775 verts++; 776 } 777 } 778 779 return true; 780} 781 782static bool PSP_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count) 783{ 784 VertV *verts = (VertV *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(VertV), 4, &cmd->data.draw.first); 785 int i; 786 787 if (!verts) { 788 return false; 789 } 790 791 cmd->data.draw.count = count; 792 for (i = 0; i < count; i++, rects++) { 793 verts->x = rects->x; 794 verts->y = rects->y; 795 verts->z = 0.0f; 796 verts++; 797 798 verts->x = rects->x + rects->w + 0.5f; 799 verts->y = rects->y + rects->h + 0.5f; 800 verts->z = 0.0f; 801 verts++; 802 } 803 804 return true; 805} 806 807static bool PSP_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 808 const SDL_FRect *srcrect, const SDL_FRect *dstrect) 809{ 810 VertTV *verts; 811 const float x = dstrect->x; 812 const float y = dstrect->y; 813 const float width = dstrect->w; 814 const float height = dstrect->h; 815 816 const float u0 = srcrect->x; 817 const float v0 = srcrect->y; 818 const float u1 = srcrect->x + srcrect->w; 819 const float v1 = srcrect->y + srcrect->h; 820 821 if ((MathAbs(u1) - MathAbs(u0)) < 64.0f) { 822 verts = (VertTV *)SDL_AllocateRenderVertices(renderer, 2 * sizeof(VertTV), 4, &cmd->data.draw.first); 823 if (!verts) { 824 return false; 825 } 826 827 cmd->data.draw.count = 1; 828 829 verts->u = u0; 830 verts->v = v0; 831 verts->x = x; 832 verts->y = y; 833 verts->z = 0; 834 verts++; 835 836 verts->u = u1; 837 verts->v = v1; 838 verts->x = x + width; 839 verts->y = y + height; 840 verts->z = 0; 841 verts++; 842 } else { 843 float start, end; 844 float curU = u0; 845 float curX = x; 846 const float endX = x + width; 847 const float slice = 64.0f; 848 const size_t count = (size_t)SDL_ceilf(width / slice); 849 size_t i; 850 float ustep = (u1 - u0) / width * slice; 851 852 if (ustep < 0.0f) { 853 ustep = -ustep; 854 } 855 856 cmd->data.draw.count = count; 857 858 verts = (VertTV *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(VertTV), 4, &cmd->data.draw.first); 859 if (!verts) { 860 return false; 861 } 862 863 for (i = 0, start = 0, end = width; i < count; i++, start += slice) { 864 const float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice; 865 const float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep; 866 867 SDL_assert(start < end); 868 869 verts->u = curU; 870 verts->v = v0; 871 verts->x = curX; 872 verts->y = y; 873 verts->z = 0; 874 verts++; 875 876 curU += sourceWidth; 877 curX += polyWidth; 878 879 verts->u = curU; 880 verts->v = v1; 881 verts->x = curX; 882 verts->y = (y + height); 883 verts->z = 0; 884 verts++; 885 } 886 } 887 888 return true; 889} 890 891static bool PSP_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 892 const SDL_FRect *srcrect, const SDL_FRect *dstrect, 893 const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y) 894{ 895 VertTV *verts = (VertTV *)SDL_AllocateRenderVertices(renderer, 4 * sizeof(VertTV), 4, &cmd->data.draw.first); 896 const float centerx = center->x; 897 const float centery = center->y; 898 const float x = dstrect->x + centerx; 899 const float y = dstrect->y + centery; 900 const float width = dstrect->w - centerx; 901 const float height = dstrect->h - centery; 902 float s, c; 903 float cw1, sw1, ch1, sh1, cw2, sw2, ch2, sh2; 904 905 float u0 = srcrect->x; 906 float v0 = srcrect->y; 907 float u1 = srcrect->x + srcrect->w; 908 float v1 = srcrect->y + srcrect->h; 909 910 if (!verts) { 911 return false; 912 } 913 914 cmd->data.draw.count = 1; 915 916 MathSincos(degToRad((float)(360 - angle)), &s, &c); 917 918 cw1 = c * -centerx; 919 sw1 = s * -centerx; 920 ch1 = c * -centery; 921 sh1 = s * -centery; 922 cw2 = c * width; 923 sw2 = s * width; 924 ch2 = c * height; 925 sh2 = s * height; 926 927 if (flip & SDL_FLIP_VERTICAL) { 928 Swap(&v0, &v1); 929 } 930 931 if (flip & SDL_FLIP_HORIZONTAL) { 932 Swap(&u0, &u1); 933 } 934 935 verts->u = u0; 936 verts->v = v0; 937 verts->x = x + cw1 + sh1; 938 verts->y = y - sw1 + ch1; 939 verts->z = 0; 940 verts++; 941 942 verts->u = u0; 943 verts->v = v1; 944 verts->x = x + cw1 + sh2; 945 verts->y = y - sw1 + ch2; 946 verts->z = 0; 947 verts++; 948 949 verts->u = u1; 950 verts->v = v1; 951 verts->x = x + cw2 + sh2; 952 verts->y = y - sw2 + ch2; 953 verts->z = 0; 954 verts++; 955 956 verts->u = u1; 957 verts->v = v0; 958 verts->x = x + cw2 + sh1; 959 verts->y = y - sw2 + ch1; 960 verts->z = 0; 961 962 if (scale_x != 1.0f || scale_y != 1.0f) { 963 verts->x *= scale_x; 964 verts->y *= scale_y; 965 verts--; 966 verts->x *= scale_x; 967 verts->y *= scale_y; 968 verts--; 969 verts->x *= scale_x; 970 verts->y *= scale_y; 971 verts--; 972 verts->x *= scale_x; 973 verts->y *= scale_y; 974 } 975 976 return true; 977} 978 979static void ResetBlendState(PSP_BlendState *state) 980{ 981 sceGuColor(0xffffffff); 982 state->color = 0xffffffff; 983 state->mode = SDL_BLENDMODE_INVALID; 984 state->texture = NULL; 985 sceGuDisable(GU_TEXTURE_2D); 986 sceGuShadeModel(GU_SMOOTH); 987 state->shadeModel = GU_SMOOTH; 988} 989 990static void StartDrawing(SDL_Renderer *renderer) 991{ 992 PSP_RenderData *data = (PSP_RenderData *)renderer->internal; 993 994 // Check if we need to start GU displaylist 995 if (!data->displayListAvail) { 996 sceGuStart(GU_DIRECT, DisplayList); 997 data->displayListAvail = true; 998 // ResetBlendState(&data->blendState); 999 } 1000 1001 // Check if we need a draw buffer change 1002 if (renderer->target != data->boundTarget) { 1003 SDL_Texture *texture = renderer->target; 1004 if (texture) { 1005 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal; 1006 // Set target, registering LRU 1007 TextureBindAsTarget(data, psp_texture); 1008 } else { 1009 // Set target back to screen 1010 sceGuDrawBufferList(data->psm, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); 1011 } 1012 data->boundTarget = texture; 1013 } 1014} 1015 1016static void PSP_SetBlendState(PSP_RenderData *data, PSP_BlendState *state) 1017{ 1018 PSP_BlendState *current = &data->blendState; 1019 1020 if (state->mode != current->mode) { 1021 switch (state->mode) { 1022 case SDL_BLENDMODE_NONE: 1023 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); 1024 sceGuDisable(GU_BLEND); 1025 break; 1026 case SDL_BLENDMODE_BLEND: 1027 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); 1028 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); 1029 sceGuEnable(GU_BLEND); 1030 break; 1031 case SDL_BLENDMODE_BLEND_PREMULTIPLIED: 1032 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); 1033 sceGuBlendFunc(GU_ADD, GU_FIX, GU_ONE_MINUS_SRC_ALPHA, 0x00FFFFFF, 0 ); 1034 sceGuEnable(GU_BLEND); 1035 break; 1036 case SDL_BLENDMODE_ADD: 1037 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); 1038 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF); 1039 sceGuEnable(GU_BLEND); 1040 break; 1041 case SDL_BLENDMODE_ADD_PREMULTIPLIED: 1042 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); 1043 sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0, 0x00FFFFFF); 1044 sceGuEnable(GU_BLEND); 1045 break; 1046 case SDL_BLENDMODE_MOD: 1047 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); 1048 sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); 1049 sceGuEnable(GU_BLEND); 1050 break; 1051 case SDL_BLENDMODE_MUL: 1052 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); 1053 // FIXME SDL_BLENDMODE_MUL is simplified, and dstA is in fact un-changed. 1054 sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); 1055 sceGuEnable(GU_BLEND); 1056 break; 1057 case SDL_BLENDMODE_INVALID: 1058 break; 1059 } 1060 } 1061 1062 if (state->color != current->color) { 1063 sceGuColor(state->color); 1064 } 1065 1066 if (state->shadeModel != current->shadeModel) { 1067 sceGuShadeModel(state->shadeModel); 1068 } 1069 1070 if (state->texture != current->texture) { 1071 if (state->texture) { 1072 TextureActivate(state->texture); 1073 sceGuEnable(GU_TEXTURE_2D); 1074 } else { 1075 sceGuDisable(GU_TEXTURE_2D); 1076 } 1077 } 1078 1079 if (state->texture) { 1080 SetTextureScaleMode(state->texture_scale_mode); 1081 SetTextureAddressMode(state->texture_address_mode_u, state->texture_address_mode_v); 1082 } 1083 1084 *current = *state; 1085} 1086 1087static void PSP_InvalidateCachedState(SDL_Renderer *renderer) 1088{ 1089 // currently this doesn't do anything. If this needs to do something (and someone is mixing their own rendering calls in!), update this. 1090} 1091 1092static void ClampCliprectToViewport(SDL_Rect *clip, const SDL_Rect *viewport) 1093{ 1094 int max_x_v, max_y_v, max_x_c, max_y_c; 1095 1096 if (clip->x < 0) { 1097 clip->w += clip->x; 1098 clip->x = 0; 1099 } 1100 1101 if (clip->y < 0) { 1102 clip->h += clip->y; 1103 clip->y = 0; 1104 } 1105 1106 max_x_c = clip->x + clip->w; 1107 max_y_c = clip->y + clip->h; 1108 1109 max_x_v = viewport->x + viewport->w; 1110 max_y_v = viewport->y + viewport->h; 1111 1112 if (max_x_c > max_x_v) { 1113 clip->w -= (max_x_v - max_x_c); 1114 } 1115 1116 if (max_y_c > max_y_v) { 1117 clip->h -= (max_y_v - max_y_c); 1118 } 1119} 1120 1121static void SetDrawState(PSP_RenderData *data) 1122{ 1123 if (data->drawstate.viewport_dirty) { 1124 SDL_Rect *viewport = &data->drawstate.viewport; 1125 /* FIXME: Find a genuine way to make viewport work (right now calling these functions here give no effect) */ 1126 /* 1127 sceGuOffset(2048 - (480 >> 1) + viewport->x, 2048 - (272 >> 1) + viewport->y); 1128 sceGuViewport(2048, 2048, viewport->w, viewport->h); 1129 */ 1130 data->drawstate.draw_offset_x = viewport->x; 1131 data->drawstate.draw_offset_y = viewport->y; 1132 data->drawstate.viewport_dirty = false; 1133 } 1134 1135 if (data->drawstate.cliprect_enabled_dirty) { 1136 if (!data->drawstate.cliprect_enabled && !data->drawstate.viewport_is_set) { 1137 sceGuScissor(0, 0, data->drawstate.drawablew, data->drawstate.drawableh); 1138 sceGuEnable(GU_SCISSOR_TEST); 1139 } 1140 data->drawstate.cliprect_enabled_dirty = false; 1141 } 1142 1143 if ((data->drawstate.cliprect_enabled || data->drawstate.viewport_is_set) && data->drawstate.cliprect_dirty) { 1144 SDL_Rect rect; 1145 SDL_Rect *viewport = &data->drawstate.viewport; 1146 SDL_copyp(&rect, &data->drawstate.cliprect); 1147 if (data->drawstate.viewport_is_set) { 1148 ClampCliprectToViewport(&rect, viewport); 1149 rect.x += viewport->x; 1150 rect.y += viewport->y; 1151 } 1152 sceGuEnable(GU_SCISSOR_TEST); 1153 sceGuScissor(rect.x, rect.y, rect.w, rect.h); 1154 data->drawstate.cliprect_dirty = false; 1155 } 1156} 1157 1158#define PSP_VERTICES_FUNK(FunkName, Type) \ 1159static const Type *FunkName(const PSP_DrawStateCache *drawstate, Uint8 *gpumem, SDL_RenderCommand *cmd, size_t count) \ 1160{ \ 1161 size_t i; \ 1162 float off_x, off_y; \ 1163 Type *verts = (Type *)(gpumem + cmd->data.draw.first); \ 1164\ 1165 if (!drawstate->viewport_is_set) { \ 1166 return verts; \ 1167 } \ 1168 \ 1169 off_x = drawstate->draw_offset_x; \ 1170 off_y = drawstate->draw_offset_y; \ 1171 \ 1172 for (i = 0; i < count; ++i) { \ 1173 verts[i].x += off_x; \ 1174 verts[i].y += off_y; \ 1175 } \ 1176\ 1177 return verts;\ 1178} 1179 1180PSP_VERTICES_FUNK(PSP_GetVertV, VertV) 1181PSP_VERTICES_FUNK(PSP_GetVertTV, VertTV) 1182PSP_VERTICES_FUNK(PSP_GetVertCV, VertCV) 1183PSP_VERTICES_FUNK(PSP_GetVertTCV, VertTCV) 1184 1185static bool PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) 1186{ 1187 PSP_RenderData *data = (PSP_RenderData *)renderer->internal; 1188 Uint8 *gpumem = NULL; 1189 int w = 0, h = 0; 1190 1191 StartDrawing(renderer); 1192 1193 /* note that before the renderer interface change, this would do extremely small 1194 batches with sceGuGetMemory()--a few vertices at a time--and it's not clear that 1195 this won't fail if you try to push 100,000 draw calls in a single batch. 1196 I don't know what the limits on PSP hardware are. It might be useful to have 1197 rendering backends report a reasonable maximum, so the higher level can flush 1198 if we appear to be exceeding that. */ 1199 gpumem = (Uint8 *)sceGuGetMemory(vertsize); 1200 if (!gpumem) { 1201 return SDL_SetError("Couldn't obtain a %d-byte vertex buffer!", (int)vertsize); 1202 } 1203 SDL_memcpy(gpumem, vertices, vertsize); 1204 1205 if (!data->boundTarget) { 1206 SDL_GetWindowSizeInPixels(renderer->window, &w, &h); 1207 } else { 1208 PSP_TextureData *psp_texture = (PSP_TextureData *)data->boundTarget->internal; 1209 w = psp_texture->width; 1210 h = psp_texture->height; 1211 } 1212 1213 if ((w != data->drawstate.drawablew) || (h != data->drawstate.drawableh)) { 1214 data->drawstate.viewport_dirty = true; // if the window dimensions changed, invalidate the current viewport, etc. 1215 data->drawstate.cliprect_dirty = true; 1216 data->drawstate.drawablew = w; 1217 data->drawstate.drawableh = h; 1218 } 1219 1220 while (cmd) { 1221 switch (cmd->command) { 1222 case SDL_RENDERCMD_SETDRAWCOLOR: 1223 { 1224 const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 1225 const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 1226 const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 1227 const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f); 1228 data->drawstate.color = GU_RGBA(r, g, b, a); 1229 break; 1230 } 1231 1232 case SDL_RENDERCMD_SETVIEWPORT: 1233 { 1234 SDL_Rect *viewport = &data->drawstate.viewport; 1235 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) { 1236 SDL_copyp(viewport, &cmd->data.viewport.rect); 1237 data->drawstate.viewport_dirty = true; 1238 data->drawstate.cliprect_dirty = true; 1239 data->drawstate.viewport_is_set = viewport->x != 0 || viewport->y != 0 || viewport->w != data->drawstate.drawablew || viewport->h != data->drawstate.drawableh; 1240 if (!data->drawstate.cliprect_enabled) { 1241 if (data->drawstate.viewport_is_set) { 1242 SDL_copyp(&data->drawstate.cliprect, viewport); 1243 data->drawstate.cliprect.x = 0; 1244 data->drawstate.cliprect.y = 0; 1245 } else { 1246 data->drawstate.cliprect_enabled_dirty = true; 1247 } 1248 } 1249 } 1250 break; 1251 } 1252 1253 case SDL_RENDERCMD_SETCLIPRECT: 1254 { 1255 const SDL_Rect *rect = &cmd->data.cliprect.rect; 1256 const SDL_Rect *viewport = &data->drawstate.viewport; 1257 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { 1258 data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; 1259 data->drawstate.cliprect_enabled_dirty = true; 1260 if (!data->drawstate.cliprect_enabled && data->drawstate.viewport_is_set) { 1261 SDL_copyp(&data->drawstate.cliprect, viewport); 1262 data->drawstate.cliprect.x = 0; 1263 data->drawstate.cliprect.y = 0; 1264 } 1265 } 1266 1267 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) { 1268 SDL_copyp(&data->drawstate.cliprect, rect); 1269 data->drawstate.cliprect_dirty = true; 1270 } 1271 break; 1272 } 1273 1274 case SDL_RENDERCMD_CLEAR: 1275 { 1276 const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 1277 const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 1278 const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 1279 const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f); 1280 sceGuClearColor(GU_RGBA(r, g, b, a)); 1281 sceGuClearStencil(a); 1282 sceGuClear(GU_COLOR_BUFFER_BIT | GU_STENCIL_BUFFER_BIT); 1283 break; 1284 } 1285 1286 case SDL_RENDERCMD_DRAW_POINTS: 1287 { 1288 const size_t count = cmd->data.draw.count; 1289 const VertV *verts; // = (VertV *)(gpumem + cmd->data.draw.first); 1290 PSP_BlendState state = { 1291 .color = data->drawstate.color, 1292 .texture = NULL, 1293 .texture_scale_mode = SDL_SCALEMODE_INVALID, 1294 .texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID, 1295 .texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID, 1296 .mode = cmd->data.draw.blend, 1297 .shadeModel = GU_FLAT 1298 }; 1299 SetDrawState(data); 1300 verts = PSP_GetVertV(&data->drawstate, gpumem, cmd, count); 1301 PSP_SetBlendState(data, &state); 1302 sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); 1303 break; 1304 } 1305 1306 case SDL_RENDERCMD_DRAW_LINES: 1307 { 1308 const size_t count = cmd->data.draw.count; 1309 const VertV *verts; // = (VertV *)(gpumem + cmd->data.draw.first); 1310 PSP_BlendState state = { 1311 .color = data->drawstate.color, 1312 .texture = NULL, 1313 .texture_scale_mode = SDL_SCALEMODE_INVALID, 1314 .texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID, 1315 .texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID, 1316 .mode = cmd->data.draw.blend, 1317 .shadeModel = GU_FLAT 1318 }; 1319 SetDrawState(data); 1320 verts = PSP_GetVertV(&data->drawstate, gpumem, cmd, count); 1321 PSP_SetBlendState(data, &state); 1322 sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); 1323 break; 1324 } 1325 1326 case SDL_RENDERCMD_FILL_RECTS: 1327 { 1328 const size_t count = cmd->data.draw.count; 1329 const VertV *verts; // = (VertV *)(gpumem + cmd->data.draw.first); 1330 PSP_BlendState state = { 1331 .color = data->drawstate.color, 1332 .texture = NULL, 1333 .texture_scale_mode = SDL_SCALEMODE_INVALID, 1334 .texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID, 1335 .texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID, 1336 .mode = cmd->data.draw.blend, 1337 .shadeModel = GU_FLAT 1338 }; 1339 SetDrawState(data); 1340 verts = PSP_GetVertV(&data->drawstate, gpumem, cmd, 2 * count); 1341 PSP_SetBlendState(data, &state); 1342 sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2 * count, 0, verts); 1343 break; 1344 } 1345 1346 case SDL_RENDERCMD_COPY: 1347 { 1348 const size_t count = cmd->data.draw.count; 1349 const VertTV *verts; // = (VertTV *)(gpumem + cmd->data.draw.first); 1350 PSP_BlendState state = { 1351 .color = data->drawstate.color, 1352 .texture = cmd->data.draw.texture, 1353 .texture_scale_mode = cmd->data.draw.texture_scale_mode, 1354 .texture_address_mode_u = cmd->data.draw.texture_address_mode_u, 1355 .texture_address_mode_v = cmd->data.draw.texture_address_mode_v, 1356 .mode = cmd->data.draw.blend, 1357 .shadeModel = GU_SMOOTH 1358 }; 1359 SetDrawState(data); 1360 verts = PSP_GetVertTV(&data->drawstate, gpumem, cmd, 2 * count); 1361 PSP_SetBlendState(data, &state); 1362 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2 * count, 0, verts); 1363 break; 1364 } 1365 1366 case SDL_RENDERCMD_COPY_EX: 1367 { 1368 const VertTV *verts; // = (VertTV *)(gpumem + cmd->data.draw.first); 1369 PSP_BlendState state = { 1370 .color = data->drawstate.color, 1371 .texture = cmd->data.draw.texture, 1372 .texture_scale_mode = cmd->data.draw.texture_scale_mode, 1373 .texture_address_mode_u = cmd->data.draw.texture_address_mode_u, 1374 .texture_address_mode_v = cmd->data.draw.texture_address_mode_v, 1375 .mode = cmd->data.draw.blend, 1376 .shadeModel = GU_SMOOTH 1377 }; 1378 SetDrawState(data); 1379 verts = PSP_GetVertTV(&data->drawstate, gpumem, cmd, 4); 1380 PSP_SetBlendState(data, &state); 1381 sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 4, 0, verts); 1382 break; 1383 } 1384 1385 case SDL_RENDERCMD_GEOMETRY: 1386 { 1387 const size_t count = cmd->data.draw.count; 1388 SetDrawState(data); 1389 if (!cmd->data.draw.texture) { 1390 const VertCV *verts = PSP_GetVertCV(&data->drawstate, gpumem, cmd, count); 1391 sceGuDisable(GU_TEXTURE_2D); 1392 // In GU_SMOOTH mode 1393 sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); 1394 sceGuEnable(GU_TEXTURE_2D); 1395 } else { 1396 const VertTCV *verts; // = (VertTCV *)(gpumem + cmd->data.draw.first); 1397 PSP_BlendState state = { 1398 .color = data->drawstate.color, 1399 .texture = cmd->data.draw.texture, 1400 .texture_scale_mode = cmd->data.draw.texture_scale_mode, 1401 .texture_address_mode_u = cmd->data.draw.texture_address_mode_u, 1402 .texture_address_mode_v = cmd->data.draw.texture_address_mode_v, 1403 .mode = cmd->data.draw.blend, 1404 .shadeModel = GU_SMOOTH 1405 }; 1406 verts = PSP_GetVertTCV(&data->drawstate, gpumem, cmd, count); 1407 PSP_SetBlendState(data, &state); 1408 sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts); 1409 } 1410 break; 1411 } 1412 1413 case SDL_RENDERCMD_NO_OP: 1414 break; 1415 } 1416 1417 cmd = cmd->next; 1418 } 1419 1420 return true; 1421} 1422 1423static bool PSP_RenderPresent(SDL_Renderer *renderer) 1424{ 1425 PSP_RenderData *data = (PSP_RenderData *)renderer->internal; 1426 if (!data->displayListAvail) { 1427 return false; 1428 } 1429 1430 data->displayListAvail = false; 1431 sceGuFinish(); 1432 sceGuSync(0, 0); 1433 1434 if ((data->vsync) && (data->vblank_not_reached)) { 1435 sceDisplayWaitVblankStart(); 1436 } 1437 data->vblank_not_reached = true; 1438 1439 data->backbuffer = data->frontbuffer; 1440 data->frontbuffer = vabsptr(sceGuSwapBuffers()); 1441 1442 return true; 1443} 1444 1445static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) 1446{ 1447 PSP_RenderData *renderdata = (PSP_RenderData *)renderer->internal; 1448 PSP_TextureData *psp_texture = (PSP_TextureData *)texture->internal; 1449 1450 if (!renderdata) { 1451 return; 1452 } 1453 1454 if (!psp_texture) { 1455 return; 1456 } 1457 1458 LRUTargetRemove(renderdata, psp_texture); 1459 TextureStorageFree(psp_texture->data); 1460 SDL_free(psp_texture); 1461 texture->internal = NULL; 1462} 1463 1464static void PSP_DestroyRenderer(SDL_Renderer *renderer) 1465{ 1466 PSP_RenderData *data = (PSP_RenderData *)renderer->internal; 1467 if (data) { 1468 if (!data->initialized) { 1469 return; 1470 } 1471 1472 sceKernelDisableSubIntr(PSP_VBLANK_INT, 0); 1473 sceKernelReleaseSubIntrHandler(PSP_VBLANK_INT, 0); 1474 sceDisplayWaitVblankStart(); 1475 sceGuDisplay(GU_FALSE); 1476 sceGuTerm(); 1477 vfree(data->backbuffer); 1478 vfree(data->frontbuffer); 1479 1480 data->initialized = false; 1481 data->displayListAvail = false; 1482 SDL_free(data); 1483 } 1484} 1485 1486static bool PSP_SetVSync(SDL_Renderer *renderer, const int vsync) 1487{ 1488 PSP_RenderData *data = renderer->internal; 1489 data->vsync = vsync; 1490 return true; 1491} 1492 1493static bool PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) 1494{ 1495 PSP_RenderData *data; 1496 int pixelformat; 1497 void *doublebuffer = NULL; 1498 1499 SDL_SetupRendererColorspace(renderer, create_props); 1500 1501 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) { 1502 return SDL_SetError("Unsupported output colorspace"); 1503 } 1504 1505 data = (PSP_RenderData *)SDL_calloc(1, sizeof(*data)); 1506 if (!data) { 1507 return false; 1508 } 1509 1510 renderer->WindowEvent = PSP_WindowEvent; 1511 renderer->CreateTexture = PSP_CreateTexture; 1512 renderer->UpdateTexture = PSP_UpdateTexture; 1513 renderer->LockTexture = PSP_LockTexture; 1514 renderer->UnlockTexture = PSP_UnlockTexture; 1515 renderer->SetRenderTarget = PSP_SetRenderTarget; 1516 renderer->QueueSetViewport = PSP_QueueNoOp; 1517 renderer->QueueSetDrawColor = PSP_QueueNoOp; 1518 renderer->QueueDrawPoints = PSP_QueueDrawPoints; 1519 renderer->QueueDrawLines = PSP_QueueDrawPoints; // lines and points queue vertices the same way. 1520 renderer->QueueGeometry = PSP_QueueGeometry; 1521 renderer->QueueFillRects = PSP_QueueFillRects; 1522 renderer->QueueCopy = PSP_QueueCopy; 1523 renderer->QueueCopyEx = PSP_QueueCopyEx; 1524 renderer->InvalidateCachedState = PSP_InvalidateCachedState; 1525 renderer->RunCommandQueue = PSP_RunCommandQueue; 1526 renderer->RenderPresent = PSP_RenderPresent; 1527 renderer->DestroyTexture = PSP_DestroyTexture; 1528 renderer->DestroyRenderer = PSP_DestroyRenderer; 1529 renderer->SetVSync = PSP_SetVSync; 1530 renderer->internal = data; 1531 PSP_InvalidateCachedState(renderer); 1532 renderer->window = window; 1533 1534 renderer->name = PSP_RenderDriver.name; 1535 renderer->npot_texture_wrap_unsupported = true; 1536 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGR565); 1537 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR1555); 1538 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR4444); 1539 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); 1540 SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 512); 1541 1542 data->initialized = true; 1543 data->most_recent_target = NULL; 1544 data->least_recent_target = NULL; 1545 1546 pixelformat = PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window)); 1547 switch (pixelformat) { 1548 case GU_PSM_4444: 1549 case GU_PSM_5650: 1550 case GU_PSM_5551: 1551 data->bpp = 2; 1552 data->psm = pixelformat; 1553 break; 1554 default: 1555 data->bpp = 4; 1556 data->psm = GU_PSM_8888; 1557 break; 1558 } 1559 1560 doublebuffer = vramalloc(PSP_FRAME_BUFFER_SIZE * data->bpp * 2); 1561 data->backbuffer = doublebuffer; 1562 data->frontbuffer = ((uint8_t *)doublebuffer) + PSP_FRAME_BUFFER_SIZE * data->bpp; 1563 1564 sceGuInit(); 1565 // setup GU 1566 sceGuStart(GU_DIRECT, DisplayList); 1567 sceGuDrawBuffer(data->psm, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); 1568 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH); 1569 1570 sceGuOffset(2048 - (PSP_SCREEN_WIDTH >> 1), 2048 - (PSP_SCREEN_HEIGHT >> 1)); 1571 sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); 1572 1573 sceGuDisable(GU_DEPTH_TEST); 1574 1575 // Scissoring 1576 sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); 1577 sceGuEnable(GU_SCISSOR_TEST); 1578 1579 // Backface culling 1580 sceGuDisable(GU_CULL_FACE); 1581 1582 // Setup initial blend state 1583 ResetBlendState(&data->blendState); 1584 1585 sceGuFinish(); 1586 sceGuSync(0, 0); 1587 sceDisplayWaitVblankStartCB(); 1588 sceGuDisplay(GU_TRUE); 1589 1590 // Improve performance when VSYC is enabled and it is not reaching the 60 FPS 1591 data->vblank_not_reached = true; 1592 sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, psp_on_vblank, data); 1593 sceKernelEnableSubIntr(PSP_VBLANK_INT, 0); 1594 1595 return true; 1596} 1597 1598SDL_RenderDriver PSP_RenderDriver = { 1599 PSP_CreateRenderer, "PSP" 1600}; 1601 1602#endif // SDL_VIDEO_RENDER_PSP 1603
[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.