Kaynağa Gözat

Remove vita2d render, add raw gxm render

Ivan Epifanov 4 yıl önce
ebeveyn
işleme
6ba8497518

+ 0 - 58
Makefile.vita.vita2d.dolce

@@ -1,58 +0,0 @@
-# Based on port by xerpi
-# Makefile to build the SDL library
-
-TARGET_LIB = libSDL2.a
-
-SOURCES = \
-	src/*.c \
-	src/atomic/*.c \
-	src/audio/*.c \
-	src/audio/vita/*.c \
-	src/cpuinfo/*.c \
-	src/events/*.c \
-	src/file/*.c \
-	src/haptic/*.c \
-	src/haptic/dummy/*.c \
-	src/joystick/*.c \
-	src/joystick/vita/*.c \
-	src/loadso/dummy/*.c \
-	src/power/*.c \
-	src/power/vita/*.c \
-	src/filesystem/vita/*.c \
-	src/render/*.c \
-	src/render/software/*.c \
-	src/render/vita2d/*.c \
-	src/sensor/*.c \
-	src/sensor/dummy/*.c \
-	src/stdlib/*.c \
-	src/thread/*.c \
-	src/thread/generic/SDL_systls.c \
-	src/thread/vita/*.c \
-	src/timer/*.c \
-	src/timer/vita/*.c \
-	src/video/*.c \
-	src/video/vita/*.c \
-	src/video/yuv2rgb/*.c \
-
-OBJS = $(shell echo $(SOURCES) | sed -e 's,\.c,\.o,g')
-
-PREFIX  = arm-dolce-eabi
-CC      = $(PREFIX)-gcc
-AR      = $(PREFIX)-ar
-CFLAGS  = -g -Wl,-q -Wall -O3 -Iinclude \
-                        -D__VITA__ -D__ARM_ARCH=7 -D__ARM_ARCH_7A__ \
-                        -mfpu=neon -mcpu=cortex-a9 -mfloat-abi=hard
-ASFLAGS = $(CFLAGS)
-
-$(TARGET_LIB): $(OBJS)
-	$(AR) rcs $@ $^
-
-clean:
-	@rm -f $(TARGET_LIB) $(OBJS)
-
-install: $(TARGET_LIB)
-	@mkdir -p "$(DOLCESDK)/arm-dolce-eabi/lib"
-	@cp  $(TARGET_LIB) $(DOLCESDK)/arm-dolce-eabi/lib
-	@mkdir -p "$(DOLCESDK)/arm-dolce-eabi/include/SDL2"
-	@cp include/*.h "$(DOLCESDK)/arm-dolce-eabi/include/SDL2"
-	@echo "Installed!"

+ 1 - 2
include/SDL_config_vita.h

@@ -140,8 +140,7 @@
 
 
 //#define SDL_VIDEO_RENDER_VITA_GLES2 1
-//#define SDL_VIDEO_RENDER_VITA_GXM 1
-#define SDL_VIDEO_RENDER_VITA_VITA2D 1
+#define SDL_VIDEO_RENDER_VITA_GXM 1
 
 #if defined(SDL_VIDEO_RENDER_VITA_GLES2) || defined(SDL_VIDEO_RENDER_VITA_GXM)
 #define SDL_VIDEO_OPENGL_ES2 1

+ 0 - 3
src/render/SDL_render.c

@@ -110,9 +110,6 @@ static const SDL_RenderDriver *render_drivers[] = {
 #if SDL_VIDEO_RENDER_VITA_GXM
     &VITA_GXM_RenderDriver,
 #endif
-#if SDL_VIDEO_RENDER_VITA_VITA2D
-    &VITA_VITA2D_RenderDriver,
-#endif
 #if SDL_VIDEO_RENDER_SW
     &SW_RenderDriver
 #endif

+ 0 - 1
src/render/SDL_sysrender.h

@@ -252,7 +252,6 @@ extern SDL_RenderDriver PSP_RenderDriver;
 extern SDL_RenderDriver SW_RenderDriver;
 extern SDL_RenderDriver VITA_GLES2_RenderDriver;
 extern SDL_RenderDriver VITA_GXM_RenderDriver;
-extern SDL_RenderDriver VITA_VITA2D_RenderDriver;
 
 /* Blend mode functions */
 extern SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode);

+ 0 - 713
src/render/vita2d/SDL_render_vita_vita2d.c

