Mac merge
This commit is contained in:
commit
c0c3d7b220
|
@ -4,14 +4,10 @@
|
||||||
#undef function
|
#undef function
|
||||||
#import <simd/simd.h>
|
#import <simd/simd.h>
|
||||||
#import <MetalKit/MetalKit.h>
|
#import <MetalKit/MetalKit.h>
|
||||||
|
|
||||||
#include "AAPLShaderTypes.h"
|
|
||||||
#define function static
|
#define function static
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
typedef id<MTLTexture> Metal_Texture;
|
|
||||||
|
|
||||||
struct Metal_Buffer{
|
struct Metal_Buffer{
|
||||||
Node node;
|
Node node;
|
||||||
|
|
||||||
|
@ -22,14 +18,57 @@ struct Metal_Buffer{
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
@interface Metal_Renderer : NSObject<MTKViewDelegate>
|
typedef id<MTLTexture> Metal_Texture;
|
||||||
@property (nonatomic) Render_Target *target;
|
|
||||||
|
|
||||||
|
// NOTE(yuval): This is a locator used to describe where a specific slot is located.
|
||||||
|
union Metal_Texture_Slot_Locator{
|
||||||
|
u32 packed;
|
||||||
|
|
||||||
|
struct{
|
||||||
|
u16 bucket_index;
|
||||||
|
u16 slot_index;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 *first_free_slot;
|
||||||
|
Metal_Texture_Slot *last_free_slot;
|
||||||
|
};
|
||||||
|
|
||||||
|
global_const u32 metal__invalid_texture_slot_locator = (u32)-1;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
|
||||||
|
@interface Metal_Renderer : NSObject<MTKViewDelegate>
|
||||||
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)mtkView target:(Render_Target*)target;
|
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)mtkView target:(Render_Target*)target;
|
||||||
|
|
||||||
- (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_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;
|
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size;
|
||||||
- (void)add_reusable_buffer:(Metal_Buffer*)buffer;
|
- (void)add_reusable_buffer:(Metal_Buffer*)buffer;
|
||||||
|
@ -37,10 +76,6 @@ struct Metal_Buffer{
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
global_const u32 metal__max_textures = 256;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
global_const char *metal__shaders_source = R"(
|
global_const char *metal__shaders_source = R"(
|
||||||
#include <metal_stdlib>
|
#include <metal_stdlib>
|
||||||
#include <simd/simd.h>
|
#include <simd/simd.h>
|
||||||
|
@ -155,16 +190,17 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
@implementation Metal_Renderer{
|
@implementation Metal_Renderer{
|
||||||
id<MTLDevice> device;
|
Render_Target *_target;
|
||||||
id<MTLRenderPipelineState> pipeline_state;
|
|
||||||
id<MTLCommandQueue> command_queue;
|
|
||||||
id<MTLCaptureScope> capture_scope;
|
|
||||||
|
|
||||||
Node buffer_cache;
|
id<MTLDevice> _device;
|
||||||
u64 last_buffer_cache_purge_time;
|
id<MTLRenderPipelineState> _pipeline_state;
|
||||||
|
id<MTLCommandQueue> _command_queue;
|
||||||
|
id<MTLCaptureScope> _capture_scope;
|
||||||
|
|
||||||
Metal_Texture *textures;
|
Node _buffer_cache;
|
||||||
u32 next_texture_handle_index;
|
u64 _last_buffer_cache_purge_time;
|
||||||
|
|
||||||
|
Metal_Texture_Slot_List _texture_slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)mtk_view target:(Render_Target*)target{
|
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView*)mtk_view target:(Render_Target*)target{
|
||||||
|
@ -177,7 +213,7 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
|
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
|
|
||||||
device = mtk_view.device;
|
_device = mtk_view.device;
|
||||||
|
|
||||||
// NOTE(yuval): Compile the shaders
|
// NOTE(yuval): Compile the shaders
|
||||||
id<MTLFunction> vertex_function = nil;
|
id<MTLFunction> vertex_function = nil;
|
||||||
|
@ -188,7 +224,7 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
|
MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
|
||||||
options.fastMathEnabled = YES;
|
options.fastMathEnabled = YES;
|
||||||
|
|
||||||
id<MTLLibrary> shader_library = [device newLibraryWithSource:shaders_source_str
|
id<MTLLibrary> shader_library = [_device newLibraryWithSource:shaders_source_str
|
||||||
options:options error:&error];
|
options:options error:&error];
|
||||||
vertex_function = [shader_library newFunctionWithName:@"vertex_shader"];
|
vertex_function = [shader_library newFunctionWithName:@"vertex_shader"];
|
||||||
fragment_function = [shader_library newFunctionWithName:@"fragment_shader"];
|
fragment_function = [shader_library newFunctionWithName:@"fragment_shader"];
|
||||||
|
@ -232,22 +268,21 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
pipeline_state_descriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
pipeline_state_descriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
||||||
pipeline_state_descriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
pipeline_state_descriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||||
|
|
||||||
pipeline_state = [device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor
|
_pipeline_state = [_device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor
|
||||||
error:&error];
|
error:&error];
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(error == nil);
|
Assert(error == nil);
|
||||||
|
|
||||||
// NOTE(yuval): Create the command queue
|
// NOTE(yuval): Create the command queue
|
||||||
command_queue = [device newCommandQueue];
|
_command_queue = [_device newCommandQueue];
|
||||||
|
|
||||||
// NOTE(yuval): Initialize buffer caching
|
// NOTE(yuval): Initialize buffer caching
|
||||||
dll_init_sentinel(&buffer_cache);
|
dll_init_sentinel(&_buffer_cache);
|
||||||
last_buffer_cache_purge_time = system_now_time();
|
_last_buffer_cache_purge_time = system_now_time();
|
||||||
|
|
||||||
// NOTE(yuval): Initialize the textures array
|
// NOTE(yuval): Initialize the texture slot list
|
||||||
textures = (Metal_Texture*)system_memory_allocate(metal__max_textures * sizeof(Metal_Texture), file_name_line_number_lit_u8);
|
block_zero_struct(&_texture_slots);
|
||||||
next_texture_handle_index = 0;
|
|
||||||
|
|
||||||
// NOTE(yuval): Create the fallback texture
|
// NOTE(yuval): Create the fallback texture
|
||||||
_target->fallback_texture_id = [self get_texture_of_dim:V3i32(2, 2, 1)
|
_target->fallback_texture_id = [self get_texture_of_dim:V3i32(2, 2, 1)
|
||||||
|
@ -260,9 +295,9 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
data:white_block];
|
data:white_block];
|
||||||
|
|
||||||
// NOTE(yuval): Create a capture scope for gpu frame capture
|
// NOTE(yuval): Create a capture scope for gpu frame capture
|
||||||
capture_scope = [[MTLCaptureManager sharedCaptureManager]
|
_capture_scope = [[MTLCaptureManager sharedCaptureManager]
|
||||||
newCaptureScopeWithDevice:device];
|
newCaptureScopeWithDevice:_device];
|
||||||
capture_scope.label = @"4coder Metal Capture Scope";
|
_capture_scope.label = @"4coder Metal Capture Scope";
|
||||||
|
|
||||||
return(self);
|
return(self);
|
||||||
}
|
}
|
||||||
|
@ -273,19 +308,30 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
|
|
||||||
- (void)drawInMTKView:(nonnull MTKView*)view{
|
- (void)drawInMTKView:(nonnull MTKView*)view{
|
||||||
#if FRED_INTERNAL
|
#if FRED_INTERNAL
|
||||||
[capture_scope beginScope];
|
[_capture_scope beginScope];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// HACK(yuval): This is the best way I found to force valid width and height without drawing on the next draw cycle (1 frame delay).
|
// HACK(yuval): This is the best way I found to force valid width and height without drawing on the next draw cycle (1 frame delay).
|
||||||
|
|
||||||
CGSize drawable_size = [view drawableSize];
|
CGSize drawable_size = [view drawableSize];
|
||||||
i32 width = (i32)Min(_target->width, drawable_size.width);
|
i32 width = (i32)Min(_target->width, drawable_size.width);
|
||||||
i32 height = (i32)Min(_target->height, drawable_size.height);
|
i32 height = (i32)Min(_target->height, drawable_size.height);
|
||||||
|
|
||||||
Font_Set *font_set = (Font_Set*)_target->font_set;
|
Font_Set *font_set = (Font_Set*)_target->font_set;
|
||||||
|
|
||||||
|
// 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){
|
||||||
|
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_last = 0;
|
||||||
|
|
||||||
// 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];
|
||||||
command_buffer.label = @"4coder Metal Render Command";
|
command_buffer.label = @"4coder Metal Render Command";
|
||||||
|
|
||||||
// NOTE(yuval): Obtain the render pass descriptor from the renderer's view
|
// NOTE(yuval): Obtain the render pass descriptor from the renderer's view
|
||||||
|
@ -302,7 +348,7 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
[render_encoder setViewport:(MTLViewport){0.0, 0.0, (double)width, (double)height, 0.0, 1.0}];
|
[render_encoder setViewport:(MTLViewport){0.0, 0.0, (double)width, (double)height, 0.0, 1.0}];
|
||||||
|
|
||||||
// NOTE(yuval): Set the render pipeline to use for drawing
|
// NOTE(yuval): Set the render pipeline to use for drawing
|
||||||
[render_encoder setRenderPipelineState:pipeline_state];
|
[render_encoder setRenderPipelineState:_pipeline_state];
|
||||||
|
|
||||||
// NOTE(yuval): Calculate the projection matrix
|
// NOTE(yuval): Calculate the projection matrix
|
||||||
float left = 0, right = (float)width;
|
float left = 0, right = (float)width;
|
||||||
|
@ -423,26 +469,55 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
[command_buffer commit];
|
[command_buffer commit];
|
||||||
|
|
||||||
#if FRED_INTERNAL
|
#if FRED_INTERNAL
|
||||||
[capture_scope endScope];
|
[_capture_scope endScope];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (u32)get_texture_of_dim:(Vec3_i32)dim kind:(Texture_Kind)kind{
|
- (u32)get_texture_of_dim:(Vec3_i32)dim kind:(Texture_Kind)kind{
|
||||||
u32 handle = next_texture_handle_index;
|
u32 handle = metal__invalid_texture_slot_locator;
|
||||||
|
|
||||||
// NOTE(yuval): Create a texture descriptor
|
// NOTE(yuval): Check for a free texture slot and allocate another slot bucket if no free slot has been found
|
||||||
MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init];
|
if (!_texture_slots.first_free_slot){
|
||||||
texture_descriptor.textureType = MTLTextureType2DArray;
|
// NOTE(yuval): Assert that the next bucket's index can fit in a u16
|
||||||
texture_descriptor.pixelFormat = MTLPixelFormatR8Unorm;
|
Assert(_texture_slots.bucket_count < ((u16)-1));
|
||||||
texture_descriptor.width = dim.x;
|
|
||||||
texture_descriptor.height = dim.y;
|
Metal_Texture_Slot_Bucket *bucket = (Metal_Texture_Slot_Bucket*)system_memory_allocate(sizeof(Metal_Texture_Slot_Bucket), file_name_line_number_lit_u8);
|
||||||
texture_descriptor.depth = dim.z;
|
|
||||||
|
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, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
sll_queue_push(_texture_slots.first_bucket, _texture_slots.last_bucket, bucket);
|
||||||
|
_texture_slots.bucket_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE(yuval): Create the texture from the device using the descriptor and add it to the textures array
|
// 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 texture = [device newTextureWithDescriptor:texture_descriptor];
|
if (_texture_slots.first_free_slot){
|
||||||
textures[handle] = texture;
|
Metal_Texture_Slot *texture_slot = _texture_slots.first_free_slot;
|
||||||
|
sll_queue_pop(_texture_slots.first_free_slot, _texture_slots.last_free_slot);
|
||||||
next_texture_handle_index += 1;
|
texture_slot->next = 0;
|
||||||
|
|
||||||
|
// NOTE(yuval): Create a texture descriptor.
|
||||||
|
MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init];
|
||||||
|
texture_descriptor.textureType = MTLTextureType2DArray;
|
||||||
|
texture_descriptor.pixelFormat = MTLPixelFormatR8Unorm;
|
||||||
|
texture_descriptor.width = dim.x;
|
||||||
|
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.
|
||||||
|
Metal_Texture texture = [_device newTextureWithDescriptor:texture_descriptor];
|
||||||
|
texture_slot->texture = texture;
|
||||||
|
|
||||||
|
handle = texture_slot->locator.packed;
|
||||||
|
}
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
@ -451,61 +526,92 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
b32 result = false;
|
b32 result = false;
|
||||||
|
|
||||||
if (data){
|
if (data){
|
||||||
Metal_Texture texture = textures[handle];
|
Metal_Texture_Slot *texture_slot = [self get_texture_slot_at_handle:handle];
|
||||||
|
if (texture_slot){
|
||||||
if (texture != 0){
|
Metal_Texture texture = texture_slot->texture;
|
||||||
MTLRegion replace_region = {
|
|
||||||
{(NSUInteger)p.x, (NSUInteger)p.y, (NSUInteger)p.z},
|
|
||||||
{(NSUInteger)dim.x, (NSUInteger)dim.y, (NSUInteger)dim.z}
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE(yuval): Fill the texture with data
|
if (texture != 0){
|
||||||
[texture replaceRegion:replace_region
|
MTLRegion replace_region = {
|
||||||
mipmapLevel:0
|
{(NSUInteger)p.x, (NSUInteger)p.y, (NSUInteger)p.z},
|
||||||
withBytes:data
|
{(NSUInteger)dim.x, (NSUInteger)dim.y, (NSUInteger)dim.z}
|
||||||
bytesPerRow:dim.x];
|
};
|
||||||
|
|
||||||
result = true;
|
// NOTE(yuval): Fill the texture with data
|
||||||
|
[texture replaceRegion:replace_region
|
||||||
|
mipmapLevel:0
|
||||||
|
withBytes:data
|
||||||
|
bytesPerRow:dim.x];
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)bind_texture:(u32)handle encoder:(id<MTLRenderCommandEncoder>)render_encoder{
|
- (void)bind_texture:(u32)handle encoder:(id<MTLRenderCommandEncoder>)render_encoder{
|
||||||
Metal_Texture texture = textures[handle];
|
Metal_Texture_Slot *texture_slot = [self get_texture_slot_at_handle:handle];
|
||||||
if (texture != 0){
|
if (texture_slot){
|
||||||
[render_encoder setFragmentTexture:texture
|
Metal_Texture texture = texture_slot->texture;
|
||||||
atIndex:0];
|
if (texture != 0){
|
||||||
|
[render_encoder setFragmentTexture:texture
|
||||||
|
atIndex: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;
|
||||||
|
for (u16 bucket_index = 0;
|
||||||
|
(bucket_index < locator.bucket_index) && bucket;
|
||||||
|
++bucket_index, bucket = bucket->next);
|
||||||
|
|
||||||
|
if (bucket && (locator.slot_index < metal__texture_slots_per_bucket)){
|
||||||
|
result = &bucket->slots[locator.slot_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (Metal_Texture_Slot*)get_texture_slot_at_handle:(u32)handle{
|
||||||
|
Metal_Texture_Slot_Locator locator;
|
||||||
|
locator.packed = handle;
|
||||||
|
|
||||||
|
Metal_Texture_Slot *result = [self get_texture_slot_at_locator:locator];
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size{
|
- (Metal_Buffer*)get_reusable_buffer_with_size:(NSUInteger)size{
|
||||||
// NOTE(yuval): This routine is a modified version of Dear ImGui's MetalContext::dequeueReusableBufferOfLength in imgui_impl_metal.mm
|
// NOTE(yuval): This routine is a modified version of Dear ImGui's MetalContext::dequeueReusableBufferOfLength in imgui_impl_metal.mm
|
||||||
|
|
||||||
u64 now = system_now_time();
|
u64 now = system_now_time();
|
||||||
|
|
||||||
// NOTE(yuval): Purge old buffers that haven't been useful for a while
|
// NOTE(yuval): Purge old buffers that haven't been useful for a while
|
||||||
if ((now - last_buffer_cache_purge_time) > 1000000){
|
if ((now - _last_buffer_cache_purge_time) > 1000000){
|
||||||
Node prev_buffer_cache = buffer_cache;
|
Node prev_buffer_cache = _buffer_cache;
|
||||||
dll_init_sentinel(&buffer_cache);
|
dll_init_sentinel(&_buffer_cache);
|
||||||
|
|
||||||
for (Node *node = prev_buffer_cache.next;
|
for (Node *node = prev_buffer_cache.next;
|
||||||
node != &buffer_cache;
|
node != &_buffer_cache;
|
||||||
node = node->next){
|
node = node->next){
|
||||||
Metal_Buffer *candidate = CastFromMember(Metal_Buffer, node, node);
|
Metal_Buffer *candidate = CastFromMember(Metal_Buffer, node, node);
|
||||||
if (candidate->last_reuse_time > last_buffer_cache_purge_time){
|
if (candidate->last_reuse_time > _last_buffer_cache_purge_time){
|
||||||
dll_insert(&buffer_cache, node);
|
dll_insert(&_buffer_cache, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last_buffer_cache_purge_time = now;
|
_last_buffer_cache_purge_time = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(yuval): See if we have a buffer we can reuse
|
// NOTE(yuval): See if we have a buffer we can reuse
|
||||||
Metal_Buffer *best_candidate = 0;
|
Metal_Buffer *best_candidate = 0;
|
||||||
for (Node *node = buffer_cache.next;
|
for (Node *node = _buffer_cache.next;
|
||||||
node != &buffer_cache;
|
node != &_buffer_cache;
|
||||||
node = node->next){
|
node = node->next){
|
||||||
Metal_Buffer *candidate = CastFromMember(Metal_Buffer, node, node);
|
Metal_Buffer *candidate = CastFromMember(Metal_Buffer, node, node);
|
||||||
if ((candidate->size >= size) && ((!best_candidate) || (best_candidate->last_reuse_time > candidate->last_reuse_time))){
|
if ((candidate->size >= size) && ((!best_candidate) || (best_candidate->last_reuse_time > candidate->last_reuse_time))){
|
||||||
|
@ -521,15 +627,15 @@ metal__make_buffer(u32 size, id<MTLDevice> device){
|
||||||
result = best_candidate;
|
result = best_candidate;
|
||||||
} else{
|
} else{
|
||||||
// NOTE(yuval): No luck; make a new buffer.
|
// NOTE(yuval): No luck; make a new buffer.
|
||||||
result = metal__make_buffer(size, device);
|
result = metal__make_buffer(size, _device);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)add_reusable_buffer:(Metal_Buffer*)buffer{
|
- (void)add_reusable_buffer:(Metal_Buffer*)buffer{
|
||||||
// NOTE(yuval): This routine is a modified version of Dear ImGui's MetalContext::enqueueReusableBuffer in imgui_impl_metal.mm
|
// NOTE(yuval): This routine is a modified version of Dear ImGui's MetalContext::enqueueReusableBuffer in imgui_impl_metal.mm
|
||||||
|
|
||||||
dll_insert(&buffer_cache, &buffer->node);
|
dll_insert(&_buffer_cache, &buffer->node);
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
See LICENSE folder for this sample’s licensing information.
|
|
||||||
|
|
||||||
Abstract:
|
|
||||||
Header containing types and enum constants shared between Metal shaders and C/ObjC source
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef AAPLShaderTypes_h
|
|
||||||
#define AAPLShaderTypes_h
|
|
||||||
|
|
||||||
#undef clamp
|
|
||||||
#include <simd/simd.h>
|
|
||||||
#define clamp(a,x,b) clamp_((a),(x),(b))
|
|
||||||
|
|
||||||
// This structure defines the layout of vertices sent to the vertex
|
|
||||||
// shader. This header is shared between the .metal shader and C code, to guarantee that
|
|
||||||
// the layout of the vertex array in the C code matches the layout that the .metal
|
|
||||||
// vertex shader expects.
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
vector_float2 position;
|
|
||||||
vector_float4 color;
|
|
||||||
} AAPLVertex;
|
|
||||||
|
|
||||||
#endif /* AAPLShaderTypes_h */
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
See LICENSE folder for this sample’s licensing information.
|
|
||||||
|
|
||||||
Abstract:
|
|
||||||
Metal shaders used for this sample
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <metal_stdlib>
|
|
||||||
#include <simd/simd.h>
|
|
||||||
|
|
||||||
using namespace metal;
|
|
||||||
|
|
||||||
// Include header shared between this Metal shader code and C code executing Metal API commands.
|
|
||||||
#import "AAPLShaderTypes.h"
|
|
||||||
|
|
||||||
// Vertex shader outputs and fragment shader inputs
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
// The [[position]] attribute of this member indicates that this value
|
|
||||||
// is the clip space position of the vertex when this structure is
|
|
||||||
// returned from the vertex function.
|
|
||||||
float4 position [[position]];
|
|
||||||
|
|
||||||
// Since this member does not have a special attribute, the rasterizer
|
|
||||||
// interpolates its value with the values of the other triangle vertices
|
|
||||||
// and then passes the interpolated value to the fragment shader for each
|
|
||||||
// fragment in the triangle.
|
|
||||||
float4 color;
|
|
||||||
|
|
||||||
} RasterizerData;
|
|
||||||
|
|
||||||
vertex RasterizerData
|
|
||||||
vertexShader(uint vertexID [[vertex_id]],
|
|
||||||
constant AAPLVertex *vertices [[buffer(AAPLVertexInputIndexVertices)]],
|
|
||||||
constant vector_uint2 *viewportSizePointer [[buffer(AAPLVertexInputIndexViewportSize)]])
|
|
||||||
{
|
|
||||||
RasterizerData out;
|
|
||||||
|
|
||||||
// Index into the array of positions to get the current vertex.
|
|
||||||
// The positions are specified in pixel dimensions (i.e. a value of 100
|
|
||||||
// is 100 pixels from the origin).
|
|
||||||
float2 pixelSpacePosition = vertices[vertexID].position.xy;
|
|
||||||
|
|
||||||
// Get the viewport size and cast to float.
|
|
||||||
vector_float2 viewportSize = vector_float2(*viewportSizePointer);
|
|
||||||
|
|
||||||
|
|
||||||
// To convert from positions in pixel space to positions in clip-space,
|
|
||||||
// divide the pixel coordinates by half the size of the viewport.
|
|
||||||
out.position = vector_float4(0.0, 0.0, 0.0, 1.0);
|
|
||||||
out.position.xy = pixelSpacePosition / (viewportSize / 2.0);
|
|
||||||
|
|
||||||
// Pass the input color directly to the rasterizer.
|
|
||||||
out.color = vertices[vertexID].color;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment float4 fragmentShader(RasterizerData in [[stage_in]])
|
|
||||||
{
|
|
||||||
// Return the interpolated color.
|
|
||||||
return in.color;
|
|
||||||
}
|
|
||||||
|
|
|
@ -285,12 +285,11 @@ gl_render(Render_Target *t){
|
||||||
t->free_texture_first = 0;
|
t->free_texture_first = 0;
|
||||||
t->free_texture_last = 0;
|
t->free_texture_last = 0;
|
||||||
|
|
||||||
u64 begin_draw = system_now_time();
|
|
||||||
for (Render_Group *group = t->group_first;
|
for (Render_Group *group = t->group_first;
|
||||||
group != 0;
|
group != 0;
|
||||||
group = group->next){
|
group = group->next){
|
||||||
Rect_i32 box = Ri32(group->clip_box);
|
Rect_i32 box = Ri32(group->clip_box);
|
||||||
|
|
||||||
Rect_i32 scissor_box = {
|
Rect_i32 scissor_box = {
|
||||||
box.x0, height - box.y1, box.x1 - box.x0, box.y1 - box.y0,
|
box.x0, height - box.y1, box.x1 - box.x0, box.y1 - box.y0,
|
||||||
};
|
};
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#include <sys/mman.h> // NOTE(yuval): Used for mmap, munmap, mprotect
|
#include <sys/mman.h> // NOTE(yuval): Used for mmap, munmap, mprotect
|
||||||
#include <sys/stat.h> // NOTE(yuval): Used for stat
|
#include <sys/stat.h> // NOTE(yuval): Used for stat
|
||||||
#include <sys/types.h> // NOTE(yuval): Used for struct stat, pid_t
|
#include <sys/types.h> // NOTE(yuval): Used for struct stat, pid_t
|
||||||
|
#include <sys/syslimits.h> // NOTE(yuval): Used for PATH_MAX
|
||||||
|
|
||||||
#include <stdlib.h> // NOTE(yuval): Used for free
|
#include <stdlib.h> // NOTE(yuval): Used for free
|
||||||
|
|
||||||
|
@ -297,6 +298,15 @@ mac_to_object(Plat_Handle handle){
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
|
function void
|
||||||
|
mac_init_recursive_mutex(pthread_mutex_t *mutex){
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
pthread_mutex_init(mutex, &attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
|
||||||
function void
|
function void
|
||||||
mac_error_box(char *msg, b32 shutdown = true){
|
mac_error_box(char *msg, b32 shutdown = true){
|
||||||
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
||||||
|
@ -584,6 +594,7 @@ mac_toggle_fullscreen(void){
|
||||||
|
|
||||||
- (void)windowDidResize:(NSNotification*)notification{
|
- (void)windowDidResize:(NSNotification*)notification{
|
||||||
mac_resize(mac_vars.window);
|
mac_resize(mac_vars.window);
|
||||||
|
[mac_vars.view display];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowDidMiniaturize:(NSNotification*)notification{
|
- (void)windowDidMiniaturize:(NSNotification*)notification{
|
||||||
|
@ -629,8 +640,7 @@ mac_toggle_fullscreen(void){
|
||||||
mac_resize(mac_vars.window);
|
mac_resize(mac_vars.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)wantsUpdateLayer
|
- (BOOL)wantsUpdateLayer{
|
||||||
{
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,11 +962,13 @@ mac_toggle_fullscreen(void){
|
||||||
float dx = event.scrollingDeltaX;
|
float dx = event.scrollingDeltaX;
|
||||||
float dy = event.scrollingDeltaY;
|
float dy = event.scrollingDeltaY;
|
||||||
|
|
||||||
i8 scroll_speed = 100;
|
i8 wheel_delta = 0;
|
||||||
if (dy > 0){
|
if (dy > 0){
|
||||||
scroll_speed *= -1;
|
wheel_delta = -100;
|
||||||
|
} else if (dy < 0){
|
||||||
|
wheel_delta = 100;
|
||||||
}
|
}
|
||||||
mac_vars.input_chunk.trans.mouse_wheel = scroll_speed;
|
mac_vars.input_chunk.trans.mouse_wheel = wheel_delta;
|
||||||
|
|
||||||
system_signal_step(0);
|
system_signal_step(0);
|
||||||
}
|
}
|
||||||
|
@ -1095,7 +1107,7 @@ main(int arg_count, char **args){
|
||||||
FCoder_App_Delegate *app_delegate = [[FCoder_App_Delegate alloc] init];
|
FCoder_App_Delegate *app_delegate = [[FCoder_App_Delegate alloc] init];
|
||||||
[NSApp setDelegate:app_delegate];
|
[NSApp setDelegate:app_delegate];
|
||||||
|
|
||||||
pthread_mutex_init(&memory_tracker_mutex, 0);
|
mac_init_recursive_mutex(&memory_tracker_mutex);
|
||||||
|
|
||||||
// NOTE(yuval): Context setup
|
// NOTE(yuval): Context setup
|
||||||
Thread_Context _tctx = {};
|
Thread_Context _tctx = {};
|
||||||
|
@ -1122,7 +1134,7 @@ main(int arg_count, char **args){
|
||||||
dll_init_sentinel(&mac_vars.free_mac_objects);
|
dll_init_sentinel(&mac_vars.free_mac_objects);
|
||||||
dll_init_sentinel(&mac_vars.timer_objects);
|
dll_init_sentinel(&mac_vars.timer_objects);
|
||||||
|
|
||||||
pthread_mutex_init(&mac_vars.thread_launch_mutex, 0);
|
mac_init_recursive_mutex(&mac_vars.thread_launch_mutex);
|
||||||
pthread_cond_init(&mac_vars.thread_launch_cv, 0);
|
pthread_cond_init(&mac_vars.thread_launch_cv, 0);
|
||||||
|
|
||||||
// NOTE(yuval): Screen scale factor calculation
|
// NOTE(yuval): Screen scale factor calculation
|
||||||
|
|
|
@ -29,12 +29,12 @@ system_get_path_sig(){
|
||||||
{
|
{
|
||||||
local_persist b32 has_stashed_4ed_path = false;
|
local_persist b32 has_stashed_4ed_path = false;
|
||||||
if (!has_stashed_4ed_path){
|
if (!has_stashed_4ed_path){
|
||||||
local_const i32 binary_path_capacity = KB(32);
|
local_const u32 binary_path_capacity = PATH_MAX;
|
||||||
u8 *memory = (u8*)system_memory_allocate(binary_path_capacity, file_name_line_number_lit_u8);
|
u8 *memory = (u8*)system_memory_allocate(binary_path_capacity, file_name_line_number_lit_u8);
|
||||||
|
|
||||||
pid_t pid = getpid();
|
pid_t pid = getpid();
|
||||||
i32 size = proc_pidpath(pid, memory, binary_path_capacity);
|
i32 size = proc_pidpath(pid, memory, binary_path_capacity);
|
||||||
Assert(size <= binary_path_capacity - 1);
|
Assert(size < binary_path_capacity);
|
||||||
|
|
||||||
mac_vars.binary_path = SCu8(memory, size);
|
mac_vars.binary_path = SCu8(memory, size);
|
||||||
mac_vars.binary_path = string_remove_last_folder(mac_vars.binary_path);
|
mac_vars.binary_path = string_remove_last_folder(mac_vars.binary_path);
|
||||||
|
@ -638,7 +638,7 @@ system_thread_get_id_sig(){
|
||||||
function
|
function
|
||||||
system_mutex_make_sig(){
|
system_mutex_make_sig(){
|
||||||
Mac_Object *object = mac_alloc_object(MacObjectKind_Mutex);
|
Mac_Object *object = mac_alloc_object(MacObjectKind_Mutex);
|
||||||
pthread_mutex_init(&object->mutex, 0);
|
mac_init_recursive_mutex(&object->mutex);
|
||||||
|
|
||||||
System_Mutex result = mac_to_plat_handle(object);
|
System_Mutex result = mac_to_plat_handle(object);
|
||||||
return(result);
|
return(result);
|
||||||
|
@ -742,6 +742,7 @@ function void*
|
||||||
mac_memory_allocate_extended(void *base, u64 size, String_Const_u8 location){
|
mac_memory_allocate_extended(void *base, u64 size, String_Const_u8 location){
|
||||||
u64 adjusted_size = size + ALLOCATION_SIZE_ADJUSTMENT;
|
u64 adjusted_size = size + ALLOCATION_SIZE_ADJUSTMENT;
|
||||||
void *memory = mmap(base, adjusted_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
void *memory = mmap(base, adjusted_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
Assert(memory != MAP_FAILED);
|
||||||
|
|
||||||
Memory_Annotation_Tracker_Node *node = (Memory_Annotation_Tracker_Node*)memory;
|
Memory_Annotation_Tracker_Node *node = (Memory_Annotation_Tracker_Node*)memory;
|
||||||
|
|
||||||
|
@ -844,9 +845,7 @@ system_memory_annotation_sig(){
|
||||||
for (Memory_Annotation_Tracker_Node *node = memory_tracker.first;
|
for (Memory_Annotation_Tracker_Node *node = memory_tracker.first;
|
||||||
node != 0;
|
node != 0;
|
||||||
node = node->next){
|
node = node->next){
|
||||||
// TODO(yuval): Fix the API so that annotations would not mess with the system memory.
|
Memory_Annotation_Node *r_node = push_array(arena, Memory_Annotation_Node, 1);
|
||||||
// Memory_Annotation_Node *r_node = push_array(arena, Memory_Annotation_Node, 1);
|
|
||||||
Memory_Annotation_Node *r_node = (Memory_Annotation_Node*)malloc(sizeof(Memory_Annotation_Node));
|
|
||||||
sll_queue_push(result.first, result.last, r_node);
|
sll_queue_push(result.first, result.last, r_node);
|
||||||
result.count += 1;
|
result.count += 1;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue