mirror of
https://github.com/ocornut/imgui.git
synced 2026-11-06 06:25:54 +01:00
Backends: Metal, Metal4: support rendering inside passes with multiple color attachments. (#9574)
Key the pipeline cache on all color attachment pixel formats of the render pass descriptor passed to backend's NewFrame().
This commit is contained in:
parent
71fc553bc4
commit
f502f9c980
@ -16,6 +16,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2026-10-06: Added support for render passes with multiple color attachments: we render to the first one and leave the others untouched. (#9574)
|
||||
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
|
||||
// 2026-04-28: Added support for standard draw callbacks (in platform_io): DrawCallback_SetSamplerLinear and DrawCallback_SetSamplerNearest. (#9378, #9381)
|
||||
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). (#9378)
|
||||
@ -58,14 +59,16 @@
|
||||
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;
|
||||
@end
|
||||
|
||||
#define IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS 8 // Metal's limit (see Metal Feature Set Tables). Not configurable.
|
||||
|
||||
// An object that encapsulates the data necessary to uniquely identify a
|
||||
// render pipeline state. These are used as cache keys.
|
||||
@interface FramebufferDescriptor : NSObject<NSCopying>
|
||||
@property (nonatomic, assign) unsigned long sampleCount;
|
||||
@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
|
||||
@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
|
||||
@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
|
||||
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor;
|
||||
- (MTLPixelFormat)colorPixelFormatAtIndex:(NSUInteger)index;
|
||||
@end
|
||||
|
||||
@interface MetalTexture : NSObject
|
||||
@ -477,23 +480,33 @@ void ImGui_ImplMetal_Shutdown()
|
||||
#pragma mark - FramebufferDescriptor implementation
|
||||
|
||||
@implementation FramebufferDescriptor
|
||||
{
|
||||
MTLPixelFormat _colorPixelFormats[IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS];
|
||||
}
|
||||
|
||||
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
|
||||
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
|
||||
for (NSUInteger n = 0; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++)
|
||||
_colorPixelFormats[n] = renderPassDescriptor.colorAttachments[n].texture.pixelFormat;
|
||||
_depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
|
||||
_stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (MTLPixelFormat)colorPixelFormatAtIndex:(NSUInteger)index
|
||||
{
|
||||
return _colorPixelFormats[index];
|
||||
}
|
||||
|
||||
- (nonnull id)copyWithZone:(nullable NSZone*)zone
|
||||
{
|
||||
FramebufferDescriptor* copy = [[FramebufferDescriptor allocWithZone:zone] init];
|
||||
copy.sampleCount = self.sampleCount;
|
||||
copy.colorPixelFormat = self.colorPixelFormat;
|
||||
memcpy(copy->_colorPixelFormats, _colorPixelFormats, sizeof(_colorPixelFormats));
|
||||
copy.depthPixelFormat = self.depthPixelFormat;
|
||||
copy.stencilPixelFormat = self.stencilPixelFormat;
|
||||
return copy;
|
||||
@ -502,10 +515,12 @@ void ImGui_ImplMetal_Shutdown()
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
NSUInteger sc = _sampleCount & 0x3;
|
||||
NSUInteger cf = _colorPixelFormat & 0x3FF;
|
||||
NSUInteger cf = _colorPixelFormats[0] & 0x3FF;
|
||||
NSUInteger df = _depthPixelFormat & 0x3FF;
|
||||
NSUInteger sf = _stencilPixelFormat & 0x3FF;
|
||||
NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;
|
||||
for (NSUInteger n = 1; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++)
|
||||
hash = hash * 31 + _colorPixelFormats[n];
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -515,7 +530,7 @@ void ImGui_ImplMetal_Shutdown()
|
||||
if (![other isKindOfClass:[FramebufferDescriptor class]])
|
||||
return NO;
|
||||
return other.sampleCount == self.sampleCount &&
|
||||
other.colorPixelFormat == self.colorPixelFormat &&
|
||||
memcmp(other->_colorPixelFormats, _colorPixelFormats, sizeof(_colorPixelFormats)) == 0 &&
|
||||
other.depthPixelFormat == self.depthPixelFormat &&
|
||||
other.stencilPixelFormat == self.stencilPixelFormat;
|
||||
}
|
||||
@ -661,7 +676,7 @@ void ImGui_ImplMetal_Shutdown()
|
||||
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
||||
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
|
||||
pipelineDescriptor.rasterSampleCount = self.framebufferDescriptor.sampleCount;
|
||||
pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;
|
||||
pipelineDescriptor.colorAttachments[0].pixelFormat = [self.framebufferDescriptor colorPixelFormatAtIndex:0];
|
||||
pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
|
||||
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
||||
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
@ -669,6 +684,11 @@ void ImGui_ImplMetal_Shutdown()
|
||||
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
||||
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
||||
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
for (NSUInteger n = 1; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++) // Don't write to other color attachments, if any.
|
||||
{
|
||||
pipelineDescriptor.colorAttachments[n].pixelFormat = [self.framebufferDescriptor colorPixelFormatAtIndex:n];
|
||||
pipelineDescriptor.colorAttachments[n].writeMask = MTLColorWriteMaskNone;
|
||||
}
|
||||
pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
|
||||
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2026-10-06: Added support for render passes with multiple color attachments: we render to the first one and leave the others untouched. (#9574)
|
||||
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
|
||||
// 2026-07-07: Metal 4: Added metal-cpp support. (#9461)
|
||||
// 2026-07-02: Metal 4: Added new Metal 4 backend implementation. (#9458)
|
||||
@ -46,14 +47,16 @@ struct ImGui_Metal4_ConstantData
|
||||
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;
|
||||
@end
|
||||
|
||||
#define IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS 8 // Metal's limit (see Metal Feature Set Tables). Not configurable.
|
||||
|
||||
// An object that encapsulates the data necessary to uniquely identify a
|
||||
// render pipeline state. These are used as cache keys.
|
||||
@interface FramebufferDescriptor : NSObject<NSCopying>
|
||||
@property (nonatomic, assign) unsigned long sampleCount;
|
||||
@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
|
||||
@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
|
||||
@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
|
||||
- (instancetype)initWithRenderPassDescriptor:(MTL4RenderPassDescriptor*)renderPassDescriptor;
|
||||
- (MTLPixelFormat)colorPixelFormatAtIndex:(NSUInteger)index;
|
||||
@end
|
||||
|
||||
@interface MetalTexture : NSObject
|
||||
@ -514,23 +517,33 @@ void ImGui_ImplMetal4_Shutdown()
|
||||
#pragma mark - FramebufferDescriptor implementation
|
||||
|
||||
@implementation FramebufferDescriptor
|
||||
{
|
||||
MTLPixelFormat _colorPixelFormats[IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS];
|
||||
}
|
||||
|
||||
- (instancetype)initWithRenderPassDescriptor:(MTL4RenderPassDescriptor*)renderPassDescriptor
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
|
||||
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
|
||||
for (NSUInteger n = 0; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++)
|
||||
_colorPixelFormats[n] = renderPassDescriptor.colorAttachments[n].texture.pixelFormat;
|
||||
_depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
|
||||
_stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (MTLPixelFormat)colorPixelFormatAtIndex:(NSUInteger)index
|
||||
{
|
||||
return _colorPixelFormats[index];
|
||||
}
|
||||
|
||||
- (nonnull id)copyWithZone:(nullable NSZone*)zone
|
||||
{
|
||||
FramebufferDescriptor* copy = [[FramebufferDescriptor allocWithZone:zone] init];
|
||||
copy.sampleCount = self.sampleCount;
|
||||
copy.colorPixelFormat = self.colorPixelFormat;
|
||||
memcpy(copy->_colorPixelFormats, _colorPixelFormats, sizeof(_colorPixelFormats));
|
||||
copy.depthPixelFormat = self.depthPixelFormat;
|
||||
copy.stencilPixelFormat = self.stencilPixelFormat;
|
||||
return copy;
|
||||
@ -539,10 +552,12 @@ void ImGui_ImplMetal4_Shutdown()
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
NSUInteger sc = _sampleCount & 0x3;
|
||||
NSUInteger cf = _colorPixelFormat & 0x3FF;
|
||||
NSUInteger cf = _colorPixelFormats[0] & 0x3FF;
|
||||
NSUInteger df = _depthPixelFormat & 0x3FF;
|
||||
NSUInteger sf = _stencilPixelFormat & 0x3FF;
|
||||
NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;
|
||||
for (NSUInteger n = 1; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++)
|
||||
hash = hash * 31 + _colorPixelFormats[n];
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -552,7 +567,7 @@ void ImGui_ImplMetal4_Shutdown()
|
||||
if (![other isKindOfClass:[FramebufferDescriptor class]])
|
||||
return NO;
|
||||
return other.sampleCount == self.sampleCount &&
|
||||
other.colorPixelFormat == self.colorPixelFormat &&
|
||||
memcmp(other->_colorPixelFormats, _colorPixelFormats, sizeof(_colorPixelFormats)) == 0 &&
|
||||
other.depthPixelFormat == self.depthPixelFormat &&
|
||||
other.stencilPixelFormat == self.stencilPixelFormat;
|
||||
}
|
||||
@ -719,7 +734,7 @@ fragment half4 fragment_main(VertexOut in [[stage_in]],
|
||||
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
||||
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
|
||||
pipelineDescriptor.rasterSampleCount = self.framebufferDescriptor.sampleCount;
|
||||
pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;
|
||||
pipelineDescriptor.colorAttachments[0].pixelFormat = [self.framebufferDescriptor colorPixelFormatAtIndex:0];
|
||||
pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
|
||||
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
||||
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
@ -727,6 +742,11 @@ fragment half4 fragment_main(VertexOut in [[stage_in]],
|
||||
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
||||
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
||||
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
for (NSUInteger n = 1; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++) // Don't write to other color attachments, if any.
|
||||
{
|
||||
pipelineDescriptor.colorAttachments[n].pixelFormat = [self.framebufferDescriptor colorPixelFormatAtIndex:n];
|
||||
pipelineDescriptor.colorAttachments[n].writeMask = MTLColorWriteMaskNone;
|
||||
}
|
||||
pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
|
||||
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
|
||||
|
||||
|
||||
@ -152,6 +152,9 @@ Other Changes:
|
||||
- Style Editor: fixed style/colors combo box applying style when opening Combo.
|
||||
- Backends:
|
||||
- QNX: added QNX Screen backend. (#9492) [@mgorchak-blackberry]
|
||||
- Metal, Metal4: added support for rendering inside a render pass with multiple color
|
||||
attachments (e.g. when merged with other passes): we render to the first color attachment
|
||||
and leave the other ones untouched. (#9574) [@tqjxlm]
|
||||
- OpenGL2, OpenGL3: added support for `platform_io.DrawCallback_SetSamplerFromTex` draw
|
||||
callback to request using the sampler associated already associated to a texture. (#9378)
|
||||
- OpenGL2, OpenGL3: fixed `DrawCallback_ResetRenderState` handler not reseting all states
|
||||
@ -173,8 +176,7 @@ Other Changes:
|
||||
- Vulkan: added for support for multiple Vulkan contexts with custom loaders. (#6616) [@lstalmir]
|
||||
- Vulkan: added support for rendering inside a render pass with multiple color attachments
|
||||
(e.g. when merged with other passes): we render to the first color attachment and leave the
|
||||
other ones untouched. (with dynamic rendering, `PipelineRenderingCreateInfo` may describe multiple
|
||||
color attachments. This requires the `independentBlend` device feature). (#9574) [@tqjxlm]
|
||||
other ones untouched. (#9574) [@tqjxlm]
|
||||
- WebGPU: fixed passing non-integer sizes to `wgpuRenderPassEncoderSetViewport()`
|
||||
when `FramebufferScale` is >1.0f. (#9515, #8628) [@WayU]
|
||||
- WebGPU: update to build with wgpu-native 29.0+. (#9377, #9532, #9530) [@lucascompython, @ivan-enzhaev]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user