@@ -1,713 +0,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-#include "../../SDL_internal.h"
-
-#if SDL_VIDEO_RENDER_VITA_VITA2D
-
-#include "SDL_hints.h"
-#include "../SDL_sysrender.h"
-
-#include <psp2/types.h>
-#include <psp2/display.h>
-#include <psp2/gxm.h>
-#include <psp2/kernel/processmgr.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#include <vita2d.h>
-
-#define sceKernelDcacheWritebackAll() (void)0
-
-/* VITA renderer implementation, based on the vita2d lib  */
-
-extern int SDL_RecreateWindow(SDL_Window *window, Uint32 flags);
-
-static SDL_Renderer *VITA_VITA2D_CreateRenderer(SDL_Window *window, Uint32 flags);
-static void VITA_VITA2D_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event);
-static SDL_bool VITA_VITA2D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
-static int VITA_VITA2D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture);
-static int VITA_VITA2D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
-    const SDL_Rect *rect, const void *pixels, int pitch);
-static int VITA_VITA2D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
-                     const SDL_Rect * rect,
-                     const Uint8 *Yplane, int Ypitch,
-                     const Uint8 *Uplane, int Upitch,
-                     const Uint8 *Vplane, int Vpitch);
-
-static int VITA_VITA2D_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
-    const SDL_Rect *rect, void **pixels, int *pitch);
-
-static void VITA_VITA2D_UnlockTexture(SDL_Renderer *renderer,
-     SDL_Texture *texture);
-
-static void VITA_VITA2D_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode);
-
-static int VITA_VITA2D_SetRenderTarget(SDL_Renderer *renderer,
-         SDL_Texture *texture);
-
-static int VITA_VITA2D_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd);
-
-static int VITA_VITA2D_QueueSetDrawColor(SDL_Renderer * renderer, SDL_RenderCommand *cmd);
-
-static int VITA_VITA2D_RenderClear(SDL_Renderer *renderer);
-
-static int VITA_VITA2D_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count);
-
-static int VITA_VITA2D_RenderDrawPoints(SDL_Renderer *renderer,
-        const SDL_FPoint *points, int count);
-
-static int VITA_VITA2D_RenderDrawLines(SDL_Renderer *renderer,
-        const SDL_FPoint *points, int count);
-
-static int VITA_VITA2D_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count);
-
-static int VITA_VITA2D_RenderFillRects(SDL_Renderer *renderer,
-        const SDL_FRect *rects, int count);
-
-static int VITA_VITA2D_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
-                            const SDL_Rect * srcrect, const SDL_FRect * dstrect);
-
-static int VITA_VITA2D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
-
-static int VITA_VITA2D_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
-    Uint32 pixel_format, void *pixels, int pitch);
-
-static int VITA_VITA2D_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
-                            const SDL_Rect * srcquad, const SDL_FRect * dstrect,
-                            const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
-
-static void VITA_VITA2D_RenderPresent(SDL_Renderer *renderer);
-static void VITA_VITA2D_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
-static void VITA_VITA2D_DestroyRenderer(SDL_Renderer *renderer);
-
-
-SDL_RenderDriver VITA_VITA2D_RenderDriver = {
-    .CreateRenderer = VITA_VITA2D_CreateRenderer,
-    .info = {
-        .name = "VITA",
-        .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC,
-        .num_texture_formats = 1,
-        .texture_formats = {
-        [0] = SDL_PIXELFORMAT_ABGR8888,
-        },
-        .max_texture_width = 1024,
-        .max_texture_height = 1024,
-     }
-};
-
-#define VITA_VITA2D_SCREEN_WIDTH     960
-#define VITA_VITA2D_SCREEN_HEIGHT    544
-
-#define VITA_VITA2D_FRAME_BUFFER_WIDTH   1024
-#define VITA_VITA2D_FRAME_BUFFER_SIZE    (VITA_VITA2D_FRAME_BUFFER_WIDTH*VITA_VITA2D_SCREEN_HEIGHT)
-
-#define COL5650(r,g,b,a)    ((r>>3) | ((g>>2)<<5) | ((b>>3)<<11))
-#define COL5551(r,g,b,a)    ((r>>3) | ((g>>3)<<5) | ((b>>3)<<10) | (a>0?0x7000:0))
-#define COL4444(r,g,b,a)    ((r>>4) | ((g>>4)<<4) | ((b>>4)<<8) | ((a>>4)<<12))
-#define COL8888(r,g,b,a)    ((r) | ((g)<<8) | ((b)<<16) | ((a)<<24))
-
-typedef struct
-{
-    void          *frontbuffer;
-    void          *backbuffer;
-    SDL_bool      initialized;
-    SDL_bool      displayListAvail;
-    unsigned int  psm;
-    unsigned int  bpp;
-    SDL_bool      vsync;
-    unsigned int  currentColor;
-    int           currentBlendMode;
-
-} VITA_VITA2D_RenderData;
-
-
-typedef struct
-{
-    vita2d_texture  *tex;
-    unsigned int    pitch;
-    unsigned int    w;
-    unsigned int    h;
-} VITA_VITA2D_TextureData;
-
-typedef struct
-{
-    SDL_Rect    srcRect;
-    SDL_FRect   dstRect;
-} VITA_VITA2D_CopyData;
-
-void
-StartDrawing(SDL_Renderer *renderer)
-{
-    VITA_VITA2D_RenderData *data = (VITA_VITA2D_RenderData *) renderer->driverdata;
-    if(data->displayListAvail)
-        return;
-
-    vita2d_start_drawing();
-
-    data->displayListAvail = SDL_TRUE;
-}
-
-SDL_Renderer *
-VITA_VITA2D_CreateRenderer(SDL_Window *window, Uint32 flags)
-{
-
-    SDL_Renderer *renderer;
-    VITA_VITA2D_RenderData *data;
-
-    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
-    if (!renderer) {
-        SDL_OutOfMemory();
-        return NULL;
-    }
-
-    data = (VITA_VITA2D_RenderData *) SDL_calloc(1, sizeof(*data));
-    if (!data) {
-        VITA_VITA2D_DestroyRenderer(renderer);
-        SDL_OutOfMemory();
-        return NULL;
-    }
-
-    renderer->WindowEvent = VITA_VITA2D_WindowEvent;
-    renderer->SupportsBlendMode = VITA_VITA2D_SupportsBlendMode;
-    renderer->CreateTexture = VITA_VITA2D_CreateTexture;
-    renderer->UpdateTexture = VITA_VITA2D_UpdateTexture;
-    renderer->UpdateTextureYUV = VITA_VITA2D_UpdateTextureYUV;
-    renderer->LockTexture = VITA_VITA2D_LockTexture;
-    renderer->UnlockTexture = VITA_VITA2D_UnlockTexture;
-    renderer->SetTextureScaleMode = VITA_VITA2D_SetTextureScaleMode;
-    renderer->SetRenderTarget = VITA_VITA2D_SetRenderTarget;
-    renderer->QueueSetViewport = VITA_VITA2D_QueueSetViewport;
-    renderer->QueueSetDrawColor = VITA_VITA2D_QueueSetDrawColor;
-    renderer->QueueDrawPoints = VITA_VITA2D_QueueDrawPoints;
-    renderer->QueueDrawLines = VITA_VITA2D_QueueDrawPoints;  // lines and points queue the same way.
-    renderer->QueueFillRects = VITA_VITA2D_QueueFillRects;
-    renderer->QueueCopy = VITA_VITA2D_QueueCopy;
-    renderer->QueueCopyEx = VITA_VITA2D_QueueCopyEx;
-    renderer->RunCommandQueue = VITA_VITA2D_RunCommandQueue;
-    renderer->RenderReadPixels = VITA_VITA2D_RenderReadPixels;
-    renderer->RenderPresent = VITA_VITA2D_RenderPresent;
-    renderer->DestroyTexture = VITA_VITA2D_DestroyTexture;
-    renderer->DestroyRenderer = VITA_VITA2D_DestroyRenderer;
-    renderer->info = VITA_VITA2D_RenderDriver.info;
-    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
-    renderer->driverdata = data;
-    renderer->window = window;
-
-    if (data->initialized != SDL_FALSE)
-        return 0;
-    data->initialized = SDL_TRUE;
-
-    if (flags & SDL_RENDERER_PRESENTVSYNC) {
-        data->vsync = SDL_TRUE;
-    } else {
-        data->vsync = SDL_FALSE;
-    }
-
-    vita2d_init();
-    vita2d_set_vblank_wait(data->vsync);
-
-    return renderer;
-}
-
-static void
-VITA_VITA2D_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
-{
-
-}
-
-static SDL_bool
-VITA_VITA2D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
-{
-    return SDL_FALSE;
-}
-
-static int
-VITA_VITA2D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
-{
-    VITA_VITA2D_TextureData* vita_texture = (VITA_VITA2D_TextureData*) SDL_calloc(1, sizeof(*vita_texture));
-
-    if(!vita_texture)
-        return -1;
-
-    vita_texture->tex = vita2d_create_empty_texture(texture->w, texture->h);
-
-    if(!vita_texture->tex)
-    {
-        SDL_free(vita_texture);
-        return SDL_OutOfMemory();
-    }
-
-    texture->driverdata = vita_texture;
-
-    VITA_VITA2D_SetTextureScaleMode(renderer, texture, texture->scaleMode);
-
-    vita_texture->w = vita2d_texture_get_width(vita_texture->tex);
-    vita_texture->h = vita2d_texture_get_height(vita_texture->tex);
-    vita_texture->pitch = vita2d_texture_get_stride(vita_texture->tex);
-
-    return 0;
-}
-
-
-static int
-VITA_VITA2D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
-    const SDL_Rect *rect, const void *pixels, int pitch)
-{
-    const Uint8 *src;
-    Uint8 *dst;
-    int row, length,dpitch;
-    src = pixels;
-
-    VITA_VITA2D_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch);
-    length = rect->w * SDL_BYTESPERPIXEL(texture->format);
-    if (length == pitch && length == dpitch) {
-        SDL_memcpy(dst, src, length*rect->h);
-    } else {
-        for (row = 0; row < rect->h; ++row) {
-            SDL_memcpy(dst, src, length);
-            src += pitch;
-            dst += dpitch;
-        }
-    }
-
-    sceKernelDcacheWritebackAll();
-    return 0;
-}
-
-static int
-VITA_VITA2D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
-    const SDL_Rect * rect,
-    const Uint8 *Yplane, int Ypitch,
-    const Uint8 *Uplane, int Upitch,
-    const Uint8 *Vplane, int Vpitch)
-{
-    return 0;
-}
-
-static int
-VITA_VITA2D_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
-    const SDL_Rect *rect, void **pixels, int *pitch)
-{
-    VITA_VITA2D_TextureData *vita_texture = (VITA_VITA2D_TextureData *) texture->driverdata;
-
-    *pixels =
-        (void *) ((Uint8 *) vita2d_texture_get_datap(vita_texture->tex)
-            + (rect->y * vita_texture->pitch) + rect->x * SDL_BYTESPERPIXEL(texture->format));
-    *pitch = vita_texture->pitch;
-    return 0;
-}
-
-static void
-VITA_VITA2D_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
-{
-    // no needs to update texture data on ps vita. VITA_VITA2D_LockTexture
-    // already return a pointer to the vita2d texture pixels buffer.
-    // This really improve framerate when using lock/unlock.
-
-    /*
-    VITA_VITA2D_TextureData *vita_texture = (VITA_VITA2D_TextureData *) texture->driverdata;
-    SDL_Rect rect;
-
-    // We do whole texture updates, at least for now
-    rect.x = 0;
-    rect.y = 0;
-    rect.w = texture->w;
-    rect.h = texture->h;
-    VITA_VITA2D_UpdateTexture(renderer, texture, &rect, vita_texture->data, vita_texture->pitch);
-    */
-}
-
-static void
-VITA_VITA2D_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
-{
-    VITA_VITA2D_TextureData *vita_texture = (VITA_VITA2D_TextureData *) texture->driverdata;
-
-    /*
-     set texture filtering according to scaleMode
-     suported hint values are nearest (0, default) or linear (1)
-     vitaScaleMode is either SCE_GXM_TEXTURE_FILTER_POINT (good for tile-map)
-     or SCE_GXM_TEXTURE_FILTER_LINEAR (good for scaling)
-     */
-
-    int vitaScaleMode = (scaleMode == SDL_ScaleModeNearest
-                        ? SCE_GXM_TEXTURE_FILTER_POINT
-                        : SCE_GXM_TEXTURE_FILTER_LINEAR);
-    vita2d_texture_set_filters(vita_texture->tex, vitaScaleMode, vitaScaleMode); 
-
-    return;
-}
-
-static int
-VITA_VITA2D_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
-{
-    return 0;
-}
-
-static int
-VITA_VITA2D_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
-{
-    return 0;
-}
-
-static int
-VITA_VITA2D_QueueSetDrawColor(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
-{
-    return 0;
-}
-
-
-static void
-VITA_VITA2D_SetBlendMode(SDL_Renderer *renderer, int blendMode)
-{
-    /*VITA_VITA2D_RenderData *data = (VITA_VITA2D_RenderData *) renderer->driverdata;
-    if (blendMode != data-> currentBlendMode) {
-        switch (blendMode) {
-        case SDL_BLENDMODE_NONE:
-                sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
-                sceGuDisable(GU_BLEND);
-            break;
-        case SDL_BLENDMODE_BLEND:
-                sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
-                sceGuEnable(GU_BLEND);
-                sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 );
-            break;
-        case SDL_BLENDMODE_ADD:
-                sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
-                sceGuEnable(GU_BLEND);
-                sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF );
-            break;
-        case SDL_BLENDMODE_MOD:
-                sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
-                sceGuEnable(GU_BLEND);
-                sceGuBlendFunc( GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0);
-            break;
-        }
-        data->currentBlendMode = blendMode;
-    }*/
-}
-
-
-
-static int
-VITA_VITA2D_RenderClear(SDL_Renderer *renderer)
-{
-    int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
-    vita2d_set_clear_color(color);
-
-    vita2d_clear_screen();
-
-    return 0;
-}
-
-static int
-VITA_VITA2D_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
-{
-    const size_t vertlen = (sizeof (float) * 2) * count;
-    float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
-    if (!verts) {
-        return -1;
-    }
-    cmd->data.draw.count = count;
-    SDL_memcpy(verts, points, vertlen);
-    return 0;
-}
-
-static int
-VITA_VITA2D_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points,
-    int count)
-{
-    int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
-    int i;
-
-    for (i = 0; i < count; ++i) {
-        vita2d_draw_pixel(points[i].x, points[i].y, color);
-    }
-
-    return 0;
-}
-
-static int
-VITA_VITA2D_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points,
-    int count)
-{
-    int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
-    int i;
-
-    for (i = 0; i < count; ++i) {
-        if (i < count -1) {
-            vita2d_draw_line(points[i].x, points[i].y, points[i+1].x, points[i+1].y, color);
-        }
-    }
-
-    return 0;
-}
-
-static int
-VITA_VITA2D_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
-{
-    const size_t outLen = count * sizeof (SDL_FRect);
-    SDL_FRect *outRects = (SDL_FRect *) SDL_AllocateRenderVertices(renderer, outLen, 0, &cmd->data.draw.first);
-
-    if (!outRects) {
-        return -1;
-    }
-    cmd->data.draw.count = count;
-    SDL_memcpy(outRects, rects, outLen);
-
-    return 0;
-}
-
-static int
-VITA_VITA2D_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects,
-                     int count)
-{
-    int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
-    int i;
-
-    for (i = 0; i < count; ++i) {
-        const SDL_FRect *rect = &rects[i];
-
-        vita2d_draw_rectangle(rect->x, rect->y, rect->w, rect->h, color);
-    }
-
-    return 0;
-}
-
-
-#define PI   3.14159265358979f
-
-#define radToDeg(x) ((x)*180.f/PI)
-#define degToRad(x) ((x)*PI/180.f)
-
-float MathAbs(float x)
-{
-    return (x < 0) ? -x : x;
-}
-
-void MathSincos(float r, float *s, float *c)
-{
-    *s = sinf(r);
-    *c = cosf(r);
-}
-
-void Swap(float *a, float *b)
-{
-    float n=*a;
-    *a = *b;
-    *b = n;
-}
-
-static int
-VITA_VITA2D_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
-    const SDL_Rect * srcrect, const SDL_FRect * dstrect)
-{
-    const size_t outLen = sizeof (VITA_VITA2D_CopyData);
-    VITA_VITA2D_CopyData *outData = (VITA_VITA2D_CopyData *) SDL_AllocateRenderVertices(renderer, outLen, 0, &cmd->data.draw.first);
-
-    if (!outData) {
-        return -1;
-    }
-    cmd->data.draw.count = 1;
-
-    SDL_memcpy(&outData->srcRect, srcrect, sizeof(SDL_Rect));
-    SDL_memcpy(&outData->dstRect, dstrect, sizeof(SDL_FRect));
-
-    Uint8 r, g, b, a;
-    SDL_GetTextureColorMod(texture, &r, &g, &b);
-    SDL_GetTextureAlphaMod(texture, &a);
-
-    cmd->data.draw.r = r;
-    cmd->data.draw.g = g;
-    cmd->data.draw.b = b;
-    cmd->data.draw.a = a;
-    cmd->data.draw.blend = renderer->blendMode;
-
-    return 0;
-}
-
-
-static int
-VITA_VITA2D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
-{
-    StartDrawing(renderer);
-
-    while (cmd) {
-        switch (cmd->command) {
-            case SDL_RENDERCMD_SETDRAWCOLOR: {
-                break;
-            }
-
-            case SDL_RENDERCMD_SETVIEWPORT: {
-                break;
-            }
-
-            case SDL_RENDERCMD_SETCLIPRECT: {
-                break;
-            }
-
-            case SDL_RENDERCMD_CLEAR: {
-                VITA_VITA2D_RenderClear(renderer);
-                break;
-            }
-
-            case SDL_RENDERCMD_DRAW_POINTS: {
-                const size_t count = cmd->data.draw.count;
-                const size_t first = cmd->data.draw.first;
-                const SDL_FPoint *points = (SDL_FPoint *) (((Uint8 *) vertices) + first);
-                VITA_VITA2D_RenderDrawPoints(renderer, points, count);
-                break;
-            }
-
-            case SDL_RENDERCMD_DRAW_LINES: {
-                const size_t count = cmd->data.draw.count;
-                const size_t first = cmd->data.draw.first;
-                const SDL_FPoint *points = (SDL_FPoint *) (((Uint8 *) vertices) + first);
-
-                VITA_VITA2D_RenderDrawLines(renderer, points, count);
-                break;
-            }
-
-            case SDL_RENDERCMD_FILL_RECTS: {
-                const size_t count = cmd->data.draw.count;
-                const size_t first = cmd->data.draw.first;
-                const SDL_FRect *rects = (SDL_FRect *) (((Uint8 *) vertices) + first);
-
-                VITA_VITA2D_RenderFillRects(renderer, rects, count);
-                break;
-            }
-
-            case SDL_RENDERCMD_COPY: {
-                const size_t first = cmd->data.draw.first;
-                const VITA_VITA2D_CopyData *copyData = (VITA_VITA2D_CopyData *) (((Uint8 *) vertices) + first);
-
-                VITA_VITA2D_TextureData *vita_texture = (VITA_VITA2D_TextureData *) cmd->data.draw.texture->driverdata;
-
-                const SDL_Rect *srcrect = &copyData->srcRect;
-                const SDL_FRect *dstrect = &copyData->dstRect;
-
-                float scaleX = dstrect->w == srcrect->w ? 1 : (float)(dstrect->w/srcrect->w);
-                float scaleY = dstrect->h == srcrect->h ? 1 : (float)(dstrect->h/srcrect->h);
-
-                Uint8 r, g, b, a;
-                r = cmd->data.draw.r;
-                g = cmd->data.draw.g;
-                b = cmd->data.draw.b;
-                a = cmd->data.draw.a;
-
-                VITA_VITA2D_SetBlendMode(renderer, cmd->data.draw.blend);
-
-                if(r == 255 && g == 255 && b == 255 && a == 255)
-                {
-                    vita2d_draw_texture_part_scale(vita_texture->tex, dstrect->x, dstrect->y,
-                        srcrect->x, srcrect->y, srcrect->w, srcrect->h, scaleX, scaleY);
-                } else {
-                    vita2d_draw_texture_tint_part_scale(vita_texture->tex, dstrect->x, dstrect->y,
-                        srcrect->x, srcrect->y, srcrect->w, srcrect->h, scaleX, scaleY, (a << 24) + (b << 16) + (g << 8) + r);
-                }
-
-                break;
-            }
-
-            case SDL_RENDERCMD_COPY_EX: {
-                break;
-            }
-
-            case SDL_RENDERCMD_NO_OP:
-                break;
-        }
-
-        cmd = cmd->next;
-    }
-
-    return 0;
-}
-
-static int
-VITA_VITA2D_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
-    Uint32 pixel_format, void *pixels, int pitch)
-{
-    return 0;
-}
-
-static int
-VITA_VITA2D_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
-    const SDL_Rect * srcquad, const SDL_FRect * dstrect,
-    const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
-{
-    return 0;
-}
-
-static void
-VITA_VITA2D_RenderPresent(SDL_Renderer *renderer)
-{
-    VITA_VITA2D_RenderData *data = (VITA_VITA2D_RenderData *) renderer->driverdata;
-    if(!data->displayListAvail)
-        return;
-
-    vita2d_end_drawing();
-    vita2d_wait_rendering_done();
-    vita2d_swap_buffers();
-
-    data->displayListAvail = SDL_FALSE;
-}
-
-static void
-VITA_VITA2D_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
-{
-    VITA_VITA2D_RenderData *renderdata = (VITA_VITA2D_RenderData *) renderer->driverdata;
-    VITA_VITA2D_TextureData *vita_texture = (VITA_VITA2D_TextureData *) texture->driverdata;
-
-    if (renderdata == 0)
-        return;
-
-    if(vita_texture == 0)
-        return;
-
-    vita2d_wait_rendering_done();
-    vita2d_free_texture(vita_texture->tex);
-    SDL_free(vita_texture);
-    texture->driverdata = NULL;
-}
-
-static void
-VITA_VITA2D_DestroyRenderer(SDL_Renderer *renderer)
-{
-    VITA_VITA2D_RenderData *data = (VITA_VITA2D_RenderData *) renderer->driverdata;
-    if (data) {
-        if (!data->initialized)
-            return;
-
-        vita2d_fini();
-
-        data->initialized = SDL_FALSE;
-        data->displayListAvail = SDL_FALSE;
-        SDL_free(data);
-    }
-    SDL_free(renderer);
-}
-
-#endif /* SDL_VIDEO_RENDER_VITA_VITA2D */
-
-/* vi: set ts=4 sw=4 expandtab: */
-

+ 958 - 0
src/render/vitagxm/SDL_render_vita_gxm.c

