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