| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | 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 |
| | |
| | | #if SDL_VIDEO_RENDER_PSP |
| | | |
| | | #include "SDL_hints.h" |
| | | #include "SDL_assert.h" |
| | | #include "../SDL_sysrender.h" |
| | | |
| | | #include <pspkernel.h> |
| | |
| | | |
| | | |
| | | /* PSP renderer implementation, based on the PGE */ |
| | | |
| | | |
| | | extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); |
| | | |
| | | |
| | | static SDL_Renderer *PSP_CreateRenderer(SDL_Window * window, Uint32 flags); |
| | | static void PSP_WindowEvent(SDL_Renderer * renderer, |
| | | const SDL_WindowEvent *event); |
| | | static int PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); |
| | | static int PSP_SetTextureColorMod(SDL_Renderer * renderer, |
| | | SDL_Texture * texture); |
| | | static int PSP_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
| | | const SDL_Rect * rect, const void *pixels, |
| | | int pitch); |
| | | static int PSP_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, |
| | | const SDL_Rect * rect, void **pixels, int *pitch); |
| | | static void PSP_UnlockTexture(SDL_Renderer * renderer, |
| | | SDL_Texture * texture); |
| | | static int PSP_SetRenderTarget(SDL_Renderer * renderer, |
| | | SDL_Texture * texture); |
| | | static int PSP_UpdateViewport(SDL_Renderer * renderer); |
| | | static int PSP_RenderClear(SDL_Renderer * renderer); |
| | | static int PSP_RenderDrawPoints(SDL_Renderer * renderer, |
| | | const SDL_FPoint * points, int count); |
| | | static int PSP_RenderDrawLines(SDL_Renderer * renderer, |
| | | const SDL_FPoint * points, int count); |
| | | static int PSP_RenderFillRects(SDL_Renderer * renderer, |
| | | const SDL_FRect * rects, int count); |
| | | static int PSP_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, |
| | | const SDL_Rect * srcrect, |
| | | const SDL_FRect * dstrect); |
| | | static int PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, |
| | | Uint32 pixel_format, void * pixels, int pitch); |
| | | static int PSP_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, |
| | | const SDL_Rect * srcrect, const SDL_FRect * dstrect, |
| | | const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip); |
| | | static void PSP_RenderPresent(SDL_Renderer * renderer); |
| | | static void PSP_DestroyTexture(SDL_Renderer * renderer, |
| | | SDL_Texture * texture); |
| | | static void PSP_DestroyRenderer(SDL_Renderer * renderer); |
| | | |
| | | /* |
| | | SDL_RenderDriver PSP_RenderDriver = { |
| | | PSP_CreateRenderer, |
| | | { |
| | | "PSP", |
| | | (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE), |
| | | 1, |
| | | {SDL_PIXELFORMAT_ABGR8888}, |
| | | 0, |
| | | 0} |
| | | }; |
| | | */ |
| | | SDL_RenderDriver PSP_RenderDriver = { |
| | | .CreateRenderer = PSP_CreateRenderer, |
| | | .info = { |
| | | .name = "PSP", |
| | | .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, |
| | | .num_texture_formats = 4, |
| | | .texture_formats = { [0] = SDL_PIXELFORMAT_BGR565, |
| | | [1] = SDL_PIXELFORMAT_ABGR1555, |
| | | [2] = SDL_PIXELFORMAT_ABGR4444, |
| | | [3] = SDL_PIXELFORMAT_ABGR8888, |
| | | }, |
| | | .max_texture_width = 512, |
| | | .max_texture_height = 512, |
| | | } |
| | | }; |
| | | |
| | | #define PSP_SCREEN_WIDTH 480 |
| | | #define PSP_SCREEN_HEIGHT 272 |
| | |
| | | |
| | | } VertTV; |
| | | |
| | | #define PI 3.14159265358979f |
| | | |
| | | #define radToDeg(x) ((x)*180.f/PI) |
| | | #define degToRad(x) ((x)*PI/180.f) |
| | | |
| | | float MathAbs(float x) |
| | | { |
| | | float result; |
| | | |
| | | __asm__ volatile ( |
| | | "mtv %1, S000\n" |
| | | "vabs.s S000, S000\n" |
| | | "mfv %0, S000\n" |
| | | : "=r"(result) : "r"(x)); |
| | | |
| | | return result; |
| | | } |
| | | |
| | | void MathSincos(float r, float *s, float *c) |
| | | { |
| | | __asm__ volatile ( |
| | | "mtv %2, S002\n" |
| | | "vcst.s S003, VFPU_2_PI\n" |
| | | "vmul.s S002, S002, S003\n" |
| | | "vrot.p C000, S002, [s, c]\n" |
| | | "mfv %0, S000\n" |
| | | "mfv %1, S001\n" |
| | | : "=r"(*s), "=r"(*c): "r"(r)); |
| | | } |
| | | |
| | | void Swap(float *a, float *b) |
| | | { |
| | | float n=*a; |
| | | *a = *b; |
| | | *b = n; |
| | | } |
| | | |
| | | /* Return next power of 2 */ |
| | | static int |
| | |
| | | return 1; |
| | | } |
| | | |
| | | SDL_Renderer * |
| | | PSP_CreateRenderer(SDL_Window * window, Uint32 flags) |
| | | { |
| | | |
| | | SDL_Renderer *renderer; |
| | | PSP_RenderData *data; |
| | | int pixelformat; |
| | | renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); |
| | | if (!renderer) { |
| | | SDL_OutOfMemory(); |
| | | return NULL; |
| | | } |
| | | |
| | | data = (PSP_RenderData *) SDL_calloc(1, sizeof(*data)); |
| | | if (!data) { |
| | | PSP_DestroyRenderer(renderer); |
| | | SDL_OutOfMemory(); |
| | | return NULL; |
| | | } |
| | | |
| | | |
| | | renderer->WindowEvent = PSP_WindowEvent; |
| | | renderer->CreateTexture = PSP_CreateTexture; |
| | | renderer->SetTextureColorMod = PSP_SetTextureColorMod; |
| | | renderer->UpdateTexture = PSP_UpdateTexture; |
| | | renderer->LockTexture = PSP_LockTexture; |
| | | renderer->UnlockTexture = PSP_UnlockTexture; |
| | | renderer->SetRenderTarget = PSP_SetRenderTarget; |
| | | renderer->UpdateViewport = PSP_UpdateViewport; |
| | | renderer->RenderClear = PSP_RenderClear; |
| | | renderer->RenderDrawPoints = PSP_RenderDrawPoints; |
| | | renderer->RenderDrawLines = PSP_RenderDrawLines; |
| | | renderer->RenderFillRects = PSP_RenderFillRects; |
| | | renderer->RenderCopy = PSP_RenderCopy; |
| | | renderer->RenderReadPixels = PSP_RenderReadPixels; |
| | | renderer->RenderCopyEx = PSP_RenderCopyEx; |
| | | renderer->RenderPresent = PSP_RenderPresent; |
| | | renderer->DestroyTexture = PSP_DestroyTexture; |
| | | renderer->DestroyRenderer = PSP_DestroyRenderer; |
| | | renderer->info = PSP_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; |
| | | } |
| | | |
| | | pixelformat=PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window)); |
| | | switch(pixelformat) |
| | | { |
| | | case GU_PSM_4444: |
| | | case GU_PSM_5650: |
| | | case GU_PSM_5551: |
| | | data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<1); |
| | | data->backbuffer = (unsigned int *)(0); |
| | | data->bpp = 2; |
| | | data->psm = pixelformat; |
| | | break; |
| | | default: |
| | | data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<2); |
| | | data->backbuffer = (unsigned int *)(0); |
| | | data->bpp = 4; |
| | | data->psm = GU_PSM_8888; |
| | | break; |
| | | } |
| | | |
| | | sceGuInit(); |
| | | /* setup GU */ |
| | | sceGuStart(GU_DIRECT, DisplayList); |
| | | sceGuDrawBuffer(data->psm, data->frontbuffer, PSP_FRAME_BUFFER_WIDTH); |
| | | sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, data->backbuffer, PSP_FRAME_BUFFER_WIDTH); |
| | | |
| | | |
| | | sceGuOffset(2048 - (PSP_SCREEN_WIDTH>>1), 2048 - (PSP_SCREEN_HEIGHT>>1)); |
| | | sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); |
| | | |
| | | data->frontbuffer = vabsptr(data->frontbuffer); |
| | | data->backbuffer = vabsptr(data->backbuffer); |
| | | |
| | | /* Scissoring */ |
| | | sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); |
| | | sceGuEnable(GU_SCISSOR_TEST); |
| | | |
| | | /* Backface culling */ |
| | | sceGuFrontFace(GU_CCW); |
| | | sceGuEnable(GU_CULL_FACE); |
| | | |
| | | /* Texturing */ |
| | | sceGuEnable(GU_TEXTURE_2D); |
| | | sceGuShadeModel(GU_SMOOTH); |
| | | sceGuTexWrap(GU_REPEAT, GU_REPEAT); |
| | | |
| | | /* Blending */ |
| | | sceGuEnable(GU_BLEND); |
| | | sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); |
| | | |
| | | sceGuTexFilter(GU_LINEAR,GU_LINEAR); |
| | | |
| | | sceGuFinish(); |
| | | sceGuSync(0,0); |
| | | sceDisplayWaitVblankStartCB(); |
| | | sceGuDisplay(GU_TRUE); |
| | | |
| | | return renderer; |
| | | } |
| | | |
| | | static void |
| | | PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) |
| | | { |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | PSP_UpdateTexture(renderer, texture, &rect, psp_texture->data, psp_texture->pitch); |
| | | } |
| | | |
| | | static void |
| | | PSP_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode) |
| | | { |
| | | /* Nothing to do because TextureActivate takes care of it */ |
| | | } |
| | | |
| | | static int |
| | | PSP_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | PSP_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd) |
| | | { |
| | | return 0; /* nothing to do in this backend. */ |
| | | } |
| | | |
| | | static int |
| | | PSP_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count) |
| | | { |
| | | VertV *verts = (VertV *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertV), 4, &cmd->data.draw.first); |
| | | int i; |
| | | |
| | | if (!verts) { |
| | | return -1; |
| | | } |
| | | |
| | | cmd->data.draw.count = count; |
| | | |
| | | for (i = 0; i < count; i++, verts++, points++) { |
| | | verts->x = points->x; |
| | | verts->y = points->y; |
| | | verts->z = 0.0f; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | PSP_UpdateViewport(SDL_Renderer * renderer) |
| | | PSP_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count) |
| | | { |
| | | VertV *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (VertV), 4, &cmd->data.draw.first); |
| | | int i; |
| | | |
| | | if (!verts) { |
| | | return -1; |
| | | } |
| | | |
| | | cmd->data.draw.count = count; |
| | | for (i = 0; i < count; i++, rects++) { |
| | | const SDL_FRect *rect = &rects[i]; |
| | | verts->x = rect->x; |
| | | verts->y = rect->y; |
| | | verts->z = 0.0f; |
| | | verts++; |
| | | |
| | | verts->x = rect->x + rect->w; |
| | | verts->y = rect->y + rect->h; |
| | | verts->z = 0.0f; |
| | | verts++; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | PSP_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, |
| | | const SDL_Rect * srcrect, const SDL_FRect * dstrect) |
| | | { |
| | | VertTV *verts; |
| | | const float x = dstrect->x; |
| | | const float y = dstrect->y; |
| | | const float width = dstrect->w; |
| | | const float height = dstrect->h; |
| | | |
| | | const float u0 = srcrect->x; |
| | | const float v0 = srcrect->y; |
| | | const float u1 = srcrect->x + srcrect->w; |
| | | const float v1 = srcrect->y + srcrect->h; |
| | | |
| | | if((MathAbs(u1) - MathAbs(u0)) < 64.0f) |
| | | { |
| | | verts = (VertTV *) SDL_AllocateRenderVertices(renderer, 2 * sizeof (VertTV), 4, &cmd->data.draw.first); |
| | | if (!verts) { |
| | | return -1; |
| | | } |
| | | |
| | | cmd->data.draw.count = 1; |
| | | |
| | | verts->u = u0; |
| | | verts->v = v0; |
| | | verts->x = x; |
| | | verts->y = y; |
| | | verts->z = 0; |
| | | verts++; |
| | | |
| | | verts->u = u1; |
| | | verts->v = v1; |
| | | verts->x = x + width; |
| | | verts->y = y + height; |
| | | verts->z = 0; |
| | | verts++; |
| | | } |
| | | else |
| | | { |
| | | float start, end; |
| | | float curU = u0; |
| | | float curX = x; |
| | | const float endX = x + width; |
| | | const float slice = 64.0f; |
| | | const size_t count = SDL_ceilf(width / slice); |
| | | size_t i; |
| | | float ustep = (u1 - u0)/width * slice; |
| | | |
| | | if(ustep < 0.0f) |
| | | ustep = -ustep; |
| | | |
| | | cmd->data.draw.count = count; |
| | | |
| | | verts = (VertTV *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertTV), 4, &cmd->data.draw.first); |
| | | if (!verts) { |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | for(i = 0, start = 0, end = width; i < count; i++, start += slice) |
| | | { |
| | | const float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice; |
| | | const float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep; |
| | | |
| | | SDL_assert(start < end); |
| | | |
| | | verts->u = curU; |
| | | verts->v = v0; |
| | | verts->x = curX; |
| | | verts->y = y; |
| | | verts->z = 0; |
| | | |
| | | curU += sourceWidth; |
| | | curX += polyWidth; |
| | | |
| | | verts->u = curU; |
| | | verts->v = v1; |
| | | verts->x = curX; |
| | | verts->y = (y + height); |
| | | verts->z = 0; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | PSP_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, |
| | | const SDL_Rect * srcrect, const SDL_FRect * dstrect, |
| | | const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) |
| | | { |
| | | VertTV *verts = (VertTV *) SDL_AllocateRenderVertices(renderer, 4 * sizeof (VertTV), 4, &cmd->data.draw.first); |
| | | 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; |
| | | |
| | | float u0 = srcrect->x; |
| | | float v0 = srcrect->y; |
| | | float u1 = srcrect->x + srcrect->w; |
| | | float v1 = srcrect->y + srcrect->h; |
| | | |
| | | |
| | | if (!verts) { |
| | | return -1; |
| | | } |
| | | |
| | | cmd->data.draw.count = 1; |
| | | |
| | | 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; |
| | | |
| | | if (flip & SDL_FLIP_VERTICAL) { |
| | | Swap(&v0, &v1); |
| | | } |
| | | |
| | | if (flip & SDL_FLIP_HORIZONTAL) { |
| | | Swap(&u0, &u1); |
| | | } |
| | | |
| | | verts->u = u0; |
| | | verts->v = v0; |
| | | verts->x = x - cw + sh; |
| | | verts->y = y - sw - ch; |
| | | verts->z = 0; |
| | | verts++; |
| | | |
| | | verts->u = u0; |
| | | verts->v = v1; |
| | | verts->x = x - cw - sh; |
| | | verts->y = y - sw + ch; |
| | | verts->z = 0; |
| | | verts++; |
| | | |
| | | verts->u = u1; |
| | | verts->v = v1; |
| | | verts->x = x + cw - sh; |
| | | verts->y = y + sw + ch; |
| | | verts->z = 0; |
| | | verts++; |
| | | |
| | | verts->u = u1; |
| | | verts->v = v0; |
| | | verts->x = x + cw + sh; |
| | | verts->y = y + sw - ch; |
| | | verts->z = 0; |
| | | verts++; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static void |
| | | PSP_SetBlendMode(SDL_Renderer * renderer, int blendMode) |
| | |
| | | case SDL_BLENDMODE_MOD: |
| | | sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); |
| | | sceGuEnable(GU_BLEND); |
| | | sceGuBlendFunc( GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); |
| | | sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); |
| | | break; |
| | | case SDL_BLENDMODE_MUL: |
| | | sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); |
| | | sceGuEnable(GU_BLEND); |
| | | sceGuBlendFunc(GU_ADD, GU_DST_COLOR, GU_ONE_MINUS_SRC_ALPHA, 0, 0); |
| | | break; |
| | | } |
| | | data->currentBlendMode = blendMode; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | static int |
| | | PSP_RenderClear(SDL_Renderer * renderer) |
| | | PSP_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) |
| | | { |
| | | /* start list */ |
| | | StartDrawing(renderer); |
| | | int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r; |
| | | sceGuClearColor(color); |
| | | sceGuClearDepth(0); |
| | | sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT|GU_FAST_CLEAR_BIT); |
| | | PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata; |
| | | size_t i; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | PSP_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; |
| | | StartDrawing(renderer); |
| | | VertV* vertices = (VertV*)sceGuGetMemory(count*sizeof(VertV)); |
| | | |
| | | for (i = 0; i < count; ++i) { |
| | | vertices[i].x = points[i].x; |
| | | vertices[i].y = points[i].y; |
| | | vertices[i].z = 0.0f; |
| | | } |
| | | sceGuDisable(GU_TEXTURE_2D); |
| | | sceGuColor(color); |
| | | sceGuShadeModel(GU_FLAT); |
| | | sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, vertices); |
| | | sceGuShadeModel(GU_SMOOTH); |
| | | sceGuEnable(GU_TEXTURE_2D); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | PSP_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; |
| | | StartDrawing(renderer); |
| | | VertV* vertices = (VertV*)sceGuGetMemory(count*sizeof(VertV)); |
| | | |
| | | for (i = 0; i < count; ++i) { |
| | | vertices[i].x = points[i].x; |
| | | vertices[i].y = points[i].y; |
| | | vertices[i].z = 0.0f; |
| | | } |
| | | |
| | | sceGuDisable(GU_TEXTURE_2D); |
| | | sceGuColor(color); |
| | | sceGuShadeModel(GU_FLAT); |
| | | sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, vertices); |
| | | sceGuShadeModel(GU_SMOOTH); |
| | | sceGuEnable(GU_TEXTURE_2D); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | PSP_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; |
| | | StartDrawing(renderer); |
| | | |
| | | for (i = 0; i < count; ++i) { |
| | | const SDL_FRect *rect = &rects[i]; |
| | | VertV* vertices = (VertV*)sceGuGetMemory((sizeof(VertV)<<1)); |
| | | vertices[0].x = rect->x; |
| | | vertices[0].y = rect->y; |
| | | vertices[0].z = 0.0f; |
| | | |
| | | vertices[1].x = rect->x + rect->w; |
| | | vertices[1].y = rect->y + rect->h; |
| | | vertices[1].z = 0.0f; |
| | | |
| | | sceGuDisable(GU_TEXTURE_2D); |
| | | sceGuColor(color); |
| | | sceGuShadeModel(GU_FLAT); |
| | | sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices); |
| | | sceGuShadeModel(GU_SMOOTH); |
| | | sceGuEnable(GU_TEXTURE_2D); |
| | | /* note that before the renderer interface change, this would do extrememly small |
| | | batches with sceGuGetMemory()--a few vertices at a time--and it's not clear that |
| | | this won't fail if you try to push 100,000 draw calls in a single batch. |
| | | I don't know what the limits on PSP hardware are. It might be useful to have |
| | | rendering backends report a reasonable maximum, so the higher level can flush |
| | | if we appear to be exceeding that. */ |
| | | Uint8 *gpumem = (Uint8 *) sceGuGetMemory(vertsize); |
| | | if (!gpumem) { |
| | | return SDL_SetError("Couldn't obtain a %d-byte vertex buffer!", (int) vertsize); |
| | | } |
| | | SDL_memcpy(gpumem, vertices, vertsize); |
| | | |
| | | return 0; |
| | | } |
| | | while (cmd) { |
| | | switch (cmd->command) { |
| | | case SDL_RENDERCMD_SETDRAWCOLOR: { |
| | | break; /* !!! FIXME: we could cache drawstate like color */ |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | |
| | | #define PI 3.14159265358979f |
| | | case SDL_RENDERCMD_SETCLIPRECT: { |
| | | const SDL_Rect *rect = &cmd->data.cliprect.rect; |
| | | if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { |
| | | data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; |
| | | data->drawstate.cliprect_enabled_dirty = SDL_TRUE; |
| | | } |
| | | if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { |
| | | SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); |
| | | data->drawstate.cliprect_dirty = SDL_TRUE; |
| | | } |
| | | break; |
| | | } |
| | | |
| | | #define radToDeg(x) ((x)*180.f/PI) |
| | | #define degToRad(x) ((x)*PI/180.f) |
| | | case SDL_RENDERCMD_CLEAR: { |
| | | 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; |
| | | const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r); |
| | | /* !!! FIXME: we could cache drawstate like clear color */ |
| | | sceGuClearColor(color); |
| | | sceGuClearDepth(0); |
| | | sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT|GU_FAST_CLEAR_BIT); |
| | | break; |
| | | } |
| | | |
| | | float MathAbs(float x) |
| | | { |
| | | float result; |
| | | case SDL_RENDERCMD_DRAW_POINTS: { |
| | | const size_t count = cmd->data.draw.count; |
| | | const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first); |
| | | const Uint8 r = cmd->data.draw.r; |
| | | const Uint8 g = cmd->data.draw.g; |
| | | const Uint8 b = cmd->data.draw.b; |
| | | const Uint8 a = cmd->data.draw.a; |
| | | const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r); |
| | | /* !!! FIXME: we could cache draw state like color, texturing, etc */ |
| | | sceGuColor(color); |
| | | sceGuDisable(GU_TEXTURE_2D); |
| | | sceGuShadeModel(GU_FLAT); |
| | | sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, verts); |
| | | sceGuShadeModel(GU_SMOOTH); |
| | | sceGuEnable(GU_TEXTURE_2D); |
| | | break; |
| | | } |
| | | |
| | | __asm__ volatile ( |
| | | "mtv %1, S000\n" |
| | | "vabs.s S000, S000\n" |
| | | "mfv %0, S000\n" |
| | | : "=r"(result) : "r"(x)); |
| | | case SDL_RENDERCMD_DRAW_LINES: { |
| | | const size_t count = cmd->data.draw.count; |
| | | const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first); |
| | | const Uint8 r = cmd->data.draw.r; |
| | | const Uint8 g = cmd->data.draw.g; |
| | | const Uint8 b = cmd->data.draw.b; |
| | | const Uint8 a = cmd->data.draw.a; |
| | | const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r); |
| | | /* !!! FIXME: we could cache draw state like color, texturing, etc */ |
| | | sceGuColor(color); |
| | | sceGuDisable(GU_TEXTURE_2D); |
| | | sceGuShadeModel(GU_FLAT); |
| | | sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, verts); |
| | | sceGuShadeModel(GU_SMOOTH); |
| | | sceGuEnable(GU_TEXTURE_2D); |
| | | break; |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | case SDL_RENDERCMD_FILL_RECTS: { |
| | | const size_t count = cmd->data.draw.count; |
| | | const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first); |
| | | const Uint8 r = cmd->data.draw.r; |
| | | const Uint8 g = cmd->data.draw.g; |
| | | const Uint8 b = cmd->data.draw.b; |
| | | const Uint8 a = cmd->data.draw.a; |
| | | const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r); |
| | | /* !!! FIXME: we could cache draw state like color, texturing, etc */ |
| | | sceGuColor(color); |
| | | sceGuDisable(GU_TEXTURE_2D); |
| | | sceGuShadeModel(GU_FLAT); |
| | | sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2 * count, 0, verts); |
| | | sceGuShadeModel(GU_SMOOTH); |
| | | sceGuEnable(GU_TEXTURE_2D); |
| | | break; |
| | | } |
| | | |
| | | void MathSincos(float r, float *s, float *c) |
| | | { |
| | | __asm__ volatile ( |
| | | "mtv %2, S002\n" |
| | | "vcst.s S003, VFPU_2_PI\n" |
| | | "vmul.s S002, S002, S003\n" |
| | | "vrot.p C000, S002, [s, c]\n" |
| | | "mfv %0, S000\n" |
| | | "mfv %1, S001\n" |
| | | : "=r"(*s), "=r"(*c): "r"(r)); |
| | | } |
| | | case SDL_RENDERCMD_COPY: { |
| | | const size_t count = cmd->data.draw.count; |
| | | const VertTV *verts = (VertTV *) (gpumem + cmd->data.draw.first); |
| | | const Uint8 alpha = cmd->data.draw.a; |
| | | TextureActivate(cmd->data.draw.texture); |
| | | PSP_SetBlendMode(renderer, cmd->data.draw.blend); |
| | | |
| | | void Swap(float *a, float *b) |
| | | { |
| | | float n=*a; |
| | | *a = *b; |
| | | *b = n; |
| | | } |
| | | if(alpha != 255) { /* !!! FIXME: is this right? */ |
| | | sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); |
| | | sceGuColor(GU_RGBA(255, 255, 255, alpha)); |
| | | } else { |
| | | sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); |
| | | sceGuColor(0xFFFFFFFF); |
| | | } |
| | | |
| | | static int |
| | | PSP_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, |
| | | const SDL_Rect * srcrect, const SDL_FRect * dstrect) |
| | | { |
| | | float x, y, width, height; |
| | | float u0, v0, u1, v1; |
| | | unsigned char alpha; |
| | | sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2 * count, 0, verts); |
| | | |
| | | x = dstrect->x; |
| | | y = dstrect->y; |
| | | width = dstrect->w; |
| | | height = dstrect->h; |
| | | if(alpha != 255) { |
| | | sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); |
| | | } |
| | | break; |
| | | } |
| | | |
| | | u0 = srcrect->x; |
| | | v0 = srcrect->y; |
| | | u1 = srcrect->x + srcrect->w; |
| | | v1 = srcrect->y + srcrect->h; |
| | | case SDL_RENDERCMD_COPY_EX: { |
| | | const VertTV *verts = (VertTV *) (gpumem + cmd->data.draw.first); |
| | | const Uint8 alpha = cmd->data.draw.a; |
| | | TextureActivate(cmd->data.draw.texture); |
| | | PSP_SetBlendMode(renderer, cmd->data.draw.blend); |
| | | |
| | | alpha = texture->a; |
| | | if(alpha != 255) { /* !!! FIXME: is this right? */ |
| | | sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); |
| | | sceGuColor(GU_RGBA(255, 255, 255, alpha)); |
| | | } else { |
| | | sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); |
| | | sceGuColor(0xFFFFFFFF); |
| | | } |
| | | |
| | | StartDrawing(renderer); |
| | | TextureActivate(texture); |
| | | PSP_SetBlendMode(renderer, renderer->blendMode); |
| | | sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, verts); |
| | | |
| | | if(alpha != 255) |
| | | { |
| | | sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); |
| | | sceGuColor(GU_RGBA(255, 255, 255, alpha)); |
| | | }else{ |
| | | sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); |
| | | sceGuColor(0xFFFFFFFF); |
| | | } |
| | | if(alpha != 255) { |
| | | sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); |
| | | } |
| | | break; |
| | | } |
| | | |
| | | if((MathAbs(u1) - MathAbs(u0)) < 64.0f) |
| | | { |
| | | VertTV* vertices = (VertTV*)sceGuGetMemory((sizeof(VertTV))<<1); |
| | | |
| | | vertices[0].u = u0; |
| | | vertices[0].v = v0; |
| | | vertices[0].x = x; |
| | | vertices[0].y = y; |
| | | vertices[0].z = 0; |
| | | |
| | | vertices[1].u = u1; |
| | | vertices[1].v = v1; |
| | | vertices[1].x = x + width; |
| | | vertices[1].y = y + height; |
| | | vertices[1].z = 0; |
| | | |
| | | sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices); |
| | | } |
| | | else |
| | | { |
| | | float start, end; |
| | | float curU = u0; |
| | | float curX = x; |
| | | float endX = x + width; |
| | | float slice = 64.0f; |
| | | float ustep = (u1 - u0)/width * slice; |
| | | |
| | | if(ustep < 0.0f) |
| | | ustep = -ustep; |
| | | |
| | | for(start = 0, end = width; start < end; start += slice) |
| | | { |
| | | VertTV* vertices = (VertTV*)sceGuGetMemory((sizeof(VertTV))<<1); |
| | | |
| | | float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice; |
| | | float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep; |
| | | |
| | | vertices[0].u = curU; |
| | | vertices[0].v = v0; |
| | | vertices[0].x = curX; |
| | | vertices[0].y = y; |
| | | vertices[0].z = 0; |
| | | |
| | | curU += sourceWidth; |
| | | curX += polyWidth; |
| | | |
| | | vertices[1].u = curU; |
| | | vertices[1].v = v1; |
| | | vertices[1].x = curX; |
| | | vertices[1].y = (y + height); |
| | | vertices[1].z = 0; |
| | | |
| | | sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices); |
| | | case SDL_RENDERCMD_NO_OP: |
| | | break; |
| | | } |
| | | |
| | | cmd = cmd->next; |
| | | } |
| | | |
| | | if(alpha != 255) |
| | | sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, |
| | | Uint32 pixel_format, void * pixels, int pitch) |
| | | |
| | | { |
| | | return SDL_Unsupported(); |
| | | } |
| | | |
| | | |
| | | static int |
| | | PSP_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, |
| | | const SDL_Rect * srcrect, const SDL_FRect * dstrect, |
| | | const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) |
| | | { |
| | | float x, y, width, height; |
| | | float u0, v0, u1, v1; |
| | | unsigned char alpha; |
| | | float centerx, centery; |
| | | |
| | | x = dstrect->x; |
| | | y = dstrect->y; |
| | | width = dstrect->w; |
| | | height = dstrect->h; |
| | | |
| | | u0 = srcrect->x; |
| | | v0 = srcrect->y; |
| | | u1 = srcrect->x + srcrect->w; |
| | | v1 = srcrect->y + srcrect->h; |
| | | |
| | | centerx = center->x; |
| | | centery = center->y; |
| | | |
| | | alpha = texture->a; |
| | | |
| | | StartDrawing(renderer); |
| | | TextureActivate(texture); |
| | | PSP_SetBlendMode(renderer, renderer->blendMode); |
| | | |
| | | if(alpha != 255) |
| | | { |
| | | sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); |
| | | sceGuColor(GU_RGBA(255, 255, 255, alpha)); |
| | | }else{ |
| | | sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); |
| | | sceGuColor(0xFFFFFFFF); |
| | | } |
| | | |
| | | /* x += width * 0.5f; */ |
| | | /* y += height * 0.5f; */ |
| | | x += centerx; |
| | | y += centery; |
| | | |
| | | float c, s; |
| | | |
| | | MathSincos(degToRad(angle), &s, &c); |
| | | |
| | | /* width *= 0.5f; */ |
| | | /* height *= 0.5f; */ |
| | | width -= centerx; |
| | | height -= centery; |
| | | |
| | | |
| | | float cw = c*width; |
| | | float sw = s*width; |
| | | float ch = c*height; |
| | | float sh = s*height; |
| | | |
| | | VertTV* vertices = (VertTV*)sceGuGetMemory(sizeof(VertTV)<<2); |
| | | |
| | | vertices[0].u = u0; |
| | | vertices[0].v = v0; |
| | | vertices[0].x = x - cw + sh; |
| | | vertices[0].y = y - sw - ch; |
| | | vertices[0].z = 0; |
| | | |
| | | vertices[1].u = u0; |
| | | vertices[1].v = v1; |
| | | vertices[1].x = x - cw - sh; |
| | | vertices[1].y = y - sw + ch; |
| | | vertices[1].z = 0; |
| | | |
| | | vertices[2].u = u1; |
| | | vertices[2].v = v1; |
| | | vertices[2].x = x + cw - sh; |
| | | vertices[2].y = y + sw + ch; |
| | | vertices[2].z = 0; |
| | | |
| | | vertices[3].u = u1; |
| | | vertices[3].v = v0; |
| | | vertices[3].x = x + cw + sh; |
| | | vertices[3].y = y + sw - ch; |
| | | vertices[3].z = 0; |
| | | |
| | | if (flip & SDL_FLIP_VERTICAL) { |
| | | Swap(&vertices[0].v, &vertices[2].v); |
| | | Swap(&vertices[1].v, &vertices[3].v); |
| | | } |
| | | if (flip & SDL_FLIP_HORIZONTAL) { |
| | | Swap(&vertices[0].u, &vertices[2].u); |
| | | Swap(&vertices[1].u, &vertices[3].u); |
| | | } |
| | | |
| | | sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, vertices); |
| | | |
| | | if(alpha != 255) |
| | | sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); |
| | | return 0; |
| | | } |
| | | |
| | | static void |
| | |
| | | SDL_free(renderer); |
| | | } |
| | | |
| | | SDL_Renderer * |
| | | PSP_CreateRenderer(SDL_Window * window, Uint32 flags) |
| | | { |
| | | |
| | | SDL_Renderer *renderer; |
| | | PSP_RenderData *data; |
| | | int pixelformat; |
| | | renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); |
| | | if (!renderer) { |
| | | SDL_OutOfMemory(); |
| | | return NULL; |
| | | } |
| | | |
| | | data = (PSP_RenderData *) SDL_calloc(1, sizeof(*data)); |
| | | if (!data) { |
| | | PSP_DestroyRenderer(renderer); |
| | | SDL_OutOfMemory(); |
| | | return NULL; |
| | | } |
| | | |
| | | |
| | | renderer->WindowEvent = PSP_WindowEvent; |
| | | renderer->CreateTexture = PSP_CreateTexture; |
| | | renderer->SetTextureColorMod = PSP_SetTextureColorMod; |
| | | renderer->UpdateTexture = PSP_UpdateTexture; |
| | | renderer->LockTexture = PSP_LockTexture; |
| | | renderer->UnlockTexture = PSP_UnlockTexture; |
| | | renderer->SetTextureScaleMode = PSP_SetTextureScaleMode; |
| | | renderer->SetRenderTarget = PSP_SetRenderTarget; |
| | | renderer->QueueSetViewport = PSP_QueueSetViewport; |
| | | renderer->QueueSetDrawColor = PSP_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ |
| | | renderer->QueueDrawPoints = PSP_QueueDrawPoints; |
| | | renderer->QueueDrawLines = PSP_QueueDrawPoints; /* lines and points queue vertices the same way. */ |
| | | renderer->QueueFillRects = PSP_QueueFillRects; |
| | | renderer->QueueCopy = PSP_QueueCopy; |
| | | renderer->QueueCopyEx = PSP_QueueCopyEx; |
| | | renderer->RunCommandQueue = PSP_RunCommandQueue; |
| | | renderer->RenderReadPixels = PSP_RenderReadPixels; |
| | | renderer->RenderPresent = PSP_RenderPresent; |
| | | renderer->DestroyTexture = PSP_DestroyTexture; |
| | | renderer->DestroyRenderer = PSP_DestroyRenderer; |
| | | renderer->info = PSP_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; |
| | | } |
| | | |
| | | pixelformat=PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window)); |
| | | switch(pixelformat) |
| | | { |
| | | case GU_PSM_4444: |
| | | case GU_PSM_5650: |
| | | case GU_PSM_5551: |
| | | data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<1); |
| | | data->backbuffer = (unsigned int *)(0); |
| | | data->bpp = 2; |
| | | data->psm = pixelformat; |
| | | break; |
| | | default: |
| | | data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<2); |
| | | data->backbuffer = (unsigned int *)(0); |
| | | data->bpp = 4; |
| | | data->psm = GU_PSM_8888; |
| | | break; |
| | | } |
| | | |
| | | sceGuInit(); |
| | | /* setup GU */ |
| | | sceGuStart(GU_DIRECT, DisplayList); |
| | | sceGuDrawBuffer(data->psm, data->frontbuffer, PSP_FRAME_BUFFER_WIDTH); |
| | | sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, data->backbuffer, PSP_FRAME_BUFFER_WIDTH); |
| | | |
| | | |
| | | sceGuOffset(2048 - (PSP_SCREEN_WIDTH>>1), 2048 - (PSP_SCREEN_HEIGHT>>1)); |
| | | sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); |
| | | |
| | | data->frontbuffer = vabsptr(data->frontbuffer); |
| | | data->backbuffer = vabsptr(data->backbuffer); |
| | | |
| | | /* Scissoring */ |
| | | sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT); |
| | | sceGuEnable(GU_SCISSOR_TEST); |
| | | |
| | | /* Backface culling */ |
| | | sceGuFrontFace(GU_CCW); |
| | | sceGuEnable(GU_CULL_FACE); |
| | | |
| | | /* Texturing */ |
| | | sceGuEnable(GU_TEXTURE_2D); |
| | | sceGuShadeModel(GU_SMOOTH); |
| | | sceGuTexWrap(GU_REPEAT, GU_REPEAT); |
| | | |
| | | /* Blending */ |
| | | sceGuEnable(GU_BLEND); |
| | | sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); |
| | | |
| | | sceGuTexFilter(GU_LINEAR,GU_LINEAR); |
| | | |
| | | sceGuFinish(); |
| | | sceGuSync(0,0); |
| | | sceDisplayWaitVblankStartCB(); |
| | | sceGuDisplay(GU_TRUE); |
| | | |
| | | return renderer; |
| | | } |
| | | |
| | | SDL_RenderDriver PSP_RenderDriver = { |
| | | .CreateRenderer = PSP_CreateRenderer, |
| | | .info = { |
| | | .name = "PSP", |
| | | .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, |
| | | .num_texture_formats = 4, |
| | | .texture_formats = { [0] = SDL_PIXELFORMAT_BGR565, |
| | | [1] = SDL_PIXELFORMAT_ABGR1555, |
| | | [2] = SDL_PIXELFORMAT_ABGR4444, |
| | | [3] = SDL_PIXELFORMAT_ABGR8888, |
| | | }, |
| | | .max_texture_width = 512, |
| | | .max_texture_height = 512, |
| | | } |
| | | }; |
| | | |
| | | #endif /* SDL_VIDEO_RENDER_PSP */ |
| | | |
| | | /* vi: set ts=4 sw=4 expandtab: */ |