multisampling in metal

This commit is contained in:
Greg Wells
2025-07-09 13:27:06 -04:00
parent 07d4e13f20
commit 89ea72b341
11 changed files with 59 additions and 20 deletions

View File

@@ -1,5 +1,7 @@
#include "metal_commands.h" #include "metal_commands.h"
#include "shader_module/metal_shader_module.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) { void metelBeginRenderPass(gnCommandBuffer buffer, gnRenderPassInfo passInfo) {
int currentColorAttachment = 0; 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) { } else if (uniform->uniform->bindings[i].type == GN_IMAGE_DESCRIPTOR) {
gnImageUniformInfo info = *(gnImageUniformInfo*)uniform->uniform->bindings[i].data; gnImageUniformInfo info = *(gnImageUniformInfo*)uniform->uniform->bindings[i].data;
[encoder setFragmentTexture:info.texture->texture->texture atIndex: uint32_t index = buffer->commandBuffer->boundGraphcisPipeline->graphicsPipeline->fragmentShaderMaps.sets[set].bindings[info.binding];
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];
} }
} }
} }

View File

@@ -9,12 +9,6 @@ gnReturnCode createMetalOutputDevice(gnOutputDeviceHandle outputDevice, gnInstan
outputDevice->outputDevice = malloc(sizeof(gnPlatformOutputDevice)); outputDevice->outputDevice = malloc(sizeof(gnPlatformOutputDevice));
outputDevice->outputDevice->device = deviceInfo.physicalDevice.physicalDevice->device.retain; outputDevice->outputDevice->device = deviceInfo.physicalDevice.physicalDevice->device.retain;
outputDevice->outputDevice->transferQueue = outputDevice->outputDevice->device.newCommandQueue; outputDevice->outputDevice->transferQueue = outputDevice->outputDevice->device.newCommandQueue;
// outputDevice->outputDevice->queueCount = deviceInfo.queueInfoCount;
// outputDevice->outputDevice->queues = malloc(sizeof(id<MTLCommandQueue>) * deviceInfo.queueInfoCount);
// for (int i = 0; i < deviceInfo.queueInfoCount; i++) {
// outputDevice->outputDevice->queues[i] = outputDevice->outputDevice->device.newCommandQueue;
// }
return GN_SUCCESS; return GN_SUCCESS;
} }

View File

@@ -14,7 +14,6 @@ struct gnPlatformOutputDevice_t {
id<MTLCommandBuffer> executingCommandBuffer; id<MTLCommandBuffer> executingCommandBuffer;
id<MTLCommandQueue> transferQueue; id<MTLCommandQueue> transferQueue;
// id<MTLRenderPipelineState> framebuffer;
} gnPlatformOutputDevice; } gnPlatformOutputDevice;
gnPhysicalDevice* getMetalDevices(gnInstanceHandle instance, uint32_t* deviceCount); gnPhysicalDevice* getMetalDevices(gnInstanceHandle instance, uint32_t* deviceCount);

View File

@@ -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) { gnReturnCode createMetalFramebuffer(gnFramebuffer framebuffer, gnOutputDevice device, gnFramebufferInfo info) {
framebuffer->framebuffer = malloc(sizeof(struct gnPlatformFramebuffer_t)); framebuffer->framebuffer = malloc(sizeof(struct gnPlatformFramebuffer_t));
if (info.attachmentCount != info.renderPassDescriptor->info.attachmentCount) { 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] setRenderTargetWidth:info.size.x];
[framebuffer->framebuffer->subpasses[i] setRenderTargetHeight:info.size.y]; [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++) { 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]; MTLRenderPassColorAttachmentDescriptor* color = framebuffer->framebuffer->subpasses[i].colorAttachments[c];
color.texture = info.attachments[attachmentIndex]->texture->texture; 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.loadAction = mtlGryphnLoadOperation(info.renderPassDescriptor->info.attachmentInfos[attachmentIndex].loadOperation);
color.storeAction = mtlGryphnStoreOperation(info.renderPassDescriptor->info.attachmentInfos[attachmentIndex].storeOperation);
if (color.loadAction == MTLLoadActionClear) if (color.loadAction == MTLLoadActionClear)
color.clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0); 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; depthAttachment.clearDepth = 1.0f;
MTLRenderPassStencilAttachmentDescriptor* stencilAttachment = framebuffer->framebuffer->subpasses[attachmentIndex].stencilAttachment; MTLRenderPassStencilAttachmentDescriptor* stencilAttachment = framebuffer->framebuffer->subpasses[attachmentIndex].stencilAttachment;
stencilAttachment.texture = info.attachments[i]->texture->texture; stencilAttachment.texture = info.attachments[attachmentIndex]->texture->texture;
} }
} }

View File

