Dreamcast: Cope better with running out of memory for vertex buffer

This commit is contained in:
UnknownShadow200 2024-07-03 18:27:46 +10:00
parent 5f5d8824fa
commit 459390ef7b
2 changed files with 25 additions and 54 deletions

View file

@ -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);

View file

@ -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;
}