From 89e2ddf07f30c9f00f2df924e8f236ced434daa8 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 8 Jul 2018 11:16:11 +0200 Subject: [PATCH] Examples: Comments + shallow coding convention tweak to be consistent across examples and with imgui_impl_osx --- examples/README.txt | 4 +- examples/example_apple_metal/README.md | 4 +- examples/imgui_impl_metal.mm | 97 ++++++++++++++++---------- 3 files changed, 67 insertions(+), 38 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index 5535c8dd..e84fae8b 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -166,12 +166,12 @@ example_win32_directx12/ example_apple_metal/ OSX & iOS + Metal. It is based on the "cross-platform" game template provided with Xcode as of Xcode 9. - Note that instead of the OSX bindings, you may want to use GLFW or SDL which will also support Windows, Linux along with OSX. + (NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.) = game template + imgui_impl_osx.mm + imgui_impl_metal.mm example_apple_opengl2/ OSX + OpenGL2. - Note that instead of the OSX bindings, you may want to use GLFW or SDL which will also support Windows, Linux along with OSX. + (NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.) = main.mm + imgui_impl_osx.mm + imgui_impl_opengl2.cpp example_glfw_opengl2/ diff --git a/examples/example_apple_metal/README.md b/examples/example_apple_metal/README.md index d43b4925..4f620327 100644 --- a/examples/example_apple_metal/README.md +++ b/examples/example_apple_metal/README.md @@ -2,5 +2,7 @@ ## Introduction -This example shows how to render ImGui with Metal. It is based on the cross-platform game template provided with Xcode as of Xcode 9. +This example shows how to integrate Dear ImGui with Metal. It is based on the "cross-platform" game template provided with Xcode as of Xcode 9. + +(NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.) diff --git a/examples/imgui_impl_metal.mm b/examples/imgui_impl_metal.mm index 8ee0643f..a4d235c9 100644 --- a/examples/imgui_impl_metal.mm +++ b/examples/imgui_impl_metal.mm @@ -128,8 +128,10 @@ void ImGui_ImplMetal_DestroyDeviceObjects() #pragma mark - MetalBuffer implementation @implementation MetalBuffer -- (instancetype)initWithBuffer:(id)buffer { - if ((self = [super init])) { +- (instancetype)initWithBuffer:(id)buffer +{ + if ((self = [super init])) + { _buffer = buffer; _lastReuseTime = [NSDate date].timeIntervalSince1970; } @@ -140,8 +142,10 @@ void ImGui_ImplMetal_DestroyDeviceObjects() #pragma mark - FramebufferDescriptor implementation @implementation FramebufferDescriptor -- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor { - if ((self = [super init])) { +- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor +{ + if ((self = [super init])) + { _sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount; _colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat; _depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat; @@ -150,7 +154,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return self; } -- (nonnull id)copyWithZone:(nullable NSZone *)zone { +- (nonnull id)copyWithZone:(nullable NSZone *)zone +{ FramebufferDescriptor *copy = [[FramebufferDescriptor allocWithZone:zone] init]; copy.sampleCount = self.sampleCount; copy.colorPixelFormat = self.colorPixelFormat; @@ -159,7 +164,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return copy; } -- (NSUInteger)hash { +- (NSUInteger)hash +{ NSUInteger sc = _sampleCount & 0x3; NSUInteger cf = _colorPixelFormat & 0x3FF; NSUInteger df = _depthPixelFormat & 0x3FF; @@ -168,12 +174,12 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return hash; } -- (BOOL)isEqual:(id)object { +- (BOOL)isEqual:(id)object +{ FramebufferDescriptor *other = object; - if (![other isKindOfClass:[FramebufferDescriptor class]]) { + if (![other isKindOfClass:[FramebufferDescriptor class]]) return NO; - } - return other.sampleCount == self.sampleCount && + return other.sampleCount == self.sampleCount && other.colorPixelFormat == self.colorPixelFormat && other.depthPixelFormat == self.depthPixelFormat && other.stencilPixelFormat == self.stencilPixelFormat; @@ -185,7 +191,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() @implementation MetalContext - (instancetype)init { - if ((self = [super init])) { + if ((self = [super init])) + { _renderPipelineStateCache = [NSMutableDictionary dictionary]; _bufferCache = [NSMutableArray array]; _lastBufferCachePurge = [NSDate date].timeIntervalSince1970; @@ -193,14 +200,20 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return self; } -- (void)makeDeviceObjectsWithDevice:(id)device { +- (void)makeDeviceObjectsWithDevice:(id)device +{ MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init]; depthStencilDescriptor.depthWriteEnabled = NO; depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways; self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor]; } -- (void)makeFontTextureWithDevice:(id)device { +// 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)device +{ ImGuiIO &io = ImGui::GetIO(); unsigned char* pixels; int width, height; @@ -220,14 +233,18 @@ void ImGui_ImplMetal_DestroyDeviceObjects() self.fontTexture = texture; } -- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device { +- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device +{ NSTimeInterval now = [NSDate date].timeIntervalSince1970; // 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]; - for (MetalBuffer *candidate in self.bufferCache) { - if (candidate.lastReuseTime > self.lastBufferCachePurge) { + for (MetalBuffer *candidate in self.bufferCache) + { + if (candidate.lastReuseTime > self.lastBufferCachePurge) + { [survivors addObject:candidate]; } } @@ -237,13 +254,12 @@ void ImGui_ImplMetal_DestroyDeviceObjects() // See if we have a buffer we can reuse MetalBuffer *bestCandidate = nil; - for (MetalBuffer *candidate in self.bufferCache) { - if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime)) { + for (MetalBuffer *candidate in self.bufferCache) + if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime)) bestCandidate = candidate; - } - } - if (bestCandidate != nil) { + if (bestCandidate != nil) + { [self.bufferCache removeObject:bestCandidate]; bestCandidate.lastReuseTime = now; return bestCandidate; @@ -254,16 +270,19 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return [[MetalBuffer alloc] initWithBuffer:backing]; } -- (void)enqueueReusableBuffer:(MetalBuffer *)buffer { +- (void)enqueueReusableBuffer:(MetalBuffer *)buffer +{ [self.bufferCache addObject:buffer]; } -- (_Nullable id)renderPipelineStateForFrameAndDevice:(id)device { +- (_Nullable id)renderPipelineStateForFrameAndDevice:(id)device +{ // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame // Thie hit rate for this cache should be very near 100%. id renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor]; - if (renderPipelineState == nil) { + 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 @@ -314,7 +333,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() "}\n"; id library = [device newLibraryWithSource:shaderSource options:nil error:&error]; - if (library == nil) { + if (library == nil) + { NSLog(@"Error: failed to create Metal library: %@", error); return nil; } @@ -322,7 +342,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() id vertexFunction = [library newFunctionWithName:@"vertex_main"]; id fragmentFunction = [library newFunctionWithName:@"fragment_main"]; - if (vertexFunction == nil || fragmentFunction == nil) { + if (vertexFunction == nil || fragmentFunction == nil) + { NSLog(@"Error: failed to find Metal shader functions in library: %@", error); return nil; } @@ -358,14 +379,16 @@ void ImGui_ImplMetal_DestroyDeviceObjects() pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat; id renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; - if (error != nil) { + if (error != nil) + { NSLog(@"Error: failed to create Metal pipeline state: %@", error); } return renderPipelineState; } -- (void)emptyRenderPipelineStateCache { +- (void)emptyRenderPipelineStateCache +{ [self.renderPipelineStateCache removeAllObjects]; } @@ -387,12 +410,15 @@ void ImGui_ImplMetal_DestroyDeviceObjects() // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPps (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, + MTLViewport viewport = + { + .originX = 0.0, .originY = 0.0, .width = double(fb_width), .height = double(fb_height), .znear = 0.0, - .zfar = 1.0 }; + .zfar = 1.0 + }; [commandEncoder setViewport:viewport]; float L = drawData->DisplayPos.x; float R = drawData->DisplayPos.x + drawData->DisplaySize.x; @@ -412,7 +438,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() size_t vertexBufferLength = 0; size_t indexBufferLength = 0; - for (int n = 0; n < drawData->CmdListsCount; n++) { + for (int n = 0; n < drawData->CmdListsCount; n++) + { const ImDrawList* cmd_list = drawData->CmdLists[n]; vertexBufferLength += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); indexBufferLength += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); @@ -461,9 +488,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() // Bind texture, Draw - if (pcmd->TextureId != NULL) { + if (pcmd->TextureId != NULL) [commandEncoder setFragmentTexture:(__bridge id)(pcmd->TextureId) atIndex:0]; - } [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:pcmd->ElemCount indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32 @@ -479,7 +505,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() } __weak id weakSelf = self; - [commandBuffer addCompletedHandler:^(id) { + [commandBuffer addCompletedHandler:^(id) + { dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf enqueueReusableBuffer:vertexBuffer]; [weakSelf enqueueReusableBuffer:indexBuffer];