Improved the Metal renderer's texture handling system to handle texture freeing.

master
Yuval Dolev 2020-01-19 18:17:57 +02:00
parent eea989aa73
commit a6fde84a3c
1 changed files with 54 additions and 54 deletions

View File

@ -20,14 +20,6 @@ struct Metal_Buffer{
typedef id<MTLTexture> Metal_Texture;
global_const u32 metal__texture_slots_per_bucket = 256;
// NOTE(yuval): This a bucket of ACTUAL texture slots.
struct Metal_Texture_Slot_Bucket{
Metal_Texture_Slot_Bucket *next;
Metal_Texture textures[metal__texture_slots_per_bucket];
};
// NOTE(yuval): This is a locator used to describe where a specific slot is located.
union Metal_Texture_Slot_Locator{
u32 packed;
@ -38,21 +30,31 @@ union Metal_Texture_Slot_Locator{
};
};
// NOTE(yuval): This is a node containing the locator inside the free slot list.
// This is a separate struct from the Texture_Slot_Locator because the locator's size has to be exactly 32 bits (to support returning the packed slot from get_texture_of_dim).
struct Metal_Texture_Slot_Locator_Node{
Metal_Texture_Slot_Locator_Node *next;
// NOTE(yuval): This is the ACTUAL texture slot. Each slot contains the texture handle, the slot locator, and a pointer to the next slot in the free list (in case the slot if not occupied).
struct Metal_Texture_Slot{
// NOTE(yuval): This is a pointer to the next texture in the free texture slots list
Metal_Texture_Slot *next;
Metal_Texture texture;
Metal_Texture_Slot_Locator locator;
};
// NOTE(yuval): This a struct contaning all texture slot buckets and the texture slot free list (a list of free texture slots described by their locators).
global_const u32 metal__texture_slots_per_bucket = 256;
// NOTE(yuval): This a bucket of ACTUAL texture slots.
struct Metal_Texture_Slot_Bucket{
Metal_Texture_Slot_Bucket *next;
Metal_Texture_Slot slots[metal__texture_slots_per_bucket];
};
// NOTE(yuval): This a struct contaning all texture slot buckets and a list of the currently free slots.
struct Metal_Texture_Slot_List{
Metal_Texture_Slot_Bucket *first_bucket;
Metal_Texture_Slot_Bucket *last_bucket;
u16 bucket_count;
Metal_Texture_Slot_Locator_Node *first_free_slot;
Metal_Texture_Slot_Locator_Node *last_free_slot;
Metal_Texture_Slot *first_free_slot;
Metal_Texture_Slot *last_free_slot;
};
global_const u32 metal__invalid_texture_slot_locator = (u32)-1;
@ -67,8 +69,8 @@ global_const u32 metal__invalid_texture_slot_locator = (u32)-1;
- (u32)get_texture_of_dim:(Vec3_i32)dim kind:(Texture_Kind)kind;
- (b32)fill_texture:(u32)texture kind:(Texture_Kind)kind pos:(Vec3_i32)p dim:(Vec3_i32)dim data:(void*)data;
- (void)bind_texture:(u32)handle encoder:(id<MTLRenderCommandEncoder>)render_encoder;
- (Metal_Texture*)get_texture_slot_at_locator:(Metal_Texture_Slot_Locator)locator;
- (Metal_Texture*)get_texture_slot_at_handle:(u32)handle;
- (Metal_Texture_Slot*)get_texture_slot_at_locator:(Metal_Texture_Slot_Locator)locator;
- (Metal_Texture_Slot*)get_texture_slot_at_handle:(u32)handle;
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size;
- (void)add_reusable_buffer:(Metal_Buffer*)buffer;
@ -316,16 +318,17 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
Font_Set *font_set = (Font_Set*)_target->font_set;
// TODO(yuval): Free any textures in the target's texture free list
#if 0
// NOTE(yuval): Free any textures in the target's texture free list
for (Render_Free_Texture *free_texture = _target->free_texture_first;
free_texture;
free_texture = free_texture->next){
/*sll_queue_push(texture_slots.first_free_slot, texture_slots.last_free_slot, free_texture)*/
Metal_Texture_Slot *texture_slot = [self get_texture_slot_at_handle:free_texture->tex_id];
if (texture_slot){
sll_queue_push(texture_slots.first_free_slot, texture_slots.last_free_slot, texture_slot);
}
}
_target->free_texture_first = 0;
_taget->free_texture_last = 0;
#endif
_target->free_texture_last = 0;
// NOTE(yuval): Create the command buffer
id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer];
@ -478,33 +481,30 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
// NOTE(yuval): Assert that the next bucket's index can fit in a u16
Assert(texture_slots.bucket_count < ((u16)-1));
Metal_Texture_Slot_Bucket *bucket =
(Metal_Texture_Slot_Bucket*)system_memory_allocate(sizeof(Metal_Texture_Slot_Bucket) + (sizeof(Metal_Texture_Slot_Locator_Node) * metal__texture_slots_per_bucket), file_name_line_number_lit_u8);
Metal_Texture_Slot_Bucket *bucket = (Metal_Texture_Slot_Bucket*)system_memory_allocate(sizeof(Metal_Texture_Slot_Bucket), file_name_line_number_lit_u8);
Metal_Texture_Slot_Locator_Node *locator_array = (Metal_Texture_Slot_Locator_Node*)(bucket + 1);
for (u32 locator_index = 0;
locator_index < metal__texture_slots_per_bucket;
++locator_index){
Metal_Texture_Slot_Locator_Node *node = &locator_array[locator_index];
node->locator.bucket_index = texture_slots.bucket_count;
node->locator.slot_index = locator_index;
for (u16 slot_index = 0;
slot_index < ArrayCount(bucket->slots);
++slot_index){
Metal_Texture_Slot *slot = &bucket->slots[slot_index];
block_zero_struct(slot);
slot->locator.bucket_index = texture_slots.bucket_count;
slot->locator.slot_index = slot_index;
sll_queue_push(texture_slots.first_free_slot, texture_slots.last_free_slot, node);
sll_queue_push(texture_slots.first_free_slot, texture_slots.last_free_slot, slot);
}
sll_queue_push(texture_slots.first_bucket, texture_slots.last_bucket, bucket);
texture_slots.bucket_count += 1;
}
Assert(texture_slots.first_free_slot);
// NOTE(yuval): Get the first free texture slot's locator and remove it from the free list
Metal_Texture_Slot_Locator locator = texture_slots.first_free_slot->locator;
sll_queue_pop(texture_slots.first_free_slot, texture_slots.last_free_slot);
Metal_Texture *texture_slot =
[self get_texture_slot_at_locator:locator];
if (texture_slot){
// NOTE(yuval): Create a texture descriptor
// NOTE(yuval): Get the first free texture slot and remove it from the free list (a slot is guarenteed to exist because we assert that above).
if (texture_slots.first_free_slot){
Metal_Texture_Slot *texture_slot = texture_slots.first_free_slot;
sll_queue_pop(texture_slots.first_free_slot, texture_slots.last_free_slot);
texture_slot->next = 0;
// NOTE(yuval): Create a texture descriptor.
MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init];
texture_descriptor.textureType = MTLTextureType2DArray;
texture_descriptor.pixelFormat = MTLPixelFormatR8Unorm;
@ -512,11 +512,11 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
texture_descriptor.height = dim.y;
texture_descriptor.depth = dim.z;
// NOTE(yuval): Create the texture from the device using the descriptor and add it to the textures array
// NOTE(yuval): Create the texture from the device using the descriptor and add it to the textures array.
Metal_Texture texture = [device newTextureWithDescriptor:texture_descriptor];
*texture_slot = texture;
texture_slot->texture = texture;
handle = locator.packed;
handle = texture_slot->locator.packed;
}
return handle;
@ -526,9 +526,9 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
b32 result = false;
if (data){
Metal_Texture *texture_slot = [self get_texture_slot_at_handle:handle];
Metal_Texture_Slot *texture_slot = [self get_texture_slot_at_handle:handle];
if (texture_slot){
Metal_Texture texture = *texture_slot;
Metal_Texture texture = texture_slot->texture;
if (texture != 0){
MTLRegion replace_region = {
@ -551,9 +551,9 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
}
- (void)bind_texture:(u32)handle encoder:(id<MTLRenderCommandEncoder>)render_encoder{
Metal_Texture *texture_slot = [self get_texture_slot_at_handle:handle];
Metal_Texture_Slot *texture_slot = [self get_texture_slot_at_handle:handle];
if (texture_slot){
Metal_Texture texture = *texture_slot;
Metal_Texture texture = texture_slot->texture;
if (texture != 0){
[render_encoder setFragmentTexture:texture
atIndex:0];
@ -561,8 +561,8 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
}
}
- (Metal_Texture*)get_texture_slot_at_locator:(Metal_Texture_Slot_Locator)locator{
Metal_Texture *result = 0;
- (Metal_Texture_Slot*)get_texture_slot_at_locator:(Metal_Texture_Slot_Locator)locator{
Metal_Texture_Slot *result = 0;
if (locator.packed != metal__invalid_texture_slot_locator){
Metal_Texture_Slot_Bucket *bucket = texture_slots.first_bucket;
@ -571,19 +571,19 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
++bucket_index, bucket = bucket->next);
if (bucket && (locator.slot_index < metal__texture_slots_per_bucket)){
result = &bucket->textures[locator.slot_index];
result = &bucket->slots[locator.slot_index];
}
}
return(result);
}
- (Metal_Texture*)get_texture_slot_at_handle:(u32)handle{
- (Metal_Texture_Slot*)get_texture_slot_at_handle:(u32)handle{
Metal_Texture_Slot_Locator locator;
locator.packed = handle;
Metal_Texture *texture_slot = [self get_texture_slot_at_locator:locator];
return(texture_slot);
Metal_Texture_Slot *result = [self get_texture_slot_at_locator:locator];
return(result);
}
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size{