@@ -0,0 +1,958 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_RENDER_VITA_GXM
+
+#include "SDL_hints.h"
+#include "../SDL_sysrender.h"
+#include "SDL_log.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "SDL_render_vita_gxm_types.h"
+#include "SDL_render_vita_gxm_tools.h"
+#include "SDL_render_vita_gxm_memory.h"
+
+static SDL_Renderer *VITA_GXM_CreateRenderer(SDL_Window *window, Uint32 flags);
+
+static void VITA_GXM_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event);
+
+static SDL_bool VITA_GXM_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
+
+static int VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture);
+
+static int VITA_GXM_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
+    const SDL_Rect *rect, const void *pixels, int pitch);
+
+static int VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
+    const SDL_Rect * rect,
+    const Uint8 *Yplane, int Ypitch,
+    const Uint8 *Uplane, int Upitch,
+    const Uint8 *Vplane, int Vpitch);
+
+static int VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
+    const SDL_Rect *rect, void **pixels, int *pitch);
+
+static void VITA_GXM_UnlockTexture(SDL_Renderer *renderer,
+    SDL_Texture *texture);
+
+static void VITA_GXM_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode);
+
+static int VITA_GXM_SetRenderTarget(SDL_Renderer *renderer,
+    SDL_Texture *texture);
+
+
+static int VITA_GXM_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd);
+
+static int VITA_GXM_QueueSetDrawColor(SDL_Renderer * renderer, SDL_RenderCommand *cmd);
+
+
+static int VITA_GXM_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count);
+static int VITA_GXM_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count);
+
+static int VITA_GXM_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+    const SDL_Rect * srcrect, const SDL_FRect * dstrect);
+
+static int VITA_GXM_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+    const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+    const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
+
+static int VITA_GXM_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd);
+
+static int VITA_GXM_RenderDrawPoints(SDL_Renderer *renderer, const SDL_RenderCommand *cmd);
+
+static int VITA_GXM_RenderDrawLines(SDL_Renderer *renderer, const SDL_RenderCommand *cmd);
+
+static int VITA_GXM_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count);
+
+static int VITA_GXM_RenderFillRects(SDL_Renderer *renderer, const SDL_RenderCommand *cmd);
+
+
+static int VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
+
+static int VITA_GXM_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
+    Uint32 pixel_format, void *pixels, int pitch);
+
+
+static void VITA_GXM_RenderPresent(SDL_Renderer *renderer);
+static void VITA_GXM_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
+static void VITA_GXM_DestroyRenderer(SDL_Renderer *renderer);
+
+
+SDL_RenderDriver VITA_GXM_RenderDriver = {
+    .CreateRenderer = VITA_GXM_CreateRenderer,
+    .info = {
+        .name = "VITA gxm",
+        .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC,
+        .num_texture_formats = 1,
+        .texture_formats = {
+            [0] = SDL_PIXELFORMAT_ABGR8888, // TODO: support more formats? ARGB8888 should be enough?
+        },
+        .max_texture_width = 1024,
+        .max_texture_height = 1024,
+     }
+};
+
+void
+StartDrawing(SDL_Renderer *renderer)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+    if(data->drawing)
+        return;
+
+    // reset blend mode
+    data->currentBlendMode = SDL_BLENDMODE_BLEND;
+    fragment_programs *in = &data->blendFragmentPrograms.blend_mode_blend;
+    data->colorFragmentProgram = in->color;
+    data->textureFragmentProgram = in->texture;
+    data->textureTintFragmentProgram = in->textureTint;
+
+    sceGxmBeginScene(
+        data->gxm_context,
+        0,
+        data->renderTarget,
+        NULL,
+        NULL,
+        data->displayBufferSync[data->backBufferIndex],
+        &data->displaySurface[data->backBufferIndex],
+        &data->depthSurface
+    );
+
+    unset_clip_rectangle(data);
+
+    data->drawing = SDL_TRUE;
+}
+
+SDL_Renderer *
+VITA_GXM_CreateRenderer(SDL_Window *window, Uint32 flags)
+{
+    SDL_Renderer *renderer;
+    VITA_GXM_RenderData *data;
+
+    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+    if (!renderer) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    data = (VITA_GXM_RenderData *) SDL_calloc(1, sizeof(VITA_GXM_RenderData));
+    if (!data) {
+        VITA_GXM_DestroyRenderer(renderer);
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    renderer->WindowEvent = VITA_GXM_WindowEvent;
+    renderer->SupportsBlendMode = VITA_GXM_SupportsBlendMode;
+    renderer->CreateTexture = VITA_GXM_CreateTexture;
+    renderer->UpdateTexture = VITA_GXM_UpdateTexture;
+    renderer->UpdateTextureYUV = VITA_GXM_UpdateTextureYUV;
+    renderer->LockTexture = VITA_GXM_LockTexture;
+    renderer->UnlockTexture = VITA_GXM_UnlockTexture;
+    renderer->SetTextureScaleMode = VITA_GXM_SetTextureScaleMode;
+    renderer->SetRenderTarget = VITA_GXM_SetRenderTarget;
+    renderer->QueueSetViewport = VITA_GXM_QueueSetViewport;
+    renderer->QueueSetDrawColor = VITA_GXM_QueueSetDrawColor;
+    renderer->QueueDrawPoints = VITA_GXM_QueueDrawPoints;
+    renderer->QueueDrawLines = VITA_GXM_QueueDrawLines;
+    renderer->QueueFillRects = VITA_GXM_QueueFillRects;
+    renderer->QueueCopy = VITA_GXM_QueueCopy;
+    renderer->QueueCopyEx = VITA_GXM_QueueCopyEx;
+    renderer->RunCommandQueue = VITA_GXM_RunCommandQueue;
+    renderer->RenderReadPixels = VITA_GXM_RenderReadPixels;
+    renderer->RenderPresent = VITA_GXM_RenderPresent;
+    renderer->DestroyTexture = VITA_GXM_DestroyTexture;
+    renderer->DestroyRenderer = VITA_GXM_DestroyRenderer;
+
+    renderer->info = VITA_GXM_RenderDriver.info;
+    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
+    renderer->driverdata = data;
+    renderer->window = window;
+
+    if (data->initialized != SDL_FALSE)
+        return 0;
+    data->initialized = SDL_TRUE;
+
+    if (flags & SDL_RENDERER_PRESENTVSYNC) {
+        data->displayData.wait_vblank = SDL_TRUE;
+    } else {
+        data->displayData.wait_vblank = SDL_FALSE;
+    }
+
+    if (gxm_init(renderer) != 0)
+    {
+        return NULL;
+    }
+
+    return renderer;
+}
+
+static void
+VITA_GXM_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
+{
+}
+
+static SDL_bool
+VITA_GXM_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
+{
+    // only for custom modes. we build all modes on init, so no custom modes, sorry
+    return SDL_FALSE;
+}
+
+static int
+VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+    VITA_GXM_TextureData* vita_texture = (VITA_GXM_TextureData*) SDL_calloc(1, sizeof(VITA_GXM_TextureData));
+
+    if (!vita_texture) {
+        return SDL_OutOfMemory();
+    }
+
+    vita_texture->tex = create_gxm_texture(data, texture->w, texture->h, SCE_GXM_TEXTURE_FORMAT_A8B8G8R8, 0); // TODO: rendertarget support, other formats
+
+    if (!vita_texture->tex) {
+        SDL_free(vita_texture);
+        return SDL_OutOfMemory();
+    }
+
+    texture->driverdata = vita_texture;
+
+    VITA_GXM_SetTextureScaleMode(renderer, texture, texture->scaleMode);
+
+    vita_texture->w = gxm_texture_get_width(vita_texture->tex);
+    vita_texture->h = gxm_texture_get_height(vita_texture->tex);
+    vita_texture->pitch = gxm_texture_get_stride(vita_texture->tex);
+
+    return 0;
+}
+
+
+static int
+VITA_GXM_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
+    const SDL_Rect *rect, const void *pixels, int pitch)
+{
+    const Uint8 *src;
+    Uint8 *dst;
+    int row, length,dpitch;
+    src = pixels;
+
+    VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch);
+    length = rect->w * SDL_BYTESPERPIXEL(texture->format);
+    if (length == pitch && length == dpitch) {
+        SDL_memcpy(dst, src, length*rect->h);
+    } else {
+        for (row = 0; row < rect->h; ++row) {
+            SDL_memcpy(dst, src, length);
+            src += pitch;
+            dst += dpitch;
+        }
+    }
+
+    return 0;
+}
+
+static int
+VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
+    const SDL_Rect * rect,
+    const Uint8 *Yplane, int Ypitch,
+    const Uint8 *Uplane, int Upitch,
+    const Uint8 *Vplane, int Vpitch)
+{
+    return 0;
+}
+
+static int
+VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
+    const SDL_Rect *rect, void **pixels, int *pitch)
+{
+    VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata;
+
+    *pixels =
+        (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex)
+            + (rect->y * vita_texture->pitch) + rect->x * SDL_BYTESPERPIXEL(texture->format));
+    *pitch = vita_texture->pitch;
+    return 0;
+}
+
+static void
+VITA_GXM_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
+{
+    // No need to update texture data on ps vita.
+    // VITA_GXM_LockTexture already returns a pointer to the texture pixels buffer.
+    // This really improves framerate when using lock/unlock.
+}
+
+static void
+VITA_GXM_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
+{
+    VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata;
+
+    /*
+     set texture filtering according to scaleMode
+     suported hint values are nearest (0, default) or linear (1)
+     vitaScaleMode is either SCE_GXM_TEXTURE_FILTER_POINT (good for tile-map)
+     or SCE_GXM_TEXTURE_FILTER_LINEAR (good for scaling)
+     */
+
+    int vitaScaleMode = (scaleMode == SDL_ScaleModeNearest
+                        ? SCE_GXM_TEXTURE_FILTER_POINT
+                        : SCE_GXM_TEXTURE_FILTER_LINEAR);
+    gxm_texture_set_filters(vita_texture->tex, vitaScaleMode, vitaScaleMode);
+
+    return;
+}
+
+static int
+VITA_GXM_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
+{
+    return 0; // TODO
+}
+
+static void
+VITA_GXM_SetBlendMode(SDL_Renderer *renderer, int blendMode)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+    if (blendMode != data->currentBlendMode)
+    {
+        fragment_programs *in = &data->blendFragmentPrograms.blend_mode_blend;
+
+        switch (blendMode)
+        {
+            case SDL_BLENDMODE_NONE:
+                in = &data->blendFragmentPrograms.blend_mode_none;
+                break;
+            case SDL_BLENDMODE_BLEND:
+                in = &data->blendFragmentPrograms.blend_mode_blend;
+                break;
+            case SDL_BLENDMODE_ADD:
+                in = &data->blendFragmentPrograms.blend_mode_add;
+                break;
+            case SDL_BLENDMODE_MOD:
+                in = &data->blendFragmentPrograms.blend_mode_mod;
+                break;
+            case SDL_BLENDMODE_MUL:
+                in = &data->blendFragmentPrograms.blend_mode_mul;
+                break;
+        }
+        data->colorFragmentProgram = in->color;
+        data->textureFragmentProgram = in->texture;
+        data->textureTintFragmentProgram = in->textureTint;
+        data->currentBlendMode = blendMode;
+    }
+}
+
+static int
+VITA_GXM_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
+{
+    return 0; // TODO
+}
+
+static int
+VITA_GXM_QueueSetDrawColor(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    const Uint8 r = cmd->data.color.r;
+    const Uint8 g = cmd->data.color.g;
+    const Uint8 b = cmd->data.color.b;
+    const Uint8 a = cmd->data.color.a;
+    data->drawstate.color = ((a << 24) | (b << 16) | (g << 8) | r);
+
+    return 0;
+}
+
+static int
+VITA_GXM_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    int color = data->drawstate.color;
+
+    color_vertex *vertex = (color_vertex *)pool_memalign(
+        data,
+        count * sizeof(color_vertex),
+        sizeof(color_vertex)
+    );
+
+    cmd->data.draw.first = (size_t)vertex;
+    cmd->data.draw.count = count;
+
+    for (int i = 0; i < count; i++)
+    {
+        vertex[i].x = points[i].x;
+        vertex[i].y = points[i].y;
+        vertex[i].z = +0.5f;
+        vertex[i].color = color;
+    }
+    return 0;
+}
+
+static int
+VITA_GXM_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+    int color = data->drawstate.color;
+
+    color_vertex *vertex = (color_vertex *)pool_memalign(
+        data,
+        (count-1) * 2 * sizeof(color_vertex),
+        sizeof(color_vertex)
+    );
+
+    cmd->data.draw.first = (size_t)vertex;
+    cmd->data.draw.count = (count-1) * 2;
+
+    for (int i = 0; i < count - 1; i++)
+    {
+        vertex[i*2].x = points[i].x;
+        vertex[i*2].y = points[i].y;
+        vertex[i*2].z = +0.5f;
+        vertex[i*2].color = color;
+
+        vertex[i*2+1].x = points[i+1].x;
+        vertex[i*2+1].y = points[i+1].y;
+        vertex[i*2+1].z = +0.5f;
+        vertex[i*2+1].color = color;
+    }
+
+    return 0;
+}
+
+static int
+VITA_GXM_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    cmd->data.draw.count = count;
+    int color = data->drawstate.color;
+
+    color_vertex *vertices = (color_vertex *)pool_memalign(
+            data,
+            4 * count * sizeof(color_vertex), // 4 vertices * count
+            sizeof(color_vertex));
+
+    for (int i =0; i < count; i++)
+    {
+        const SDL_FRect *rect = &rects[i];
+
+        vertices[4*i+0].x = rect->x;
+        vertices[4*i+0].y = rect->y;
+        vertices[4*i+0].z = +0.5f;
+        vertices[4*i+0].color = color;
+
+        vertices[4*i+1].x = rect->x + rect->w;
+        vertices[4*i+1].y = rect->y;
+        vertices[4*i+1].z = +0.5f;
+        vertices[4*i+1].color = color;
+
+        vertices[4*i+2].x = rect->x;
+        vertices[4*i+2].y = rect->y + rect->h;
+        vertices[4*i+2].z = +0.5f;
+        vertices[4*i+2].color = color;
+
+        vertices[4*i+3].x = rect->x + rect->w;
+        vertices[4*i+3].y = rect->y + rect->h;
+        vertices[4*i+3].z = +0.5f;
+        vertices[4*i+3].color = color;
+    }
+
+    cmd->data.draw.first = (size_t)vertices;
+
+    return 0;
+}
+
+
+#define PI   3.14159265358979f
+
+#define degToRad(x) ((x)*PI/180.f)
+
+void MathSincos(float r, float *s, float *c)
+{
+    *s = sinf(r);
+    *c = cosf(r);
+}
+
+void Swap(float *a, float *b)
+{
+    float n=*a;
+    *a = *b;
+    *b = n;
+}
+
+static int
+VITA_GXM_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+    const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+{
+
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    Uint8 r, g, b, a;
+    SDL_GetTextureColorMod(texture, &r, &g, &b);
+    SDL_GetTextureAlphaMod(texture, &a);
+
+    cmd->data.draw.r = r;
+    cmd->data.draw.g = g;
+    cmd->data.draw.b = b;
+    cmd->data.draw.a = a;
+    cmd->data.draw.blend = renderer->blendMode;
+
+    cmd->data.draw.count = 1;
+
+    texture_vertex *vertices = (texture_vertex *)pool_memalign(
+            data,
+            4 * sizeof(texture_vertex), // 4 vertices
+            sizeof(texture_vertex));
+
+    cmd->data.draw.first = (size_t)vertices;
+    cmd->data.draw.texture = texture;
+
+    const float u0 = (float)srcrect->x / (float)texture->w;
+    const float v0 = (float)srcrect->y / (float)texture->h;
+    const float u1 = (float)(srcrect->x + srcrect->w) / (float)texture->w;
+    const float v1 = (float)(srcrect->y + srcrect->h) / (float)texture->h;
+
+    vertices[0].x = dstrect->x;
+    vertices[0].y = dstrect->y;
+    vertices[0].z = +0.5f;
+    vertices[0].u = u0;
+    vertices[0].v = v0;
+
+    vertices[1].x = dstrect->x + dstrect->w;
+    vertices[1].y = dstrect->y;
+    vertices[1].z = +0.5f;
+    vertices[1].u = u1;
+    vertices[1].v = v0;
+
+    vertices[2].x = dstrect->x;
+    vertices[2].y = dstrect->y + dstrect->h;
+    vertices[2].z = +0.5f;
+    vertices[2].u = u0;
+    vertices[2].v = v1;
+
+    vertices[3].x = dstrect->x + dstrect->w;
+    vertices[3].y = dstrect->y + dstrect->h;
+    vertices[3].z = +0.5f;
+    vertices[3].u = u1;
+    vertices[3].v = v1;
+
+    return 0;
+}
+
+static int
+VITA_GXM_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+    const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+    const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    Uint8 r, g, b, a;
+    SDL_GetTextureColorMod(texture, &r, &g, &b);
+    SDL_GetTextureAlphaMod(texture, &a);
+
+    cmd->data.draw.r = r;
+    cmd->data.draw.g = g;
+    cmd->data.draw.b = b;
+    cmd->data.draw.a = a;
+    cmd->data.draw.blend = renderer->blendMode;
+
+    cmd->data.draw.count = 1;
+
+    texture_vertex *vertices = (texture_vertex *)pool_memalign(
+            data,
+            4 * sizeof(texture_vertex), // 4 vertices
+            sizeof(texture_vertex));
+
+    cmd->data.draw.first = (size_t)vertices;
+    cmd->data.draw.texture = texture;
+
+    float u0 = (float)srcrect->x / (float)texture->w;
+    float v0 = (float)srcrect->y / (float)texture->h;
+    float u1 = (float)(srcrect->x + srcrect->w) / (float)texture->w;
+    float v1 = (float)(srcrect->y + srcrect->h) / (float)texture->h;
+
+    if (flip & SDL_FLIP_VERTICAL) {
+        Swap(&v0, &v1);
+    }
+
+    if (flip & SDL_FLIP_HORIZONTAL) {
+        Swap(&u0, &u1);
+    }
+
+    const float centerx = center->x;
+    const float centery = center->y;
+    const float x = dstrect->x + centerx;
+    const float y = dstrect->y + centery;
+    const float width = dstrect->w - centerx;
+    const float height = dstrect->h - centery;
+    float s, c;
+
+    MathSincos(degToRad(angle), &s, &c);
+
+    const float cw = c * width;
+    const float sw = s * width;
+    const float ch = c * height;
+    const float sh = s * height;
+
+    vertices[0].x = x - cw + sh;
+    vertices[0].y = y - sw - ch;
+    vertices[0].z = +0.5f;
+    vertices[0].u = u0;
+    vertices[0].v = v0;
+
+    vertices[1].x = x + cw + sh;
+    vertices[1].y = y + sw - ch;
+    vertices[1].z = +0.5f;
+    vertices[1].u = u1;
+    vertices[1].v = v0;
+
+
+    vertices[2].x = x - cw - sh;
+    vertices[2].y = y - sw + ch;
+    vertices[2].z = +0.5f;
+    vertices[2].u = u0;
+    vertices[2].v = v1;
+
+    vertices[3].x = x + cw - sh;
+    vertices[3].y = y + sw + ch;
+    vertices[3].z = +0.5f;
+    vertices[3].u = u1;
+    vertices[3].v = v1;
+
+    return 0;
+}
+
+
+static int
+VITA_GXM_RenderClear(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    float clear_color[4];
+    clear_color[0] = (cmd->data.color.r)/255.0f;
+    clear_color[1] = (cmd->data.color.g)/255.0f;
+    clear_color[2] = (cmd->data.color.b)/255.0f;
+    clear_color[3] = (cmd->data.color.a)/255.0f;
+
+    // set clear shaders
+    sceGxmSetVertexProgram(data->gxm_context, data->clearVertexProgram);
+    sceGxmSetFragmentProgram(data->gxm_context, data->clearFragmentProgram);
+
+    // set the clear color
+    void *color_buffer;
+    sceGxmReserveFragmentDefaultUniformBuffer(data->gxm_context, &color_buffer);
+    sceGxmSetUniformDataF(color_buffer, data->clearClearColorParam, 0, 4, clear_color);
+
+    // draw the clear triangle
+    sceGxmSetVertexStream(data->gxm_context, 0, data->clearVertices);
+    sceGxmDraw(data->gxm_context, SCE_GXM_PRIMITIVE_TRIANGLES, SCE_GXM_INDEX_FORMAT_U16, data->linearIndices, 3);
+
+    return 0;
+}
+
+
+static int
+VITA_GXM_RenderDrawPoints(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    sceGxmSetVertexProgram(data->gxm_context, data->colorVertexProgram);
+    sceGxmSetFragmentProgram(data->gxm_context, data->colorFragmentProgram);
+
+    void *vertexDefaultBuffer;
+    sceGxmReserveVertexDefaultUniformBuffer(data->gxm_context, &vertexDefaultBuffer);
+    sceGxmSetUniformDataF(vertexDefaultBuffer, data->colorWvpParam, 0, 16, data->ortho_matrix);
+
+    sceGxmSetVertexStream(data->gxm_context, 0, (const void*)cmd->data.draw.first);
+
+    sceGxmSetFrontPolygonMode(data->gxm_context, SCE_GXM_POLYGON_MODE_POINT);
+    sceGxmDraw(data->gxm_context, SCE_GXM_PRIMITIVE_POINTS, SCE_GXM_INDEX_FORMAT_U16, data->linearIndices, cmd->data.draw.count);
+    sceGxmSetFrontPolygonMode(data->gxm_context, SCE_GXM_POLYGON_MODE_TRIANGLE_FILL);
+
+    return 0;
+}
+
+static int
+VITA_GXM_RenderDrawLines(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    sceGxmSetVertexProgram(data->gxm_context, data->colorVertexProgram);
+    sceGxmSetFragmentProgram(data->gxm_context, data->colorFragmentProgram);
+
+    void *vertexDefaultBuffer;
+
+    sceGxmReserveVertexDefaultUniformBuffer(data->gxm_context, &vertexDefaultBuffer);
+
+    sceGxmSetUniformDataF(vertexDefaultBuffer, data->colorWvpParam, 0, 16, data->ortho_matrix);
+
+    sceGxmSetVertexStream(data->gxm_context, 0, (const void*)cmd->data.draw.first);
+
+    sceGxmSetFrontPolygonMode(data->gxm_context, SCE_GXM_POLYGON_MODE_LINE);
+    sceGxmDraw(data->gxm_context, SCE_GXM_PRIMITIVE_LINES, SCE_GXM_INDEX_FORMAT_U16, data->linearIndices, cmd->data.draw.count);
+    sceGxmSetFrontPolygonMode(data->gxm_context, SCE_GXM_POLYGON_MODE_TRIANGLE_FILL);
+    return 0;
+}
+
+
+static int
+VITA_GXM_RenderFillRects(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    sceGxmSetVertexProgram(data->gxm_context, data->colorVertexProgram);
+    sceGxmSetFragmentProgram(data->gxm_context, data->colorFragmentProgram);
+
+    void *vertexDefaultBuffer;
+    sceGxmReserveVertexDefaultUniformBuffer(data->gxm_context, &vertexDefaultBuffer);
+    sceGxmSetUniformDataF(vertexDefaultBuffer, data->colorWvpParam, 0, 16, data->ortho_matrix);
+
+    sceGxmSetVertexStream(data->gxm_context, 0, (const void*)cmd->data.draw.first);
+    sceGxmDraw(data->gxm_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, data->linearIndices, 4 * cmd->data.draw.count);
+
+    return 0;
+}
+
+
+
+static int
+VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
+{
+    StartDrawing(renderer);
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    while (cmd) {
+        switch (cmd->command) {
+            case SDL_RENDERCMD_SETDRAWCOLOR: {
+                break;
+            }
+
+            case SDL_RENDERCMD_SETVIEWPORT: {
+/*                SDL_Rect *viewport = &data->drawstate.viewport;
+                if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
+                    SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
+                    data->drawstate.viewport_dirty = SDL_TRUE;
+                }*/
+                break;
+            }
+
+            case SDL_RENDERCMD_SETCLIPRECT: {
+                const SDL_Rect *rect = &cmd->data.cliprect.rect;
+                if (cmd->data.cliprect.enabled)
+                {
+                    set_clip_rectangle(data, rect->x, rect->y, rect->w, rect->h);
+                }
+                else
+                {
+                    unset_clip_rectangle(data);
+                }
+                break;
+            }
+
+            case SDL_RENDERCMD_CLEAR: {
+                VITA_GXM_RenderClear(renderer, cmd);
+                break;
+            }
+
+            case SDL_RENDERCMD_DRAW_POINTS: {
+                VITA_GXM_SetBlendMode(renderer, cmd->data.draw.blend);
+                VITA_GXM_RenderDrawPoints(renderer, cmd);
+                break;
+            }
+
+            case SDL_RENDERCMD_DRAW_LINES: {
+                VITA_GXM_SetBlendMode(renderer, cmd->data.draw.blend);
+                VITA_GXM_RenderDrawLines(renderer, cmd);
+                break;
+            }
+
+            case SDL_RENDERCMD_FILL_RECTS: {
+                VITA_GXM_SetBlendMode(renderer, cmd->data.draw.blend);
+                VITA_GXM_RenderFillRects(renderer, cmd);
+                break;
+            }
+
+            case SDL_RENDERCMD_COPY:
+            case SDL_RENDERCMD_COPY_EX: {
+                SDL_BlendMode blend;
+                SDL_GetTextureBlendMode(cmd->data.draw.texture, &blend);
+                VITA_GXM_SetBlendMode(renderer, blend);
+
+                Uint8 r, g, b, a;
+                r = cmd->data.draw.r;
+                g = cmd->data.draw.g;
+                b = cmd->data.draw.b;
+                a = cmd->data.draw.a;
+
+                sceGxmSetVertexProgram(data->gxm_context, data->textureVertexProgram);
+
+                if(r == 255 && g == 255 && b == 255 && a == 255)
+                {
+                    sceGxmSetFragmentProgram(data->gxm_context, data->textureFragmentProgram);
+                }
+                else
+                {
+                    sceGxmSetFragmentProgram(data->gxm_context, data->textureTintFragmentProgram);
+                    void *texture_tint_color_buffer;
+                    sceGxmReserveFragmentDefaultUniformBuffer(data->gxm_context, &texture_tint_color_buffer);
+
+                    float *tint_color = pool_memalign(
+                        data,
+                        4 * sizeof(float), // RGBA
+                        sizeof(float)
+                    );
+
+                    tint_color[0] = r / 255.0f;
+                    tint_color[1] = g / 255.0f;
+                    tint_color[2] = b / 255.0f;
+                    tint_color[3] = a / 255.0f;
+
+                    sceGxmSetUniformDataF(texture_tint_color_buffer, data->textureTintColorParam, 0, 4, tint_color);
+
+                }
+
+                void *vertex_wvp_buffer;
+                sceGxmReserveVertexDefaultUniformBuffer(data->gxm_context, &vertex_wvp_buffer);
+                sceGxmSetUniformDataF(vertex_wvp_buffer, data->textureWvpParam, 0, 16, data->ortho_matrix);
+
+                VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) cmd->data.draw.texture->driverdata;
+
+                sceGxmSetFragmentTexture(data->gxm_context, 0, &vita_texture->tex->gxm_tex);
+
+                sceGxmSetVertexStream(data->gxm_context, 0, (const void*)cmd->data.draw.first);
+                sceGxmDraw(data->gxm_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, data->linearIndices, 4 * cmd->data.draw.count);
+
+                break;
+            }
+
+            case SDL_RENDERCMD_NO_OP:
+                break;
+        }
+
+        cmd = cmd->next;
+    }
+
+    return 0;
+}
+
+static int
+VITA_GXM_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
+    Uint32 pixel_format, void *pixels, int pitch)
+{
+    SceDisplayFrameBuf framebuf;
+    SDL_memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf));
+    sceDisplayGetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_IMMEDIATE);
+
+    // TODO
+    //pixels = framebuf.base;
+
+    return 0;
+
+}
+
+
+static void
+VITA_GXM_RenderPresent(SDL_Renderer *renderer)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    if(!data->drawing)
+        return;
+
+    sceGxmEndScene(data->gxm_context, NULL, NULL);
+    sceGxmFinish(data->gxm_context);
+
+    data->displayData.address = data->displayBufferData[data->backBufferIndex];
+
+    sceGxmDisplayQueueAddEntry(
+        data->displayBufferSync[data->frontBufferIndex],    // OLD fb
+        data->displayBufferSync[data->backBufferIndex],     // NEW fb
+        &data->displayData
+    );
+
+    // update buffer indices
+    data->frontBufferIndex = data->backBufferIndex;
+    data->backBufferIndex = (data->backBufferIndex + 1) % VITA_GXM_BUFFERS;
+    data->pool_index = 0;
+    data->drawing = SDL_FALSE;
+}
+
+static void
+VITA_GXM_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+    VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata;
+
+    if (data == 0)
+        return;
+
+    if(vita_texture == 0)
+        return;
+
+    if(vita_texture->tex == 0)
+        return;
+
+    sceGxmFinish(data->gxm_context);
+
+    if (vita_texture->tex->gxm_rendertarget) {
+        sceGxmDestroyRenderTarget(vita_texture->tex->gxm_rendertarget);
+    }
+
+    if (vita_texture->tex->depth_UID) {
+        gpu_free(vita_texture->tex->depth_UID);
+    }
+
+    if (vita_texture->tex->palette_UID) {
+        gpu_free(vita_texture->tex->palette_UID);
+    }
+
+    gpu_free(vita_texture->tex->data_UID);
+    SDL_free(vita_texture->tex);
+    SDL_free(vita_texture);
+
+    texture->driverdata = NULL;
+}
+
+static void
+VITA_GXM_DestroyRenderer(SDL_Renderer *renderer)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+    if (data) {
+        if (!data->initialized)
+            return;
+
+        gxm_finish(renderer);
+
+        data->initialized = SDL_FALSE;
+        data->drawing = SDL_FALSE;
+        SDL_free(data);
+    }
+    SDL_free(renderer);
+}
+
+#endif /* SDL_VIDEO_RENDER_VITA_GXM */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 117 - 0
src/render/vitagxm/SDL_render_vita_gxm_memory.c

