parent
a23e9fb1b5
commit
df71e28084
@ -6,9 +6,9 @@
|
|||||||
// [X] Renderer: User texture binding. Use 'MTLTexture.gpuResourceID' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
// [X] Renderer: User texture binding. Use 'MTLTexture.gpuResourceID' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||||
|
// [X] Renderer: Multi-viewport support (multiple windows).
|
||||||
// Missing features or Issues:
|
// Missing features or Issues:
|
||||||
// [ ] Texture view pool support? Reevaluate which type to use for ImtextureID.
|
// [ ] Texture view pool support? Reevaluate which type to use for ImtextureID.
|
||||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
|
||||||
|
|
||||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
|||||||
@ -6,9 +6,10 @@
|
|||||||
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||||
|
// [X] Renderer: Multi-viewport support (multiple windows).
|
||||||
|
|
||||||
// Missing features or Issues:
|
// Missing features or Issues:
|
||||||
// [ ] Texture view pool support? Reevaluate which type to use for ImtextureID.
|
// [ ] Texture view pool support? Reevaluate which type to use for ImtextureID.
|
||||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
|
||||||
|
|
||||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
@ -33,11 +34,21 @@
|
|||||||
#include <Metal/Metal.hpp>
|
#include <Metal/Metal.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
static void ImGui_ImplMetal_InitMultiViewportSupport();
|
||||||
|
static void ImGui_ImplMetal_ShutdownMultiViewportSupport();
|
||||||
|
static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows();
|
||||||
|
static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows();
|
||||||
|
|
||||||
#pragma mark - Support classes and structs
|
#pragma mark - Support classes and structs
|
||||||
|
|
||||||
|
#define METAL_IMGUI_VIEWPORTS_PER_CHUNK 64
|
||||||
|
|
||||||
struct ImGui_Metal4_ConstantData
|
struct ImGui_Metal4_ConstantData
|
||||||
{
|
{
|
||||||
float ModelViewProjectionMatrix[4][4];
|
// 1 projection matrix is encoded as 4x4 float.
|
||||||
|
// Store up to 64 of them in same constant buffer, so multiple viewports can use same constant buffer.
|
||||||
|
float ModelViewProjectionMatrix[METAL_IMGUI_VIEWPORTS_PER_CHUNK][4][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
@interface MetalBuffer : NSObject
|
@interface MetalBuffer : NSObject
|
||||||
@ -76,13 +87,15 @@ struct ImGui_Metal4_ConstantData
|
|||||||
@property (nonatomic, strong) NSMutableDictionary* renderPipelineStateCache;
|
@property (nonatomic, strong) NSMutableDictionary* renderPipelineStateCache;
|
||||||
@property (nonatomic, assign) NSUInteger framesInFlight;
|
@property (nonatomic, assign) NSUInteger framesInFlight;
|
||||||
@property (nonatomic, assign) NSUInteger currentFrameSlot;
|
@property (nonatomic, assign) NSUInteger currentFrameSlot;
|
||||||
@property (nonatomic, strong) NSArray<id<MTLBuffer>>* constantBuffers;
|
|
||||||
@property (nonatomic, assign) ImGui_Metal4_ConstantData** constantBufferContentsArray;
|
|
||||||
@property (nonatomic, strong) NSMutableArray<NSMutableArray<MetalBuffer*>*>* bufferCaches;
|
@property (nonatomic, strong) NSMutableArray<NSMutableArray<MetalBuffer*>*>* bufferCaches;
|
||||||
@property (nonatomic, strong) NSObject* bufferCacheLock;
|
@property (nonatomic, strong) NSObject* bufferCacheLock;
|
||||||
@property (nonatomic, assign) double lastBufferCachePurge;
|
@property (nonatomic, assign) double lastBufferCachePurge;
|
||||||
- (id<MTLBuffer>)currentConstantBuffer;
|
@property (nonatomic, strong) NSArray<id<MTLSharedEvent>>* events; // for tracking when a commands are complete to reset allocator
|
||||||
- (ImGui_Metal4_ConstantData*)currentConstantBufferContents;
|
@property (nonatomic) uint64_t eventValue;
|
||||||
|
@property (nonatomic, strong) NSArray<id<MTL4CommandAllocator>>* commandAllocators;
|
||||||
|
@property (nonatomic, strong) NSMutableArray<NSMutableArray<id<MTLBuffer>>*>* constantBuffers;
|
||||||
|
@property (nonatomic) uint64_t constantBufferChunkCount;
|
||||||
|
@property (nonatomic) uint64_t currentConstantBufferIndex;
|
||||||
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
|
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
|
||||||
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device;
|
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device;
|
||||||
@end
|
@end
|
||||||
@ -145,6 +158,10 @@ void ImGui_ImplMetal4_NewFrame(MTL4RenderPassDescriptor* renderPassDescriptor, i
|
|||||||
bd->SharedMetalContext.currentFrameSlot = (NSUInteger)frameInFlightIndex;
|
bd->SharedMetalContext.currentFrameSlot = (NSUInteger)frameInFlightIndex;
|
||||||
if (bd->SharedMetalContext.depthStencilState == nil)
|
if (bd->SharedMetalContext.depthStencilState == nil)
|
||||||
ImGui_ImplMetal4_CreateDeviceObjects(bd->SharedMetalContext.device);
|
ImGui_ImplMetal4_CreateDeviceObjects(bd->SharedMetalContext.device);
|
||||||
|
|
||||||
|
bd->SharedMetalContext.currentConstantBufferIndex = 0;
|
||||||
|
[bd->SharedMetalContext.events[frameInFlightIndex] waitUntilSignaledValue:bd->SharedMetalContext.eventValue timeoutMS:UINT64_MAX];
|
||||||
|
[bd->SharedMetalContext.commandAllocators[frameInFlightIndex] reset];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui_ImplMetal4_SetupRenderState(ImDrawData* draw_data, id<MTL4CommandBuffer> commandBuffer,
|
static void ImGui_ImplMetal4_SetupRenderState(ImDrawData* draw_data, id<MTL4CommandBuffer> commandBuffer,
|
||||||
@ -183,11 +200,18 @@ static void ImGui_ImplMetal4_SetupRenderState(ImDrawData* draw_data, id<MTL4Comm
|
|||||||
{ 0.0f, 0.0f, 1/(F-N), 0.0f },
|
{ 0.0f, 0.0f, 1/(F-N), 0.0f },
|
||||||
{ (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
|
{ (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
|
||||||
};
|
};
|
||||||
ImGui_Metal4_ConstantData* constantBufferContents = [bd->SharedMetalContext currentConstantBufferContents];
|
|
||||||
memcpy(constantBufferContents->ModelViewProjectionMatrix, ortho_projection, sizeof(ortho_projection));
|
int currentChunk = (int)((float)bd->SharedMetalContext.currentConstantBufferIndex / (float)METAL_IMGUI_VIEWPORTS_PER_CHUNK);
|
||||||
|
int currentIndex = bd->SharedMetalContext.currentConstantBufferIndex % METAL_IMGUI_VIEWPORTS_PER_CHUNK;
|
||||||
|
|
||||||
|
int currentFrameIndex = (int)bd->SharedMetalContext.currentFrameSlot;
|
||||||
|
id<MTLBuffer> constantBuffer = bd->SharedMetalContext.constantBuffers[currentFrameIndex][currentChunk];
|
||||||
|
ImGui_Metal4_ConstantData* constantBufferContents = (ImGui_Metal4_ConstantData*)constantBuffer.contents;
|
||||||
|
|
||||||
|
memcpy(&constantBufferContents->ModelViewProjectionMatrix[currentIndex], ortho_projection, sizeof(ortho_projection));
|
||||||
|
|
||||||
id<MTL4ArgumentTable> argumentTable = bd->SharedMetalContext.argumentTable;
|
id<MTL4ArgumentTable> argumentTable = bd->SharedMetalContext.argumentTable;
|
||||||
[argumentTable setAddress:[bd->SharedMetalContext currentConstantBuffer].gpuAddress atIndex:1];
|
[argumentTable setAddress:constantBuffer.gpuAddress+(uint64_t)currentIndex * sizeof(constantBufferContents->ModelViewProjectionMatrix[0]) atIndex:1];
|
||||||
[argumentTable setAddress:(vertexBuffer.buffer.gpuAddress + vertexBufferOffset) attributeStride:sizeof(ImDrawVert) atIndex:0];
|
[argumentTable setAddress:(vertexBuffer.buffer.gpuAddress + vertexBufferOffset) attributeStride:sizeof(ImDrawVert) atIndex:0];
|
||||||
[argumentTable setSamplerState:bd->SharedMetalContext.samplerStateLinear.gpuResourceID atIndex:0];
|
[argumentTable setSamplerState:bd->SharedMetalContext.samplerStateLinear.gpuResourceID atIndex:0];
|
||||||
[commandEncoder setArgumentTable:argumentTable atStages:MTLRenderStageVertex | MTLRenderStageFragment];
|
[commandEncoder setArgumentTable:argumentTable atStages:MTLRenderStageVertex | MTLRenderStageFragment];
|
||||||
@ -234,7 +258,22 @@ void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, id<MTL4CommandBuffer
|
|||||||
MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
|
MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
|
||||||
|
|
||||||
bd->RenderCommandEncoder = commandEncoder;
|
bd->RenderCommandEncoder = commandEncoder;
|
||||||
|
|
||||||
|
// check if more chunks are required
|
||||||
|
const int chunksRequired = 1 + (int)((float)bd->SharedMetalContext.currentConstantBufferIndex / (float)METAL_IMGUI_VIEWPORTS_PER_CHUNK);
|
||||||
|
if (chunksRequired > bd->SharedMetalContext.constantBufferChunkCount)
|
||||||
|
{
|
||||||
|
for (NSUInteger i = 0; i < bd->SharedMetalContext.framesInFlight; i++)
|
||||||
|
{
|
||||||
|
id<MTLBuffer> buffer = [bd->SharedMetalContext.device newBufferWithLength:sizeof(ImGui_Metal4_ConstantData) options:MTLResourceStorageModeShared];
|
||||||
|
[bd->SharedMetalContext.constantBuffers[i] addObject:buffer];
|
||||||
|
[bd->SharedMetalContext.residencySet addAllocation:buffer];
|
||||||
|
}
|
||||||
|
bd->SharedMetalContext.constantBufferChunkCount++;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui_ImplMetal4_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0);
|
ImGui_ImplMetal4_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0);
|
||||||
|
bd->SharedMetalContext.currentConstantBufferIndex++;
|
||||||
|
|
||||||
// Will project scissor/clipping rectangles into framebuffer space
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
@ -415,27 +454,33 @@ bool ImGui_ImplMetal4_CreateDeviceObjects(id<MTLDevice> device)
|
|||||||
samplerDescriptor.mipFilter = MTLSamplerMipFilterNearest;
|
samplerDescriptor.mipFilter = MTLSamplerMipFilterNearest;
|
||||||
bd->SharedMetalContext.samplerStateNearest = [device newSamplerStateWithDescriptor:samplerDescriptor];
|
bd->SharedMetalContext.samplerStateNearest = [device newSamplerStateWithDescriptor:samplerDescriptor];
|
||||||
|
|
||||||
NSMutableArray<id<MTLBuffer>>* constantBuffers = [NSMutableArray array];
|
NSMutableArray<id<MTL4CommandAllocator>>* commandAllocators = [NSMutableArray array];
|
||||||
ImGui_Metal4_ConstantData** constantBufferContentsArray = (ImGui_Metal4_ConstantData**)malloc(sizeof(ImGui_Metal4_ConstantData*) * bd->SharedMetalContext.framesInFlight);
|
NSMutableArray<id<MTLSharedEvent>>* events = [NSMutableArray array];
|
||||||
|
bd->SharedMetalContext.constantBuffers = [NSMutableArray array];
|
||||||
for (NSUInteger i = 0; i < bd->SharedMetalContext.framesInFlight; i++)
|
for (NSUInteger i = 0; i < bd->SharedMetalContext.framesInFlight; i++)
|
||||||
{
|
{
|
||||||
id<MTLBuffer> constantBuffer = [device newBufferWithLength:sizeof(ImGui_Metal4_ConstantData) options:MTLResourceStorageModeShared];
|
events[i] = [device newSharedEvent];
|
||||||
[constantBuffers addObject:constantBuffer];
|
commandAllocators[i] = [device newCommandAllocator];
|
||||||
constantBufferContentsArray[i] = (ImGui_Metal4_ConstantData*)constantBuffer.contents;
|
bd->SharedMetalContext.constantBuffers[i] = [NSMutableArray array];
|
||||||
[bd->SharedMetalContext.residencySet addAllocation:constantBuffer];
|
id<MTLBuffer> buffer = [device newBufferWithLength:sizeof(ImGui_Metal4_ConstantData) options:MTLResourceStorageModeShared];
|
||||||
|
[bd->SharedMetalContext.constantBuffers[i] addObject:buffer];
|
||||||
|
[bd->SharedMetalContext.residencySet addAllocation:buffer];
|
||||||
}
|
}
|
||||||
bd->SharedMetalContext.constantBuffers = constantBuffers;
|
bd->SharedMetalContext.constantBufferChunkCount = 1;
|
||||||
bd->SharedMetalContext.constantBufferContentsArray = constantBufferContentsArray;
|
bd->SharedMetalContext.events = events;
|
||||||
|
|
||||||
MTL4ArgumentTableDescriptor* argumentTableDescriptor = [[MTL4ArgumentTableDescriptor alloc] init];
|
MTL4ArgumentTableDescriptor* argumentTableDescriptor = [[MTL4ArgumentTableDescriptor alloc] init];
|
||||||
argumentTableDescriptor.maxBufferBindCount = 8;
|
argumentTableDescriptor.maxBufferBindCount = 2; // vertex buffer + constant buffer
|
||||||
argumentTableDescriptor.maxTextureBindCount = 8;
|
argumentTableDescriptor.maxTextureBindCount = 1; // font atlas or user texture
|
||||||
argumentTableDescriptor.maxSamplerStateBindCount = 8;
|
argumentTableDescriptor.maxSamplerStateBindCount = 2;
|
||||||
argumentTableDescriptor.supportAttributeStrides = YES; // required: vertex buffer is bound via setAddress:stride:atIndex: for stage_in fetch
|
argumentTableDescriptor.supportAttributeStrides = YES; // required: vertex buffer is bound via setAddress:stride:atIndex: for stage_in fetch
|
||||||
|
|
||||||
|
bd->SharedMetalContext.commandAllocators = commandAllocators;
|
||||||
|
|
||||||
bd->SharedMetalContext.argumentTable = [device newArgumentTableWithDescriptor:argumentTableDescriptor error:&error];
|
bd->SharedMetalContext.argumentTable = [device newArgumentTableWithDescriptor:argumentTableDescriptor error:&error];
|
||||||
IM_ASSERT(bd->SharedMetalContext.argumentTable != nil && error == nil);
|
IM_ASSERT(bd->SharedMetalContext.argumentTable != nil && error == nil);
|
||||||
|
|
||||||
|
ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,6 +496,8 @@ void ImGui_ImplMetal4_DestroyDeviceObjects()
|
|||||||
[bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
|
[bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
|
||||||
bd->SharedMetalContext.samplerStateLinear = nil;
|
bd->SharedMetalContext.samplerStateLinear = nil;
|
||||||
bd->SharedMetalContext.samplerStateNearest = nil;
|
bd->SharedMetalContext.samplerStateNearest = nil;
|
||||||
|
ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows();
|
||||||
|
[bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplMetal4_Init(id<MTLDevice> device, id<MTL4CommandQueue> commandQueue, int framesInFlight)
|
bool ImGui_ImplMetal4_Init(id<MTLDevice> device, id<MTL4CommandQueue> commandQueue, int framesInFlight)
|
||||||
@ -465,6 +512,7 @@ bool ImGui_ImplMetal4_Init(id<MTLDevice> device, id<MTL4CommandQueue> commandQue
|
|||||||
io.BackendRendererName = "imgui_impl_metal4";
|
io.BackendRendererName = "imgui_impl_metal4";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||||
|
|
||||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
platform_io.DrawCallback_ResetRenderState = ImGui_ImplMetal4_DrawCallback_ResetRenderState;
|
platform_io.DrawCallback_ResetRenderState = ImGui_ImplMetal4_DrawCallback_ResetRenderState;
|
||||||
@ -479,6 +527,8 @@ bool ImGui_ImplMetal4_Init(id<MTLDevice> device, id<MTL4CommandQueue> commandQue
|
|||||||
for (NSUInteger i = 0; i < framesInFlight; i++)
|
for (NSUInteger i = 0; i < framesInFlight; i++)
|
||||||
[bufferCaches addObject:[NSMutableArray array]];
|
[bufferCaches addObject:[NSMutableArray array]];
|
||||||
bd->SharedMetalContext.bufferCaches = bufferCaches;
|
bd->SharedMetalContext.bufferCaches = bufferCaches;
|
||||||
|
|
||||||
|
ImGui_ImplMetal_InitMultiViewportSupport();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,6 +540,7 @@ void ImGui_ImplMetal4_Shutdown()
|
|||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
|
||||||
|
ImGui_ImplMetal_ShutdownMultiViewportSupport();
|
||||||
ImGui_ImplMetal4_DestroyDeviceObjects();
|
ImGui_ImplMetal4_DestroyDeviceObjects();
|
||||||
ImGui_ImplMetal4_DestroyBackendData();
|
ImGui_ImplMetal4_DestroyBackendData();
|
||||||
|
|
||||||
@ -587,17 +638,6 @@ void ImGui_ImplMetal4_Shutdown()
|
|||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
free(_constantBufferContentsArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id<MTLBuffer>)currentConstantBuffer
|
|
||||||
{
|
|
||||||
return self.constantBuffers[self.currentFrameSlot];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (ImGui_Metal4_ConstantData*)currentConstantBufferContents
|
|
||||||
{
|
|
||||||
return self.constantBufferContentsArray[self.currentFrameSlot];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
|
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
|
||||||
@ -739,6 +779,159 @@ fragment half4 fragment_main(VertexOut in [[stage_in]],
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Multi-viewport support
|
||||||
|
|
||||||
|
#import <QuartzCore/CAMetalLayer.h>
|
||||||
|
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||||
|
// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
|
||||||
|
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct ImGuiViewportDataMetal
|
||||||
|
{
|
||||||
|
CAMetalLayer* MetalLayer;
|
||||||
|
id<MTLCommandQueue> CommandQueue;
|
||||||
|
MTL4RenderPassDescriptor* RenderPassDescriptor;
|
||||||
|
void* Handle = nullptr;
|
||||||
|
bool FirstFrame = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_CreateWindow(ImGuiViewport* viewport)
|
||||||
|
{
|
||||||
|
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
|
||||||
|
ImGuiViewportDataMetal* data = IM_NEW(ImGuiViewportDataMetal)();
|
||||||
|
viewport->RendererUserData = data;
|
||||||
|
|
||||||
|
// PlatformHandleRaw should always be a NSWindow*, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
||||||
|
// Some back-ends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the NSWindow*.
|
||||||
|
void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle;
|
||||||
|
IM_ASSERT(handle != nullptr);
|
||||||
|
|
||||||
|
id<MTLDevice> device = bd->SharedMetalContext.device;
|
||||||
|
CAMetalLayer* layer = [CAMetalLayer layer];
|
||||||
|
layer.device = device;
|
||||||
|
layer.framebufferOnly = YES;
|
||||||
|
layer.pixelFormat = bd->SharedMetalContext.framebufferDescriptor.colorPixelFormat;
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
NSWindow* window = (__bridge NSWindow*)handle;
|
||||||
|
NSView* view = window.contentView;
|
||||||
|
view.layer = layer;
|
||||||
|
view.wantsLayer = YES;
|
||||||
|
#endif
|
||||||
|
data->MetalLayer = layer;
|
||||||
|
data->CommandQueue = [device newCommandQueue];
|
||||||
|
data->RenderPassDescriptor = [[MTL4RenderPassDescriptor alloc] init];
|
||||||
|
data->Handle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_DestroyWindow(ImGuiViewport* viewport)
|
||||||
|
{
|
||||||
|
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
|
||||||
|
if (ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData)
|
||||||
|
IM_DELETE(data);
|
||||||
|
viewport->RendererUserData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static CGSize MakeScaledSize(CGSize size, CGFloat scale)
|
||||||
|
{
|
||||||
|
return CGSizeMake(size.width * scale, size.height * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||||
|
{
|
||||||
|
ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData;
|
||||||
|
data->MetalLayer.drawableSize = MakeScaledSize(CGSizeMake(size.x, size.y), viewport->DpiScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*)
|
||||||
|
{
|
||||||
|
ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData;
|
||||||
|
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle;
|
||||||
|
NSWindow* window = (__bridge NSWindow*)handle;
|
||||||
|
|
||||||
|
// Always render the first frame, regardless of occlusionState, to avoid an initial flicker
|
||||||
|
if ((window.occlusionState & NSWindowOcclusionStateVisible) == 0 && !data->FirstFrame)
|
||||||
|
{
|
||||||
|
// Do not render windows which are completely occluded. Calling -[CAMetalLayer nextDrawable] will hang for
|
||||||
|
// approximately 1 second if the Metal layer is completely occluded.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->FirstFrame = false;
|
||||||
|
|
||||||
|
float fb_scale = (float)window.backingScaleFactor;
|
||||||
|
if (data->MetalLayer.contentsScale != fb_scale)
|
||||||
|
{
|
||||||
|
data->MetalLayer.contentsScale = fb_scale;
|
||||||
|
data->MetalLayer.drawableSize = MakeScaledSize(window.frame.size, fb_scale);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
id <CAMetalDrawable> drawable = [data->MetalLayer nextDrawable];
|
||||||
|
if (drawable == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MTL4RenderPassDescriptor* renderPassDescriptor = data->RenderPassDescriptor;
|
||||||
|
renderPassDescriptor.colorAttachments[0].texture = drawable.texture;
|
||||||
|
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 0);
|
||||||
|
if ((viewport->Flags & ImGuiViewportFlags_NoRendererClear) == 0)
|
||||||
|
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||||
|
|
||||||
|
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
|
||||||
|
id <MTL4CommandBuffer> commandBuffer = [bd->SharedMetalContext.device newCommandBuffer];
|
||||||
|
[commandBuffer beginCommandBufferWithAllocator:bd->SharedMetalContext.commandAllocators[bd->SharedMetalContext.currentFrameSlot]];
|
||||||
|
|
||||||
|
id <MTL4RenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||||
|
ImGui_ImplMetal4_RenderDrawData(viewport->DrawData, commandBuffer, renderEncoder);
|
||||||
|
[renderEncoder endEncoding];
|
||||||
|
[commandBuffer endCommandBuffer];
|
||||||
|
|
||||||
|
[bd->SharedMetalContext.commandQueue waitForDrawable:drawable];
|
||||||
|
[bd->SharedMetalContext.commandQueue commit:&commandBuffer count:1];
|
||||||
|
[bd->SharedMetalContext.commandQueue signalDrawable:drawable];
|
||||||
|
[drawable present];
|
||||||
|
[bd->SharedMetalContext.commandQueue signalEvent:bd->SharedMetalContext.events[bd->SharedMetalContext.currentFrameSlot] value:++(bd->SharedMetalContext.eventValue)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_InitMultiViewportSupport()
|
||||||
|
{
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
platform_io.Renderer_CreateWindow = ImGui_ImplMetal_CreateWindow;
|
||||||
|
platform_io.Renderer_DestroyWindow = ImGui_ImplMetal_DestroyWindow;
|
||||||
|
platform_io.Renderer_SetWindowSize = ImGui_ImplMetal_SetWindowSize;
|
||||||
|
platform_io.Renderer_RenderWindow = ImGui_ImplMetal_RenderWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_ShutdownMultiViewportSupport()
|
||||||
|
{
|
||||||
|
ImGui::DestroyPlatformWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows()
|
||||||
|
{
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||||
|
if (!platform_io.Viewports[i]->RendererUserData)
|
||||||
|
ImGui_ImplMetal_CreateWindow(platform_io.Viewports[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows()
|
||||||
|
{
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||||
|
if (platform_io.Viewports[i]->RendererUserData)
|
||||||
|
ImGui_ImplMetal_DestroyWindow(platform_io.Viewports[i]);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
#endif // #ifndef IMGUI_DISABLE
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
|
|||||||
@ -177,6 +177,8 @@ Docking+Viewports Branch:
|
|||||||
- Fixed behavior change/regression in 1.92.8 where a window using the
|
- Fixed behavior change/regression in 1.92.8 where a window using the
|
||||||
ImGuiWindowFlags_AlwaysAutoResize flag would have ItemWidth default
|
ImGuiWindowFlags_AlwaysAutoResize flag would have ItemWidth default
|
||||||
change when docked. (#9355, #9443) [@reybits]
|
change when docked. (#9355, #9443) [@reybits]
|
||||||
|
- Backends:
|
||||||
|
- Metal4: added multi-viewport support. (#9465, #9451) [@hoffstadt]
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user