Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delayed texture deletion (Fixes #28) #71

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions libvita2d/include/vita2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,16 @@ vita2d_texture *vita2d_create_empty_texture(unsigned int w, unsigned int h);
vita2d_texture *vita2d_create_empty_texture_format(unsigned int w, unsigned int h, SceGxmTextureFormat format);
vita2d_texture *vita2d_create_empty_texture_rendertarget(unsigned int w, unsigned int h, SceGxmTextureFormat format);

// Mark texture for deletion; will be deleted at next vita2d_swap_buffers() or
// when vita2d_gc_textures() is called (to avoid GPU crashes when deleting
// textures still required by the GPU to finish rendering the current frame)
void vita2d_free_texture(vita2d_texture *texture);

// This will be called automatically by vita2d_swap_buffers(), but you can call
// it earlier in case you allocate/deallocate many textures in a single frame;
// returns the number of texture objects freed
int vita2d_gc_textures();

unsigned int vita2d_texture_get_width(const vita2d_texture *texture);
unsigned int vita2d_texture_get_height(const vita2d_texture *texture);
unsigned int vita2d_texture_get_stride(const vita2d_texture *texture);
Expand Down
7 changes: 7 additions & 0 deletions libvita2d/source/vita2d.c
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,10 @@ int vita2d_fini()
// wait until rendering is done
sceGxmFinish(_vita2d_context);

// in case vita2d_free_texture() was called after the last vita2d_swap_buffers(),
// we need to GC textures here again, otherwise we would leak texture objects
vita2d_gc_textures();

// clean up allocations
sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, clearFragmentProgram);
sceGxmShaderPatcherReleaseVertexProgram(shaderPatcher, clearVertexProgram);
Expand Down Expand Up @@ -844,6 +848,9 @@ void vita2d_swap_buffers()
frontBufferIndex = backBufferIndex;
backBufferIndex = (backBufferIndex + 1) % DISPLAY_BUFFER_COUNT;
}

// free any textures marked for deletion
vita2d_gc_textures();
}

void vita2d_start_drawing()
Expand Down
43 changes: 42 additions & 1 deletion libvita2d/source/vita2d_texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ vita2d_texture * vita2d_create_empty_texture_rendertarget(unsigned int w, unsign
return _vita2d_create_empty_texture_format_advanced(w, h, format, 1);
}

void vita2d_free_texture(vita2d_texture *texture)
static void _vita2d_free_texture_internal(vita2d_texture *texture)
{
if (texture) {
if (texture->gxm_rtgt) {
Expand All @@ -214,6 +214,47 @@ void vita2d_free_texture(vita2d_texture *texture)
}
}

typedef struct texture_freelist_entry texture_freelist_entry;

// TODO: If we store the "next" pointer in vita2d_texture, we can
// use it for an intrusive linked list and don't need to malloc
struct texture_freelist_entry {
vita2d_texture *texture;
texture_freelist_entry *next;
};

// Note: Operations on _texture_freelist are not threadsafe at the moment
static texture_freelist_entry *_texture_freelist = NULL;

void vita2d_free_texture(vita2d_texture *texture)
{
texture_freelist_entry *entry = malloc(sizeof(texture_freelist_entry));
entry->texture = texture;
entry->next = _texture_freelist;
_texture_freelist = entry;
}

int vita2d_gc_textures()
{
if (_texture_freelist == NULL) {
// Nothing to do, exit early without waiting
return 0;
}

// Need to free textures, wait for GPU first
vita2d_wait_rendering_done();

int res = 0;
while (_texture_freelist != NULL) {
texture_freelist_entry *entry = _texture_freelist;
_texture_freelist = entry->next;
_vita2d_free_texture_internal(entry->texture);
free(entry);
++res;
}
return res;
}

unsigned int vita2d_texture_get_width(const vita2d_texture *texture)
{
return sceGxmTextureGetWidth(&texture->gxm_tex);
Expand Down