@@ -0,0 +1,117 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_RENDER_VITA_GXM
+
+#include "SDL_render_vita_gxm_memory.h"
+
+void *
+gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid)
+{
+    void *mem;
+
+    if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW) {
+        size = ALIGN(size, 256*1024);
+    } else {
+        size = ALIGN(size, 4*1024);
+    }
+
+    *uid = sceKernelAllocMemBlock("gpu_mem", type, size, NULL);
+
+    if (*uid < 0)
+        return NULL;
+
+    if (sceKernelGetMemBlockBase(*uid, &mem) < 0)
+        return NULL;
+
+    if (sceGxmMapMemory(mem, size, attribs) < 0)
+        return NULL;
+
+    return mem;
+}
+
+void
+gpu_free(SceUID uid)
+{
+    void *mem = NULL;
+    if (sceKernelGetMemBlockBase(uid, &mem) < 0)
+        return;
+    sceGxmUnmapMemory(mem);
+    sceKernelFreeMemBlock(uid);
+}
+
+void *
+vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset)
+{
+    void *mem = NULL;
+
+    size = ALIGN(size, 4096);
+    *uid = sceKernelAllocMemBlock("vertex_usse", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, size, NULL);
+
+    if (sceKernelGetMemBlockBase(*uid, &mem) < 0)
+        return NULL;
+    if (sceGxmMapVertexUsseMemory(mem, size, usse_offset) < 0)
+        return NULL;
+
+    return mem;
+}
+
+void
+vertex_usse_free(SceUID uid)
+{
+    void *mem = NULL;
+    if (sceKernelGetMemBlockBase(uid, &mem) < 0)
+        return;
+    sceGxmUnmapVertexUsseMemory(mem);
+    sceKernelFreeMemBlock(uid);
+}
+
+void *
+fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset)
+{
+    void *mem = NULL;
+
+    size = ALIGN(size, 4096);
+    *uid = sceKernelAllocMemBlock("fragment_usse", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, size, NULL);
+
+    if (sceKernelGetMemBlockBase(*uid, &mem) < 0)
+        return NULL;
+    if (sceGxmMapFragmentUsseMemory(mem, size, usse_offset) < 0)
+        return NULL;
+
+    return mem;
+}
+
+void
+fragment_usse_free(SceUID uid)
+{
+    void *mem = NULL;
+    if (sceKernelGetMemBlockBase(uid, &mem) < 0)
+        return;
+    sceGxmUnmapFragmentUsseMemory(mem);
+    sceKernelFreeMemBlock(uid);
+}
+
+#endif /* SDL_VIDEO_RENDER_VITA_GXM */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 40 - 0
src/render/vitagxm/SDL_render_vita_gxm_memory.h