@@ -3,6 +3,7 @@
#include "debugger/gryphn_debugger.h" #include "debugger/gryphn_debugger.h"
#include "shader_module/metal_shader_module.h" #include "shader_module/metal_shader_module.h"
#include "surface/metal_surface.h" #include "surface/metal_surface.h"
#include "texture/metal_texture.h"
#include "utils/math/gryphn_vec3.h" #include "utils/math/gryphn_vec3.h"
@@ -44,6 +45,7 @@ MTLCompareFunction mtlGrypnCompareOperation(gnCompareOperation operation) {
gnReturnCode createMetalGraphicsPipeline(gnGraphicsPipeline graphicsPipeline, gnOutputDevice device, gnGraphicsPipelineInfo info) { gnReturnCode createMetalGraphicsPipeline(gnGraphicsPipeline graphicsPipeline, gnOutputDevice device, gnGraphicsPipelineInfo info) {
graphicsPipeline->graphicsPipeline = malloc(sizeof(struct gnPlatformGraphicsPipeline_t)); graphicsPipeline->graphicsPipeline = malloc(sizeof(struct gnPlatformGraphicsPipeline_t));
MTLRenderPipelineDescriptor* descriptor = [[MTLRenderPipelineDescriptor alloc] init]; MTLRenderPipelineDescriptor* descriptor = [[MTLRenderPipelineDescriptor alloc] init];
descriptor.rasterSampleCount = mtlSampleCount(info.multisample.samples);
if (info.subpassIndex >= info.renderPassDescriptor->info.subpassCount) { if (info.subpassIndex >= info.renderPassDescriptor->info.subpassCount) {
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){ gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){

View File

@@ -19,7 +19,6 @@ gnReturnCode metalPresent(gnOutputDeviceHandle device, gnPresentInfo info) {
}]; }];
id<MTLBlitCommandEncoder> blit = [commandBuffer blitCommandEncoder]; id<MTLBlitCommandEncoder> blit = [commandBuffer blitCommandEncoder];
[blit copyFromTexture:info.presentationQueues[i]->images[info.imageIndices[i]]->texture->texture [blit copyFromTexture:info.presentationQueues[i]->images[info.imageIndices[i]]->texture->texture
sourceSlice:0 sourceSlice:0
sourceLevel:0 sourceLevel:0

View File

@@ -18,6 +18,11 @@ void destroyMetalWindowSurface(gnWindowSurface windowSurface) {
free(windowSurface->windowSurface); free(windowSurface->windowSurface);
} }
gnImageFormat mtlMetalFormatToGryphn(MTLPixelFormat format) {
if (format == MTLPixelFormatBGRA8Unorm_sRGB) return GN_FORMAT_BGRA8_SRGB;
return GN_FORMAT_NONE;
}
gnSurfaceDetails getMetalSurfaceDetails( gnSurfaceDetails getMetalSurfaceDetails(
gnWindowSurface windowSurface, gnPhysicalDevice device gnWindowSurface windowSurface, gnPhysicalDevice device
) { ) {
@@ -35,6 +40,7 @@ MTLPixelFormat mtlGryphnFormatToMetalFormat(gnImageFormat format) {
switch (format) { switch (format) {
case GN_FORMAT_NONE: return MTLPixelFormatInvalid; case GN_FORMAT_NONE: return MTLPixelFormatInvalid;
case GN_FORMAT_BGRA8_SRGB: return MTLPixelFormatBGRA8Unorm_sRGB; 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_RGBA8_SRGB: return MTLPixelFormatRGBA8Unorm_sRGB;
case GN_FORMAT_D24S8_UINT: return MTLPixelFormatDepth24Unorm_Stencil8; case GN_FORMAT_D24S8_UINT: return MTLPixelFormatDepth24Unorm_Stencil8;
case GN_FORMAT_D32S8_UINT: return MTLPixelFormatDepth32Float_Stencil8; case GN_FORMAT_D32S8_UINT: return MTLPixelFormatDepth32Float_Stencil8;
@@ -43,6 +49,7 @@ MTLPixelFormat mtlGryphnFormatToMetalFormat(gnImageFormat format) {
CGColorSpaceRef mtlGryphnColorSpaceToMetalColorSpace(gnColorSpace colorSpace) { CGColorSpaceRef mtlGryphnColorSpaceToMetalColorSpace(gnColorSpace colorSpace) {
switch (colorSpace) { switch (colorSpace) {
case GN_COLOR_SPACE_NONE: { return CGColorSpaceCreateWithName(kCGColorSpaceSRGB); } // very bad if here
case GN_COLOR_SPACE_SRGB_NONLINEAR: { return CGColorSpaceCreateWithName(kCGColorSpaceSRGB); } case GN_COLOR_SPACE_SRGB_NONLINEAR: { return CGColorSpaceCreateWithName(kCGColorSpaceSRGB); }
} }
} }

View File

@@ -1,11 +1,16 @@
#pragma once #pragma once
#include "textures/gryphn_texture.h" #include "textures/gryphn_texture.h"
#import <Metal/MTLTexture.h> #import <Metal/MTLTexture.h>
#import <Metal/MTLSampler.h>
typedef struct gnPlatformTexture_t { typedef struct gnPlatformTexture_t {
id<MTLTexture> texture; id<MTLTexture> texture;
id<MTLSamplerState> sampler;
} gnPlatformTexture; } gnPlatformTexture;
gnReturnCode createMetalTexture(gnTexture texture, gnDevice device, const gnTextureInfo info); gnReturnCode createMetalTexture(gnTexture texture, gnDevice device, const gnTextureInfo info);
void metalTextureData(gnTextureHandle texture, void* pixelData); void metalTextureData(gnTextureHandle texture, void* pixelData);
void metalDestroyTexture(gnTexture texture); void metalDestroyTexture(gnTexture texture);
NSUInteger mtlSampleCount(gnMultisampleCountFlags flags);

View File

@@ -16,18 +16,30 @@ NSUInteger mtlSampleCount(gnMultisampleCountFlags flags) {
gnReturnCode createMetalTexture(gnTexture texture, gnDevice device, const gnTextureInfo info) { gnReturnCode createMetalTexture(gnTexture texture, gnDevice device, const gnTextureInfo info) {
texture->texture = malloc(sizeof(struct gnPlatformTexture_t)); texture->texture = malloc(sizeof(struct gnPlatformTexture_t));
MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init]; MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];
textureDescriptor.pixelFormat = mtlGryphnFormatToMetalFormat(info.format);
textureDescriptor.width = info.extent.width; textureDescriptor.width = info.extent.width;
textureDescriptor.height = info.extent.height; textureDescriptor.height = info.extent.height;
textureDescriptor.depth = info.extent.depth; textureDescriptor.depth = info.extent.depth;
textureDescriptor.sampleCount = mtlSampleCount(info.samples); textureDescriptor.sampleCount = mtlSampleCount(info.samples);
if (textureDescriptor.sampleCount >= 2) textureDescriptor.pixelFormat = mtlGryphnFormatToMetalFormat(info.format);
textureDescriptor.usage = MTLTextureUsageRenderTarget;
if (textureDescriptor.sampleCount >= 2) {
textureDescriptor.textureType = MTLTextureType2DMultisample; textureDescriptor.textureType = MTLTextureType2DMultisample;
else }
else {
textureDescriptor.textureType = MTLTextureType2D; 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]; texture->texture->texture = [device->outputDevice->device newTextureWithDescriptor:textureDescriptor];
[textureDescriptor release]; [textureDescriptor release];
[samplerDesc release];
return GN_SUCCESS; return GN_SUCCESS;
} }

View File

@@ -75,12 +75,13 @@ gnSurfaceFormat* vkGetSurfaceFormats(
for (int i = 0; i < *formatCount; i++) { for (int i = 0; i < *formatCount; i++) {
switch (vkFormats[i].format) { switch (vkFormats[i].format) {
case VK_FORMAT_B8G8R8A8_SRGB: { formats[i].format = GN_FORMAT_BGRA8_SRGB; break; } 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) { switch (vkFormats[i].colorSpace) {
case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: { formats[i].colorSpace = GN_COLOR_SPACE_SRGB_NONLINEAR; break; } 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) { switch (format) {
case GN_FORMAT_NONE: return VK_FORMAT_UNDEFINED; case GN_FORMAT_NONE: return VK_FORMAT_UNDEFINED;
case GN_FORMAT_BGRA8_SRGB: return VK_FORMAT_B8G8R8A8_SRGB; 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_RGBA8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB;
case GN_FORMAT_D32S8_UINT: return VK_FORMAT_D32_SFLOAT_S8_UINT; case GN_FORMAT_D32S8_UINT: return VK_FORMAT_D32_SFLOAT_S8_UINT;
case GN_FORMAT_D24S8_UINT: return VK_FORMAT_D24_UNORM_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) { VkColorSpaceKHR vkGryphnColorSpaceToVulkanColorSpace(gnColorSpace colorSpace) {
switch (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; } case GN_COLOR_SPACE_SRGB_NONLINEAR: { return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; }
} }
} }

View File

@@ -29,6 +29,7 @@ CAMetalLayer* gnCreateCAMetalLayer(NSWindow* window) {
[view setWantsLayer:YES]; [view setWantsLayer:YES];
CGSize viewSize = view.bounds.size; CGSize viewSize = view.bounds.size;
CGFloat scale = window.screen.backingScaleFactor; CGFloat scale = window.screen.backingScaleFactor;
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
layer.drawableSize = CGSizeMake(viewSize.width * scale, layer.drawableSize = CGSizeMake(viewSize.width * scale,
viewSize.height * scale); viewSize.height * scale);
return layer; return layer;
@@ -41,7 +42,7 @@ void gnResizeCAMetalLayer(NSWindow* window) {
CGFloat scale = window.screen.backingScaleFactor; CGFloat scale = window.screen.backingScaleFactor;
layer.drawableSize = CGSizeMake(viewSize.width * scale, layer.drawableSize = CGSizeMake(viewSize.width * scale,
viewSize.height * scale); viewSize.height * scale);
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
} }
// CAMetalLayer* gnGetCAMetalLayer(NSWindow* window) { // CAMetalLayer* gnGetCAMetalLayer(NSWindow* window) {