Improved the Metal renderer's texture handling system to handle texture freeing.
							parent
							
								
									eea989aa73
								
							
						
					
					
						commit
						a6fde84a3c
					
				|  | @ -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); | ||||
|     // 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; | ||||
|          | ||||
|     Metal_Texture *texture_slot = | ||||
|         [self get_texture_slot_at_locator:locator]; | ||||
|     if (texture_slot){ | ||||
|         // NOTE(yuval): Create a texture descriptor | ||||
|         // 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{ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Yuval Dolev
						Yuval Dolev