From 89ea72b341147a78c0424b07238424f639adb492 Mon Sep 17 00:00:00 2001 From: Greg Wells Date: Wed, 9 Jul 2025 13:27:06 -0400 Subject: [PATCH] multisampling in metal --- .../src/commands/commands/metal_commands.m | 7 ++++-- .../metal/src/devices/metal_output_device.m | 6 ----- .../metal/src/devices/metal_output_devices.h | 1 - .../src/framebuffers/metal_framebuffer.m | 22 +++++++++++++++---- .../metal_graphics_pipeline.m | 2 ++ .../apis/metal/src/present/metal_present.m | 1 - .../apis/metal/src/surface/metal_surface.m | 7 ++++++ .../apis/metal/src/texture/metal_texture.h | 5 +++++ .../apis/metal/src/texture/metal_texture.m | 18 ++++++++++++--- .../src/vulkan_surface/vulkan_surface.c | 7 ++++-- .../platform_macos/gryphn_platform_macos.m | 3 ++- 11 files changed, 59 insertions(+), 20 deletions(-) diff --git a/projects/apis/metal/src/commands/commands/metal_commands.m b/projects/apis/metal/src/commands/commands/metal_commands.m index ba24f4d..1894be1 100644 --- a/projects/apis/metal/src/commands/commands/metal_commands.m +++ b/projects/apis/metal/src/commands/commands/metal_commands.m @@ -1,5 +1,7 @@ #include "metal_commands.h" #include "shader_module/metal_shader_module.h" +#include "renderpass/metal_render_pass.h" +#include "utils/math/gryphn_math.h" void metelBeginRenderPass(gnCommandBuffer buffer, gnRenderPassInfo passInfo) { int currentColorAttachment = 0; @@ -127,8 +129,9 @@ void metalBindUniform(gnCommandBufferHandle buffer, gnUniform uniform, uint32_t ]; } else if (uniform->uniform->bindings[i].type == GN_IMAGE_DESCRIPTOR) { gnImageUniformInfo info = *(gnImageUniformInfo*)uniform->uniform->bindings[i].data; - [encoder setFragmentTexture:info.texture->texture->texture atIndex: - buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->fragmentShaderMaps.sets[set].bindings[info.binding]]; + uint32_t index = buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->fragmentShaderMaps.sets[set].bindings[info.binding]; + [encoder setFragmentTexture:info.texture->texture->texture atIndex:index]; + [encoder setFragmentSamplerState:info.texture->texture->sampler atIndex:index]; } } } diff --git a/projects/apis/metal/src/devices/metal_output_device.m b/projects/apis/metal/src/devices/metal_output_device.m index 11df6d5..820131a 100644 --- a/projects/apis/metal/src/devices/metal_output_device.m +++ b/projects/apis/metal/src/devices/metal_output_device.m @@ -9,12 +9,6 @@ gnReturnCode createMetalOutputDevice(gnOutputDeviceHandle outputDevice, gnInstan outputDevice->outputDevice = malloc(sizeof(gnPlatformOutputDevice)); outputDevice->outputDevice->device = deviceInfo.physicalDevice.physicalDevice->device.retain; outputDevice->outputDevice->transferQueue = outputDevice->outputDevice->device.newCommandQueue; - // outputDevice->outputDevice->queueCount = deviceInfo.queueInfoCount; - // outputDevice->outputDevice->queues = malloc(sizeof(id) * deviceInfo.queueInfoCount); - // for (int i = 0; i < deviceInfo.queueInfoCount; i++) { - // outputDevice->outputDevice->queues[i] = outputDevice->outputDevice->device.newCommandQueue; - // } - return GN_SUCCESS; } diff --git a/projects/apis/metal/src/devices/metal_output_devices.h b/projects/apis/metal/src/devices/metal_output_devices.h index 4960bab..5617a19 100644 --- a/projects/apis/metal/src/devices/metal_output_devices.h +++ b/projects/apis/metal/src/devices/metal_output_devices.h @@ -14,7 +14,6 @@ struct gnPlatformOutputDevice_t { id executingCommandBuffer; id transferQueue; - // id framebuffer; } gnPlatformOutputDevice; gnPhysicalDevice* getMetalDevices(gnInstanceHandle instance, uint32_t* deviceCount); diff --git a/projects/apis/metal/src/framebuffers/metal_framebuffer.m b/projects/apis/metal/src/framebuffers/metal_framebuffer.m index 57818d7..2866908 100644 --- a/projects/apis/metal/src/framebuffers/metal_framebuffer.m +++ b/projects/apis/metal/src/framebuffers/metal_framebuffer.m @@ -28,6 +28,13 @@ MTLStoreAction mtlGryphnStoreOperation(gnStoreOperation storeOperation) { } } +MTLStoreAction mtlGryphnStoreOperationResolve(gnStoreOperation storeOperation) { + switch (storeOperation) { + case GN_STORE_OPERATION_STORE: return MTLStoreActionStoreAndMultisampleResolve; + case GN_STORE_OPERATION_DONT_CARE: return MTLStoreActionDontCare; + } +} + gnReturnCode createMetalFramebuffer(gnFramebuffer framebuffer, gnOutputDevice device, gnFramebufferInfo info) { framebuffer->framebuffer = malloc(sizeof(struct gnPlatformFramebuffer_t)); if (info.attachmentCount != info.renderPassDescriptor->info.attachmentCount) { @@ -45,13 +52,20 @@ gnReturnCode createMetalFramebuffer(gnFramebuffer framebuffer, gnOutputDevice de [framebuffer->framebuffer->subpasses[i] setRenderTargetWidth:info.size.x]; [framebuffer->framebuffer->subpasses[i] setRenderTargetHeight:info.size.y]; + gnBool resolve = !(info.renderPassDescriptor->info.subpassInfos[i].resolveAttachments == NULL); + for (int c = 0; c < info.renderPassDescriptor->info.subpassInfos[i].colorAttachmentCount; c++) { - uint32_t attachmentIndex = info.renderPassDescriptor->info.subpassInfos[i].colorAttachments[i].index; + uint32_t attachmentIndex = info.renderPassDescriptor->info.subpassInfos[i].colorAttachments[c].index, resolveAttachemntIndex = 0; MTLRenderPassColorAttachmentDescriptor* color = framebuffer->framebuffer->subpasses[i].colorAttachments[c]; color.texture = info.attachments[attachmentIndex]->texture->texture; - + if (resolve) { + resolveAttachemntIndex = info.renderPassDescriptor->info.subpassInfos[i].resolveAttachments[c].index; + color.resolveTexture = info.attachments[resolveAttachemntIndex]->texture->texture; + color.storeAction = mtlGryphnStoreOperationResolve(info.renderPassDescriptor->info.attachmentInfos[attachmentIndex].storeOperation); + } else { + color.storeAction = mtlGryphnStoreOperation(info.renderPassDescriptor->info.attachmentInfos[attachmentIndex].storeOperation); + } color.loadAction = mtlGryphnLoadOperation(info.renderPassDescriptor->info.attachmentInfos[attachmentIndex].loadOperation); - color.storeAction = mtlGryphnStoreOperation(info.renderPassDescriptor->info.attachmentInfos[attachmentIndex].storeOperation); if (color.loadAction == MTLLoadActionClear) color.clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0); @@ -66,7 +80,7 @@ gnReturnCode createMetalFramebuffer(gnFramebuffer framebuffer, gnOutputDevice de depthAttachment.clearDepth = 1.0f; MTLRenderPassStencilAttachmentDescriptor* stencilAttachment = framebuffer->framebuffer->subpasses[attachmentIndex].stencilAttachment; - stencilAttachment.texture = info.attachments[i]->texture->texture; + stencilAttachment.texture = info.attachments[attachmentIndex]->texture->texture; } } diff --git a/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.m b/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.m index bbe27e3..96aba06 100644 --- a/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.m +++ b/projects/apis/metal/src/pipelines/graphics_pipeline/metal_graphics_pipeline.m @@ -3,6 +3,7 @@ #include "debugger/gryphn_debugger.h" #include "shader_module/metal_shader_module.h" #include "surface/metal_surface.h" +#include "texture/metal_texture.h" #include "utils/math/gryphn_vec3.h" @@ -44,6 +45,7 @@ MTLCompareFunction mtlGrypnCompareOperation(gnCompareOperation operation) { gnReturnCode createMetalGraphicsPipeline(gnGraphicsPipeline graphicsPipeline, gnOutputDevice device, gnGraphicsPipelineInfo info) { graphicsPipeline->graphicsPipeline = malloc(sizeof(struct gnPlatformGraphicsPipeline_t)); MTLRenderPipelineDescriptor* descriptor = [[MTLRenderPipelineDescriptor alloc] init]; + descriptor.rasterSampleCount = mtlSampleCount(info.multisample.samples); if (info.subpassIndex >= info.renderPassDescriptor->info.subpassCount) { gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){ diff --git a/projects/apis/metal/src/present/metal_present.m b/projects/apis/metal/src/present/metal_present.m index 9ea2cf4..71a4066 100644 --- a/projects/apis/metal/src/present/metal_present.m +++ b/projects/apis/metal/src/present/metal_present.m @@ -19,7 +19,6 @@ gnReturnCode metalPresent(gnOutputDeviceHandle device, gnPresentInfo info) { }]; id blit = [commandBuffer blitCommandEncoder]; - [blit copyFromTexture:info.presentationQueues[i]->images[info.imageIndices[i]]->texture->texture sourceSlice:0 sourceLevel:0 diff --git a/projects/apis/metal/src/surface/metal_surface.m b/projects/apis/metal/src/surface/metal_surface.m index 0e5c8d2..2b50fe4 100644 --- a/projects/apis/metal/src/surface/metal_surface.m +++ b/projects/apis/metal/src/surface/metal_surface.m @@ -18,6 +18,11 @@ void destroyMetalWindowSurface(gnWindowSurface windowSurface) { free(windowSurface->windowSurface); } +gnImageFormat mtlMetalFormatToGryphn(MTLPixelFormat format) { + if (format == MTLPixelFormatBGRA8Unorm_sRGB) return GN_FORMAT_BGRA8_SRGB; + return GN_FORMAT_NONE; +} + gnSurfaceDetails getMetalSurfaceDetails( gnWindowSurface windowSurface, gnPhysicalDevice device ) { @@ -35,6 +40,7 @@ MTLPixelFormat mtlGryphnFormatToMetalFormat(gnImageFormat format) { switch (format) { case GN_FORMAT_NONE: return MTLPixelFormatInvalid; case GN_FORMAT_BGRA8_SRGB: return MTLPixelFormatBGRA8Unorm_sRGB; + case GN_FORMAT_BGRA8: return MTLPixelFormatBGRA8Unorm; case GN_FORMAT_RGBA8_SRGB: return MTLPixelFormatRGBA8Unorm_sRGB; case GN_FORMAT_D24S8_UINT: return MTLPixelFormatDepth24Unorm_Stencil8; case GN_FORMAT_D32S8_UINT: return MTLPixelFormatDepth32Float_Stencil8; @@ -43,6 +49,7 @@ MTLPixelFormat mtlGryphnFormatToMetalFormat(gnImageFormat format) { CGColorSpaceRef mtlGryphnColorSpaceToMetalColorSpace(gnColorSpace colorSpace) { switch (colorSpace) { + case GN_COLOR_SPACE_NONE: { return CGColorSpaceCreateWithName(kCGColorSpaceSRGB); } // very bad if here case GN_COLOR_SPACE_SRGB_NONLINEAR: { return CGColorSpaceCreateWithName(kCGColorSpaceSRGB); } } } diff --git a/projects/apis/metal/src/texture/metal_texture.h b/projects/apis/metal/src/texture/metal_texture.h index 4b202a1..891d36d 100644 --- a/projects/apis/metal/src/texture/metal_texture.h +++ b/projects/apis/metal/src/texture/metal_texture.h @@ -1,11 +1,16 @@ #pragma once #include "textures/gryphn_texture.h" #import +#import typedef struct gnPlatformTexture_t { id texture; + id sampler; } gnPlatformTexture; gnReturnCode createMetalTexture(gnTexture texture, gnDevice device, const gnTextureInfo info); void metalTextureData(gnTextureHandle texture, void* pixelData); void metalDestroyTexture(gnTexture texture); + + +NSUInteger mtlSampleCount(gnMultisampleCountFlags flags); diff --git a/projects/apis/metal/src/texture/metal_texture.m b/projects/apis/metal/src/texture/metal_texture.m index 6efd21a..5adc9d5 100644 --- a/projects/apis/metal/src/texture/metal_texture.m +++ b/projects/apis/metal/src/texture/metal_texture.m @@ -16,18 +16,30 @@ NSUInteger mtlSampleCount(gnMultisampleCountFlags flags) { gnReturnCode createMetalTexture(gnTexture texture, gnDevice device, const gnTextureInfo info) { texture->texture = malloc(sizeof(struct gnPlatformTexture_t)); MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init]; - textureDescriptor.pixelFormat = mtlGryphnFormatToMetalFormat(info.format); textureDescriptor.width = info.extent.width; textureDescriptor.height = info.extent.height; textureDescriptor.depth = info.extent.depth; textureDescriptor.sampleCount = mtlSampleCount(info.samples); - if (textureDescriptor.sampleCount >= 2) + textureDescriptor.pixelFormat = mtlGryphnFormatToMetalFormat(info.format); + textureDescriptor.usage = MTLTextureUsageRenderTarget; + if (textureDescriptor.sampleCount >= 2) { textureDescriptor.textureType = MTLTextureType2DMultisample; - else + } + else { textureDescriptor.textureType = MTLTextureType2D; + } + MTLSamplerDescriptor *samplerDesc = [[MTLSamplerDescriptor alloc] init]; + samplerDesc.minFilter = MTLSamplerMinMagFilterLinear; + samplerDesc.magFilter = MTLSamplerMinMagFilterLinear; + samplerDesc.mipFilter = MTLSamplerMipFilterNotMipmapped; + samplerDesc.sAddressMode = MTLSamplerAddressModeClampToEdge; + samplerDesc.tAddressMode = MTLSamplerAddressModeClampToEdge; + samplerDesc.normalizedCoordinates = YES; + texture->texture->sampler = [device->outputDevice->device newSamplerStateWithDescriptor:samplerDesc]; texture->texture->texture = [device->outputDevice->device newTextureWithDescriptor:textureDescriptor]; [textureDescriptor release]; + [samplerDesc release]; return GN_SUCCESS; } diff --git a/projects/apis/vulkan/src/vulkan_surface/vulkan_surface.c b/projects/apis/vulkan/src/vulkan_surface/vulkan_surface.c index 99cd1de..9e323ef 100644 --- a/projects/apis/vulkan/src/vulkan_surface/vulkan_surface.c +++ b/projects/apis/vulkan/src/vulkan_surface/vulkan_surface.c @@ -75,12 +75,13 @@ gnSurfaceFormat* vkGetSurfaceFormats( for (int i = 0; i < *formatCount; i++) { switch (vkFormats[i].format) { case VK_FORMAT_B8G8R8A8_SRGB: { formats[i].format = GN_FORMAT_BGRA8_SRGB; break; } - default: break; + case VK_FORMAT_B8G8R8A8_UNORM: { formats[i].format = GN_FORMAT_BGRA8; break; } + default: { formats[i].format = GN_FORMAT_NONE; break; } } switch (vkFormats[i].colorSpace) { case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: { formats[i].colorSpace = GN_COLOR_SPACE_SRGB_NONLINEAR; break; } - default: break; + default: { formats[i].colorSpace = GN_COLOR_SPACE_NONE; break; }; } } } @@ -112,6 +113,7 @@ VkFormat vkGryphnFormatToVulkanFormat(gnImageFormat format) { switch (format) { case GN_FORMAT_NONE: return VK_FORMAT_UNDEFINED; case GN_FORMAT_BGRA8_SRGB: return VK_FORMAT_B8G8R8A8_SRGB; + case GN_FORMAT_BGRA8: return VK_FORMAT_B8G8R8A8_UNORM; case GN_FORMAT_RGBA8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB; case GN_FORMAT_D32S8_UINT: return VK_FORMAT_D32_SFLOAT_S8_UINT; case GN_FORMAT_D24S8_UINT: return VK_FORMAT_D24_UNORM_S8_UINT; @@ -119,6 +121,7 @@ VkFormat vkGryphnFormatToVulkanFormat(gnImageFormat format) { } VkColorSpaceKHR vkGryphnColorSpaceToVulkanColorSpace(gnColorSpace colorSpace) { switch (colorSpace) { + case GN_COLOR_SPACE_NONE: { return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; }; // this is a problem if we are trying to convert it case GN_COLOR_SPACE_SRGB_NONLINEAR: { return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; } } } diff --git a/projects/platform/platform_macos/gryphn_platform_macos.m b/projects/platform/platform_macos/gryphn_platform_macos.m index 7c12c82..8865700 100644 --- a/projects/platform/platform_macos/gryphn_platform_macos.m +++ b/projects/platform/platform_macos/gryphn_platform_macos.m @@ -29,6 +29,7 @@ CAMetalLayer* gnCreateCAMetalLayer(NSWindow* window) { [view setWantsLayer:YES]; CGSize viewSize = view.bounds.size; CGFloat scale = window.screen.backingScaleFactor; + layer.pixelFormat = MTLPixelFormatBGRA8Unorm; layer.drawableSize = CGSizeMake(viewSize.width * scale, viewSize.height * scale); return layer; @@ -41,7 +42,7 @@ void gnResizeCAMetalLayer(NSWindow* window) { CGFloat scale = window.screen.backingScaleFactor; layer.drawableSize = CGSizeMake(viewSize.width * scale, viewSize.height * scale); - + layer.pixelFormat = MTLPixelFormatBGRA8Unorm; } // CAMetalLayer* gnGetCAMetalLayer(NSWindow* window) {