SDL_render_psp.c (31229B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 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 #if SDL_VIDEO_RENDER_PSP 24 25 #include "SDL_hints.h" 26 #include "../SDL_sysrender.h" 27 28 #include <pspkernel.h> 29 #include <pspdisplay.h> 30 #include <pspgu.h> 31 #include <pspgum.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <math.h> 35 #include <pspge.h> 36 #include <stdarg.h> 37 #include <stdlib.h> 38 #include <vram.h> 39 40 41 42 43 /* PSP renderer implementation, based on the PGE */ 44 45 #define PSP_SCREEN_WIDTH 480 46 #define PSP_SCREEN_HEIGHT 272 47 48 #define PSP_FRAME_BUFFER_WIDTH 512 49 #define PSP_FRAME_BUFFER_SIZE (PSP_FRAME_BUFFER_WIDTH*PSP_SCREEN_HEIGHT) 50 51 static unsigned int __attribute__((aligned(16))) DisplayList[262144]; 52 53 54 #define COL5650(r,g,b,a) ((r>>3) | ((g>>2)<<5) | ((b>>3)<<11)) 55 #define COL5551(r,g,b,a) ((r>>3) | ((g>>3)<<5) | ((b>>3)<<10) | (a>0?0x7000:0)) 56 #define COL4444(r,g,b,a) ((r>>4) | ((g>>4)<<4) | ((b>>4)<<8) | ((a>>4)<<12)) 57 #define COL8888(r,g,b,a) ((r) | ((g)<<8) | ((b)<<16) | ((a)<<24)) 58 59 60 typedef struct 61 { 62 void* frontbuffer ; 63 void* backbuffer ; 64 SDL_bool initialized ; 65 SDL_bool displayListAvail ; 66 unsigned int psm ; 67 unsigned int bpp ; 68 69 SDL_bool vsync; 70 unsigned int currentColor; 71 int currentBlendMode; 72 73 } PSP_RenderData; 74 75 76 typedef struct 77 { 78 void *data; /**< Image data. */ 79 unsigned int size; /**< Size of data in bytes. */ 80 unsigned int width; /**< Image width. */ 81 unsigned int height; /**< Image height. */ 82 unsigned int textureWidth; /**< Texture width (power of two). */ 83 unsigned int textureHeight; /**< Texture height (power of two). */ 84 unsigned int bits; /**< Image bits per pixel. */ 85 unsigned int format; /**< Image format - one of ::pgePixelFormat. */ 86 unsigned int pitch; 87 SDL_bool swizzled; /**< Is image swizzled. */ 88 89 } PSP_TextureData; 90 91 typedef struct 92 { 93 float x, y, z; 94 } VertV; 95 96 97 typedef struct 98 { 99 float u, v; 100 float x, y, z; 101 102 } VertTV; 103 104 #define PI 3.14159265358979f 105 106 #define radToDeg(x) ((x)*180.f/PI) 107 #define degToRad(x) ((x)*PI/180.f) 108 109 float MathAbs(float x) 110 { 111 float result; 112 113 __asm__ volatile ( 114 "mtv %1, S000\n" 115 "vabs.s S000, S000\n" 116 "mfv %0, S000\n" 117 : "=r"(result) : "r"(x)); 118 119 return result; 120 } 121 122 void MathSincos(float r, float *s, float *c) 123 { 124 __asm__ volatile ( 125 "mtv %2, S002\n" 126 "vcst.s S003, VFPU_2_PI\n" 127 "vmul.s S002, S002, S003\n" 128 "vrot.p C000, S002, [s, c]\n" 129 "mfv %0, S000\n" 130 "mfv %1, S001\n" 131 : "=r"(*s), "=r"(*c): "r"(r)); 132 } 133 134 void Swap(float *a, float *b) 135 { 136 float n=*a; 137 *a = *b; 138 *b = n; 139 } 140 141 /* Return next power of 2 */ 142 static int 143 TextureNextPow2(unsigned int w) 144 { 145 if(w == 0) 146 return 0; 147 148 unsigned int n = 2; 149 150 while(w > n) 151 n <<= 1; 152 153 return n; 154 } 155 156 157 static int 158 PixelFormatToPSPFMT(Uint32 format) 159 { 160 switch (format) { 161 case SDL_PIXELFORMAT_BGR565: 162 return GU_PSM_5650; 163 case SDL_PIXELFORMAT_ABGR1555: 164 return GU_PSM_5551; 165 case SDL_PIXELFORMAT_ABGR4444: 166 return GU_PSM_4444; 167 case SDL_PIXELFORMAT_ABGR8888: 168 return GU_PSM_8888; 169 default: 170 return GU_PSM_8888; 171 } 172 } 173 174 void 175 StartDrawing(SDL_Renderer * renderer) 176 { 177 PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata; 178 if(data->displayListAvail) 179 return; 180 181 sceGuStart(GU_DIRECT, DisplayList); 182 data->displayListAvail = SDL_TRUE; 183 } 184 185 186 int 187 TextureSwizzle(PSP_TextureData *psp_texture) 188 { 189 if(psp_texture->swizzled) 190 return 1; 191 192 int bytewidth = psp_texture->textureWidth*(psp_texture->bits>>3); 193 int height = psp_texture->size / bytewidth; 194 195 int rowblocks = (bytewidth>>4); 196 int rowblocksadd = (rowblocks-1)<<7; 197 unsigned int blockaddress = 0; 198 unsigned int *src = (unsigned int*) psp_texture->data; 199 200 unsigned char *data = NULL; 201 data = malloc(psp_texture->size); 202 203 int j; 204 205 for(j = 0; j < height; j++, blockaddress += 16) 206 { 207 unsigned int *block; 208 209 block = (unsigned int*)&data[blockaddress]; 210 211 int i; 212 213 for(i = 0; i < rowblocks; i++) 214 { 215 *block++ = *src++; 216 *block++ = *src++; 217 *block++ = *src++; 218 *block++ = *src++; 219 block += 28; 220 } 221 222 if((j & 0x7) == 0x7) 223 blockaddress += rowblocksadd; 224 } 225 226 free(psp_texture->data); 227 psp_texture->data = data; 228 psp_texture->swizzled = SDL_TRUE; 229 230 return 1; 231 } 232 int TextureUnswizzle(PSP_TextureData *psp_texture) 233 { 234 if(!psp_texture->swizzled) 235 return 1; 236 237 int blockx, blocky; 238 239 int bytewidth = psp_texture->textureWidth*(psp_texture->bits>>3); 240 int height = psp_texture->size / bytewidth; 241 242 int widthblocks = bytewidth/16; 243 int heightblocks = height/8; 244 245 int dstpitch = (bytewidth - 16)/4; 246 int dstrow = bytewidth * 8; 247 248 unsigned int *src = (unsigned int*) psp_texture->data; 249 250 unsigned char *data = NULL; 251 252 data = malloc(psp_texture->size); 253 254 if(!data) 255 return 0; 256 257 sceKernelDcacheWritebackAll(); 258 259 int j; 260 261 unsigned char *ydst = (unsigned char *)data; 262 263 for(blocky = 0; blocky < heightblocks; ++blocky) 264 { 265 unsigned char *xdst = ydst; 266 267 for(blockx = 0; blockx < widthblocks; ++blockx) 268 { 269 unsigned int *block; 270 271 block = (unsigned int*)xdst; 272 273 for(j = 0; j < 8; ++j) 274 { 275 *(block++) = *(src++); 276 *(block++) = *(src++); 277 *(block++) = *(src++); 278 *(block++) = *(src++); 279 block += dstpitch; 280 } 281 282 xdst += 16; 283 } 284 285 ydst += dstrow; 286 } 287 288 free(psp_texture->data); 289 290 psp_texture->data = data; 291 292 psp_texture->swizzled = SDL_FALSE; 293 294 return 1; 295 } 296 297 static void 298 PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) 299 { 300 } 301 302 303 static int 304 PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 305 { 306 /* PSP_RenderData *renderdata = (PSP_RenderData *) renderer->driverdata; */ 307 PSP_TextureData* psp_texture = (PSP_TextureData*) SDL_calloc(1, sizeof(*psp_texture)); 308 309 if(!psp_texture) 310 return -1; 311 312 psp_texture->swizzled = SDL_FALSE; 313 psp_texture->width = texture->w; 314 psp_texture->height = texture->h; 315 psp_texture->textureHeight = TextureNextPow2(texture->h); 316 psp_texture->textureWidth = TextureNextPow2(texture->w); 317 psp_texture->format = PixelFormatToPSPFMT(texture->format); 318 319 switch(psp_texture->format) 320 { 321 case GU_PSM_5650: 322 case GU_PSM_5551: 323 case GU_PSM_4444: 324 psp_texture->bits = 16; 325 break; 326 327 case GU_PSM_8888: 328 psp_texture->bits = 32; 329 break; 330 331 default: 332 return -1; 333 } 334 335 psp_texture->pitch = psp_texture->textureWidth * SDL_BYTESPERPIXEL(texture->format); 336 psp_texture->size = psp_texture->textureHeight*psp_texture->pitch; 337 psp_texture->data = SDL_calloc(1, psp_texture->size); 338 339 if(!psp_texture->data) 340 { 341 SDL_free(psp_texture); 342 return SDL_OutOfMemory(); 343 } 344 texture->driverdata = psp_texture; 345 346 return 0; 347 } 348 349 static int 350 PSP_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) 351 { 352 return SDL_Unsupported(); 353 } 354 355 void 356 TextureActivate(SDL_Texture * texture) 357 { 358 PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata; 359 int scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GU_NEAREST : GU_LINEAR; 360 361 /* Swizzling is useless with small textures. */ 362 if (texture->w >= 16 || texture->h >= 16) 363 { 364 TextureSwizzle(psp_texture); 365 } 366 367 sceGuEnable(GU_TEXTURE_2D); 368 sceGuTexWrap(GU_REPEAT, GU_REPEAT); 369 sceGuTexMode(psp_texture->format, 0, 0, psp_texture->swizzled); 370 sceGuTexFilter(scaleMode, scaleMode); /* GU_NEAREST good for tile-map */ 371 /* GU_LINEAR good for scaling */ 372 sceGuTexImage(0, psp_texture->textureWidth, psp_texture->textureHeight, psp_texture->textureWidth, psp_texture->data); 373 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); 374 } 375 376 377 static int 378 PSP_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 379 const SDL_Rect * rect, const void *pixels, int pitch) 380 { 381 /* PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata; */ 382 const Uint8 *src; 383 Uint8 *dst; 384 int row, length,dpitch; 385 src = pixels; 386 387 PSP_LockTexture(renderer, texture,rect,(void **)&dst, &dpitch); 388 length = rect->w * SDL_BYTESPERPIXEL(texture->format); 389 if (length == pitch && length == dpitch) { 390 SDL_memcpy(dst, src, length*rect->h); 391 } else { 392 for (row = 0; row < rect->h; ++row) { 393 SDL_memcpy(dst, src, length); 394 src += pitch; 395 dst += dpitch; 396 } 397 } 398 399 sceKernelDcacheWritebackAll(); 400 return 0; 401 } 402 403 static int 404 PSP_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 405 const SDL_Rect * rect, void **pixels, int *pitch) 406 { 407 PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata; 408 409 *pixels = 410 (void *) ((Uint8 *) psp_texture->data + rect->y * psp_texture->pitch + 411 rect->x * SDL_BYTESPERPIXEL(texture->format)); 412 *pitch = psp_texture->pitch; 413 return 0; 414 } 415 416 static void 417 PSP_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) 418 { 419 PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata; 420 SDL_Rect rect; 421 422 /* We do whole texture updates, at least for now */ 423 rect.x = 0; 424 rect.y = 0; 425 rect.w = texture->w; 426 rect.h = texture->h; 427 PSP_UpdateTexture(renderer, texture, &rect, psp_texture->data, psp_texture->pitch); 428 } 429 430 static void 431 PSP_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode) 432 { 433 /* Nothing to do because TextureActivate takes care of it */ 434 } 435 436 static int 437 PSP_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) 438 { 439 return 0; 440 } 441 442 static int 443 PSP_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd) 444 { 445 return 0; /* nothing to do in this backend. */ 446 } 447 448 static int 449 PSP_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count) 450 { 451 VertV *verts = (VertV *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertV), 4, &cmd->data.draw.first); 452 int i; 453 454 if (!verts) { 455 return -1; 456 } 457 458 cmd->data.draw.count = count; 459 460 for (i = 0; i < count; i++, verts++, points++) { 461 verts->x = points->x; 462 verts->y = points->y; 463 verts->z = 0.0f; 464 } 465 466 return 0; 467 } 468 469 static int 470 PSP_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count) 471 { 472 VertV *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (VertV), 4, &cmd->data.draw.first); 473 int i; 474 475 if (!verts) { 476 return -1; 477 } 478 479 cmd->data.draw.count = count; 480 for (i = 0; i < count; i++, rects++) { 481 const SDL_FRect *rect = &rects[i]; 482 verts->x = rect->x; 483 verts->y = rect->y; 484 verts->z = 0.0f; 485 verts++; 486 487 verts->x = rect->x + rect->w; 488 verts->y = rect->y + rect->h; 489 verts->z = 0.0f; 490 verts++; 491 } 492 493 return 0; 494 } 495 496 static int 497 PSP_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, 498 const SDL_Rect * srcrect, const SDL_FRect * dstrect) 499 { 500 VertTV *verts; 501 const float x = dstrect->x; 502 const float y = dstrect->y; 503 const float width = dstrect->w; 504 const float height = dstrect->h; 505 506 const float u0 = srcrect->x; 507 const float v0 = srcrect->y; 508 const float u1 = srcrect->x + srcrect->w; 509 const float v1 = srcrect->y + srcrect->h; 510 511 if((MathAbs(u1) - MathAbs(u0)) < 64.0f) 512 { 513 verts = (VertTV *) SDL_AllocateRenderVertices(renderer, 2 * sizeof (VertTV), 4, &cmd->data.draw.first); 514 if (!verts) { 515 return -1; 516 } 517 518 cmd->data.draw.count = 1; 519 520 verts->u = u0; 521 verts->v = v0; 522 verts->x = x; 523 verts->y = y; 524 verts->z = 0; 525 verts++; 526 527 verts->u = u1; 528 verts->v = v1; 529 verts->x = x + width; 530 verts->y = y + height; 531 verts->z = 0; 532 verts++; 533 } 534 else 535 { 536 float start, end; 537 float curU = u0; 538 float curX = x; 539 const float endX = x + width; 540 const float slice = 64.0f; 541 const size_t count = SDL_ceilf(width / slice); 542 size_t i; 543 float ustep = (u1 - u0)/width * slice; 544 545 if(ustep < 0.0f) 546 ustep = -ustep; 547 548 cmd->data.draw.count = count; 549 550 verts = (VertTV *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertTV), 4, &cmd->data.draw.first); 551 if (!verts) { 552 return -1; 553 } 554 555 556 for(i = 0, start = 0, end = width; i < count; i++, start += slice) 557 { 558 const float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice; 559 const float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep; 560 561 SDL_assert(start < end); 562 563 verts->u = curU; 564 verts->v = v0; 565 verts->x = curX; 566 verts->y = y; 567 verts->z = 0; 568 569 curU += sourceWidth; 570 curX += polyWidth; 571 572 verts->u = curU; 573 verts->v = v1; 574 verts->x = curX; 575 verts->y = (y + height); 576 verts->z = 0; 577 } 578 } 579 580 return 0; 581 } 582 583 static int 584 PSP_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, 585 const SDL_Rect * srcrect, const SDL_FRect * dstrect, 586 const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) 587 { 588 VertTV *verts = (VertTV *) SDL_AllocateRenderVertices(renderer, 4 * sizeof (VertTV), 4, &cmd->data.draw.first); 589 const float centerx = center->x; 590 const float centery = center->y; 591 const float x = dstrect->x + centerx; 592 const float y = dstrect->y + centery; 593 const float width = dstrect->w - centerx; 594 const float height = dstrect->h - centery; 595 float s, c; 596 597 float u0 = srcrect->x; 598 float v0 = srcrect->y; 599 float u1 = srcrect->x + srcrect->w; 600 float v1 = srcrect->y + srcrect->h; 601 602 603 if (!verts) { 604 return -1; 605 } 606 607 cmd->data.draw.count = 1; 608 609 MathSincos(degToRad(angle), &s, &c); 610 611 const float cw = c * width; 612 const float sw = s * width; 613 const float ch = c * height; 614 const float sh = s * height; 615 616 if (flip & SDL_FLIP_VERTICAL) { 617 Swap(&v0, &v1); 618 } 619 620 if (flip & SDL_FLIP_HORIZONTAL) { 621 Swap(&u0, &u1); 622 } 623 624 verts->u = u0; 625 verts->v = v0; 626 verts->x = x - cw + sh; 627 verts->y = y - sw - ch; 628 verts->z = 0; 629 verts++; 630 631 verts->u = u0; 632 verts->v = v1; 633 verts->x = x - cw - sh; 634 verts->y = y - sw + ch; 635 verts->z = 0; 636 verts++; 637 638 verts->u = u1; 639 verts->v = v1; 640 verts->x = x + cw - sh; 641 verts->y = y + sw + ch; 642 verts->z = 0; 643 verts++; 644 645 verts->u = u1; 646 verts->v = v0; 647 verts->x = x + cw + sh; 648 verts->y = y + sw - ch; 649 verts->z = 0; 650 verts++; 651 652 return 0; 653 } 654 655 static void 656 PSP_SetBlendMode(SDL_Renderer * renderer, int blendMode) 657 { 658 PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata; 659 if (blendMode != data-> currentBlendMode) { 660 switch (blendMode) { 661 case SDL_BLENDMODE_NONE: 662 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); 663 sceGuDisable(GU_BLEND); 664 break; 665 case SDL_BLENDMODE_BLEND: 666 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); 667 sceGuEnable(GU_BLEND); 668 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); 669 break; 670 case SDL_BLENDMODE_ADD: 671 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); 672 sceGuEnable(GU_BLEND); 673 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF ); 674 break; 675 case SDL_BLENDMODE_MOD: 676 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); 677 sceGuEnable(GU_BLEND); 678 sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); 679 break; 680 case SDL_BLENDMODE_MUL: 681 sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); 682 sceGuEnable(GU_BLEND); 683 sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); 684 break; 685 } 686 data->currentBlendMode = blendMode; 687 } 688 } 689 690 static int 691 PSP_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) 692 { 693 PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata; 694 size_t i; 695 696 StartDrawing(renderer); 697 698 /* note that before the renderer interface change, this would do extrememly small 699 batches with sceGuGetMemory()--a few vertices at a time--and it's not clear that 700 this won't fail if you try to push 100,000 draw calls in a single batch. 701 I don't know what the limits on PSP hardware are. It might be useful to have 702 rendering backends report a reasonable maximum, so the higher level can flush 703 if we appear to be exceeding that. */ 704 Uint8 *gpumem = (Uint8 *) sceGuGetMemory(vertsize); 705 if (!gpumem) { 706 return SDL_SetError("Couldn't obtain a %d-byte vertex buffer!", (int) vertsize); 707 } 708 SDL_memcpy(gpumem, vertices, vertsize); 709 710 while (cmd) { 711 switch (cmd->command) { 712 case SDL_RENDERCMD_SETDRAWCOLOR: { 713 break; /* !!! FIXME: we could cache drawstate like color */ 714 } 715 716 case SDL_RENDERCMD_SETVIEWPORT: { 717 SDL_Rect *viewport = &data->drawstate.viewport; 718 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) { 719 SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)); 720 data->drawstate.viewport_dirty = SDL_TRUE; 721 } 722 break; 723 } 724 725 case SDL_RENDERCMD_SETCLIPRECT: { 726 const SDL_Rect *rect = &cmd->data.cliprect.rect; 727 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { 728 data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; 729 data->drawstate.cliprect_enabled_dirty = SDL_TRUE; 730 } 731 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { 732 SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); 733 data->drawstate.cliprect_dirty = SDL_TRUE; 734 } 735 break; 736 } 737 738 case SDL_RENDERCMD_CLEAR: { 739 const Uint8 r = cmd->data.color.r; 740 const Uint8 g = cmd->data.color.g; 741 const Uint8 b = cmd->data.color.b; 742 const Uint8 a = cmd->data.color.a; 743 const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r); 744 /* !!! FIXME: we could cache drawstate like clear color */ 745 sceGuClearColor(color); 746 sceGuClearDepth(0); 747 sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT|GU_FAST_CLEAR_BIT); 748 break; 749 } 750 751 case SDL_RENDERCMD_DRAW_POINTS: { 752 const size_t count = cmd->data.draw.count; 753 const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first); 754 const Uint8 r = cmd->data.draw.r; 755 const Uint8 g = cmd->data.draw.g; 756 const Uint8 b = cmd->data.draw.b; 757 const Uint8 a = cmd->data.draw.a; 758 const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r); 759 /* !!! FIXME: we could cache draw state like color, texturing, etc */ 760 sceGuColor(color); 761 sceGuDisable(GU_TEXTURE_2D); 762 sceGuShadeModel(GU_FLAT); 763 sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, verts); 764 sceGuShadeModel(GU_SMOOTH); 765 sceGuEnable(GU_TEXTURE_2D); 766 break; 767 } 768 769 case SDL_RENDERCMD_DRAW_LINES: { 770 const size_t count = cmd->data.draw.count; 771 const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first); 772 const Uint8 r = cmd->data.draw.r; 773 const Uint8 g = cmd->data.draw.g; 774 const Uint8 b = cmd->data.draw.b; 775 const Uint8 a = cmd->data.draw.a; 776 const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r); 777 /* !!! FIXME: we could cache draw state like color, texturing, etc */ 778 sceGuColor(color); 779 sceGuDisable(GU_TEXTURE_2D); 780 sceGuShadeModel(GU_FLAT); 781 sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, verts); 782 sceGuShadeModel(GU_SMOOTH); 783 sceGuEnable(GU_TEXTURE_2D); 784 break; 785 } 786 787 case SDL_RENDERCMD_FILL_RECTS: { 788 const size_t count = cmd->data.draw.count; 789 const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first); 790 const Uint8 r = cmd->data.draw.r; 791 const Uint8 g = cmd->data.draw.g; 792 const Uint8 b = cmd->data.draw.b; 793 const Uint8 a = cmd->data.draw.a; 794 const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r); 795 /* !!! FIXME: we could cache draw state like color, texturing, etc */ 796 sceGuColor(color); 797 sceGuDisable(GU_TEXTURE_2D); 798 sceGuShadeModel(GU_FLAT); 799 sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2 * count, 0, verts); 800 sceGuShadeModel(GU_SMOOTH); 801 sceGuEnable(GU_TEXTURE_2D); 802 break; 803 } 804 805 case SDL_RENDERCMD_COPY: { 806 const size_t count = cmd->data.draw.count; 807 const VertTV *verts = (VertTV *) (gpumem + cmd->data.draw.first); 808 const Uint8 alpha = cmd->data.draw.a; 809 TextureActivate(cmd->data.draw.texture); 810 PSP_SetBlendMode(renderer, cmd->data.draw.blend); 811 812 if(alpha != 255) { /* !!! FIXME: is this right? */ 813 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); 814 sceGuColor(GU_RGBA(255, 255, 255, alpha)); 815 } else { 816 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); 817 sceGuColor(0xFFFFFFFF); 818 } 819 820 sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2 * count, 0, verts); 821 822 if(alpha != 255) { 823 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); 824 } 825 break; 826 } 827 828 case SDL_RENDERCMD_COPY_EX: { 829 const VertTV *verts = (VertTV *) (gpumem + cmd->data.draw.first); 830 const Uint8 alpha = cmd->data.draw.a; 831 TextureActivate(cmd->data.draw.texture); 832 PSP_SetBlendMode(renderer, cmd->data.draw.blend); 833 834 if(alpha != 255) { /* !!! FIXME: is this right? */ 835 sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); 836 sceGuColor(GU_RGBA(255, 255, 255, alpha)); 837 } else { 838 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); 839 sceGuColor(0xFFFFFFFF); 840 } 841 842 sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, verts); 843 844 if(alpha != 255) { 845 sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); 846 } 847 break; 848 } 849 850 case SDL_RENDERCMD_NO_OP: 851 break; 852 } 853 854 cmd = cmd->next; 855 } 856 857 return 0; 858 } 859 860 static int 861 PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 862 Uint32 pixel_format, void * pixels, int pitch) 863 { 864 return SDL_Unsupported(); 865 } 866 867 static void 868 PSP_RenderPresent(SDL_Renderer * renderer) 869 { 870 PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata; 871 if(!data->displayListAvail) 872 return; 873 874 data->displayListAvail = SDL_FALSE; 875 sceGuFinish(); 876 sceGuSync(0,0); 877 878 /* if(data->vsync) */ 879 sceDisplayWaitVblankStart(); 880 881 data->backbuffer = data->frontbuffer; 882 data->frontbuffer = vabsptr(sceGuSwapBuffers()); 883 884 } 885 886 static void 887 PSP_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) 888 { 889 PSP_RenderData *renderdata = (PSP_RenderData *) renderer->driverdata; 890 PSP_TextureData *psp_texture = (PSP_TextureData *) texture->driverdata; 891 892 if (renderdata == 0) 893 return; 894 895 if(psp_texture == 0) 896 return; 897 898 SDL_free(psp_texture->data); 899 SDL_free(psp_texture); 900 texture->driverdata = NULL; 901 } 902 903 static void 904 PSP_DestroyRenderer(SDL_Renderer * renderer) 905 { 906 PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata; 907 if (data) { 908 if (!data->initialized) 909 return; 910 911 StartDrawing(renderer); 912 913 sceGuTerm(); 914 /* vfree(data->backbuffer); */ 915 /* vfree(data->frontbuffer); */ 916 917 data->initialized = SDL_FALSE; 918 data->displayListAvail = SDL_FALSE; 919 SDL_free(data); 920 } 921 SDL_free(renderer); 922 } 923 924 SDL_Renderer * 925 PSP_CreateRenderer(SDL_Window * window, Uint32 flags) 926 { 927 928 SDL_Renderer *renderer; 929 PSP_RenderData *data; 930 int pixelformat; 931 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); 932 if (!renderer) { 933 SDL_OutOfMemory(); 934 return NULL; 935 } 936 937 data = (PSP_RenderData *) SDL_calloc(1, sizeof(*data)); 938 if (!data) { 939 PSP_DestroyRenderer(renderer); 940 SDL_OutOfMemory(); 941 return NULL; 942 } 943 944 945 renderer->WindowEvent = PSP_WindowEvent; 946 renderer->CreateTexture = PSP_CreateTexture; 947 renderer->SetTextureColorMod = PSP_SetTextureColorMod; 948 renderer->UpdateTexture = PSP_UpdateTexture; 949 renderer->LockTexture = PSP_LockTexture; 950 renderer->UnlockTexture = PSP_UnlockTexture; 951 renderer->SetTextureScaleMode = PSP_SetTextureScaleMode; 952 renderer->SetRenderTarget = PSP_SetRenderTarget; 953 renderer->QueueSetViewport = PSP_QueueSetViewport; 954 renderer->QueueSetDrawColor = PSP_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ 955 renderer->QueueDrawPoints = PSP_QueueDrawPoints; 956 renderer->QueueDrawLines = PSP_QueueDrawPoints; /* lines and points queue vertices the same way. */ 957 renderer->QueueFillRects = PSP_QueueFillRects; 958 renderer->QueueCopy = PSP_QueueCopy; 959 renderer->QueueCopyEx = PSP_QueueCopyEx; 960 renderer->RunCommandQueue = PSP_RunCommandQueue; 961 renderer->RenderReadPixels = PSP_RenderReadPixels; 962 renderer->RenderPresent = PSP_RenderPresent; 963 renderer->DestroyTexture = PSP_DestroyTexture; 964 renderer->DestroyRenderer = PSP_DestroyRenderer; 965 renderer->info = PSP_RenderDriver.info; 966 renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); 967 renderer->driverdata = data; 968 renderer->window = window; 969 970 if (data->initialized != SDL_FALSE) 971 return 0; 972 data->initialized = SDL_TRUE; 973 974 if (flags & SDL_RENDERER_PRESENTVSYNC) { 975 data->vsync = SDL_TRUE; 976 } else { 977 data->vsync = SDL_FALSE; 978 } 979 980 pixelformat=PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window)); 981 switch(pixelformat) 982 { 983 case GU_PSM_4444: 984 case GU_PSM_5650: 985 case GU_PSM_5551: 986 data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<1); 987 data->backbuffer = (unsigned int *)(0); 988 data->bpp = 2; 989 data->psm = pixelformat; 990 break; 991 default: 992 data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<2); 993 data->backbuffer = (unsigned int *)(0); 994 data->bpp = 4; 995 data->psm = GU_PSM_8888; 996 break; 997 } 998 999 sceGuInit(); 1000 /* setup GU */ 1001 sceGuStart(GU_DIRECT, DisplayList); 1002 sceGuDrawBuffer(data->psm, data->frontbuffer, PSP_FRAME_BUFFER_WIDTH); 1003 sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, data->backbuffer, PSP_FRAME_BUFFER_WIDTH); 1004 1005 1006 sceGuOffset(2048 - (PSP_SCREEN_WIDTH>>1), 2048 - (PSP_SCREEN_HEIGHT>>1)); 1007 sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); 1008 1009 data->frontbuffer = vabsptr(data->frontbuffer); 1010 data->backbuffer = vabsptr(data->backbuffer); 1011 1012 /* Scissoring */ 1013 sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); 1014 sceGuEnable(GU_SCISSOR_TEST); 1015 1016 /* Backface culling */ 1017 sceGuFrontFace(GU_CCW); 1018 sceGuEnable(GU_CULL_FACE); 1019 1020 /* Texturing */ 1021 sceGuEnable(GU_TEXTURE_2D); 1022 sceGuShadeModel(GU_SMOOTH); 1023 sceGuTexWrap(GU_REPEAT, GU_REPEAT); 1024 1025 /* Blending */ 1026 sceGuEnable(GU_BLEND); 1027 sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); 1028 1029 sceGuTexFilter(GU_LINEAR,GU_LINEAR); 1030 1031 sceGuFinish(); 1032 sceGuSync(0,0); 1033 sceDisplayWaitVblankStartCB(); 1034 sceGuDisplay(GU_TRUE); 1035 1036 return renderer; 1037 } 1038 1039 SDL_RenderDriver PSP_RenderDriver = { 1040 .CreateRenderer = PSP_CreateRenderer, 1041 .info = { 1042 .name = "PSP", 1043 .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, 1044 .num_texture_formats = 4, 1045 .texture_formats = { [0] = SDL_PIXELFORMAT_BGR565, 1046 [1] = SDL_PIXELFORMAT_ABGR1555, 1047 [2] = SDL_PIXELFORMAT_ABGR4444, 1048 [3] = SDL_PIXELFORMAT_ABGR8888, 1049 }, 1050 .max_texture_width = 512, 1051 .max_texture_height = 512, 1052 } 1053 }; 1054 1055 #endif /* SDL_VIDEO_RENDER_PSP */ 1056 1057 /* vi: set ts=4 sw=4 expandtab: */ 1058