@@ -0,0 +1,40 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_RENDER_VITA_GXM_MEMORY_H
+#define SDL_RENDER_VITA_GXM_MEMORY_H
+
+#include <psp2/gxm.h>
+#include <psp2/types.h>
+#include <psp2/kernel/sysmem.h>
+
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+
+void *gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid);
+void gpu_free(SceUID uid);
+void *vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset);
+void vertex_usse_free(SceUID uid);
+void *fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset);
+void fragment_usse_free(SceUID uid);
+
+#endif /* SDL_RENDER_VITA_GXM_MEMORY_H */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 313 - 0
src/render/vitagxm/SDL_render_vita_gxm_shaders.h

@@ -0,0 +1,313 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_RENDER_VITA_GXM_SHADERS_H
+#define SDL_RENDER_VITA_GXM_SHADERS_H
+
+#include <psp2/gxm.h>
+
+#define gxm_shader_clear_f_size 232
+static const unsigned char gxm_shader_clear_f[gxm_shader_clear_f_size] = {
+    0x47, 0x58, 0x50, 0x00, 0x01, 0x05, 0x50, 0x03, 
+    0xe8, 0x00, 0x00, 0x00, 0xa2, 0x55, 0x22, 0x3e, 
+    0xc6, 0x7e, 0x77, 0xf1, 0x01, 0x00, 0x18, 0x00, 
+    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0xa4, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 
+    0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x68, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x5c, 0x00, 0x00, 0x00, 0xc0, 0x3d, 0x03, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 
+    0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x07, 0x44, 0xfa, 0x02, 0x80, 0x19, 0xf0, 
+    0x7e, 0x0d, 0x80, 0x40, 0x0e, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 
+    0x01, 0xe4, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x75, 0x43, 0x6c, 0x65, 
+    0x61, 0x72, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 
+};
+
+#define gxm_shader_clear_v_size 252
+static const unsigned char gxm_shader_clear_v[gxm_shader_clear_v_size] = {
+    0x47, 0x58, 0x50, 0x00, 0x01, 0x05, 0x50, 0x03, 
+    0xfa, 0x00, 0x00, 0x00, 0xdc, 0x25, 0x34, 0x74, 
+    0x53, 0x4a, 0x7a, 0x5b, 0x04, 0x00, 0x19, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0xb8, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x74, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x78, 0x00, 0x00, 0x00, 0xc0, 0x3d, 0x03, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x44, 0xfa, 
+    0x01, 0x00, 0x04, 0x90, 0x85, 0x11, 0xa5, 0x08, 
+    0x01, 0x80, 0x56, 0x90, 0x81, 0x11, 0x83, 0x08, 
+    0x00, 0x00, 0x20, 0xa0, 0x00, 0x50, 0x27, 0xfb, 
+    0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x61, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 
+    0x6e, 0x00, 0x00, 0x00, 
+};
+
+#define gxm_shader_color_f_size 212
+static const unsigned char gxm_shader_color_f[gxm_shader_color_f_size] = {
+    0x47, 0x58, 0x50, 0x00, 0x01, 0x05, 0x50, 0x03, 
+    0xd4, 0x00, 0x00, 0x00, 0x9c, 0xd6, 0x9b, 0xf7, 
+    0x78, 0x00, 0x5d, 0x31, 0x01, 0x10, 0x18, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0xac, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 
+    0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x78, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x6c, 0x00, 0x00, 0x00, 0xc0, 0x3d, 0x03, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 
+    0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x0f, 0xa0, 0xd0, 0x0e, 0x00, 0x00, 0x00, 0x00, 
+    0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x07, 0x44, 0xfa, 0x02, 0x80, 0x19, 0xa0, 
+    0x7e, 0x0d, 0x80, 0x40, 
+};
+
+#define gxm_shader_color_v_size 344
+static const unsigned char gxm_shader_color_v[gxm_shader_color_v_size] = {
+    0x47, 0x58, 0x50, 0x00, 0x01, 0x05, 0x50, 0x03, 
+    0x55, 0x01, 0x00, 0x00, 0x2e, 0x35, 0x0f, 0x26, 
+    0x23, 0x46, 0x37, 0xbb, 0x00, 0x00, 0x19, 0x00, 
+    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
+    0xe8, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x74, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 
+    0xa0, 0x00, 0x00, 0x00, 0xc0, 0x3d, 0x03, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x08, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x44, 0xfa, 
+    0x80, 0x00, 0x08, 0x83, 0x21, 0x1d, 0x80, 0x38, 
+    0x02, 0x80, 0x81, 0xaf, 0x9c, 0x0d, 0xc0, 0x40, 
+    0x0e, 0x86, 0xb9, 0xff, 0xbc, 0x0d, 0xc0, 0x40, 
+    0x04, 0x11, 0x49, 0xcf, 0x80, 0x8f, 0xb1, 0x18, 
+    0x02, 0x11, 0x45, 0xcf, 0x80, 0x8f, 0xb1, 0x18, 
+    0x00, 0x11, 0x01, 0xc0, 0x81, 0x81, 0xb1, 0x18, 
+    0x01, 0xd1, 0x42, 0xc0, 0x81, 0x81, 0xb1, 0x18, 
+    0x00, 0x00, 0x20, 0xa0, 0x00, 0x50, 0x27, 0xfb, 
+    0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 
+    0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x2a, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x21, 0x00, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 
+    0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x61, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 
+    0x6e, 0x00, 0x61, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 
+    0x00, 0x77, 0x76, 0x70, 0x00, 0x00, 0x00, 0x00, 
+};
+
+#define gxm_shader_texture_f_size 256
+static const unsigned char gxm_shader_texture_f[gxm_shader_texture_f_size] = {
+    0x47, 0x58, 0x50, 0x00, 0x01, 0x05, 0x50, 0x03, 
+    0x00, 0x01, 0x00, 0x00, 0x2f, 0x18, 0xe0, 0x2b, 
+    0x1f, 0x21, 0x47, 0x49, 0x01, 0x08, 0x18, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0xa4, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x78, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x64, 0x00, 0x00, 0x00, 0xc0, 0x3d, 0x03, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 
+    0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 
+    0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x00, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x07, 0x44, 0xfa, 0x30, 0x00, 0x00, 0x00, 
+    0x02, 0x04, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x00, 
+};
+
+#define gxm_shader_texture_tint_f_size 324
+static const unsigned char gxm_shader_texture_tint_f[gxm_shader_texture_tint_f_size] = {
+    0x47, 0x58, 0x50, 0x00, 0x01, 0x05, 0x50, 0x03, 
+    0x43, 0x01, 0x00, 0x00, 0x44, 0x2f, 0x5d, 0xfe, 
+    0x9e, 0xda, 0xf8, 0x6f, 0x05, 0x08, 0x18, 0x00, 
+    0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
+    0xcc, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 
+    0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x78, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x84, 0x00, 0x00, 0x00, 0xc0, 0x3d, 0x03, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 
+    0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 
+    0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x00, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0xc0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x07, 0x44, 0xfa, 0x00, 0x00, 0x00, 0x00, 
+    0x40, 0x09, 0x00, 0xf8, 0x02, 0x80, 0x99, 0xff, 
+    0xbc, 0x0d, 0xc0, 0x40, 0x02, 0x80, 0xb9, 0xaf, 
+    0xbc, 0x0d, 0x80, 0x40, 0x7c, 0x0f, 0x04, 0x00, 
+    0x86, 0x47, 0xa4, 0x10, 0x0e, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 
+    0x01, 0xe4, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 
+    0x02, 0x04, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x75, 0x54, 0x69, 0x6e, 
+    0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x74, 
+    0x65, 0x78, 0x00, 0x00, 
+};
+
+#define gxm_shader_texture_v_size 344
+static const unsigned char gxm_shader_texture_v[gxm_shader_texture_v_size] = {
+    0x47, 0x58, 0x50, 0x00, 0x01, 0x05, 0x50, 0x03, 
+    0x58, 0x01, 0x00, 0x00, 0xa3, 0x36, 0x7b, 0x62, 
+    0x1b, 0x80, 0x1c, 0xb0, 0x00, 0x00, 0x19, 0x00, 
+    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
+    0xe8, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x74, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 
+    0xa0, 0x00, 0x00, 0x00, 0xc0, 0x3d, 0x03, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x44, 0xfa, 
+    0x80, 0x00, 0x08, 0x83, 0x21, 0x0d, 0x80, 0x38, 
+    0x02, 0x80, 0x81, 0xaf, 0x9c, 0x0d, 0xc0, 0x40, 
+    0x0e, 0x86, 0xb9, 0xff, 0xbc, 0x0d, 0xc0, 0x40, 
+    0x04, 0x11, 0x49, 0xcf, 0x80, 0x8f, 0xb1, 0x18, 
+    0x02, 0x11, 0x45, 0xcf, 0x80, 0x8f, 0xb1, 0x18, 
+    0x00, 0x11, 0x01, 0xc0, 0x81, 0x81, 0xb1, 0x18, 
+    0x01, 0xd1, 0x42, 0xc0, 0x81, 0x81, 0xb1, 0x18, 
+    0x00, 0x00, 0x20, 0xa0, 0x00, 0x50, 0x27, 0xfb, 
+    0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 
+    0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x2a, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 
+    0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
+    0x24, 0x00, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 
+    0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x61, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 
+    0x6e, 0x00, 0x61, 0x54, 0x65, 0x78, 0x63, 0x6f, 
+    0x6f, 0x72, 0x64, 0x00, 0x77, 0x76, 0x70, 0x00, 
+};
+
+
+static const SceGxmProgram *const clearVertexProgramGxp         = (const SceGxmProgram*)gxm_shader_clear_v;
+static const SceGxmProgram *const clearFragmentProgramGxp       = (const SceGxmProgram *)gxm_shader_clear_f;
+static const SceGxmProgram *const colorVertexProgramGxp         = (const SceGxmProgram *)gxm_shader_color_v;
+static const SceGxmProgram *const colorFragmentProgramGxp       = (const SceGxmProgram *)gxm_shader_color_f;
+static const SceGxmProgram *const textureVertexProgramGxp       = (const SceGxmProgram *)gxm_shader_texture_v;
+static const SceGxmProgram *const textureFragmentProgramGxp     = (const SceGxmProgram *)gxm_shader_texture_f;
+static const SceGxmProgram *const textureTintFragmentProgramGxp = (const SceGxmProgram *)gxm_shader_texture_tint_f;
+
+#endif // SDL_RENDER_VITA_GXM_SHADERS_H
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 1147 - 0
src/render/vitagxm/SDL_render_vita_gxm_tools.c

