From 459390ef7b642b57e0d8b5179f00a0105615e60c Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 3 Jul 2024 18:27:46 +1000 Subject: [PATCH] Dreamcast: Cope better with running out of memory for vertex buffer --- src/Graphics_Dreamcast.c | 20 ++++++++- third_party/gldc/src/aligned_vector.h | 59 +++------------------------ 2 files changed, 25 insertions(+), 54 deletions(-) diff --git a/src/Graphics_Dreamcast.c b/src/Graphics_Dreamcast.c index d56f5087b..c673c4a96 100644 --- a/src/Graphics_Dreamcast.c +++ b/src/Graphics_Dreamcast.c @@ -507,10 +507,27 @@ cc_bool Gfx_WarnIfNecessary(void) { *----------------------------------------------------------Drawing--------------------------------------------------------* *#########################################################################################################################*/ extern void apply_poly_header(pvr_poly_hdr_t* header, int list_type); +static cc_bool loggedNoVRAM; extern Vertex* DrawColouredQuads(const void* src, Vertex* dst, int numQuads); extern Vertex* DrawTexturedQuads(const void* src, Vertex* dst, int numQuads); +static Vertex* ReserveOutput(AlignedVector* vec, uint32_t elems) { + Vertex* beg; + for (;;) + { + if ((beg = aligned_vector_reserve(vec, elems))) return beg; + // Try to reduce view distance to save on RAM + if (Game_ReduceVRAM()) continue; + + if (!loggedNoVRAM) { + loggedNoVRAM = true; + Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating temp memory"); + } + return NULL; + } +} + void DrawQuads(int count, void* src) { if (!count) return; PolyList* output = _glActivePolyList(); @@ -518,7 +535,8 @@ void DrawQuads(int count, void* src) { uint32_t header_required = (vec->size == 0) || STATE_DIRTY; // Reserve room for the vertices and header - Vertex* beg = aligned_vector_reserve(&output->vector, vec->size + (header_required) + count); + Vertex* beg = ReserveOutput(&output->vector, vec->size + (header_required) + count); + if (!beg) return; if (header_required) { apply_poly_header((pvr_poly_hdr_t*)beg, output->list_type); diff --git a/third_party/gldc/src/aligned_vector.h b/third_party/gldc/src/aligned_vector.h index 9ed0f6bf8..b95209638 100644 --- a/third_party/gldc/src/aligned_vector.h +++ b/third_party/gldc/src/aligned_vector.h @@ -30,12 +30,6 @@ typedef struct { #define ROUND_TO_CHUNK_SIZE(v) \ ((((v) + ALIGNED_VECTOR_CHUNK_SIZE - 1) / ALIGNED_VECTOR_CHUNK_SIZE) * ALIGNED_VECTOR_CHUNK_SIZE) - -AV_FORCE_INLINE void* aligned_vector_at(const AlignedVector* vector, const uint32_t index) { - assert(index < vector->size); - return vector->data + (index * AV_ELEMENT_SIZE); -} - AV_FORCE_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count) { uint32_t original_byte_size = (vector->size * AV_ELEMENT_SIZE); @@ -49,66 +43,25 @@ AV_FORCE_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t ele uint32_t new_byte_size = (element_count * AV_ELEMENT_SIZE); uint8_t* original_data = vector->data; - vector->data = (uint8_t*) memalign(0x20, new_byte_size); - assert(vector->data); + uint8_t* data = (uint8_t*) memalign(0x20, new_byte_size); + if (!data) return NULL; - memcpy(vector->data, original_data, original_byte_size); + memcpy(data, original_data, original_byte_size); free(original_data); + vector->data = data; vector->capacity = element_count; return vector->data + original_byte_size; } -/* Resizes the array and returns a pointer to the first new element (if upsizing) or NULL (if downsizing) */ -AV_FORCE_INLINE void* aligned_vector_resize(AlignedVector* vector, const uint32_t element_count) { - void* ret = NULL; - - uint32_t previous_count = vector->size; - if(vector->capacity <= element_count) { - /* If we didn't have capacity, increase capacity (slow) */ - - aligned_vector_reserve(vector, element_count); - vector->size = element_count; - - ret = aligned_vector_at(vector, previous_count); - - av_assert(vector->size == element_count); - av_assert(vector->size <= vector->capacity); - } else if(previous_count < element_count) { - /* So we grew, but had the capacity, just get a pointer to - * where we were */ - vector->size = element_count; - av_assert(vector->size < vector->capacity); - ret = aligned_vector_at(vector, previous_count); - } else if(vector->size != element_count) { - vector->size = element_count; - av_assert(vector->size < vector->capacity); - } - - return ret; -} - AV_FORCE_INLINE void* aligned_vector_push_back(AlignedVector* vector, const void* objs, uint32_t count) { - /* Resize enough room */ - assert(count); -#ifndef NDEBUG - uint32_t initial_size = vector->size; -#endif - - uint8_t* dest = (uint8_t*) aligned_vector_resize(vector, vector->size + count); + uint8_t* dest = (uint8_t*) aligned_vector_reserve(vector, vector->size + count); assert(dest); /* Copy the objects in */ memcpy(dest, objs, count * AV_ELEMENT_SIZE); - assert(vector->size == initial_size + count); + vector->size += count; return dest; } - -AV_FORCE_INLINE void* aligned_vector_extend(AlignedVector* vector, const uint32_t additional_count) { - void* ret = aligned_vector_resize(vector, vector->size + additional_count); - assert(ret); // Should always return something - return ret; -} -