mirror of
https://github.com/AntonioND/nitro-engine.git
synced 2025-06-18 16:45:33 -04:00
library: Refactor allocator
Remove support for asking for a specific alignment. Now, the only supported alignment is 16 bytes, and all sizes are rounded up to 16 bytes. This is the minimum alignment needed for some palettes, which is the most restrictive case. This change is a bit wasteful, but it only really matters for 4-color palettes and textures, which can be aligned to 8 bytes, and it isn't a problem because: - 4-color palettes, which can be aligned to 8 bytes, would rarely use fewer than 4 colors. Even if they do use fewer than 4 colors, it would only waste 8 bytes. - Textures: It's impossible that a texture doesn't have a size that is multiple of 16. It can only happen if the texture has a width of 8 pixels and a height that isn't a multiple of two... which is a very unusual situation. The benefit of this change is that the code is much easier to understand and much more maintainable, which will be needed when support for compressed textures is added, as the code will need to support more features.
This commit is contained in:
parent
406364d3db
commit
f3f4af0daf
@ -18,29 +18,35 @@ typedef enum {
|
||||
NE_STATE_LOCKED
|
||||
} ne_chunk_state;
|
||||
|
||||
typedef struct {
|
||||
void *previous, *next; // Pointers to other chunks, NULL if start or end
|
||||
|
||||
ne_chunk_state status; // Used, free or locked
|
||||
void *start, *end; // Pointers to the start and end of the pool
|
||||
typedef struct NEChunk {
|
||||
struct NEChunk *previous; // Pointer to previous chunk. NULL if this is the first one
|
||||
struct NEChunk *next; // Pointer to next chunk. NULL if this is the last one
|
||||
ne_chunk_state state; // Used, free or locked
|
||||
void *start, *end; // Pointers to the start and end of this memory chunk
|
||||
} NEChunk;
|
||||
|
||||
typedef struct {
|
||||
// Values in bytes. Total memory does not include locked memory
|
||||
size_t Free, Used, Total, Locked;
|
||||
unsigned int FreePercent; // Locked memory doesn't count
|
||||
size_t free, used, total, locked;
|
||||
unsigned int free_percent; // Locked memory doesn't count
|
||||
} NEMemInfo;
|
||||
|
||||
void NE_AllocInit(NEChunk **first_element, void *start, void *end);
|
||||
void NE_AllocEnd(NEChunk *first_element);
|
||||
#define NE_ALLOC_MIN_SIZE (16)
|
||||
|
||||
void *NE_Alloc(NEChunk *first_element, size_t size, unsigned int align);
|
||||
void NE_Free(NEChunk *first_element, void *pointer);
|
||||
// They return 0 on success. On error, they returns a negative number.
|
||||
int NE_AllocInit(NEChunk **first_element, void *start, void *end);
|
||||
int NE_AllocEnd(NEChunk **first_element);
|
||||
|
||||
void NE_Lock(NEChunk *first_element, void *pointer);
|
||||
void NE_Unlock(NEChunk *first_element, void *pointer);
|
||||
// Returns NULL on error, or a valid pointer on success.
|
||||
void *NE_Alloc(NEChunk *first_element, size_t size);
|
||||
// Returns 0 on success. On error, it returns a negative number.
|
||||
int NE_Free(NEChunk *first_element, void *pointer);
|
||||
|
||||
//int NE_GetSize(NEChunk *first_chunk, void *pointer);
|
||||
void NE_MemGetInformation(NEChunk *first_element, NEMemInfo *info);
|
||||
// They return 0 on success. On error, they returns a negative number.
|
||||
int NE_Lock(NEChunk *first_element, void *pointer);
|
||||
int NE_Unlock(NEChunk *first_element, void *pointer);
|
||||
|
||||
// Returns 0 on success. On error, it returns a negative number.
|
||||
int NE_MemGetInformation(NEChunk *first_element, NEMemInfo *info);
|
||||
|
||||
#endif // NE_ALLOC_H__
|
||||
|
498
source/NEAlloc.c
498
source/NEAlloc.c
@ -9,297 +9,174 @@
|
||||
#include "NEMain.h"
|
||||
#include "NEAlloc.h"
|
||||
|
||||
void NE_AllocInit(NEChunk **first_chunk, void *start, void *end)
|
||||
int NE_AllocInit(NEChunk **first_chunk, void *start, void *end)
|
||||
{
|
||||
NE_AssertPointer(first_chunk, "NULL pointer");
|
||||
NE_Assert(end > start, "End must be after the start");
|
||||
if (first_chunk == NULL)
|
||||
return -1;
|
||||
|
||||
if (end <= start)
|
||||
return -2;
|
||||
|
||||
*first_chunk = malloc(sizeof(NEChunk));
|
||||
NE_AssertPointer(*first_chunk, "Couldn't allocate chunk");
|
||||
|
||||
(*first_chunk)->previous = NULL;
|
||||
(*first_chunk)->status = NE_STATE_FREE;
|
||||
(*first_chunk)->state = NE_STATE_FREE;
|
||||
(*first_chunk)->start = start;
|
||||
(*first_chunk)->end = end;
|
||||
(*first_chunk)->next = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NE_AllocEnd(NEChunk *first_chunk)
|
||||
int NE_AllocEnd(NEChunk **first_chunk)
|
||||
{
|
||||
NE_AssertPointer(first_chunk, "NULL pointer");
|
||||
if (first_chunk == NULL)
|
||||
return -1;
|
||||
|
||||
NEChunk *chunk_search, *chunk_current = first_chunk;
|
||||
NEChunk *this = *first_chunk;
|
||||
|
||||
while (1)
|
||||
while (this != NULL)
|
||||
{
|
||||
chunk_search = chunk_current->next;
|
||||
free(chunk_current);
|
||||
if (chunk_search == NULL)
|
||||
break;
|
||||
chunk_current = chunk_search;
|
||||
NEChunk *next = this->next;
|
||||
free(this);
|
||||
this = next;
|
||||
}
|
||||
|
||||
*first_chunk = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *NE_Alloc(NEChunk *first_chunk, size_t size, unsigned int align)
|
||||
void *NE_Alloc(NEChunk *first_chunk, size_t size)
|
||||
{
|
||||
NE_AssertPointer(first_chunk, "NULL pointer");
|
||||
if ((first_chunk == NULL) || (size == 0))
|
||||
return NULL;
|
||||
|
||||
// Minimum alignment...
|
||||
if (align < 4)
|
||||
align = 4;
|
||||
// Force sizes multiple of NE_ALLOC_MIN_SIZE
|
||||
const size_t mask = NE_ALLOC_MIN_SIZE - 1;
|
||||
if ((size & mask) != 0)
|
||||
size += NE_ALLOC_MIN_SIZE - (size & mask);
|
||||
|
||||
NEChunk *chunk_search = first_chunk;
|
||||
NEChunk *this = first_chunk;
|
||||
|
||||
for ( ; chunk_search != NULL; chunk_search = chunk_search->next)
|
||||
for ( ; this != NULL; this = this->next)
|
||||
{
|
||||
// Skip non-free chunks
|
||||
if (chunk_search->status != NE_STATE_FREE)
|
||||
if (this->state != NE_STATE_FREE)
|
||||
continue;
|
||||
|
||||
// Let's check if we can allocate here.
|
||||
NEChunk *free_chunk = chunk_search;
|
||||
uintptr_t this_start = (uintptr_t)this->start;
|
||||
uintptr_t this_end = (uintptr_t)this->end;
|
||||
|
||||
uintptr_t free_chunk_start = (uintptr_t)free_chunk->start;
|
||||
uintptr_t free_chunk_end = (uintptr_t)free_chunk->end;
|
||||
size_t this_size = this_end - this_start;
|
||||
|
||||
size_t chunk_size = free_chunk_end - free_chunk_start;
|
||||
|
||||
// If this chunk doesn't have enough space, simply skip it
|
||||
if (chunk_size < size)
|
||||
// If this chunk doesn't have enough space, simply skip it.
|
||||
if (this_size < size)
|
||||
continue;
|
||||
|
||||
// If we only have the space requested, it can be easy
|
||||
if (chunk_size == size)
|
||||
// If we have exactly the space requested, we're done.
|
||||
if (this_size == size)
|
||||
{
|
||||
// If it is already aligned, we're done
|
||||
if ((free_chunk_start & (align - 1)) == 0)
|
||||
{
|
||||
free_chunk->status = NE_STATE_USED;
|
||||
return free_chunk->start;
|
||||
}
|
||||
|
||||
// If not, there isn't enough space in this chunk.
|
||||
// Continue with the next one.
|
||||
continue;
|
||||
this->state = NE_STATE_USED;
|
||||
return this->start;
|
||||
}
|
||||
|
||||
// If we have more space than requested
|
||||
// If we have more space than requested, split this chunk:
|
||||
//
|
||||
// | THIS | NEXT |
|
||||
// +-----------------+------+ Before
|
||||
// | NOT USED | USED |
|
||||
//
|
||||
// | THIS | NEW | NEXT |
|
||||
// +------+----------+------+ After
|
||||
// | USED | NOT USED | USED |
|
||||
|
||||
// If it is aligned...
|
||||
if ((free_chunk_start & (align - 1)) == 0)
|
||||
// Get next chunk and create a new one.
|
||||
|
||||
NEChunk *next = this->next;
|
||||
|
||||
NEChunk *new = malloc(sizeof(NEChunk));
|
||||
NE_AssertPointer(new, "Couldn't allocate chunk metadata.");
|
||||
|
||||
// Flag the new chunk as free and this one as used
|
||||
|
||||
new->state = NE_STATE_FREE;
|
||||
this->state = NE_STATE_USED;
|
||||
|
||||
// Update pointers in the linked list
|
||||
// ----------------------------------
|
||||
|
||||
new->previous = this;
|
||||
this->next = new;
|
||||
|
||||
if (next == NULL)
|
||||
{
|
||||
// Get next chunk and create a new one.
|
||||
NEChunk *next_chunk = free_chunk->next;
|
||||
NEChunk *new_chunk = malloc(sizeof(NEChunk));
|
||||
NE_AssertPointer(new_chunk,
|
||||
"Couldn't allocate chunk. (1)");
|
||||
|
||||
// Set as used
|
||||
free_chunk->status = NE_STATE_USED;
|
||||
|
||||
// Set as free
|
||||
new_chunk->status = NE_STATE_FREE;
|
||||
|
||||
// Now, free will point to new, and new will point to next.
|
||||
|
||||
//
|
||||
// | FREE | NEXT |
|
||||
// +-----------------+------+
|
||||
// | NOT USED | USED |
|
||||
//
|
||||
// | FREE | NEW | NEXT |
|
||||
// +------+----------+------+
|
||||
// | USED | NOT USED | USED |
|
||||
|
||||
if (next_chunk != NULL)
|
||||
{
|
||||
// If this is not last chunk...
|
||||
new_chunk->next = next_chunk;
|
||||
next_chunk->previous = new_chunk;
|
||||
|
||||
// Shouldn't be free
|
||||
NE_Assert(next_chunk->status != NE_STATE_FREE,
|
||||
"Possible list corruption. (1)");
|
||||
}
|
||||
else
|
||||
{
|
||||
new_chunk->next = NULL;
|
||||
}
|
||||
|
||||
new_chunk->previous = free_chunk;
|
||||
free_chunk->next = new_chunk;
|
||||
|
||||
// Now, set pointers...
|
||||
new_chunk->end = free_chunk->end;
|
||||
|
||||
free_chunk->end = (void *)(free_chunk_start + size);
|
||||
|
||||
new_chunk->start = free_chunk->end;
|
||||
|
||||
// Ready!!
|
||||
return free_chunk->start;
|
||||
new->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we need to align it, it is a bit more complicated... Check if
|
||||
// even with disalignment we can create room for this
|
||||
uintptr_t end_ptr = (free_chunk_start & (~(align - 1)))
|
||||
+ align + size;
|
||||
new->next = next;
|
||||
next->previous = new;
|
||||
|
||||
if (end_ptr < free_chunk_end)
|
||||
{
|
||||
// Get chunks adjacent to this one, and create 2
|
||||
// new chunks
|
||||
NEChunk *next_chunk = free_chunk->next;
|
||||
NEChunk *new_chunk = malloc(sizeof(NEChunk));
|
||||
NEChunk *new2_chunk = malloc(sizeof(NEChunk));
|
||||
NE_AssertPointer(new_chunk,
|
||||
"Couldn't allocate chunk. (2)");
|
||||
NE_AssertPointer(new2_chunk,
|
||||
"Couldn't allocate chunk. (3)");
|
||||
|
||||
// Set as used
|
||||
new_chunk->status = NE_STATE_USED;
|
||||
|
||||
// Set as free
|
||||
new2_chunk->status = NE_STATE_FREE;
|
||||
|
||||
// | FREE | NEXT |
|
||||
// +----------------------+------+
|
||||
// | NOT USED | USED |
|
||||
//
|
||||
// | FREE |NEW | NEW 2 | NEXT |
|
||||
// +~~~~~~~~+----+--------+------+
|
||||
// |NOT USED|USED|NOT USED| USED |
|
||||
|
||||
free_chunk->next = new_chunk;
|
||||
new_chunk->previous = free_chunk;
|
||||
|
||||
new_chunk->next = new2_chunk;
|
||||
new2_chunk->previous = new_chunk;
|
||||
|
||||
if (next_chunk != NULL)
|
||||
{
|
||||
// If this is not last chunk...
|
||||
new2_chunk->next = next_chunk;
|
||||
next_chunk->previous = new2_chunk;
|
||||
|
||||
// Shouldn't be free
|
||||
NE_Assert(next_chunk->status != NE_STATE_FREE,
|
||||
"Possible list corruption. (2)");
|
||||
}
|
||||
else
|
||||
{
|
||||
new2_chunk->next = NULL;
|
||||
}
|
||||
|
||||
// Now, set pointers acording to the size...
|
||||
new2_chunk->end = free_chunk->end;
|
||||
|
||||
free_chunk->end = (void *)((free_chunk_start & ~(align - 1)) + align);
|
||||
new_chunk->start = free_chunk->end;
|
||||
new_chunk->end = (void *)((uintptr_t)new_chunk->start + size);
|
||||
new2_chunk->start = new_chunk->end;
|
||||
|
||||
// Ready!!
|
||||
return new_chunk->start;
|
||||
}
|
||||
else if (end_ptr == free_chunk_end)
|
||||
{
|
||||
// Easy case
|
||||
|
||||
// Get chunks next to this, and create 2 new ones.
|
||||
NEChunk *next_chunk = free_chunk->next;
|
||||
NEChunk *new_chunk = malloc(sizeof(NEChunk));
|
||||
NE_AssertPointer(new_chunk,
|
||||
"NE_Alloc: Couldn't allocate chunk. (4)");
|
||||
|
||||
// Set as used
|
||||
new_chunk->status = NE_STATE_USED;
|
||||
|
||||
// | FREE | NEXT |
|
||||
// +----------------------+------+
|
||||
// | NOT USED | USED |
|
||||
//
|
||||
// | FREE | NEW | NEXT |
|
||||
// +~~~~~~~~+-------------+------+
|
||||
// |NOT USED| USED | USED |
|
||||
|
||||
free_chunk->next = new_chunk;
|
||||
new_chunk->previous = free_chunk;
|
||||
|
||||
if (next_chunk != NULL)
|
||||
{
|
||||
// If this is not last chunk...
|
||||
new_chunk->next = next_chunk;
|
||||
next_chunk->previous = new_chunk;
|
||||
|
||||
// Shouldn't be free
|
||||
NE_Assert(next_chunk->status != NE_STATE_FREE,
|
||||
"Possible list corruption. (3)");
|
||||
}
|
||||
else
|
||||
{
|
||||
new_chunk->next = NULL;
|
||||
}
|
||||
|
||||
// Now, set pointers acording to the size...
|
||||
new_chunk->end = free_chunk->end;
|
||||
|
||||
free_chunk->end = (void *)((free_chunk_start & ~(align - 1)) + align);
|
||||
new_chunk->start = free_chunk->end;
|
||||
|
||||
// Ready!!
|
||||
return new_chunk->start;
|
||||
}
|
||||
// It shouldn't be free because deallocating a chunk should merge it
|
||||
// with any free chunk next to it.
|
||||
NE_Assert(next->state != NE_STATE_FREE,
|
||||
"Possible list corruption");
|
||||
}
|
||||
|
||||
// Update pointers to start and end of this chunk and the new chunk
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
new->end = this->end;
|
||||
this->end = (void *)(this_start + size);
|
||||
new->start = this->end;
|
||||
|
||||
return this->start;
|
||||
}
|
||||
|
||||
// No more chunks... Not enough free space.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NE_Free(NEChunk *first_chunk, void *pointer)
|
||||
int NE_Free(NEChunk *first_chunk, void *pointer)
|
||||
{
|
||||
NE_AssertPointer(first_chunk, "NULL pointer");
|
||||
if (first_chunk == NULL)
|
||||
return -1;
|
||||
|
||||
NEChunk *chunk_search = first_chunk;
|
||||
NEChunk *this = first_chunk;
|
||||
|
||||
// Look for the chunk that corresponds to the given pointer
|
||||
while (1)
|
||||
{
|
||||
// Check if we have reached the end of the list
|
||||
if (chunk_search == NULL)
|
||||
{
|
||||
NE_DebugPrint("Chunk not found");
|
||||
return;
|
||||
}
|
||||
// Check if we have reached the end without finding the chunk
|
||||
if (this == NULL)
|
||||
return -2;
|
||||
|
||||
// If this is the chunk we're looking for, exit loop
|
||||
if (chunk_search->start == pointer)
|
||||
if (this->start == pointer)
|
||||
break;
|
||||
|
||||
chunk_search = chunk_search->next;
|
||||
this = this->next;
|
||||
}
|
||||
|
||||
// If the specified chunk is free or locked, it can't be freed.
|
||||
if (chunk_search->status != NE_STATE_USED)
|
||||
return;
|
||||
if (this->state != NE_STATE_USED)
|
||||
return -3;
|
||||
|
||||
// Chunk found. Free it.
|
||||
chunk_search->status = NE_STATE_FREE;
|
||||
this->state = NE_STATE_FREE;
|
||||
|
||||
// Now, check if we can join this free chunk with the previous or the
|
||||
// next one
|
||||
NEChunk *previous_chunk = chunk_search->previous;
|
||||
NEChunk *next_chunk = chunk_search->next;
|
||||
NEChunk *previous = this->previous;
|
||||
NEChunk *next = this->next;
|
||||
|
||||
// Check the previous one
|
||||
if (previous_chunk && previous_chunk->status == NE_STATE_FREE)
|
||||
if (previous && previous->state == NE_STATE_FREE)
|
||||
{
|
||||
// We can join them
|
||||
//
|
||||
// | PREVIOUS | FREEING | NEXT |
|
||||
// | PREVIOUS | THIS | NEXT |
|
||||
// +----------+----------+------+
|
||||
// | NOT USED | NOT USED | ???? |
|
||||
//
|
||||
@ -307,187 +184,158 @@ void NE_Free(NEChunk *first_chunk, void *pointer)
|
||||
// +---------------------+------+
|
||||
// | NOT USED | ???? |
|
||||
|
||||
if (next_chunk)
|
||||
if (next)
|
||||
{
|
||||
// First, join the previous and the next
|
||||
next_chunk->previous = previous_chunk;
|
||||
previous_chunk->next = next_chunk;
|
||||
next->previous = previous;
|
||||
previous->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_chunk->next = NULL;
|
||||
previous->next = NULL;
|
||||
}
|
||||
|
||||
// Expand the previous one
|
||||
previous_chunk->end = chunk_search->end;
|
||||
previous->end = this->end;
|
||||
|
||||
// Delete current chunk
|
||||
free(chunk_search);
|
||||
free(this);
|
||||
|
||||
// Check the next one
|
||||
if (next_chunk && next_chunk->status == NE_STATE_FREE)
|
||||
{
|
||||
// We can join them
|
||||
|
||||
// | PREVIOUS | NEXT | NEXT_NEXT |
|
||||
// +--------------------+----------+-----------+
|
||||
// | NOT USED | NOT USED | USED |
|
||||
//
|
||||
// | PREVIOUS | NEXT_NEXT |
|
||||
// +-------------------------------+-----------+
|
||||
// | NOT USED | USED |
|
||||
|
||||
NEChunk *next_next_chunk = next_chunk->next;
|
||||
|
||||
if (next_next_chunk)
|
||||
{
|
||||
// Next Next shouldn't be free. If not,
|
||||
// something bad is happening here.
|
||||
NE_Assert(next_next_chunk->status != NE_STATE_FREE,
|
||||
"Possible list corruption. (1)");
|
||||
|
||||
// First, join the previous and the next next
|
||||
next_next_chunk->previous = previous_chunk;
|
||||
previous_chunk->next = next_next_chunk;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_chunk->next = NULL;
|
||||
}
|
||||
|
||||
// Expand the previous one
|
||||
previous_chunk->end = next_chunk->end;
|
||||
|
||||
// Delete next chunk
|
||||
free(next_chunk);
|
||||
}
|
||||
|
||||
// Done!
|
||||
return;
|
||||
// Change the active chunk to try to join it with the next one.
|
||||
this = previous;
|
||||
}
|
||||
|
||||
// Check the next one
|
||||
if (next_chunk && next_chunk->status == NE_STATE_FREE)
|
||||
if (next && next->state == NE_STATE_FREE)
|
||||
{
|
||||
// We can join them
|
||||
|
||||
// | FREE | NEXT | NEXT NEXT |
|
||||
// +----------+----------+-----------+
|
||||
//
|
||||
// | THIS | NEXT | NEXT NEXT |
|
||||
// +----------+----------+-----------+ Before
|
||||
// | NOT USED | NOT USED | USED |
|
||||
//
|
||||
// | FREE | NEXT NEXT |
|
||||
// +---------------------+-----------+
|
||||
// | THIS | NEXT NEXT |
|
||||
// +---------------------+-----------+ After
|
||||
// | NOT USED | USED |
|
||||
|
||||
NEChunk *next_next_chunk = next_chunk->next;
|
||||
NEChunk *next_next = next->next;
|
||||
|
||||
if (next_next_chunk)
|
||||
if (next_next)
|
||||
{
|
||||
// Next Next should be used or locked. If not,
|
||||
// something bad is happening here.
|
||||
NE_Assert(next_next_chunk->status != NE_STATE_FREE,
|
||||
NE_Assert(next_next->state != NE_STATE_FREE,
|
||||
"Possible list corruption. (2)");
|
||||
|
||||
// First, join the free and the next next
|
||||
next_next_chunk->previous = chunk_search;
|
||||
chunk_search->next = next_next_chunk;
|
||||
// First, join this chunk and the next next chunk
|
||||
next_next->previous = this;
|
||||
this->next = next_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk_search->next = NULL;
|
||||
this->next = NULL;
|
||||
}
|
||||
|
||||
// Expand the free one
|
||||
chunk_search->end = next_chunk->end;
|
||||
// Expand this node one
|
||||
this->end = next->end;
|
||||
|
||||
// Delete next chunk
|
||||
free(next_chunk);
|
||||
|
||||
// Done!
|
||||
return;
|
||||
free(next);
|
||||
}
|
||||
|
||||
// We've done everything we can after freeing the chunk, exit
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NE_Lock(NEChunk *first_chunk, void *pointer)
|
||||
int NE_Lock(NEChunk *first_chunk, void *pointer)
|
||||
{
|
||||
NE_AssertPointer(first_chunk, "NULL pointer");
|
||||
if (first_chunk == NULL)
|
||||
return -1;
|
||||
|
||||
NEChunk *chunk_search = first_chunk;
|
||||
NEChunk *this = first_chunk;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (chunk_search->start == pointer)
|
||||
if (this->start == pointer)
|
||||
{
|
||||
// Found!
|
||||
chunk_search->status = NE_STATE_LOCKED;
|
||||
return;
|
||||
// Check if we are trying to lock a chunk that isn't in use
|
||||
if (this->state != NE_STATE_USED)
|
||||
return -2;
|
||||
|
||||
this->state = NE_STATE_LOCKED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (chunk_search->next == NULL)
|
||||
return;
|
||||
// Couldn't find a chunk at the specified address
|
||||
if (this->next == NULL)
|
||||
return -3;
|
||||
|
||||
chunk_search = chunk_search->next;
|
||||
this = this->next;
|
||||
}
|
||||
}
|
||||
|
||||
void NE_Unlock(NEChunk *first_chunk, void *pointer)
|
||||
int NE_Unlock(NEChunk *first_chunk, void *pointer)
|
||||
{
|
||||
NE_AssertPointer(first_chunk, "NULL pointer");
|
||||
if (first_chunk == NULL)
|
||||
return -1;
|
||||
|
||||
NEChunk *chunk_search = first_chunk;
|
||||
NEChunk *this = first_chunk;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (chunk_search->start == pointer)
|
||||
if (this->start == pointer)
|
||||
{
|
||||
// Found!
|
||||
if (chunk_search->status == NE_STATE_LOCKED)
|
||||
chunk_search->status = NE_STATE_USED;
|
||||
// Check if we are trying to unlock a chunk that isn't locked
|
||||
if (this->state != NE_STATE_LOCKED)
|
||||
return -2;
|
||||
|
||||
return;
|
||||
this->state = NE_STATE_USED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (chunk_search->next == NULL)
|
||||
return;
|
||||
// Couldn't find a chunk at the specified address
|
||||
if (this->next == NULL)
|
||||
return -3;
|
||||
|
||||
chunk_search = chunk_search->next;
|
||||
this = this->next;
|
||||
}
|
||||
}
|
||||
|
||||
void NE_MemGetInformation(NEChunk *first_chunk, NEMemInfo *info)
|
||||
int NE_MemGetInformation(NEChunk *first_chunk, NEMemInfo *info)
|
||||
{
|
||||
NE_AssertPointer(first_chunk, "NULL list pointer");
|
||||
NE_AssertPointer(info, "NULL info pointer");
|
||||
if ((first_chunk == NULL) || (info == NULL))
|
||||
return -1;
|
||||
|
||||
info->Free = info->Used = info->Total = info->Locked = 0;
|
||||
info->free = 0;
|
||||
info->used = 0;
|
||||
info->total = 0;
|
||||
info->locked = 0;
|
||||
|
||||
NEChunk *chunk_search = first_chunk;
|
||||
NEChunk *this = first_chunk;
|
||||
|
||||
for ( ; chunk_search != NULL; chunk_search = chunk_search->next)
|
||||
for ( ; this != NULL; this = this->next)
|
||||
{
|
||||
size_t size = (uintptr_t)chunk_search->end
|
||||
- (uintptr_t)chunk_search->start;
|
||||
size_t size = (uintptr_t)this->end - (uintptr_t)this->start;
|
||||
|
||||
switch (chunk_search->status)
|
||||
switch (this->state)
|
||||
{
|
||||
case NE_STATE_FREE:
|
||||
info->Free += size;
|
||||
info->Total += size;
|
||||
info->free += size;
|
||||
info->total += size;
|
||||
break;
|
||||
case NE_STATE_USED:
|
||||
info->Used += size;
|
||||
info->Total += size;
|
||||
info->used += size;
|
||||
info->total += size;
|
||||
break;
|
||||
case NE_STATE_LOCKED:
|
||||
info->Locked += size;
|
||||
// Locked memory isn't added to the total
|
||||
info->locked += size;
|
||||
break;
|
||||
default:
|
||||
NE_DebugPrint("Unknown chunk state");
|
||||
return -2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
info->FreePercent = (info->Free * 100) / info->Total;
|
||||
info->free_percent = (info->free * 100) / info->total;
|
||||
return 0;
|
||||
}
|
||||
|
@ -98,8 +98,9 @@ int NE_PaletteLoad(NE_Palette *pal, u16 *pointer, u16 numcolor, int format)
|
||||
return 0;
|
||||
}
|
||||
|
||||
NE_PalInfo[slot].pointer = NE_Alloc(NE_PalAllocList, numcolor << 1,
|
||||
1 << (4 - (format == NE_PAL4)));
|
||||
NE_PalInfo[slot].pointer = NE_Alloc(NE_PalAllocList, numcolor << 1);
|
||||
// Aligned to 16 bytes (except 8 bytes for NE_PAL4).
|
||||
|
||||
if (NE_PalInfo[slot].pointer == NULL)
|
||||
{
|
||||
NE_DebugPrint("Not enough memory");
|
||||
@ -183,10 +184,10 @@ int NE_PaletteFreeMem(void)
|
||||
if (!ne_palette_system_inited)
|
||||
return 0;
|
||||
|
||||
NEMemInfo Info;
|
||||
NE_MemGetInformation(NE_PalAllocList, &Info);
|
||||
NEMemInfo info;
|
||||
NE_MemGetInformation(NE_PalAllocList, &info);
|
||||
|
||||
return Info.Free;
|
||||
return info.free;
|
||||
}
|
||||
|
||||
int NE_PaletteFreeMemPercent(void)
|
||||
@ -194,10 +195,10 @@ int NE_PaletteFreeMemPercent(void)
|
||||
if (!ne_palette_system_inited)
|
||||
return 0;
|
||||
|
||||
NEMemInfo Info;
|
||||
NE_MemGetInformation(NE_PalAllocList, &Info);
|
||||
NEMemInfo info;
|
||||
NE_MemGetInformation(NE_PalAllocList, &info);
|
||||
|
||||
return Info.FreePercent;
|
||||
return info.free_percent;
|
||||
}
|
||||
|
||||
void NE_PaletteDefragMem(void)
|
||||
@ -221,8 +222,8 @@ void NE_PaletteDefragMem(void)
|
||||
int size = NE_GetSize(NE_PalAllocList, (void*)NE_PalInfo[i].pointer);
|
||||
|
||||
NE_Free(NE_PalAllocList, (void*)NE_PalInfo[i].pointer);
|
||||
void *pointer = NE_Alloc(NE_PalAllocList, size,
|
||||
1 << (4 - (NE_PalInfo[i].format == NE_PAL4)));
|
||||
void *pointer = NE_Alloc(NE_PalAllocList, size);
|
||||
// Aligned to 16 bytes (except 8 bytes for NE_PAL4).
|
||||
|
||||
NE_AssertPointer(pointer, "Couldn't reallocate palette");
|
||||
|
||||
@ -244,7 +245,7 @@ void NE_PaletteSystemEnd(void)
|
||||
if (!ne_palette_system_inited)
|
||||
return;
|
||||
|
||||
NE_AllocEnd(NE_PalAllocList);
|
||||
NE_AllocEnd(&NE_PalAllocList);
|
||||
|
||||
free(NE_PalInfo);
|
||||
|
||||
|
@ -344,7 +344,7 @@ int NE_MaterialTexLoad(NE_Material *tex, NE_TextureFormat fmt,
|
||||
if (!invalidwidth)
|
||||
size = (sizeX * sizeY << 1) >> __NE_TextureSizeShift[fmt];
|
||||
|
||||
u32 *addr = (u32 *) NE_Alloc(NE_TexAllocList, size, 8);
|
||||
u32 *addr = (u32 *) NE_Alloc(NE_TexAllocList, size); // Aligned to 8 bytes
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
@ -464,10 +464,10 @@ void NE_TextureSystemReset(int max_textures, int max_palettes,
|
||||
// four banks of VRAM. It is needed to allocate one chunk for each and
|
||||
// lock the ones that aren't allowed to be used by Nitro Engine.
|
||||
|
||||
NE_Alloc(NE_TexAllocList, 128 * 1024, 0); // VRAM_A
|
||||
NE_Alloc(NE_TexAllocList, 128 * 1024, 0); // VRAM_B
|
||||
NE_Alloc(NE_TexAllocList, 128 * 1024, 0); // VRAM_C
|
||||
NE_Alloc(NE_TexAllocList, 128 * 1024, 0); // VRAM_D
|
||||
NE_Alloc(NE_TexAllocList, 128 * 1024); // VRAM_A
|
||||
NE_Alloc(NE_TexAllocList, 128 * 1024); // VRAM_B
|
||||
NE_Alloc(NE_TexAllocList, 128 * 1024); // VRAM_C
|
||||
NE_Alloc(NE_TexAllocList, 128 * 1024); // VRAM_D
|
||||
|
||||
if (bank_flags & NE_VRAM_A)
|
||||
{
|
||||
@ -559,10 +559,10 @@ int NE_TextureFreeMem(void)
|
||||
if (!ne_texture_system_inited)
|
||||
return 0;
|
||||
|
||||
NEMemInfo Info;
|
||||
NE_MemGetInformation(NE_TexAllocList, &Info);
|
||||
NEMemInfo info;
|
||||
NE_MemGetInformation(NE_TexAllocList, &info);
|
||||
|
||||
return Info.Free;
|
||||
return info.free;
|
||||
}
|
||||
|
||||
int NE_TextureFreeMemPercent(void)
|
||||
@ -570,10 +570,10 @@ int NE_TextureFreeMemPercent(void)
|
||||
if (!ne_texture_system_inited)
|
||||
return 0;
|
||||
|
||||
NEMemInfo Info;
|
||||
NE_MemGetInformation(NE_TexAllocList, &Info);
|
||||
NEMemInfo info;
|
||||
NE_MemGetInformation(NE_TexAllocList, &info);
|
||||
|
||||
return Info.FreePercent;
|
||||
return info.free_percent;
|
||||
}
|
||||
|
||||
void NE_TextureDefragMem(void)
|
||||
@ -598,7 +598,8 @@ void NE_TextureDefragMem(void)
|
||||
{
|
||||
int size = NE_GetSize(NE_TexAllocList, (void*)NE_Texture[i].adress);
|
||||
NE_Free(NE_TexAllocList,(void*)NE_Texture[i].adress);
|
||||
void *pointer = NE_Alloc(NE_TexAllocList, size, 8);
|
||||
void *pointer = NE_Alloc(NE_TexAllocList, size);
|
||||
// Aligned to 8 bytes
|
||||
|
||||
NE_AssertPointer(pointer, "Couldn't reallocate texture");
|
||||
|
||||
@ -621,7 +622,7 @@ void NE_TextureSystemEnd(void)
|
||||
if (!ne_texture_system_inited)
|
||||
return;
|
||||
|
||||
NE_AllocEnd(NE_TexAllocList);
|
||||
NE_AllocEnd(&NE_TexAllocList);
|
||||
|
||||
free(NE_Texture);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user