@@ -0,0 +1,1147 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_RENDER_VITA_GXM
+
+#include "SDL_hints.h"
+#include "../SDL_sysrender.h"
+#include "SDL_log.h"
+
+#include <psp2/kernel/processmgr.h>
+#include <psp2/appmgr.h>
+#include <psp2/display.h>
+#include <psp2/gxm.h>
+#include <psp2/types.h>
+#include <psp2/kernel/sysmem.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "SDL_render_vita_gxm_tools.h"
+#include "SDL_render_vita_gxm_types.h"
+#include "SDL_render_vita_gxm_memory.h"
+#include "SDL_render_vita_gxm_shaders.h"
+
+static void
+init_orthographic_matrix(float *m, float left, float right, float bottom, float top, float near, float far)
+{
+    m[0x0] = 2.0f/(right-left);
+    m[0x4] = 0.0f;
+    m[0x8] = 0.0f;
+    m[0xC] = -(right+left)/(right-left);
+
+    m[0x1] = 0.0f;
+    m[0x5] = 2.0f/(top-bottom);
+    m[0x9] = 0.0f;
+    m[0xD] = -(top+bottom)/(top-bottom);
+
+    m[0x2] = 0.0f;
+    m[0x6] = 0.0f;
+    m[0xA] = -2.0f/(far-near);
+    m[0xE] = (far+near)/(far-near);
+
+    m[0x3] = 0.0f;
+    m[0x7] = 0.0f;
+    m[0xB] = 0.0f;
+    m[0xF] = 1.0f;
+}
+
+
+static void *
+patcher_host_alloc(void *user_data, unsigned int size)
+{
+    (void)user_data;
+    void *mem = SDL_malloc(size);
+    return mem;
+}
+
+static void
+patcher_host_free(void *user_data, void *mem)
+{
+    (void)user_data;
+    SDL_free(mem);
+}
+
+void *
+pool_malloc(VITA_GXM_RenderData *data, unsigned int size)
+{
+
+    if ((data->pool_index + size) < VITA_GXM_POOL_SIZE) {
+        void *addr = (void *)((unsigned int)data->pool_addr + data->pool_index);
+        data->pool_index += size;
+        return addr;
+    }
+    SDL_LogError(SDL_LOG_CATEGORY_RENDER, "POOL OVERFLOW\n");
+    return NULL;
+}
+
+void *
+pool_memalign(VITA_GXM_RenderData *data, unsigned int size, unsigned int alignment)
+{
+    unsigned int new_index = (data->pool_index + alignment - 1) & ~(alignment - 1);
+    if ((new_index + size) < VITA_GXM_POOL_SIZE) {
+        void *addr = (void *)((unsigned int)data->pool_addr + new_index);
+        data->pool_index = new_index + size;
+        return addr;
+    }
+    SDL_LogError(SDL_LOG_CATEGORY_RENDER, "POOL OVERFLOW\n");
+    return NULL;
+}
+
+static int
+tex_format_to_bytespp(SceGxmTextureFormat format)
+{
+    switch (format & 0x9f000000U) {
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U8:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_S8:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_P8:
+        return 1;
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U4U4U4U4:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U8U3U3U2:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U1U5U5U5:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U5U6U5:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_S5S5U6:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U8U8:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_S8S8:
+        return 2;
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U8U8U8:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_S8S8S8:
+        return 3;
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U8U8U8U8:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_S8S8S8S8:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_F32:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_U32:
+    case SCE_GXM_TEXTURE_BASE_FORMAT_S32:
+    default:
+        return 4;
+    }
+}
+
+static void
+display_callback(const void *callback_data)
+{
+    SceDisplayFrameBuf framebuf;
+    const VITA_GXM_DisplayData *display_data = (const VITA_GXM_DisplayData *)callback_data;
+
+    SDL_memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf));
+    framebuf.size        = sizeof(SceDisplayFrameBuf);
+    framebuf.base        = display_data->address;
+    framebuf.pitch       = VITA_GXM_SCREEN_STRIDE;
+    framebuf.pixelformat = VITA_GXM_PIXEL_FORMAT;
+    framebuf.width       = VITA_GXM_SCREEN_WIDTH;
+    framebuf.height      = VITA_GXM_SCREEN_HEIGHT;
+    sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME);
+
+    if (display_data->wait_vblank) {
+        sceDisplayWaitVblankStart();
+    }
+}
+
+static void
+free_fragment_programs(VITA_GXM_RenderData *data, fragment_programs *out)
+{
+    sceGxmShaderPatcherReleaseFragmentProgram(data->shaderPatcher, out->color);
+    sceGxmShaderPatcherReleaseFragmentProgram(data->shaderPatcher, out->texture);
+    sceGxmShaderPatcherReleaseFragmentProgram(data->shaderPatcher, out->textureTint);
+}
+
+static void
+make_fragment_programs(VITA_GXM_RenderData *data, fragment_programs *out,
+    const SceGxmBlendInfo *blend_info)
+{
+    int err;
+
+    err = sceGxmShaderPatcherCreateFragmentProgram(
+        data->shaderPatcher,
+        data->colorFragmentProgramId,
+        SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
+        0,
+        blend_info,
+        colorVertexProgramGxp,
+        &out->color
+    );
+
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d\n", err);
+        return;
+    }
+
+    err = sceGxmShaderPatcherCreateFragmentProgram(
+        data->shaderPatcher,
+        data->textureFragmentProgramId,
+        SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
+        0,
+        blend_info,
+        textureVertexProgramGxp,
+        &out->texture
+    );
+
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d\n", err);
+        return;
+    }
+
+    err = sceGxmShaderPatcherCreateFragmentProgram(
+        data->shaderPatcher,
+        data->textureTintFragmentProgramId,
+        SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
+        0,
+        blend_info,
+        textureVertexProgramGxp,
+        &out->textureTint
+    );
+
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d\n", err);
+        return;
+    }
+}
+
+
+static void
+set_stencil_mask(VITA_GXM_RenderData *data, float x, float y, float w, float h)
+{
+    color_vertex *vertices = (color_vertex *)pool_memalign(
+        data,
+        4 * sizeof(color_vertex), // 4 vertices
+        sizeof(color_vertex)
+    );
+
+    vertices[0].x = x;
+    vertices[0].y = y;
+    vertices[0].z = +0.5f;
+    vertices[0].color = 0;
+
+    vertices[1].x = x + w;
+    vertices[1].y = y;
+    vertices[1].z = +0.5f;
+    vertices[1].color = 0;
+
+    vertices[2].x = x;
+    vertices[2].y = y + h;
+    vertices[2].z = +0.5f;
+    vertices[2].color = 0;
+
+    vertices[3].x = x + w;
+    vertices[3].y = y + h;
+    vertices[3].z = +0.5f;
+    vertices[3].color = 0;
+
+    sceGxmSetVertexProgram(data->gxm_context, data->colorVertexProgram);
+    sceGxmSetFragmentProgram(data->gxm_context, data->colorFragmentProgram);
+
+    void *vertexDefaultBuffer;
+    sceGxmReserveVertexDefaultUniformBuffer(data->gxm_context, &vertexDefaultBuffer);
+    sceGxmSetUniformDataF(vertexDefaultBuffer, data->colorWvpParam, 0, 16, data->ortho_matrix);
+
+    sceGxmSetVertexStream(data->gxm_context, 0, vertices);
+    sceGxmDraw(data->gxm_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, data->linearIndices, 4);
+}
+
+
+void
+set_clip_rectangle(VITA_GXM_RenderData *data, int x_min, int y_min, int x_max, int y_max)
+{
+    if(data->drawing) {
+        // clear the stencil buffer to 0
+        sceGxmSetFrontStencilFunc(
+            data->gxm_context,
+            SCE_GXM_STENCIL_FUNC_NEVER,
+            SCE_GXM_STENCIL_OP_ZERO,
+            SCE_GXM_STENCIL_OP_ZERO,
+            SCE_GXM_STENCIL_OP_ZERO,
+            0xFF,
+            0xFF
+        );
+
+        set_stencil_mask(data, 0, 0, VITA_GXM_SCREEN_WIDTH, VITA_GXM_SCREEN_HEIGHT);
+
+        // set the stencil to 1 in the desired region
+        sceGxmSetFrontStencilFunc(
+            data->gxm_context,
+            SCE_GXM_STENCIL_FUNC_NEVER,
+            SCE_GXM_STENCIL_OP_REPLACE,
+            SCE_GXM_STENCIL_OP_REPLACE,
+            SCE_GXM_STENCIL_OP_REPLACE,
+            0xFF,
+            0xFF
+        );
+
+        set_stencil_mask(data, x_min, y_min, x_max - x_min, y_max - y_min);
+
+        // set the stencil function to only accept pixels where the stencil is 1
+        sceGxmSetFrontStencilFunc(
+            data->gxm_context,
+            SCE_GXM_STENCIL_FUNC_EQUAL,
+            SCE_GXM_STENCIL_OP_KEEP,
+            SCE_GXM_STENCIL_OP_KEEP,
+            SCE_GXM_STENCIL_OP_KEEP,
+            0xFF,
+            0xFF
+        );
+    }
+}
+
+void
+unset_clip_rectangle(VITA_GXM_RenderData *data)
+{
+    sceGxmSetFrontStencilFunc(
+        data->gxm_context,
+        SCE_GXM_STENCIL_FUNC_ALWAYS,
+        SCE_GXM_STENCIL_OP_KEEP,
+        SCE_GXM_STENCIL_OP_KEEP,
+        SCE_GXM_STENCIL_OP_KEEP,
+        0xFF,
+        0xFF
+    );
+}
+
+int
+gxm_init(SDL_Renderer *renderer)
+{
+    unsigned int i, x, y;
+    int err;
+
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    SceGxmInitializeParams initializeParams;
+    SDL_memset(&initializeParams, 0, sizeof(SceGxmInitializeParams));
+    initializeParams.flags                          = 0;
+    initializeParams.displayQueueMaxPendingCount    = VITA_GXM_PENDING_SWAPS;
+    initializeParams.displayQueueCallback           = display_callback;
+    initializeParams.displayQueueCallbackDataSize   = sizeof(VITA_GXM_DisplayData);
+    initializeParams.parameterBufferSize            = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE;
+
+    err = sceGxmInitialize(&initializeParams);
+
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "gxm init failed: %d\n", err);
+        return err;
+    }
+
+    // allocate ring buffer memory using default sizes
+    void *vdmRingBuffer = gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+        SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE,
+        4,
+        SCE_GXM_MEMORY_ATTRIB_READ,
+        &data->vdmRingBufferUid);
+
+    void *vertexRingBuffer = gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+        SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE,
+        4,
+        SCE_GXM_MEMORY_ATTRIB_READ,
+        &data->vertexRingBufferUid);
+
+    void *fragmentRingBuffer = gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+        SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE,
+        4,
+        SCE_GXM_MEMORY_ATTRIB_READ,
+        &data->fragmentRingBufferUid);
+
+    unsigned int fragmentUsseRingBufferOffset;
+    void *fragmentUsseRingBuffer = fragment_usse_alloc(
+        SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE,
+        &data->fragmentUsseRingBufferUid,
+        &fragmentUsseRingBufferOffset);
+
+    SDL_memset(&data->contextParams, 0, sizeof(SceGxmContextParams));
+    data->contextParams.hostMem                       = SDL_malloc(SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE);
+    data->contextParams.hostMemSize                   = SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE;
+    data->contextParams.vdmRingBufferMem              = vdmRingBuffer;
+    data->contextParams.vdmRingBufferMemSize          = SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE;
+    data->contextParams.vertexRingBufferMem           = vertexRingBuffer;
+    data->contextParams.vertexRingBufferMemSize       = SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE;
+    data->contextParams.fragmentRingBufferMem         = fragmentRingBuffer;
+    data->contextParams.fragmentRingBufferMemSize     = SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE;
+    data->contextParams.fragmentUsseRingBufferMem     = fragmentUsseRingBuffer;
+    data->contextParams.fragmentUsseRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE;
+    data->contextParams.fragmentUsseRingBufferOffset  = fragmentUsseRingBufferOffset;
+
+    err = sceGxmCreateContext(&data->contextParams, &data->gxm_context);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create context failed: %d\n", err);
+        return err;
+    }
+
+    // set up parameters
+    SceGxmRenderTargetParams renderTargetParams;
+    SDL_memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams));
+    renderTargetParams.flags                = 0;
+    renderTargetParams.width                = VITA_GXM_SCREEN_WIDTH;
+    renderTargetParams.height               = VITA_GXM_SCREEN_HEIGHT;
+    renderTargetParams.scenesPerFrame       = 1;
+    renderTargetParams.multisampleMode      = 0;
+    renderTargetParams.multisampleLocations = 0;
+    renderTargetParams.driverMemBlock       = -1; // Invalid UID
+
+    // create the render target
+    err = sceGxmCreateRenderTarget(&renderTargetParams, &data->renderTarget);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "render target creation failed: %d\n", err);
+        return err;
+    }
+
+    // allocate memory and sync objects for display buffers
+    for (i = 0; i < VITA_GXM_BUFFERS; i++) {
+
+        // allocate memory for display
+        data->displayBufferData[i] = gpu_alloc(
+            SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
+            4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT,
+            SCE_GXM_COLOR_SURFACE_ALIGNMENT,
+            SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
+            &data->displayBufferUid[i]);
+
+        // memset the buffer to black
+        for (y = 0; y < VITA_GXM_SCREEN_HEIGHT; y++) {
+            unsigned int *row = (unsigned int *)data->displayBufferData[i] + y * VITA_GXM_SCREEN_STRIDE;
+            for (x = 0; x < VITA_GXM_SCREEN_WIDTH; x++) {
+                row[x] = 0xff000000;
+            }
+        }
+
+        // initialize a color surface for this display buffer
+        err = sceGxmColorSurfaceInit(
+            &data->displaySurface[i],
+            VITA_GXM_COLOR_FORMAT,
+            SCE_GXM_COLOR_SURFACE_LINEAR,
+            SCE_GXM_COLOR_SURFACE_SCALE_NONE,
+            SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
+            VITA_GXM_SCREEN_WIDTH,
+            VITA_GXM_SCREEN_HEIGHT,
+            VITA_GXM_SCREEN_STRIDE,
+            data->displayBufferData[i]
+        );
+
+        if (err != SCE_OK) {
+            SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %d\n", err);
+            return err;
+        }
+
+
+        // create a sync object that we will associate with this buffer
+        err = sceGxmSyncObjectCreate(&data->displayBufferSync[i]);
+        if (err != SCE_OK) {
+            SDL_LogError(SDL_LOG_CATEGORY_RENDER, "sync object creation failed: %d\n", err);
+            return err;
+        }
+
+    }
+
+    // compute the memory footprint of the depth buffer
+    const unsigned int alignedWidth = ALIGN(VITA_GXM_SCREEN_WIDTH, SCE_GXM_TILE_SIZEX);
+    const unsigned int alignedHeight = ALIGN(VITA_GXM_SCREEN_HEIGHT, SCE_GXM_TILE_SIZEY);
+
+    unsigned int sampleCount = alignedWidth * alignedHeight;
+    unsigned int depthStrideInSamples = alignedWidth;
+
+    // allocate the depth buffer
+    data->depthBufferData = gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+        4 * sampleCount,
+        SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT,
+        SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
+        &data->depthBufferUid);
+
+    // allocate the stencil buffer
+    data->stencilBufferData = gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+        4 * sampleCount,
+        SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT,
+        SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
+        &data->stencilBufferUid);
+
+    // create the SceGxmDepthStencilSurface structure
+    err = sceGxmDepthStencilSurfaceInit(
+        &data->depthSurface,
+        SCE_GXM_DEPTH_STENCIL_FORMAT_S8D24,
+        SCE_GXM_DEPTH_STENCIL_SURFACE_TILED,
+        depthStrideInSamples,
+        data->depthBufferData,
+        data->stencilBufferData);
+
+    // set the stencil test reference (this is currently assumed to always remain 1 after here for region clipping)
+    sceGxmSetFrontStencilRef(data->gxm_context, 1);
+
+
+    // set the stencil function (this wouldn't actually be needed, as the set clip rectangle function has to call this at the begginning of every scene)
+    sceGxmSetFrontStencilFunc(
+        data->gxm_context,
+        SCE_GXM_STENCIL_FUNC_ALWAYS,
+        SCE_GXM_STENCIL_OP_KEEP,
+        SCE_GXM_STENCIL_OP_KEEP,
+        SCE_GXM_STENCIL_OP_KEEP,
+        0xFF,
+        0xFF);
+
+    // set buffer sizes for this sample
+    const unsigned int patcherBufferSize        = 64*1024;
+    const unsigned int patcherVertexUsseSize    = 64*1024;
+    const unsigned int patcherFragmentUsseSize  = 64*1024;
+
+    // allocate memory for buffers and USSE code
+    void *patcherBuffer = gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+        patcherBufferSize,
+        4,
+        SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
+        &data->patcherBufferUid);
+
+    unsigned int patcherVertexUsseOffset;
+    void *patcherVertexUsse = vertex_usse_alloc(
+        patcherVertexUsseSize,
+        &data->patcherVertexUsseUid,
+        &patcherVertexUsseOffset);
+
+    unsigned int patcherFragmentUsseOffset;
+    void *patcherFragmentUsse = fragment_usse_alloc(
+        patcherFragmentUsseSize,
+        &data->patcherFragmentUsseUid,
+        &patcherFragmentUsseOffset);
+
+    // create a shader patcher
+    SceGxmShaderPatcherParams patcherParams;
+    SDL_memset(&patcherParams, 0, sizeof(SceGxmShaderPatcherParams));
+    patcherParams.userData                  = NULL;
+    patcherParams.hostAllocCallback         = &patcher_host_alloc;
+    patcherParams.hostFreeCallback          = &patcher_host_free;
+    patcherParams.bufferAllocCallback       = NULL;
+    patcherParams.bufferFreeCallback        = NULL;
+    patcherParams.bufferMem                 = patcherBuffer;
+    patcherParams.bufferMemSize             = patcherBufferSize;
+    patcherParams.vertexUsseAllocCallback   = NULL;
+    patcherParams.vertexUsseFreeCallback    = NULL;
+    patcherParams.vertexUsseMem             = patcherVertexUsse;
+    patcherParams.vertexUsseMemSize         = patcherVertexUsseSize;
+    patcherParams.vertexUsseOffset          = patcherVertexUsseOffset;
+    patcherParams.fragmentUsseAllocCallback = NULL;
+    patcherParams.fragmentUsseFreeCallback  = NULL;
+    patcherParams.fragmentUsseMem           = patcherFragmentUsse;
+    patcherParams.fragmentUsseMemSize       = patcherFragmentUsseSize;
+    patcherParams.fragmentUsseOffset        = patcherFragmentUsseOffset;
+
+    err = sceGxmShaderPatcherCreate(&patcherParams, &data->shaderPatcher);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "shader patcher creation failed: %d\n", err);
+        return err;
+    }
+
+
+    // check the shaders
+    err = sceGxmProgramCheck(clearVertexProgramGxp);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (clear vertex) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmProgramCheck(clearFragmentProgramGxp);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (clear fragment) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmProgramCheck(colorVertexProgramGxp);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (color vertex) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmProgramCheck(colorFragmentProgramGxp);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (color fragment) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmProgramCheck(textureVertexProgramGxp);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture vertex) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmProgramCheck(textureFragmentProgramGxp);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture fragment) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmProgramCheck(textureTintFragmentProgramGxp);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture tint fragment) failed: %d\n", err);
+        return err;
+    }
+
+    // register programs with the patcher
+    err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, clearVertexProgramGxp, &data->clearVertexProgramId);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (clear vertex) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, clearFragmentProgramGxp, &data->clearFragmentProgramId);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (clear fragment) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, colorVertexProgramGxp, &data->colorVertexProgramId);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (color vertex) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, colorFragmentProgramGxp, &data->colorFragmentProgramId);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (color fragment) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, textureVertexProgramGxp, &data->textureVertexProgramId);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture vertex) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, textureFragmentProgramGxp, &data->textureFragmentProgramId);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture fragment) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, textureTintFragmentProgramGxp, &data->textureTintFragmentProgramId);
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture tint fragment) failed: %d\n", err);
+        return err;
+    }
+
+    // Fill SceGxmBlendInfo
+    static const SceGxmBlendInfo blend_info_none = {
+        .colorFunc = SCE_GXM_BLEND_FUNC_NONE,
+        .alphaFunc = SCE_GXM_BLEND_FUNC_NONE,
+        .colorSrc  = SCE_GXM_BLEND_FACTOR_ZERO,
+        .colorDst  = SCE_GXM_BLEND_FACTOR_ZERO,
+        .alphaSrc  = SCE_GXM_BLEND_FACTOR_ZERO,
+        .alphaDst  = SCE_GXM_BLEND_FACTOR_ZERO,
+        .colorMask = SCE_GXM_COLOR_MASK_ALL
+    };
+
+    static const SceGxmBlendInfo blend_info_blend = {
+        .colorFunc = SCE_GXM_BLEND_FUNC_ADD,
+        .alphaFunc = SCE_GXM_BLEND_FUNC_ADD,
+        .colorSrc  = SCE_GXM_BLEND_FACTOR_SRC_ALPHA,
+        .colorDst  = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+        .alphaSrc  = SCE_GXM_BLEND_FACTOR_ONE,
+        .alphaDst  = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+        .colorMask = SCE_GXM_COLOR_MASK_ALL
+    };
+
+    static const SceGxmBlendInfo blend_info_add = {
+        .colorFunc = SCE_GXM_BLEND_FUNC_ADD,
+        .alphaFunc = SCE_GXM_BLEND_FUNC_ADD,
+        .colorSrc  = SCE_GXM_BLEND_FACTOR_SRC_ALPHA,
+        .colorDst  = SCE_GXM_BLEND_FACTOR_ONE,
+        .alphaSrc  = SCE_GXM_BLEND_FACTOR_ZERO,
+        .alphaDst  = SCE_GXM_BLEND_FACTOR_ONE,
+        .colorMask = SCE_GXM_COLOR_MASK_ALL
+    };
+
+    static const SceGxmBlendInfo blend_info_mod = {
+        .colorFunc = SCE_GXM_BLEND_FUNC_ADD,
+        .alphaFunc = SCE_GXM_BLEND_FUNC_ADD,
+
+        .colorSrc  = SCE_GXM_BLEND_FACTOR_ZERO,
+        .colorDst  = SCE_GXM_BLEND_FACTOR_SRC_COLOR,
+
+        .alphaSrc  = SCE_GXM_BLEND_FACTOR_ZERO,
+        .alphaDst  = SCE_GXM_BLEND_FACTOR_ONE,
+        .colorMask = SCE_GXM_COLOR_MASK_ALL
+    };
+
+    static const SceGxmBlendInfo blend_info_mul = {
+        .colorFunc = SCE_GXM_BLEND_FUNC_ADD,
+        .alphaFunc = SCE_GXM_BLEND_FUNC_ADD,
+        .colorSrc  = SCE_GXM_BLEND_FACTOR_DST_COLOR,
+        .colorDst  = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+        .alphaSrc  = SCE_GXM_BLEND_FACTOR_DST_ALPHA,
+        .alphaDst  = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
+        .colorMask = SCE_GXM_COLOR_MASK_ALL
+    };
+
+    // get attributes by name to create vertex format bindings
+    const SceGxmProgramParameter *paramClearPositionAttribute = sceGxmProgramFindParameterByName(clearVertexProgramGxp, "aPosition");
+
+    // create clear vertex format
+    SceGxmVertexAttribute clearVertexAttributes[1];
+    SceGxmVertexStream clearVertexStreams[1];
+    clearVertexAttributes[0].streamIndex    = 0;
+    clearVertexAttributes[0].offset         = 0;
+    clearVertexAttributes[0].format         = SCE_GXM_ATTRIBUTE_FORMAT_F32;
+    clearVertexAttributes[0].componentCount = 2;
+    clearVertexAttributes[0].regIndex       = sceGxmProgramParameterGetResourceIndex(paramClearPositionAttribute);
+    clearVertexStreams[0].stride            = sizeof(clear_vertex);
+    clearVertexStreams[0].indexSource       = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
+
+    // create clear programs
+    err = sceGxmShaderPatcherCreateVertexProgram(
+        data->shaderPatcher,
+        data->clearVertexProgramId,
+        clearVertexAttributes,
+        1,
+        clearVertexStreams,
+        1,
+        &data->clearVertexProgram
+    );
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (clear vertex) failed: %d\n", err);
+        return err;
+    }
+
+    err = sceGxmShaderPatcherCreateFragmentProgram(
+        data->shaderPatcher,
+        data->clearFragmentProgramId,
+        SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
+        0,
+        NULL,
+        clearVertexProgramGxp,
+        &data->clearFragmentProgram
+    );
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (clear fragment) failed: %d\n", err);
+        return err;
+    }
+
+    // create the clear triangle vertex/index data
+    data->clearVertices = (clear_vertex *)gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+        3*sizeof(clear_vertex),
+        4,
+        SCE_GXM_MEMORY_ATTRIB_READ,
+        &data->clearVerticesUid
+    );
+
+    // Allocate a 64k * 2 bytes = 128 KiB buffer and store all possible
+    // 16-bit indices in linear ascending order, so we can use this for
+    // all drawing operations where we don't want to use indexing.
+    data->linearIndices = (uint16_t *)gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+        UINT16_MAX*sizeof(uint16_t),
+        sizeof(uint16_t),
+        SCE_GXM_MEMORY_ATTRIB_READ,
+        &data->linearIndicesUid
+    );
+
+    for (uint32_t i=0; i<=UINT16_MAX; ++i)
+    {
+        data->linearIndices[i] = i;
+    }
+
+    data->clearVertices[0].x = -1.0f;
+    data->clearVertices[0].y = -1.0f;
+    data->clearVertices[1].x =  3.0f;
+    data->clearVertices[1].y = -1.0f;
+    data->clearVertices[2].x = -1.0f;
+    data->clearVertices[2].y =  3.0f;
+
+    const SceGxmProgramParameter *paramColorPositionAttribute = sceGxmProgramFindParameterByName(colorVertexProgramGxp, "aPosition");
+
+    const SceGxmProgramParameter *paramColorColorAttribute = sceGxmProgramFindParameterByName(colorVertexProgramGxp, "aColor");
+
+    // create color vertex format
+    SceGxmVertexAttribute colorVertexAttributes[2];
+    SceGxmVertexStream colorVertexStreams[1];
+    /* x,y,z: 3 float 32 bits */
+    colorVertexAttributes[0].streamIndex = 0;
+    colorVertexAttributes[0].offset = 0;
+    colorVertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
+    colorVertexAttributes[0].componentCount = 3; // (x, y, z)
+    colorVertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(paramColorPositionAttribute);
+    /* color: 4 unsigned char  = 32 bits */
+    colorVertexAttributes[1].streamIndex = 0;
+    colorVertexAttributes[1].offset = 12; // (x, y, z) * 4 = 12 bytes
+    colorVertexAttributes[1].format = SCE_GXM_ATTRIBUTE_FORMAT_U8N;
+    colorVertexAttributes[1].componentCount = 4; // (color)
+    colorVertexAttributes[1].regIndex = sceGxmProgramParameterGetResourceIndex(paramColorColorAttribute);
+    // 16 bit (short) indices
+    colorVertexStreams[0].stride = sizeof(color_vertex);
+    colorVertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
+
+    // create color shaders
+    err = sceGxmShaderPatcherCreateVertexProgram(
+        data->shaderPatcher,
+        data->colorVertexProgramId,
+        colorVertexAttributes,
+        2,
+        colorVertexStreams,
+        1,
+        &data->colorVertexProgram
+    );
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (color vertex) failed: %d\n", err);
+        return err;
+    }
+
+    const SceGxmProgramParameter *paramTexturePositionAttribute = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "aPosition");
+    const SceGxmProgramParameter *paramTextureTexcoordAttribute = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "aTexcoord");
+
+    // create texture vertex format
+    SceGxmVertexAttribute textureVertexAttributes[2];
+    SceGxmVertexStream textureVertexStreams[1];
+    /* x,y,z: 3 float 32 bits */
+    textureVertexAttributes[0].streamIndex = 0;
+    textureVertexAttributes[0].offset = 0;
+    textureVertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
+    textureVertexAttributes[0].componentCount = 3; // (x, y, z)
+    textureVertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(paramTexturePositionAttribute);
+    /* u,v: 2 floats 32 bits */
+    textureVertexAttributes[1].streamIndex = 0;
+    textureVertexAttributes[1].offset = 12; // (x, y, z) * 4 = 12 bytes
+    textureVertexAttributes[1].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
+    textureVertexAttributes[1].componentCount = 2; // (u, v)
+    textureVertexAttributes[1].regIndex = sceGxmProgramParameterGetResourceIndex(paramTextureTexcoordAttribute);
+    // 16 bit (short) indices
+    textureVertexStreams[0].stride = sizeof(texture_vertex);
+    textureVertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
+
+    // create texture shaders
+    err = sceGxmShaderPatcherCreateVertexProgram(
+        data->shaderPatcher,
+        data->textureVertexProgramId,
+        textureVertexAttributes,
+        2,
+        textureVertexStreams,
+        1,
+        &data->textureVertexProgram
+    );
+    if (err != SCE_OK) {
+        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (texture vertex) failed: %d\n", err);
+        return err;
+    }
+
+    // Create variations of the fragment program based on blending mode
+    make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_none, &blend_info_none);
+    make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_blend, &blend_info_blend);
+    make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_add, &blend_info_add);
+    make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mod, &blend_info_mod);
+    make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mul, &blend_info_mul);
+
+    // Default to blend blending mode
+    fragment_programs *in = &data->blendFragmentPrograms.blend_mode_blend;
+
+    data->colorFragmentProgram = in->color;
+    data->textureFragmentProgram = in->texture;
+    data->textureTintFragmentProgram = in->textureTint;
+
+    // find vertex uniforms by name and cache parameter information
+    data->clearClearColorParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(clearFragmentProgramGxp, "uClearColor");
+    data->colorWvpParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(colorVertexProgramGxp, "wvp");
+    data->textureWvpParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(textureVertexProgramGxp, "wvp");
+    data->textureTintColorParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(textureTintFragmentProgramGxp, "uTintColor");
+
+    // Allocate memory for the memory pool
+    data->pool_addr = gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_RW,
+        VITA_GXM_POOL_SIZE,
+        sizeof(void *),
+        SCE_GXM_MEMORY_ATTRIB_READ,
+        &data->poolUid
+    );
+
+    init_orthographic_matrix(data->ortho_matrix, 0.0f, VITA_GXM_SCREEN_WIDTH, VITA_GXM_SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f);
+
+    data->backBufferIndex = 0;
+    data->frontBufferIndex = 0;
+    data->pool_index = 0;
+
+    return 0;
+}
+
+void gxm_finish(SDL_Renderer *renderer)
+{
+    VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
+
+    // wait until rendering is done
+    sceGxmFinish(data->gxm_context);
+
+    // clean up allocations
+    sceGxmShaderPatcherReleaseFragmentProgram(data->shaderPatcher, data->clearFragmentProgram);
+    sceGxmShaderPatcherReleaseVertexProgram(data->shaderPatcher, data->clearVertexProgram);
+    sceGxmShaderPatcherReleaseVertexProgram(data->shaderPatcher, data->colorVertexProgram);
+    sceGxmShaderPatcherReleaseVertexProgram(data->shaderPatcher, data->textureVertexProgram);
+
+
+    free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_none);
+    free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_blend);
+    free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_add);
+    free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mod);
+    free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mul);
+
+    gpu_free(data->linearIndicesUid);
+    gpu_free(data->clearVerticesUid);
+
+    // wait until display queue is finished before deallocating display buffers
+    sceGxmDisplayQueueFinish();
+
+    // clean up display queue
+    gpu_free(data->depthBufferUid);
+
+    for (size_t i = 0; i < VITA_GXM_BUFFERS; i++)
+    {
+        // clear the buffer then deallocate
+        SDL_memset(data->displayBufferData[i], 0, VITA_GXM_SCREEN_HEIGHT * VITA_GXM_SCREEN_STRIDE * 4);
+        gpu_free(data->displayBufferUid[i]);
+
+        // destroy the sync object
+        sceGxmSyncObjectDestroy(data->displayBufferSync[i]);
+    }
+
+    // free the depth and stencil buffer
+    gpu_free(data->depthBufferUid);
+    gpu_free(data->stencilBufferUid);
+
+    // unregister programs and destroy shader patcher
+    sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->clearFragmentProgramId);
+    sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->clearVertexProgramId);
+    sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->colorFragmentProgramId);
+    sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->colorVertexProgramId);
+    sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureFragmentProgramId);
+    sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureTintFragmentProgramId);
+    sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureVertexProgramId);
+
+    sceGxmShaderPatcherDestroy(data->shaderPatcher);
+    fragment_usse_free(data->patcherFragmentUsseUid);
+    vertex_usse_free(data->patcherVertexUsseUid);
+    gpu_free(data->patcherBufferUid);
+
+    // destroy the render target
+    sceGxmDestroyRenderTarget(data->renderTarget);
+
+    // destroy the gxm context
+    sceGxmDestroyContext(data->gxm_context);
+    fragment_usse_free(data->fragmentUsseRingBufferUid);
+    gpu_free(data->fragmentRingBufferUid);
+    gpu_free(data->vertexRingBufferUid);
+    gpu_free(data->vdmRingBufferUid);
+    SDL_free(data->contextParams.hostMem);
+
+    gpu_free(data->poolUid);
+
+    // terminate libgxm
+    sceGxmTerminate();
+}
+
+// textures
+
+void
+free_gxm_texture(gxm_texture *texture)
+{
+    if (texture) {
+        if (texture->gxm_rendertarget) {
+            sceGxmDestroyRenderTarget(texture->gxm_rendertarget);
+        }
+        if (texture->depth_UID) {
+            gpu_free(texture->depth_UID);
+        }
+        if (texture->palette_UID) {
+            gpu_free(texture->palette_UID);
+        }
+        gpu_free(texture->data_UID);
+        SDL_free(texture);
+    }
+}
+
+SceGxmTextureFormat
+gxm_texture_get_format(const gxm_texture *texture)
+{
+    return sceGxmTextureGetFormat(&texture->gxm_tex);
+}
+
+unsigned int
+gxm_texture_get_width(const gxm_texture *texture)
+{
+    return sceGxmTextureGetWidth(&texture->gxm_tex);
+}
+
+unsigned int
+gxm_texture_get_height(const gxm_texture *texture)
+{
+    return sceGxmTextureGetHeight(&texture->gxm_tex);
+}
+
+unsigned int
+gxm_texture_get_stride(const gxm_texture *texture)
+{
+    return ((gxm_texture_get_width(texture) + 7) & ~7)
+        * tex_format_to_bytespp(gxm_texture_get_format(texture));
+}
+
+void *
+gxm_texture_get_datap(const gxm_texture *texture)
+{
+    return sceGxmTextureGetData(&texture->gxm_tex);
+}
+
+gxm_texture *
+create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget)
+{
+    format = SCE_GXM_TEXTURE_FORMAT_A8B8G8R8;
+    gxm_texture *texture = SDL_malloc(sizeof(gxm_texture));
+    if (!texture)
+        return NULL;
+
+    const int tex_size =  ((w + 7) & ~ 7) * h * tex_format_to_bytespp(format);
+
+    /* Allocate a GPU buffer for the texture */
+    void *texture_data = gpu_alloc(
+        SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
+        tex_size,
+        SCE_GXM_TEXTURE_ALIGNMENT,
+        SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
+        &texture->data_UID
+    );
+
+    if (!texture_data) {
+        free(texture);
+        return NULL;
+    }
+
+    /* Clear the texture */
+    SDL_memset(texture_data, 0, tex_size);
+
+    /* Create the gxm texture */
+    sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, w, h, 0);
+
+    if ((format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_P8) {
+        const int pal_size = 256 * sizeof(uint32_t);
+
+        void *texture_palette = gpu_alloc(
+            SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
+            pal_size,
+            SCE_GXM_PALETTE_ALIGNMENT,
+            SCE_GXM_MEMORY_ATTRIB_READ,
+            &texture->palette_UID);
+
+        if (!texture_palette) {
+            texture->palette_UID = 0;
+            free_gxm_texture(texture);
+            return NULL;
+        }
+
+        SDL_memset(texture_palette, 0, pal_size);
+
+        sceGxmTextureSetPalette(&texture->gxm_tex, texture_palette);
+    } else {
+        texture->palette_UID = 0;
+    }
+
+    if (isRenderTarget) {
+
+        int err = sceGxmColorSurfaceInit(
+            &texture->gxm_colorsurface,
+            SCE_GXM_COLOR_FORMAT_A8B8G8R8,
+            SCE_GXM_COLOR_SURFACE_LINEAR,
+            SCE_GXM_COLOR_SURFACE_SCALE_NONE,
+            SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
+            w,
+            h,
+            w,
+            texture_data
+        );
+
+        if (err < 0) {
+            free_gxm_texture(texture);
+            SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %d\n", err);
+            return NULL;
+        }
+
+        // create the depth/stencil surface
+        const uint32_t alignedWidth = ALIGN(w, SCE_GXM_TILE_SIZEX);
+        const uint32_t alignedHeight = ALIGN(h, SCE_GXM_TILE_SIZEY);
+        uint32_t sampleCount = alignedWidth*alignedHeight;
+        uint32_t depthStrideInSamples = alignedWidth;
+
+        // allocate it
+        void *depthBufferData = gpu_alloc(
+            SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
+            4*sampleCount,
+            SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT,
+            SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
+            &texture->depth_UID);
+
+        // create the SceGxmDepthStencilSurface structure
+        err = sceGxmDepthStencilSurfaceInit(
+            &texture->gxm_depthstencil,
+            SCE_GXM_DEPTH_STENCIL_FORMAT_S8D24,
+            SCE_GXM_DEPTH_STENCIL_SURFACE_TILED,
+            depthStrideInSamples,
+            depthBufferData,
+            NULL);
+
+        if (err < 0) {
+            free_gxm_texture(texture);
+            SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %d\n", err);
+            return NULL;
+        }
+
+        SceGxmRenderTarget *tgt = NULL;
+
+        // set up parameters
+        SceGxmRenderTargetParams renderTargetParams;
+        memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams));
+        renderTargetParams.flags = 0;
+        renderTargetParams.width = w;
+        renderTargetParams.height = h;
+        renderTargetParams.scenesPerFrame = 1;
+        renderTargetParams.multisampleMode = SCE_GXM_MULTISAMPLE_NONE;
+        renderTargetParams.multisampleLocations = 0;
+        renderTargetParams.driverMemBlock = -1;
+
+        // create the render target
+        err = sceGxmCreateRenderTarget(&renderTargetParams, &tgt);
+
+        texture->gxm_rendertarget = tgt;
+
+        if (err < 0) {
+            free_gxm_texture(texture);
+            SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %d\n", err);
+            return NULL;
+        }
+
+    }
+
+    return texture;
+}
+
+void
+gxm_texture_set_filters(gxm_texture *texture, SceGxmTextureFilter min_filter, SceGxmTextureFilter mag_filter)
+{
+    sceGxmTextureSetMinFilter(&texture->gxm_tex, min_filter);
+    sceGxmTextureSetMagFilter(&texture->gxm_tex, mag_filter);
+}
+
+#endif /* SDL_VIDEO_RENDER_VITA_GXM */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 61 - 0
src/render/vitagxm/SDL_render_vita_gxm_tools.h

