From c1f152292b23a8d1af27c3559942fefded645590 Mon Sep 17 00:00:00 2001 From: stdgregwar Date: Sun, 27 Dec 2020 11:43:22 +0100 Subject: [PATCH] Spill render targets to ram on PSP --- src/render/psp/SDL_render_psp.c | 230 +++++++++++++++++++++++++++----- 1 file changed, 193 insertions(+), 37 deletions(-) diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 8dc40d90c3..28e01c0e1d 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -74,8 +74,8 @@ typedef struct PSP_TextureData unsigned int format; /**< Image format - one of ::pgePixelFormat. */ unsigned int pitch; SDL_bool swizzled; /**< Is image swizzled. */ - struct PSP_TextureData* prevhot; /**< More recently used render target */ - struct PSP_TextureData* nexthot; /**< Less recently used render target */ + struct PSP_TextureData* prevhotw; /**< More recently used render target */ + struct PSP_TextureData* nexthotw; /**< Less recently used render target */ } PSP_TextureData; @@ -165,6 +165,12 @@ Swap(float *a, float *b) *b = n; } +static inline int +InVram(void* data) +{ + return data < 0x04200000; +} + /* Return next power of 2 */ static int TextureNextPow2(unsigned int w) @@ -203,35 +209,70 @@ PixelFormatToPSPFMT(Uint32 format) } } +///SECTION render target LRU management static void -StartDrawing(SDL_Renderer * renderer) -{ - PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata; - - // Check if we need to start GU displaylist - if(!data->displayListAvail) { - sceGuStart(GU_DIRECT, DisplayList); - data->displayListAvail = SDL_TRUE; +LRUTargetRelink(PSP_TextureData* psp_texture) { + if(psp_texture->prevhotw) { + psp_texture->prevhotw->nexthotw = psp_texture->nexthotw; } - - // Check if we need a draw buffer change - if(renderer->target != data->boundTarget) { - SDL_Texture* texture = renderer->target; - if(texture) { - PSP_TextureData* psp_texture = (PSP_TextureData*) texture->driverdata; - // Set target back to screen - sceGuDrawBufferList(psp_texture->format, vrelptr(psp_texture->data), psp_texture->textureWidth); - } else { - // Set target back to screen - sceGuDrawBufferList(data->psm, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); - } - data->boundTarget = texture; + if(psp_texture->nexthotw) { + psp_texture->nexthotw->prevhotw = psp_texture->prevhotw; } } +static void +LRUTargetFixTail(PSP_RenderData* data, PSP_TextureData* psp_texture) { + if(data->least_recent_target == psp_texture) { + data->least_recent_target = psp_texture->prevhotw; + } else if(!data->least_recent_target) { + data->least_recent_target = psp_texture; + } +} + +static void +LRUTargetPushFront(PSP_RenderData* data, PSP_TextureData* psp_texture) { + psp_texture->nexthotw = data->most_recent_target; + if(data->most_recent_target) { + data->most_recent_target->prevhotw = psp_texture; + } + LRUTargetFixTail(data, psp_texture); +} + +static void +LRUTargetBringFront(PSP_RenderData* data, PSP_TextureData* psp_texture) { + if(data->most_recent_target == psp_texture) { + return; //nothing to do + } + LRUTargetRelink(psp_texture); + psp_texture->prevhotw = NULL; + psp_texture->nexthotw = NULL; + LRUTargetPushFront(data, psp_texture); +} + +static void +LRUTargetRemove(PSP_RenderData* data, PSP_TextureData* psp_texture) { + LRUTargetRelink(psp_texture); + if(data->most_recent_target == psp_texture) { + data->most_recent_target = psp_texture->nexthotw; + } + if(data->least_recent_target == psp_texture) { + data->least_recent_target = psp_texture->prevhotw; + } + psp_texture->prevhotw = NULL; + psp_texture->nexthotw = NULL; +} + +static void +TextureStorageFree(void* storage) { + if(InVram(storage)) { + vfree(storage); + } else { + SDL_free(storage); + } +} static int -TextureSwizzle(PSP_TextureData *psp_texture) +TextureSwizzle(PSP_TextureData *psp_texture, void* dst) { int bytewidth, height; int rowblocks, rowblocksadd; @@ -251,7 +292,14 @@ TextureSwizzle(PSP_TextureData *psp_texture) src = (unsigned int*) psp_texture->data; - data = SDL_malloc(psp_texture->size); + data = dst; + if(!data) { + data = SDL_malloc(psp_texture->size); + } + + if(!data) { + return SDL_OutOfMemory(); + } for(j = 0; j < height; j++, blockaddress += 16) { @@ -272,7 +320,7 @@ TextureSwizzle(PSP_TextureData *psp_texture) blockaddress += rowblocksadd; } - SDL_free(psp_texture->data); + TextureStorageFree(psp_texture->data); psp_texture->data = data; psp_texture->swizzled = SDL_TRUE; @@ -281,7 +329,7 @@ TextureSwizzle(PSP_TextureData *psp_texture) } static int -TextureUnswizzle(PSP_TextureData *psp_texture) +TextureUnswizzle(PSP_TextureData *psp_texture, void* dst) { int bytewidth, height; int widthblocks, heightblocks; @@ -306,10 +354,14 @@ TextureUnswizzle(PSP_TextureData *psp_texture) src = (unsigned int*) psp_texture->data; - data = SDL_malloc(psp_texture->size); + data = dst; + + if(!data) { + data = SDL_malloc(psp_texture->size); + } if(!data) - return 0; + return SDL_OutOfMemory(); ydst = (unsigned char *)data; @@ -338,7 +390,7 @@ TextureUnswizzle(PSP_TextureData *psp_texture) ydst += dstrow; } - SDL_free(psp_texture->data); + TextureStorageFree(psp_texture->data); psp_texture->data = data; @@ -348,6 +400,80 @@ TextureUnswizzle(PSP_TextureData *psp_texture) return 1; } +static int +TextureSpillToSram(PSP_RenderData* data, PSP_TextureData* psp_texture) +{ + // Assumes the texture is in VRAM + if(psp_texture->swizzled) { + //Texture was swizzled in vram, just copy to system memory + void* data = SDL_malloc(psp_texture->size); + if(!data) { + return SDL_OutOfMemory(); + } + + SDL_memcpy(data, psp_texture->data, psp_texture->size); + vfree(psp_texture->data); + psp_texture->data = data; + return 0; + } else { + return TextureSwizzle(psp_texture, NULL); //Will realloc in sysram + } +} + +static int +TexturePromoteToVram(PSP_RenderData* data, PSP_TextureData* psp_texture, SDL_bool target) +{ + // Assumes texture in sram and a large enough continuous block in vram + void* tdata = valloc(psp_texture->size); + if(psp_texture->swizzled && target) { + return TextureUnswizzle(psp_texture, tdata); + } else { + SDL_memcpy(tdata, psp_texture->data, psp_texture->size); + SDL_free(psp_texture->data); + psp_texture->data = tdata; + return 0; + } +} + +static int +TextureSpillLRU(PSP_RenderData* data) { + PSP_TextureData* lru = data->least_recent_target; + if(lru) { + if(TextureSpillToSram(data, lru) < 0) { + return -1; + } + LRUTargetRemove(data, lru); + } + return 0; +} + +static int +TextureSpillTargetsForSpace(PSP_RenderData* data, size_t size) +{ + while(vlargestblock() < size) { + if(TextureSpillLRU(data) < 0) { + return -1; + } + } + return 0; +} + +static int +TextureBindAsTarget(PSP_RenderData* data, PSP_TextureData* psp_texture) { + if(!InVram(psp_texture->data)) { + // Bring back the texture in vram + if(TextureSpillTargetsForSpace(data, psp_texture->size) < 0) { + return -1; + } + if(TexturePromoteToVram(data, psp_texture, SDL_TRUE) < 0) { + return -1; + } + } + LRUTargetBringFront(data, psp_texture); + sceGuDrawBufferList(psp_texture->format, vrelptr(psp_texture->data), psp_texture->textureWidth); + return 0; +} + static void PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) { @@ -357,7 +483,7 @@ PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) static int PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { -/* PSP_RenderData *renderdata = (PSP_RenderData *) renderer->driverdata; */ + PSP_RenderData *data = renderer->driverdata; PSP_TextureData* psp_texture = (PSP_TextureData*) SDL_calloc(1, sizeof(*psp_texture)); if(!psp_texture) @@ -389,7 +515,13 @@ PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) psp_texture->pitch = psp_texture->textureWidth * SDL_BYTESPERPIXEL(texture->format); psp_texture->size = psp_texture->textureHeight*psp_texture->pitch; if(texture->access & SDL_TEXTUREACCESS_TARGET) { + if(TextureSpillTargetsForSpace(renderer->driverdata, psp_texture->size) < 0){ + return -1; + } psp_texture->data = valloc(psp_texture->size); + if(psp_texture->data) { + LRUTargetPushFront(data, psp_texture); + } } else { psp_texture->data = SDL_calloc(1, psp_texture->size); } @@ -426,7 +558,7 @@ TextureActivate(SDL_Texture * texture) /* Swizzling is useless with small textures. */ if (TextureShouldSwizzle(psp_texture, texture)) { - TextureSwizzle(psp_texture); + TextureSwizzle(psp_texture, NULL); } sceGuEnable(GU_TEXTURE_2D); @@ -812,6 +944,34 @@ PSP_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * t return 0; } + +static void +StartDrawing(SDL_Renderer * renderer) +{ + PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata; + + // Check if we need to start GU displaylist + if(!data->displayListAvail) { + sceGuStart(GU_DIRECT, DisplayList); + data->displayListAvail = SDL_TRUE; + } + + // Check if we need a draw buffer change + if(renderer->target != data->boundTarget) { + SDL_Texture* texture = renderer->target; + if(texture) { + PSP_TextureData* psp_texture = (PSP_TextureData*) texture->driverdata; + // Set target, registering LRU + TextureBindAsTarget(data, psp_texture); + } else { + // Set target back to screen + sceGuDrawBufferList(data->psm, vrelptr(data->frontbuffer), PSP_FRAME_BUFFER_WIDTH); + } + data->boundTarget = texture; + } +} + + static void PSP_SetBlendMode(SDL_Renderer * renderer, int blendMode) { @@ -1072,11 +1232,7 @@ PSP_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) if(psp_texture == 0) return; - if(InVram(psp_texture->data)) { - vfree(psp_texture->data); - } else { - SDL_free(psp_texture->data); - } + TextureStorageFree(psp_texture->data); SDL_free(psp_texture); texture->driverdata = NULL; }