From 95ed83137f373bfde4f3d4aa256498e2b15173fa Mon Sep 17 00:00:00 2001 From: Ivan Epifanov Date: Fri, 25 Mar 2022 15:22:10 +0300 Subject: [PATCH] Vita: Use preallocated memory pool for textures --- src/render/vitagxm/SDL_render_vita_gxm.c | 2 +- .../vitagxm/SDL_render_vita_gxm_memory.c | 76 +++++++++++++-- .../vitagxm/SDL_render_vita_gxm_memory.h | 16 +-- .../vitagxm/SDL_render_vita_gxm_tools.c | 97 ++++++++++--------- .../vitagxm/SDL_render_vita_gxm_tools.h | 2 +- .../vitagxm/SDL_render_vita_gxm_types.h | 4 + 6 files changed, 137 insertions(+), 60 deletions(-) diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c index 0dac8eaa3..98b03e629 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm.c +++ b/src/render/vitagxm/SDL_render_vita_gxm.c @@ -1246,7 +1246,7 @@ VITA_GXM_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) sceGxmFinish(data->gxm_context); - free_gxm_texture(vita_texture->tex); + free_gxm_texture(data, vita_texture->tex); SDL_free(vita_texture); diff --git a/src/render/vitagxm/SDL_render_vita_gxm_memory.c b/src/render/vitagxm/SDL_render_vita_gxm_memory.c index d3322730a..271a68c26 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_memory.c +++ b/src/render/vitagxm/SDL_render_vita_gxm_memory.c @@ -26,7 +26,7 @@ #include "SDL_render_vita_gxm_memory.h" void * -mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid) +vita_mem_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid) { void *mem; @@ -51,7 +51,7 @@ mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignm } void -mem_gpu_free(SceUID uid) +vita_mem_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) @@ -61,7 +61,71 @@ mem_gpu_free(SceUID uid) } void * -mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) +vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size) +{ + void *mem; + + if (data->texturePool == NULL) { + int poolsize; + int ret; + SceKernelFreeMemorySizeInfo info; + info.size = sizeof(SceKernelFreeMemorySizeInfo); + sceKernelGetFreeMemorySize(&info); + + poolsize = ALIGN(info.size_cdram, 256*1024); + if (poolsize > info.size_cdram) { + poolsize = ALIGN(info.size_cdram - 256*1024, 256*1024); + } + data->texturePoolUID = sceKernelAllocMemBlock("gpu_texture_pool", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, poolsize, NULL); + if (data->texturePoolUID < 0) { + return NULL; + } + + ret = sceKernelGetMemBlockBase(data->texturePoolUID, &mem); + if ( ret < 0) + { + return NULL; + } + data->texturePool = sceClibMspaceCreate(mem, poolsize); + + if (data->texturePool == NULL) { + return NULL; + } + ret = sceGxmMapMemory(mem, poolsize, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE); + if (ret < 0) + { + return NULL; + } + } + return sceClibMspaceMemalign(data->texturePool, SCE_GXM_TEXTURE_ALIGNMENT, size); +} + +void +vita_gpu_mem_free(VITA_GXM_RenderData *data, void* ptr) +{ + if (data->texturePool != NULL) + { + sceClibMspaceFree(data->texturePool, ptr); + } +} + +void +vita_gpu_mem_destroy(VITA_GXM_RenderData *data) +{ + void *mem = NULL; + if (data->texturePool != NULL) + { + sceClibMspaceDestroy(data->texturePool); + data->texturePool = NULL; + if (sceKernelGetMemBlockBase(data->texturePoolUID, &mem) < 0) + return; + sceGxmUnmapMemory(mem); + sceKernelFreeMemBlock(data->texturePoolUID); + } +} + +void * +vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) { void *mem = NULL; @@ -77,7 +141,7 @@ mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) } void -mem_vertex_usse_free(SceUID uid) +vita_mem_vertex_usse_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) @@ -87,7 +151,7 @@ mem_vertex_usse_free(SceUID uid) } void * -mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) +vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) { void *mem = NULL; @@ -103,7 +167,7 @@ mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offse } void -mem_fragment_usse_free(SceUID uid) +vita_mem_fragment_usse_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) diff --git a/src/render/vitagxm/SDL_render_vita_gxm_memory.h b/src/render/vitagxm/SDL_render_vita_gxm_memory.h index 51bc8a80a..d7116654b 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_memory.h +++ b/src/render/vitagxm/SDL_render_vita_gxm_memory.h @@ -25,15 +25,19 @@ #include #include #include +#include "SDL_render_vita_gxm_types.h" #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) -void *mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid); -void mem_gpu_free(SceUID uid); -void *mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); -void mem_vertex_usse_free(SceUID uid); -void *mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); -void mem_fragment_usse_free(SceUID uid); +void *vita_mem_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid); +void vita_mem_free(SceUID uid); +void *vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size); +void vita_gpu_mem_free(VITA_GXM_RenderData *data, void* ptr); +void vita_gpu_mem_destroy(VITA_GXM_RenderData *data); +void *vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +void vita_mem_vertex_usse_free(SceUID uid); +void *vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +void vita_mem_fragment_usse_free(SceUID uid); #endif /* SDL_RENDER_VITA_GXM_MEMORY_H */ diff --git a/src/render/vitagxm/SDL_render_vita_gxm_tools.c b/src/render/vitagxm/SDL_render_vita_gxm_tools.c index 0ecae3839..035e8a63c 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_tools.c +++ b/src/render/vitagxm/SDL_render_vita_gxm_tools.c @@ -416,28 +416,28 @@ gxm_init(SDL_Renderer *renderer) } // allocate ring buffer memory using default sizes - vdmRingBuffer = mem_gpu_alloc( + vdmRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->vdmRingBufferUid); - vertexRingBuffer = mem_gpu_alloc( + vertexRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->vertexRingBufferUid); - fragmentRingBuffer = mem_gpu_alloc( + fragmentRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->fragmentRingBufferUid); - fragmentUsseRingBuffer = mem_fragment_usse_alloc( + fragmentUsseRingBuffer = vita_mem_fragment_usse_alloc( SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE, &data->fragmentUsseRingBufferUid, &fragmentUsseRingBufferOffset); @@ -482,7 +482,7 @@ gxm_init(SDL_Renderer *renderer) for (i = 0; i < VITA_GXM_BUFFERS; i++) { // allocate memory for display - data->displayBufferData[i] = mem_gpu_alloc( + data->displayBufferData[i] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT, SCE_GXM_COLOR_SURFACE_ALIGNMENT, @@ -527,7 +527,7 @@ gxm_init(SDL_Renderer *renderer) // allocate the depth buffer - data->depthBufferData = mem_gpu_alloc( + data->depthBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4 * sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -535,7 +535,7 @@ gxm_init(SDL_Renderer *renderer) &data->depthBufferUid); // allocate the stencil buffer - data->stencilBufferData = mem_gpu_alloc( + data->stencilBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4 * sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -567,19 +567,19 @@ gxm_init(SDL_Renderer *renderer) // allocate memory for buffers and USSE code - patcherBuffer = mem_gpu_alloc( + patcherBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, patcherBufferSize, 4, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, &data->patcherBufferUid); - patcherVertexUsse = mem_vertex_usse_alloc( + patcherVertexUsse = vita_mem_vertex_usse_alloc( patcherVertexUsseSize, &data->patcherVertexUsseUid, &patcherVertexUsseOffset); - patcherFragmentUsse = mem_fragment_usse_alloc( + patcherFragmentUsse = vita_mem_fragment_usse_alloc( patcherFragmentUsseSize, &data->patcherFragmentUsseUid, &patcherFragmentUsseOffset); @@ -730,7 +730,7 @@ gxm_init(SDL_Renderer *renderer) } // create the clear triangle vertex/index data - data->clearVertices = (clear_vertex *)mem_gpu_alloc( + data->clearVertices = (clear_vertex *)vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 3*sizeof(clear_vertex), 4, @@ -742,7 +742,7 @@ gxm_init(SDL_Renderer *renderer) // 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 *)mem_gpu_alloc( + data->linearIndices = (uint16_t *)vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, UINT16_MAX*sizeof(uint16_t), sizeof(uint16_t), @@ -873,7 +873,7 @@ gxm_init(SDL_Renderer *renderer) data->textureWvpParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(textureVertexProgramGxp, "wvp"); // Allocate memory for the memory pool - data->pool_addr[0] = mem_gpu_alloc( + data->pool_addr[0] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, VITA_GXM_POOL_SIZE, sizeof(void *), @@ -881,7 +881,7 @@ gxm_init(SDL_Renderer *renderer) &data->poolUid[0] ); - data->pool_addr[1] = mem_gpu_alloc( + data->pool_addr[1] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, VITA_GXM_POOL_SIZE, sizeof(void *), @@ -920,28 +920,28 @@ void gxm_finish(SDL_Renderer *renderer) free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mod); free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mul); - mem_gpu_free(data->linearIndicesUid); - mem_gpu_free(data->clearVerticesUid); + vita_mem_free(data->linearIndicesUid); + vita_mem_free(data->clearVerticesUid); // wait until display queue is finished before deallocating display buffers sceGxmDisplayQueueFinish(); // clean up display queue - mem_gpu_free(data->depthBufferUid); + vita_mem_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); - mem_gpu_free(data->displayBufferUid[i]); + vita_mem_free(data->displayBufferUid[i]); // destroy the sync object sceGxmSyncObjectDestroy(data->displayBufferSync[i]); } // Free the depth and stencil buffer - mem_gpu_free(data->depthBufferUid); - mem_gpu_free(data->stencilBufferUid); + vita_mem_free(data->depthBufferUid); + vita_mem_free(data->stencilBufferUid); // unregister programs and destroy shader patcher sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->clearFragmentProgramId); @@ -952,23 +952,24 @@ void gxm_finish(SDL_Renderer *renderer) sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureVertexProgramId); sceGxmShaderPatcherDestroy(data->shaderPatcher); - mem_fragment_usse_free(data->patcherFragmentUsseUid); - mem_vertex_usse_free(data->patcherVertexUsseUid); - mem_gpu_free(data->patcherBufferUid); + vita_mem_fragment_usse_free(data->patcherFragmentUsseUid); + vita_mem_vertex_usse_free(data->patcherVertexUsseUid); + vita_mem_free(data->patcherBufferUid); // destroy the render target sceGxmDestroyRenderTarget(data->renderTarget); // destroy the gxm context sceGxmDestroyContext(data->gxm_context); - mem_fragment_usse_free(data->fragmentUsseRingBufferUid); - mem_gpu_free(data->fragmentRingBufferUid); - mem_gpu_free(data->vertexRingBufferUid); - mem_gpu_free(data->vdmRingBufferUid); + vita_mem_fragment_usse_free(data->fragmentUsseRingBufferUid); + vita_mem_free(data->fragmentRingBufferUid); + vita_mem_free(data->vertexRingBufferUid); + vita_mem_free(data->vdmRingBufferUid); SDL_free(data->contextParams.hostMem); - mem_gpu_free(data->poolUid[0]); - mem_gpu_free(data->poolUid[1]); + vita_mem_free(data->poolUid[0]); + vita_mem_free(data->poolUid[1]); + vita_gpu_mem_destroy(data); // terminate libgxm sceGxmTerminate(); @@ -977,16 +978,20 @@ void gxm_finish(SDL_Renderer *renderer) // textures void -free_gxm_texture(gxm_texture *texture) +free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture) { if (texture) { if (texture->gxm_rendertarget) { sceGxmDestroyRenderTarget(texture->gxm_rendertarget); } if (texture->depth_UID) { - mem_gpu_free(texture->depth_UID); + vita_mem_free(texture->depth_UID); + } + if (texture->cdram) { + vita_gpu_mem_free(data, sceGxmTextureGetData(&texture->gxm_tex)); + } else { + vita_mem_free(texture->data_UID); } - mem_gpu_free(texture->data_UID); SDL_free(texture); } } @@ -1033,24 +1038,24 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc *return_pitch = aligned_w * tex_format_to_bytespp(format); /* Allocate a GPU buffer for the texture */ - texture_data = mem_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 + texture_data = vita_gpu_mem_alloc( + data, + tex_size ); /* Try SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE in case we're out of VRAM */ if (!texture_data) { SDL_LogWarn(SDL_LOG_CATEGORY_RENDER, "CDRAM texture allocation failed\n"); - texture_data = mem_gpu_alloc( + texture_data = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, tex_size, SCE_GXM_TEXTURE_ALIGNMENT, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, &texture->data_UID ); + texture->cdram = 0; + } else { + texture->cdram = 1; } if (!texture_data) { @@ -1064,7 +1069,7 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc /* Create the gxm texture */ ret = sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, texture_w, h, 0); if (ret < 0) { - free_gxm_texture(texture); + free_gxm_texture(data, texture); SDL_LogError(SDL_LOG_CATEGORY_RENDER, "texture init failed: %x\n", ret); return NULL; } @@ -1090,13 +1095,13 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc ); if (err < 0) { - free_gxm_texture(texture); + free_gxm_texture(data, texture); SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %x\n", err); return NULL; } // allocate it - depthBufferData = mem_gpu_alloc( + depthBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4*sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -1113,7 +1118,7 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc NULL); if (err < 0) { - free_gxm_texture(texture); + free_gxm_texture(data, texture); SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %x\n", err); return NULL; } @@ -1138,7 +1143,7 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc texture->gxm_rendertarget = tgt; if (err < 0) { - free_gxm_texture(texture); + free_gxm_texture(data, texture); SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %x\n", err); return NULL; } @@ -1188,7 +1193,7 @@ void gxm_init_for_common_dialog(void) for (int i = 0; i < VITA_GXM_BUFFERS; i += 1) { buffer_for_common_dialog[i].displayData.wait_vblank = SDL_TRUE; - buffer_for_common_dialog[i].displayData.address = mem_gpu_alloc( + buffer_for_common_dialog[i].displayData.address = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT, SCE_GXM_COLOR_SURFACE_ALIGNMENT, @@ -1236,7 +1241,7 @@ void gxm_term_for_common_dialog(void) sceGxmDisplayQueueFinish(); for (int i = 0; i < VITA_GXM_BUFFERS; i += 1) { - mem_gpu_free(buffer_for_common_dialog[i].uid); + vita_mem_free(buffer_for_common_dialog[i].uid); sceGxmSyncObjectDestroy(buffer_for_common_dialog[i].sync); } } diff --git a/src/render/vitagxm/SDL_render_vita_gxm_tools.h b/src/render/vitagxm/SDL_render_vita_gxm_tools.h index 8e9caeb21..67659889d 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_tools.h +++ b/src/render/vitagxm/SDL_render_vita_gxm_tools.h @@ -49,7 +49,7 @@ 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, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale); -void free_gxm_texture(gxm_texture *texture); +void free_gxm_texture(VITA_GXM_RenderData *data, 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); diff --git a/src/render/vitagxm/SDL_render_vita_gxm_types.h b/src/render/vitagxm/SDL_render_vita_gxm_types.h index 2bf8d3585..c5cbf5898 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_types.h +++ b/src/render/vitagxm/SDL_render_vita_gxm_types.h @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -79,6 +80,7 @@ typedef struct gxm_texture { SceGxmColorSurface gxm_colorsurface; SceGxmDepthStencilSurface gxm_depthstencil; SceUID depth_UID; + SDL_bool cdram; } gxm_texture; typedef struct fragment_programs { @@ -186,6 +188,8 @@ typedef struct blend_fragment_programs blendFragmentPrograms; gxm_drawstate_cache drawstate; + SceClibMspace texturePool; + SceUID texturePoolUID; } VITA_GXM_RenderData; typedef struct