sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_render_psp.c (31229B)


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