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