@@ -0,0 +1,61 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_RENDER_VITA_GXM_TOOLS_H
+#define SDL_RENDER_VITA_GXM_TOOLS_H
+
+#include "../../SDL_internal.h"
+
+#include "SDL_hints.h"
+#include "../SDL_sysrender.h"
+
+#include <psp2/kernel/processmgr.h>
+#include <psp2/appmgr.h>
+#include <psp2/display.h>
+#include <psp2/gxm.h>
+#include <psp2/types.h>
+#include <psp2/kernel/sysmem.h>
+
+#include "SDL_render_vita_gxm_types.h"
+
+void *pool_malloc(VITA_GXM_RenderData *data, unsigned int size);
+void *pool_memalign(VITA_GXM_RenderData *data, unsigned int size, unsigned int alignment);
+
+void set_clip_rectangle(VITA_GXM_RenderData *data, int x_min, int y_min, int x_max, int y_max);
+void unset_clip_rectangle(VITA_GXM_RenderData *data);
+
+int gxm_init(SDL_Renderer *renderer);
+void gxm_finish(SDL_Renderer *renderer);
+
+gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget);
+void free_gxm_texture(gxm_texture *texture);
+
+void gxm_texture_set_filters(gxm_texture *texture, SceGxmTextureFilter min_filter, SceGxmTextureFilter mag_filter);
+SceGxmTextureFormat gxm_texture_get_format(const gxm_texture *texture);
+
+unsigned int gxm_texture_get_width(const gxm_texture *texture);
+unsigned int gxm_texture_get_height(const gxm_texture *texture);
+unsigned int gxm_texture_get_stride(const gxm_texture *texture);
+void *gxm_texture_get_datap(const gxm_texture *texture);
+
+#endif /* SDL_RENDER_VITA_GXM_TOOLS_H */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 194 - 0
src/render/vitagxm/SDL_render_vita_gxm_types.h

