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