Improved the Metal renderer's texture handling system to handle texture freeing.
This commit is contained in:
parent
eea989aa73
commit
a6fde84a3c
|
@ -20,14 +20,6 @@ struct Metal_Buffer{
|
||||||
|
|
||||||
typedef id<MTLTexture> Metal_Texture;
|
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.
|
// NOTE(yuval): This is a locator used to describe where a specific slot is located.
|
||||||
union Metal_Texture_Slot_Locator{
|
union Metal_Texture_Slot_Locator{
|
||||||
u32 packed;
|
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.
|
// 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).
|
||||||
// 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{
|
||||||
struct Metal_Texture_Slot_Locator_Node{
|
// NOTE(yuval): This is a pointer to the next texture in the free texture slots list
|
||||||
Metal_Texture_Slot_Locator_Node *next;
|
Metal_Texture_Slot *next;
|
||||||
|
|
||||||
|
Metal_Texture texture;
|
||||||
Metal_Texture_Slot_Locator locator;
|
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{
|
struct Metal_Texture_Slot_List{
|
||||||
Metal_Texture_Slot_Bucket *first_bucket;
|
Metal_Texture_Slot_Bucket *first_bucket;
|
||||||
Metal_Texture_Slot_Bucket *last_bucket;
|
Metal_Texture_Slot_Bucket *last_bucket;
|
||||||
u16 bucket_count;
|
u16 bucket_count;
|
||||||
|
|
||||||
Metal_Texture_Slot_Locator_Node *first_free_slot;
|
Metal_Texture_Slot *first_free_slot;
|
||||||
Metal_Texture_Slot_Locator_Node *last_free_slot;
|
Metal_Texture_Slot *last_free_slot;
|
||||||
};
|
};
|
||||||
|
|
||||||
global_const u32 metal__invalid_texture_slot_locator = (u32)-1;
|
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;
|
- (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;
|
- (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;
|
- (void)bind_texture:(u32)handle encoder:(id<MTLRenderCommandEncoder>)render_encoder;
|
||||||
- (Metal_Texture*)get_texture_slot_at_locator:(Metal_Texture_Slot_Locator)locator;
|
- (Metal_Texture_Slot*)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_handle:(u32)handle;
|
||||||
|
|
||||||
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size;
|
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size;
|
||||||
- (void)add_reusable_buffer:(Metal_Buffer*)buffer;
|
- (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;
|
Font_Set *font_set = (Font_Set*)_target->font_set;
|
||||||
|
|
||||||
// TODO(yuval): Free any textures in the target's texture free list
|
// NOTE(yuval): Free any textures in the target's texture free list
|
||||||
#if 0
|
|
||||||
for (Render_Free_Texture *free_texture = _target->free_texture_first;
|
for (Render_Free_Texture *free_texture = _target->free_texture_first;
|
||||||
free_texture;
|
free_texture;
|
||||||
free_texture = free_texture->next){
|
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;
|
_target->free_texture_first = 0;
|
||||||
_taget->free_texture_last = 0;
|
_target->free_texture_last = 0;
|
||||||
#endif
|
|
||||||
|
|
||||||
// NOTE(yuval): Create the command buffer
|
// NOTE(yuval): Create the command buffer
|
||||||
id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer];
|
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
|
// NOTE(yuval): Assert that the next bucket's index can fit in a u16
|
||||||
Assert(texture_slots.bucket_count < ((u16)-1));
|
Assert(texture_slots.bucket_count < ((u16)-1));
|
||||||
|
|
||||||
Metal_Texture_Slot_Bucket *bucket =
|
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_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_Locator_Node *locator_array = (Metal_Texture_Slot_Locator_Node*)(bucket + 1);
|
for (u16 slot_index = 0;
|
||||||
for (u32 locator_index = 0;
|
slot_index < ArrayCount(bucket->slots);
|
||||||
locator_index < metal__texture_slots_per_bucket;
|
++slot_index){
|
||||||
++locator_index){
|
Metal_Texture_Slot *slot = &bucket->slots[slot_index];
|
||||||
Metal_Texture_Slot_Locator_Node *node = &locator_array[locator_index];
|
block_zero_struct(slot);
|
||||||
node->locator.bucket_index = texture_slots.bucket_count;
|
slot->locator.bucket_index = texture_slots.bucket_count;
|
||||||
node->locator.slot_index = locator_index;
|
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);
|
sll_queue_push(texture_slots.first_bucket, texture_slots.last_bucket, bucket);
|
||||||
texture_slots.bucket_count += 1;
|
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
|
// 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).
|
||||||
Metal_Texture_Slot_Locator locator = texture_slots.first_free_slot->locator;
|
if (texture_slots.first_free_slot){
|
||||||
sll_queue_pop(texture_slots.first_free_slot, texture_slots.last_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;
|
||||||
|
|
||||||
Metal_Texture *texture_slot =
|
// NOTE(yuval): Create a texture descriptor.
|
||||||
[self get_texture_slot_at_locator:locator];
|
|
||||||
if (texture_slot){
|
|
||||||
// NOTE(yuval): Create a texture descriptor
|
|
||||||
MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init];
|
MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init];
|
||||||
texture_descriptor.textureType = MTLTextureType2DArray;
|
texture_descriptor.textureType = MTLTextureType2DArray;
|
||||||
texture_descriptor.pixelFormat = MTLPixelFormatR8Unorm;
|
texture_descriptor.pixelFormat = MTLPixelFormatR8Unorm;
|
||||||
|
@ -512,11 +512,11 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
texture_descriptor.height = dim.y;
|
texture_descriptor.height = dim.y;
|
||||||
texture_descriptor.depth = dim.z;
|
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];
|
Metal_Texture texture = [device newTextureWithDescriptor:texture_descriptor];
|
||||||
*texture_slot = texture;
|
texture_slot->texture = texture;
|
||||||
|
|
||||||
handle = locator.packed;
|
handle = texture_slot->locator.packed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
|
@ -526,9 +526,9 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
b32 result = false;
|
b32 result = false;
|
||||||
|
|
||||||
if (data){
|
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){
|
if (texture_slot){
|
||||||
Metal_Texture texture = *texture_slot;
|
Metal_Texture texture = texture_slot->texture;
|
||||||
|
|
||||||
if (texture != 0){
|
if (texture != 0){
|
||||||
MTLRegion replace_region = {
|
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{
|
- (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){
|
if (texture_slot){
|
||||||
Metal_Texture texture = *texture_slot;
|
Metal_Texture texture = texture_slot->texture;
|
||||||
if (texture != 0){
|
if (texture != 0){
|
||||||
[render_encoder setFragmentTexture:texture
|
[render_encoder setFragmentTexture:texture
|
||||||
atIndex:0];
|
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_Slot*)get_texture_slot_at_locator:(Metal_Texture_Slot_Locator)locator{
|
||||||
Metal_Texture *result = 0;
|
Metal_Texture_Slot *result = 0;
|
||||||
|
|
||||||
if (locator.packed != metal__invalid_texture_slot_locator){
|
if (locator.packed != metal__invalid_texture_slot_locator){
|
||||||
Metal_Texture_Slot_Bucket *bucket = texture_slots.first_bucket;
|
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);
|
++bucket_index, bucket = bucket->next);
|
||||||
|
|
||||||
if (bucket && (locator.slot_index < metal__texture_slots_per_bucket)){
|
if (bucket && (locator.slot_index < metal__texture_slots_per_bucket)){
|
||||||
result = &bucket->textures[locator.slot_index];
|
result = &bucket->slots[locator.slot_index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return(result);
|
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;
|
Metal_Texture_Slot_Locator locator;
|
||||||
locator.packed = handle;
|
locator.packed = handle;
|
||||||
|
|
||||||
Metal_Texture *texture_slot = [self get_texture_slot_at_locator:locator];
|
Metal_Texture_Slot *result = [self get_texture_slot_at_locator:locator];
|
||||||
return(texture_slot);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size{
|
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size{
|
||||||
|
|
Loading…
Reference in New Issue