Examples: Comments + shallow coding convention tweak to be consistent across examples and with imgui_impl_osx

This commit is contained in:
omar 2018-07-08 11:16:11 +02:00
parent 569e0f07f1
commit 89e2ddf07f
3 changed files with 67 additions and 38 deletions

View File

@ -166,12 +166,12 @@ example_win32_directx12/
example_apple_metal/ example_apple_metal/
OSX & iOS + Metal. OSX & iOS + Metal.
It is based on the "cross-platform" game template provided with Xcode as of Xcode 9. 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 = game template + imgui_impl_osx.mm + imgui_impl_metal.mm
example_apple_opengl2/ example_apple_opengl2/
OSX + 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 = main.mm + imgui_impl_osx.mm + imgui_impl_opengl2.cpp
example_glfw_opengl2/ example_glfw_opengl2/

View File

@ -2,5 +2,7 @@
## Introduction ## 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.)

View File

@ -128,8 +128,10 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
#pragma mark - MetalBuffer implementation #pragma mark - MetalBuffer implementation
@implementation MetalBuffer @implementation MetalBuffer
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer { - (instancetype)initWithBuffer:(id<MTLBuffer>)buffer
if ((self = [super init])) { {
if ((self = [super init]))
{
_buffer = buffer; _buffer = buffer;
_lastReuseTime = [NSDate date].timeIntervalSince1970; _lastReuseTime = [NSDate date].timeIntervalSince1970;
} }
@ -140,8 +142,10 @@ 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]))
{
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount; _sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat; _colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
_depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat; _depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
@ -150,7 +154,8 @@ 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;
@ -159,7 +164,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return copy; return copy;
} }
- (NSUInteger)hash { - (NSUInteger)hash
{
NSUInteger sc = _sampleCount & 0x3; NSUInteger sc = _sampleCount & 0x3;
NSUInteger cf = _colorPixelFormat & 0x3FF; NSUInteger cf = _colorPixelFormat & 0x3FF;
NSUInteger df = _depthPixelFormat & 0x3FF; NSUInteger df = _depthPixelFormat & 0x3FF;
@ -168,11 +174,11 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return hash; return hash;
} }
- (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 &&
other.colorPixelFormat == self.colorPixelFormat && other.colorPixelFormat == self.colorPixelFormat &&
other.depthPixelFormat == self.depthPixelFormat && other.depthPixelFormat == self.depthPixelFormat &&
@ -185,7 +191,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
@implementation MetalContext @implementation MetalContext
- (instancetype)init { - (instancetype)init {
if ((self = [super init])) { if ((self = [super init]))
{
_renderPipelineStateCache = [NSMutableDictionary dictionary]; _renderPipelineStateCache = [NSMutableDictionary dictionary];
_bufferCache = [NSMutableArray array]; _bufferCache = [NSMutableArray array];
_lastBufferCachePurge = [NSDate date].timeIntervalSince1970; _lastBufferCachePurge = [NSDate date].timeIntervalSince1970;
@ -193,14 +200,20 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return self; return self;
} }
- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device { - (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device
{
MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init]; MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
depthStencilDescriptor.depthWriteEnabled = NO; depthStencilDescriptor.depthWriteEnabled = NO;
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways; depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor]; self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
} }
- (void)makeFontTextureWithDevice:(id<MTLDevice>)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<MTLDevice>)device
{
ImGuiIO &io = ImGui::GetIO(); ImGuiIO &io = ImGui::GetIO();
unsigned char* pixels; unsigned char* pixels;
int width, height; int width, height;
@ -220,14 +233,18 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
self.fontTexture = texture; self.fontTexture = texture;
} }
- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device { - (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
{
NSTimeInterval now = [NSDate date].timeIntervalSince1970; NSTimeInterval now = [NSDate date].timeIntervalSince1970;
// 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];
} }
} }
@ -237,13 +254,12 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
// 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;
}
}
if (bestCandidate != nil) { if (bestCandidate != nil)
{
[self.bufferCache removeObject:bestCandidate]; [self.bufferCache removeObject:bestCandidate];
bestCandidate.lastReuseTime = now; bestCandidate.lastReuseTime = now;
return bestCandidate; return bestCandidate;
@ -254,16 +270,19 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return [[MetalBuffer alloc] initWithBuffer:backing]; return [[MetalBuffer alloc] initWithBuffer:backing];
} }
- (void)enqueueReusableBuffer:(MetalBuffer *)buffer { - (void)enqueueReusableBuffer:(MetalBuffer *)buffer
{
[self.bufferCache addObject:buffer]; [self.bufferCache addObject:buffer];
} }
- (_Nullable id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device { - (_Nullable id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device
{
// Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame // 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%. // Thie hit rate for this cache should be very near 100%.
id<MTLRenderPipelineState> renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor]; id<MTLRenderPipelineState> renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor];
if (renderPipelineState == nil) { if (renderPipelineState == nil)
{
// No luck; make a new render pipeline state // No luck; make a new render pipeline state
renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device]; renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device];
// Cache render pipeline state for later reuse // Cache render pipeline state for later reuse
@ -314,7 +333,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
"}\n"; "}\n";
id<MTLLibrary> library = [device newLibraryWithSource:shaderSource options:nil error:&error]; id<MTLLibrary> library = [device newLibraryWithSource:shaderSource options:nil error:&error];
if (library == nil) { if (library == nil)
{
NSLog(@"Error: failed to create Metal library: %@", error); NSLog(@"Error: failed to create Metal library: %@", error);
return nil; return nil;
} }
@ -322,7 +342,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"]; id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"]; id<MTLFunction> 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); NSLog(@"Error: failed to find Metal shader functions in library: %@", error);
return nil; return nil;
} }
@ -358,14 +379,16 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat; pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
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 { - (void)emptyRenderPipelineStateCache
{
[self.renderPipelineStateCache removeAllObjects]; [self.renderPipelineStateCache removeAllObjects];
} }
@ -387,12 +410,15 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
// Setup viewport, orthographic projection matrix // Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPps (top left) to // 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. // 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, .originY = 0.0,
.width = double(fb_width), .width = double(fb_width),
.height = double(fb_height), .height = double(fb_height),
.znear = 0.0, .znear = 0.0,
.zfar = 1.0 }; .zfar = 1.0
};
[commandEncoder setViewport:viewport]; [commandEncoder setViewport:viewport];
float L = drawData->DisplayPos.x; float L = drawData->DisplayPos.x;
float R = drawData->DisplayPos.x + drawData->DisplaySize.x; float R = drawData->DisplayPos.x + drawData->DisplaySize.x;
@ -412,7 +438,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
size_t vertexBufferLength = 0; size_t vertexBufferLength = 0;
size_t indexBufferLength = 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]; const ImDrawList* cmd_list = drawData->CmdLists[n];
vertexBufferLength += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); vertexBufferLength += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);
indexBufferLength += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); indexBufferLength += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);
@ -461,9 +488,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
// Bind texture, Draw // Bind texture, Draw
if (pcmd->TextureId != NULL) { if (pcmd->TextureId != NULL)
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(pcmd->TextureId) atIndex:0]; [commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(pcmd->TextureId) atIndex:0];
}
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:pcmd->ElemCount indexCount:pcmd->ElemCount
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32 indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
@ -479,7 +505,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
} }
__weak id weakSelf = self; __weak id weakSelf = self;
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>) { [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)
{
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf enqueueReusableBuffer:vertexBuffer]; [weakSelf enqueueReusableBuffer:vertexBuffer];
[weakSelf enqueueReusableBuffer:indexBuffer]; [weakSelf enqueueReusableBuffer:indexBuffer];