@ -46,7 +46,7 @@ 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;  
					 
					 
					 
					@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;  
					 
					 
					 
					@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;  
					 
					 
					 
					@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor  *)renderPassDescriptor;  
					 
					 
					 
					- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor;  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					@end  
					 
					 
					 
					@end  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					// A singleton that stores long-lived objects that are needed by the Metal  
					 
					 
					 
					// A singleton that stores long-lived objects that are needed by the Metal  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -55,26 +55,13 @@ 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@interface MetalContext : NSObject  
					 
					 
					 
					@interface MetalContext : NSObject  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, strong) id<MTLDevice>                 device;  
					 
					 
					 
					@property (nonatomic, strong) id<MTLDevice>                 device;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, strong) id<MTLDepthStencilState>      depthStencilState;  
					 
					 
					 
					@property (nonatomic, strong) id<MTLDepthStencilState>      depthStencilState;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, strong) FramebufferDescriptor * framebufferDescriptor; // framebuffer descriptor for current frame; transient  
					 
					 
					 
					@property (nonatomic, strong) FramebufferDescriptor*         framebufferDescriptor; // framebuffer descriptor for current frame; transient  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, strong) NSMutableDictionary * renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors  
					 
					 
					 
					@property (nonatomic, strong) NSMutableDictionary*           renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors  
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, strong, nullable) id<MTLTexture>      fontTexture;  
					 
					 
					 
					@property (nonatomic, strong, nullable) id<MTLTexture>      fontTexture;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, strong) NSMutableArray<MetalBuffer  *>  *bufferCache;  
					 
					 
					 
					@property (nonatomic, strong) NSMutableArray<MetalBuffer*>*  bufferCache;  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					@property (nonatomic, assign) double                        lastBufferCachePurge;  
					 
					 
					 
					@property (nonatomic, assign) double                        lastBufferCachePurge;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device;  
					 
					 
					 
					- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)makeFontTextureWithDevice:(id<MTLDevice>)device;  
					 
					 
					 
					- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device;  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
					- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)enqueueReusableBuffer:(MetalBuffer *)buffer;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)emptyRenderPipelineStateCache;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)setupRenderState:(ImDrawData *)drawData  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					           commandBuffer:(id<MTLCommandBuffer>)commandBuffer  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					          commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					     renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            vertexBuffer:(MetalBuffer *)vertexBuffer  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					      vertexBufferOffset:(size_t)vertexBufferOffset;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)renderDrawData:(ImDrawData *)drawData  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					         commandBuffer:(id<MTLCommandBuffer>)commandBuffer  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					@end  
					 
					 
					 
					@end  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					struct ImGui_ImplMetal_Data  
					 
					 
					 
					struct ImGui_ImplMetal_Data  
				
			 
			
		
	
	
		
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
					 
					@ -148,7 +135,7 @@ void ImGui_ImplMetal_Shutdown() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_DestroyBackendData();  
					 
					 
					 
					    ImGui_ImplMetal_DestroyBackendData();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor  *renderPassDescriptor)  
					 
					 
					 
					void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor*  renderPassDescriptor)  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    IM_ASSERT(bd->SharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?");  
					 
					 
					 
					    IM_ASSERT(bd->SharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?");  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -158,19 +145,186 @@ void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor *renderPassDescriptor) 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device);  
					 
					 
					 
					        ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					static void ImGui_ImplMetal_SetupRenderState(ImDrawData* drawData, id<MTLCommandBuffer> commandBuffer,  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    id<MTLRenderCommandEncoder> commandEncoder, id<MTLRenderPipelineState> renderPipelineState,  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    MetalBuffer* vertexBuffer, size_t vertexBufferOffset)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    IM_UNUSED(commandBuffer);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [commandEncoder setCullMode:MTLCullModeNone];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [commandEncoder setDepthStencilState:bd->SharedMetalContext.depthStencilState];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // Setup viewport, orthographic projection matrix  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // Our visible imgui space lies from draw_data->DisplayPos (top left) to  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    MTLViewport viewport =  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        .originX = 0.0,  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        .originY = 0.0,  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        .width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x),  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        .height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y),  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        .znear = 0.0,  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        .zfar = 1.0  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    };  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [commandEncoder setViewport:viewport];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    float L = drawData->DisplayPos.x;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    float R = drawData->DisplayPos.x + drawData->DisplaySize.x;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    float T = drawData->DisplayPos.y;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    float B = drawData->DisplayPos.y + drawData->DisplaySize.y;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    float N = (float)viewport.znear;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    float F = (float)viewport.zfar;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    const float ortho_projection[4][4] =  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        { 2.0f/(R-L),   0.0f,           0.0f,   0.0f },  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        { 0.0f,         2.0f/(T-B),     0.0f,   0.0f },  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        { 0.0f,         0.0f,        1/(F-N),   0.0f },  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        { (R+L)/(L-R),  (T+B)/(B-T), N/(F-N),   1.0f },  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    };  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [commandEncoder setRenderPipelineState:renderPipelineState];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					// Metal Render function.  
					 
					 
					 
					// Metal Render function.  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)  
					 
					 
					 
					void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawD ata, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [bd->SharedMetalContext renderDrawData:draw_data commandBuffer:commandBuffer commandEncoder:commandEncoder];  
					 
					 
					 
					    MetalContext* ctx = bd->SharedMetalContext;  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        return;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // The hit rate for this cache should be very near 100%.  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    id<MTLRenderPipelineState> renderPipelineState = ctx.renderPipelineStateCache[ctx.framebufferDescriptor];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    if (renderPipelineState == nil)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        // No luck; make a new render pipeline state  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        renderPipelineState = [ctx renderPipelineStateForFramebufferDescriptor:ctx.framebufferDescriptor device:commandBuffer.device];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        // Cache render pipeline state for later reuse  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        ctx.renderPipelineStateCache[ctx.framebufferDescriptor] = renderPipelineState;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    MetalBuffer* vertexBuffer = [ctx dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    ImGui_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // Will project scissor/clipping rectangles into framebuffer space  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    ImVec2 clip_off = drawData->DisplayPos;         // (0,0) unless using multi-viewports  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // Render command lists  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    size_t vertexBufferOffset = 0;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    size_t indexBufferOffset = 0;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    for (int n = 0; n < drawData->CmdListsCount; n++)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        const ImDrawList* cmd_list = drawData->CmdLists[n];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            if (pcmd->UserCallback)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                // User callback, registered via ImDrawList::AddCallback()  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    ImGui_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                else  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    pcmd->UserCallback(cmd_list, pcmd);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            else  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                // Project scissor/clipping rectangles into framebuffer space  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                // Clamp to viewport as setScissorRect() won't accept values that are off bounds  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    continue;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    continue;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                // Apply scissor/clipping rectangle  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                MTLScissorRect scissorRect =  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    .x = NSUInteger(clip_min.x),  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    .y = NSUInteger(clip_min.y),  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    .width = NSUInteger(clip_max.x - clip_min.x),  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    .height = NSUInteger(clip_max.y - clip_min.y)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                };  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                [commandEncoder setScissorRect:scissorRect];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                // Bind texture, Draw  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                if (ImTextureID tex_id = pcmd->GetTexID())  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                    [commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                                           indexCount:pcmd->ElemCount  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                                            indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                                          indexBuffer:indexBuffer.buffer  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                                    indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        dispatch_async(dispatch_get_main_queue(), ^{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            [bd->SharedMetalContext.bufferCache addObject:vertexBuffer];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					            [bd->SharedMetalContext.bufferCache addObject:indexBuffer];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					        });  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    }];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device)  
					 
					 
					 
					bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGuiIO& io = ImGui::GetIO();  
					 
					 
					 
					    ImGuiIO& io = ImGui::GetIO();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [bd->SharedMetalContext makeFontTextureWithDevice:device];  
					 
					 
					 
					
 
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
					    io.Fonts->SetTexID((__bridge void *)bd->SharedMetalContext.fontTexture); // ImTextureID == void*  
					 
					 
					 
					    // We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.  
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    // You can make that change in your implementation.  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    unsigned char* pixels;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    int width, height;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    MTLTextureDescriptor* textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                                                                                                 width:(NSUInteger)width  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                                                                                                height:(NSUInteger)height  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					                                                                                             mipmapped:NO];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    textureDescriptor.usage = MTLTextureUsageShaderRead;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					#if TARGET_OS_OSX || TARGET_OS_MACCATALYST  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    textureDescriptor.storageMode = MTLStorageModeManaged;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					#else  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    textureDescriptor.storageMode = MTLStorageModeShared;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					#endif  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    id <MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    bd->SharedMetalContext.fontTexture = texture;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    io.Fonts->SetTexID((__bridge void*)bd->SharedMetalContext.fontTexture); // ImTextureID == void*  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    return (bd->SharedMetalContext.fontTexture != nil);  
					 
					 
					 
					    return (bd->SharedMetalContext.fontTexture != nil);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -186,7 +340,10 @@ void ImGui_ImplMetal_DestroyFontsTexture() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)  
					 
					 
					 
					bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [bd->SharedMetalContext makeDeviceObjectsWithDevice:device];  
					 
					 
					 
					    MTLDepthStencilDescriptor* depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    depthStencilDescriptor.depthWriteEnabled = NO;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					    bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_CreateFontsTexture(device);  
					 
					 
					 
					    ImGui_ImplMetal_CreateFontsTexture(device);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    return true;  
					 
					 
					 
					    return true;  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -196,7 +353,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_DestroyFontsTexture();  
					 
					 
					 
					    ImGui_ImplMetal_DestroyFontsTexture();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [bd->SharedMetalContext emptyRenderPipelineStateCache ];  
					 
					 
					 
					    [bd->SharedMetalContext.renderPipelineStateCache removeAllObjects ];  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#pragma mark - MetalBuffer implementation  
					 
					 
					 
					#pragma mark - MetalBuffer implementation  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -216,7 +373,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#pragma mark - FramebufferDescriptor implementation  
					 
					 
					 
					#pragma mark - FramebufferDescriptor implementation  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@implementation FramebufferDescriptor  
					 
					 
					 
					@implementation FramebufferDescriptor  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor  *)renderPassDescriptor  
					 
					 
					 
					- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    if ((self = [super init]))  
					 
					 
					 
					    if ((self = [super init]))  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					    {  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -228,9 +385,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    return self;  
					 
					 
					 
					    return self;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (nonnull id)copyWithZone:(nullable NSZone  *)zone  
					 
					 
					 
					- (nonnull id)copyWithZone:(nullable NSZone*)zone  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    FramebufferDescriptor  *copy = [[FramebufferDescriptor allocWithZone:zone] init];  
					 
					 
					 
					    FramebufferDescriptor*  copy = [[FramebufferDescriptor allocWithZone:zone] init];  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					    copy.sampleCount = self.sampleCount;  
					 
					 
					 
					    copy.sampleCount = self.sampleCount;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    copy.colorPixelFormat = self.colorPixelFormat;  
					 
					 
					 
					    copy.colorPixelFormat = self.colorPixelFormat;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    copy.depthPixelFormat = self.depthPixelFormat;  
					 
					 
					 
					    copy.depthPixelFormat = self.depthPixelFormat;  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -250,7 +407,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (BOOL)isEqual:(id)object  
					 
					 
					 
					- (BOOL)isEqual:(id)object  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    FramebufferDescriptor  *other = object;  
					 
					 
					 
					    FramebufferDescriptor*  other = object;  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					    if (![other isKindOfClass:[FramebufferDescriptor class]])  
					 
					 
					 
					    if (![other isKindOfClass:[FramebufferDescriptor class]])  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        return NO;  
					 
					 
					 
					        return NO;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    return other.sampleCount == self.sampleCount      &&  
					 
					 
					 
					    return other.sampleCount == self.sampleCount      &&  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -264,7 +421,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#pragma mark - MetalContext implementation  
					 
					 
					 
					#pragma mark - MetalContext implementation  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@implementation MetalContext  
					 
					 
					 
					@implementation MetalContext  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (instancetype)init {  
					 
					 
					 
					- (instancetype)init  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					 
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    if ((self = [super init]))  
					 
					 
					 
					    if ((self = [super init]))  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					    {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        _renderPipelineStateCache = [NSMutableDictionary dictionary];  
					 
					 
					 
					        _renderPipelineStateCache = [NSMutableDictionary dictionary];  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -274,61 +432,24 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    return self;  
					 
					 
					 
					    return self;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device  
					 
					 
					 
					- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    depthStencilDescriptor.depthWriteEnabled = NO;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					// We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					// In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					// However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					// You can make that change in your implementation.  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)makeFontTextureWithDevice:(id<MTLDevice>)device  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGuiIO &io = ImGui::GetIO();  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    unsigned char* pixels;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    int width, height;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                                                                                                 width:(NSUInteger)width  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                                                                                                height:(NSUInteger)height  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                                                                                             mipmapped:NO];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    textureDescriptor.usage = MTLTextureUsageShaderRead;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#if TARGET_OS_OSX || TARGET_OS_MACCATALYST  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    textureDescriptor.storageMode = MTLStorageModeManaged;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#else  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    textureDescriptor.storageMode = MTLStorageModeShared;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#endif  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    id <MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    self.fontTexture = texture;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device  
					 
					 
					 
					 
				
			 
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    uint64_t now = GetMachAbsoluteTimeInSeconds();  
					 
					 
					 
					    uint64_t now = GetMachAbsoluteTimeInSeconds();  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // Purge old buffers that haven't been useful for a while  
					 
					 
					 
					    // Purge old buffers that haven't been useful for a while  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    if (now - self.lastBufferCachePurge > 1.0)  
					 
					 
					 
					    if (now - self.lastBufferCachePurge > 1.0)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					    {  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        NSMutableArray *survivors = [NSMutableArray array];  
					 
					 
					 
					        NSMutableArray* survivors = [NSMutableArray array];  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
					        for (MetalBuffer *candidate in self.bufferCache)  
					 
					 
					 
					        for (MetalBuffer* candidate in self.bufferCache)  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
					        {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					            if (candidate.lastReuseTime > self.lastBufferCachePurge)  
					 
					 
					 
					            if (candidate.lastReuseTime > self.lastBufferCachePurge)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                [survivors addObject:candidate];  
					 
					 
					 
					                [survivors addObject:candidate];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        self.bufferCache = [survivors mutableCopy];  
					 
					 
					 
					        self.bufferCache = [survivors mutableCopy];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        self.lastBufferCachePurge = now;  
					 
					 
					 
					        self.lastBufferCachePurge = now;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    }  
					 
					 
					 
					    }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // See if we have a buffer we can reuse  
					 
					 
					 
					    // See if we have a buffer we can reuse  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    MetalBuffer  *bestCandidate = nil;  
					 
					 
					 
					    MetalBuffer* bestCandidate = nil;  
				
			 
			
				
				
			
		
	
		
		
			
				
					
					 
					 
					 
					    for (MetalBuffer  *candidate in self.bufferCache)  
					 
					 
					 
					    for (MetalBuffer* candidate in self.bufferCache)  
				
			 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					        if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))  
					 
					 
					 
					        if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            bestCandidate = candidate;  
					 
					 
					 
					            bestCandidate = candidate;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -344,34 +465,12 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    return [[MetalBuffer alloc] initWithBuffer:backing];  
					 
					 
					 
					    return [[MetalBuffer alloc] initWithBuffer:backing];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)enqueueReusableBuffer:(MetalBuffer *)buffer  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [self.bufferCache addObject:buffer];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (_Nullable id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // The hit rate for this cache should be very near 100%.  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    id<MTLRenderPipelineState> renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    if (renderPipelineState == nil)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        // No luck; make a new render pipeline state  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        // Cache render pipeline state for later reuse  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    return renderPipelineState;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.  
					 
					 
					 
					// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (id<MTLRenderPipelineState>)_ renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor  *)descriptor device:(id<MTLDevice>)device  
					 
					 
					 
					- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					{  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    NSError  *error = nil;  
					 
					 
					 
					    NSError* error = nil;  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    NSString  *shaderSource = @""  
					 
					 
					 
					    NSString* shaderSource = @""  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					    "#include <metal_stdlib>\n"  
					 
					 
					 
					    "#include <metal_stdlib>\n"  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    "using namespace metal;\n"  
					 
					 
					 
					    "using namespace metal;\n"  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    "\n"  
					 
					 
					 
					    "\n"  
				
			 
			
		
	
	
		
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
					 
					@ -423,7 +522,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        return nil;  
					 
					 
					 
					        return nil;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    }  
					 
					 
					 
					    }  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    MTLVertexDescriptor  *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];  
					 
					 
					 
					    MTLVertexDescriptor*  vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					    vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos);  
					 
					 
					 
					    vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position  
					 
					 
					 
					    vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    vertexDescriptor.attributes[0].bufferIndex = 0;  
					 
					 
					 
					    vertexDescriptor.attributes[0].bufferIndex = 0;  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -437,7 +536,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;  
					 
					 
					 
					    vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);  
					 
					 
					 
					    vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    MTLRenderPipelineDescriptor  *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];  
					 
					 
					 
					    MTLRenderPipelineDescriptor*  pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];  
				
			 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 
					 
					 
					    pipelineDescriptor.vertexFunction = vertexFunction;  
					 
					 
					 
					    pipelineDescriptor.vertexFunction = vertexFunction;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    pipelineDescriptor.fragmentFunction = fragmentFunction;  
					 
					 
					 
					    pipelineDescriptor.fragmentFunction = fragmentFunction;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    pipelineDescriptor.vertexDescriptor = vertexDescriptor;  
					 
					 
					 
					    pipelineDescriptor.vertexDescriptor = vertexDescriptor;  
				
			 
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
							 
						
					 
					 
					@ -455,163 +554,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects() 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];  
					 
					 
					 
					    id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    if (error != nil)  
					 
					 
					 
					    if (error != nil)  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        NSLog(@"Error: failed to create Metal pipeline state: %@", error);  
					 
					 
					 
					        NSLog(@"Error: failed to create Metal pipeline state: %@", error);  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    return renderPipelineState;  
					 
					 
					 
					    return renderPipelineState;  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					}  
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					
 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)emptyRenderPipelineStateCache  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [self.renderPipelineStateCache removeAllObjects];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)setupRenderState:(ImDrawData *)drawData  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					           commandBuffer:(id<MTLCommandBuffer>)commandBuffer  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					          commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					     renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            vertexBuffer:(MetalBuffer *)vertexBuffer  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					      vertexBufferOffset:(size_t)vertexBufferOffset  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [commandEncoder setCullMode:MTLCullModeNone];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [commandEncoder setDepthStencilState:bd->SharedMetalContext.depthStencilState];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // Setup viewport, orthographic projection matrix  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // Our visible imgui space lies from draw_data->DisplayPos (top left) to  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    MTLViewport viewport =  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        .originX = 0.0,  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        .originY = 0.0,  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        .width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x),  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        .height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y),  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        .znear = 0.0,  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        .zfar = 1.0  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    };  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [commandEncoder setViewport:viewport];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    float L = drawData->DisplayPos.x;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    float R = drawData->DisplayPos.x + drawData->DisplaySize.x;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    float T = drawData->DisplayPos.y;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    float B = drawData->DisplayPos.y + drawData->DisplaySize.y;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    float N = (float)viewport.znear;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    float F = (float)viewport.zfar;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    const float ortho_projection[4][4] =  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        { 2.0f/(R-L),   0.0f,           0.0f,   0.0f },  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        { 0.0f,         2.0f/(T-B),     0.0f,   0.0f },  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        { 0.0f,         0.0f,        1/(F-N),   0.0f },  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        { (R+L)/(L-R),  (T+B)/(B-T), N/(F-N),   1.0f },  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    };  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [commandEncoder setRenderPipelineState:renderPipelineState];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					- (void)renderDrawData:(ImDrawData *)drawData  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					         commandBuffer:(id<MTLCommandBuffer>)commandBuffer  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					{  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        return;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    id<MTLRenderPipelineState> renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    MetalBuffer* vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    MetalBuffer* indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:0];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // Will project scissor/clipping rectangles into framebuffer space  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImVec2 clip_off = drawData->DisplayPos;         // (0,0) unless using multi-viewports  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    // Render command lists  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    size_t vertexBufferOffset = 0;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    size_t indexBufferOffset = 0;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    for (int n = 0; n < drawData->CmdListsCount; n++)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        const ImDrawList* cmd_list = drawData->CmdLists[n];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            if (pcmd->UserCallback)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                // User callback, registered via ImDrawList::AddCallback()  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    [self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:vertexBufferOffset];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                else  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    pcmd->UserCallback(cmd_list, pcmd);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            else  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                // Project scissor/clipping rectangles into framebuffer space  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                // Clamp to viewport as setScissorRect() won't accept values that are off bounds  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    continue;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    continue;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                // Apply scissor/clipping rectangle  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                MTLScissorRect scissorRect =  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    .x = NSUInteger(clip_min.x),  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    .y = NSUInteger(clip_min.y),  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    .width = NSUInteger(clip_max.x - clip_min.x),  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    .height = NSUInteger(clip_max.y - clip_min.y)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                };  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                [commandEncoder setScissorRect:scissorRect];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                // Bind texture, Draw  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                if (ImTextureID tex_id = pcmd->GetTexID())  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                    [commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                                           indexCount:pcmd->ElemCount  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                                            indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                                          indexBuffer:indexBuffer.buffer  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					                                    indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    }  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#if __has_feature(objc_arc)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    __weak id weakSelf = self;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#else  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    __unsafe_unretained id weakSelf = self;  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					#endif  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    {  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        dispatch_async(dispatch_get_main_queue(), ^{  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            [weakSelf enqueueReusableBuffer:vertexBuffer];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					            [weakSelf enqueueReusableBuffer:indexBuffer];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					        });  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					    }];  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					}  
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					
 
					 
					 
					 
					 
				
			 
			
		
	
		
		
			
				
					
					 
					 
					 
					@end  
					 
					 
					 
					@end