1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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
51static 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
60typedef 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
76typedef 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
91typedef struct
92{
93 float x, y, z;
94} VertV;
95
96
97typedef 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
109float 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
122void 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
134void Swap(float *a, float *b)
135{
136 float n=*a;
137 *a = *b;
138 *b = n;
139}
140
141/* Return next power of 2 */
142static int
143TextureNextPow2(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
157static int
158PixelFormatToPSPFMT(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
174void
175StartDrawing(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
186int
187TextureSwizzle(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}
232int 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
297static void
298PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
299{
300}
301
302
303static int
304PSP_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
349static int
350PSP_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
351{
352 return SDL_Unsupported();
353}
354
355void
356TextureActivate(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
377static int
378PSP_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
403static int
404PSP_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
416static void
417PSP_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
430static void
431PSP_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
432{
433 /* Nothing to do because TextureActivate takes care of it */
434}
435
436static int
437PSP_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
438{
439 return 0;
440}
441
442static int
443PSP_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
444{
445 return 0; /* nothing to do in this backend. */
446}
447
448static int
449PSP_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
469static int
470PSP_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
496static int
497PSP_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
583static int
584PSP_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
655static void
656PSP_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
690static int
691PSP_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
860static int
861PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
862 Uint32 pixel_format, void * pixels, int pitch)
863{
864 return SDL_Unsupported();
865}
866
867static void
868PSP_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
886static void
887PSP_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
903static void
904PSP_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
924SDL_Renderer *
925PSP_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
1039SDL_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
1059