src/render/psp/SDL_render_psp.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Wed, 29 Oct 2014 20:20:47 +0100
changeset 9201 21d9f9babb30
parent 8590 6e6bd53feff0
child 9544 520452e88618
permissions -rw-r--r--
Fixed bug 2647 - Memory leak in SDL_AddHintCallback function - SDL_hints.c

Nitz

Variable entry going out of scope leaks the storage it points to, at:

/* Need to add a hint entry for this watcher */
hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
if (!hint) {
return;
}

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