@@ -0,0 +1,194 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_RENDER_VITA_GXM_TYPES_H
+#define SDL_RENDER_VITA_GXM_TYPES_H
+
+#include "../../SDL_internal.h"
+
+#include "SDL_hints.h"
+#include "../SDL_sysrender.h"
+
+#include <psp2/kernel/processmgr.h>
+#include <psp2/appmgr.h>
+#include <psp2/display.h>
+#include <psp2/gxm.h>
+#include <psp2/types.h>
+#include <psp2/kernel/sysmem.h>
+
+#include <string.h>
+
+#define VITA_GXM_SCREEN_WIDTH     960
+#define VITA_GXM_SCREEN_HEIGHT    544
+#define VITA_GXM_SCREEN_STRIDE    960
+
+#define VITA_GXM_COLOR_FORMAT    SCE_GXM_COLOR_FORMAT_A8B8G8R8
+#define VITA_GXM_PIXEL_FORMAT    SCE_DISPLAY_PIXELFORMAT_A8B8G8R8
+
+#define VITA_GXM_BUFFERS          3
+#define VITA_GXM_PENDING_SWAPS    2
+#define VITA_GXM_POOL_SIZE        2 * 1024 * 1024
+
+typedef struct
+{
+    void     *address;
+    Uint8    wait_vblank;
+} VITA_GXM_DisplayData;
+
+typedef struct clear_vertex {
+    float x;
+    float y;
+} clear_vertex;
+
+typedef struct color_vertex {
+    float x;
+    float y;
+    float z;
+    unsigned int color;
+} color_vertex;
+
+typedef struct texture_vertex {
+    float x;
+    float y;
+    float z;
+    float u;
+    float v;
+} texture_vertex;
+
+typedef struct gxm_texture {
+    SceGxmTexture gxm_tex;
+    SceUID data_UID;
+    SceUID palette_UID;
+    SceGxmRenderTarget *gxm_rendertarget;
+    SceGxmColorSurface gxm_colorsurface;
+    SceGxmDepthStencilSurface gxm_depthstencil;
+    SceUID depth_UID;
+} gxm_texture;
+
+typedef struct fragment_programs {
+    SceGxmFragmentProgram *color;
+    SceGxmFragmentProgram *texture;
+    SceGxmFragmentProgram *textureTint;
+} fragment_programs;
+
+typedef struct blend_fragment_programs {
+    fragment_programs blend_mode_none;
+    fragment_programs blend_mode_blend;
+    fragment_programs blend_mode_add;
+    fragment_programs blend_mode_mod;
+    fragment_programs blend_mode_mul;
+} blend_fragment_programs;
+
+typedef struct
+{
+    SDL_Rect viewport;
+    SDL_bool viewport_dirty;
+    SDL_Texture *texture;
+    SDL_Texture *target;
+    Uint32 color;
+} gxm_drawstate_cache;
+
+typedef struct
+{
+    SDL_bool      initialized;
+    SDL_bool      drawing;
+
+    unsigned int  psm;
+    unsigned int  bpp;
+
+    int           currentBlendMode;
+
+    VITA_GXM_DisplayData displayData;
+
+    SceUID vdmRingBufferUid;
+    SceUID vertexRingBufferUid;
+    SceUID fragmentRingBufferUid;
+    SceUID fragmentUsseRingBufferUid;
+    SceGxmContextParams contextParams;
+    SceGxmContext *gxm_context;
+    SceGxmRenderTarget *renderTarget;
+    SceUID displayBufferUid[VITA_GXM_BUFFERS];
+    void *displayBufferData[VITA_GXM_BUFFERS];
+    SceGxmColorSurface displaySurface[VITA_GXM_BUFFERS];
+    SceGxmSyncObject *displayBufferSync[VITA_GXM_BUFFERS];
+
+    SceUID depthBufferUid;
+    SceUID stencilBufferUid;
+    SceGxmDepthStencilSurface depthSurface;
+    void *depthBufferData;
+    void *stencilBufferData;
+
+    unsigned int backBufferIndex;
+    unsigned int frontBufferIndex;
+
+    void* pool_addr;
+    SceUID poolUid;
+    unsigned int pool_index;
+
+    float ortho_matrix[4*4];
+
+    SceGxmVertexProgram *colorVertexProgram;
+    SceGxmFragmentProgram *colorFragmentProgram;
+    SceGxmVertexProgram *textureVertexProgram;
+    SceGxmFragmentProgram *textureFragmentProgram;
+    SceGxmFragmentProgram *textureTintFragmentProgram;
+    SceGxmProgramParameter *clearClearColorParam;
+    SceGxmProgramParameter *colorWvpParam;
+    SceGxmProgramParameter *textureWvpParam;
+    SceGxmProgramParameter *textureTintColorParam;
+
+    SceGxmShaderPatcher *shaderPatcher;
+    SceGxmVertexProgram *clearVertexProgram;
+    SceGxmFragmentProgram *clearFragmentProgram;
+
+    SceGxmShaderPatcherId clearVertexProgramId;
+    SceGxmShaderPatcherId clearFragmentProgramId;
+    SceGxmShaderPatcherId colorVertexProgramId;
+    SceGxmShaderPatcherId colorFragmentProgramId;
+    SceGxmShaderPatcherId textureVertexProgramId;
+    SceGxmShaderPatcherId textureFragmentProgramId;
+    SceGxmShaderPatcherId textureTintFragmentProgramId;
+
+    SceUID patcherBufferUid;
+    SceUID patcherVertexUsseUid;
+    SceUID patcherFragmentUsseUid;
+
+    SceUID clearVerticesUid;
+    SceUID linearIndicesUid;
+    clear_vertex *clearVertices;
+    uint16_t *linearIndices;
+
+    blend_fragment_programs blendFragmentPrograms;
+
+    gxm_drawstate_cache drawstate;
+} VITA_GXM_RenderData;
+
+typedef struct
+{
+    gxm_texture  *tex;
+    unsigned int    pitch;
+    unsigned int    w;
+    unsigned int    h;
+} VITA_GXM_TextureData;
+
+#endif /* SDL_RENDER_VITA_GXM_TYPES_H */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 4 - 0
src/render/vitagxm/shader_src/clear_f.cg

@@ -0,0 +1,4 @@
+float4 main( uniform float4 uClearColor) : COLOR
+{
+    return uClearColor;
+}

+ 4 - 0
src/render/vitagxm/shader_src/clear_v.cg

@@ -0,0 +1,4 @@
+float4 main(float2 aPosition) : POSITION
+{
+    return float4(aPosition, 1.f, 1.f);
+}

+ 4 - 0
src/render/vitagxm/shader_src/color_f.cg

@@ -0,0 +1,4 @@
+float4 main(float4 vColor : COLOR)
+{
+    return vColor;
+}

+ 11 - 0
src/render/vitagxm/shader_src/color_v.cg

@@ -0,0 +1,11 @@
+void main(
+    float3 aPosition,
+    float4 aColor,
+    uniform float4x4 wvp,
+    float4 out vPosition : POSITION,
+    float4 out vColor : COLOR
+)
+{
+    vPosition = mul(float4(aPosition, 1.f), wvp);
+    vColor = aColor;
+}

+ 4 - 0
src/render/vitagxm/shader_src/texture_f.cg

@@ -0,0 +1,4 @@
+float4 main(float2 vTexcoord : TEXCOORD0, uniform sampler2D tex)
+{
+    return tex2D(tex, vTexcoord);
+}

+ 4 - 0
src/render/vitagxm/shader_src/texture_tint_f.cg

@@ -0,0 +1,4 @@
+float4 main( float2 vTexcoord : TEXCOORD0, uniform sampler2D tex, uniform float4 uTintColor)
+{
+    return tex2D(tex, vTexcoord) * uTintColor;
+}

+ 11 - 0
src/render/vitagxm/shader_src/texture_v.cg

@@ -0,0 +1,11 @@
+void main(
+    float3 aPosition,
+    float2 aTexcoord,
+    uniform float4x4 wvp,
+    float4 out vPosition : POSITION,
+    float2 out vTexcoord : TEXCOORD0
+)
+{
+    vPosition = mul(float4(aPosition, 1.f), wvp);
+    vTexcoord = aTexcoord;
+}