redo metal presentation
This commit is contained in:
@@ -4,12 +4,60 @@
|
|||||||
#include "instance/metal_instance.h"
|
#include "instance/metal_instance.h"
|
||||||
#include "instance/gryphn_instance.h"
|
#include "instance/gryphn_instance.h"
|
||||||
|
|
||||||
|
#include "metal_shader.msl"
|
||||||
|
|
||||||
gnReturnCode createMetalOutputDevice(gnInstanceHandle instance, gnOutputDeviceHandle outputDevice, gnOutputDeviceInfo deviceInfo) {
|
gnReturnCode createMetalOutputDevice(gnInstanceHandle instance, gnOutputDeviceHandle outputDevice, gnOutputDeviceInfo deviceInfo) {
|
||||||
if (instance == GN_NULL_HANDLE) return GN_INVALID_HANDLE;
|
if (instance == GN_NULL_HANDLE) return GN_INVALID_HANDLE;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
// create full screen quad
|
||||||
|
float verticies[] = {
|
||||||
|
-1.0f, -1.0f, 0.0f, 1.0f,
|
||||||
|
1.0f, -1.0f, 1.0f, 1.0f,
|
||||||
|
-1.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
1.0f, 1.0f, 1.0f, 0.0f,
|
||||||
|
};
|
||||||
|
outputDevice->outputDevice->fullScreenQuadBuffer =
|
||||||
|
[outputDevice->outputDevice->device
|
||||||
|
newBufferWithBytes:verticies
|
||||||
|
length:sizeof(verticies)
|
||||||
|
options:MTLResourceStorageModeShared
|
||||||
|
];
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
outputDevice->outputDevice->fullScreenShader = [outputDevice->outputDevice->device
|
||||||
|
newLibraryWithSource:@(shader_source)
|
||||||
|
options:nil
|
||||||
|
error:&error
|
||||||
|
];
|
||||||
|
if (!outputDevice->outputDevice->fullScreenShader) {
|
||||||
|
gnDebuggerSetErrorMessage(instance->debugger, (gnMessageData){
|
||||||
|
.message = gnCombineStrings(gnCreateString("Failed to create shader for output device: \n"), error.localizedDescription.UTF8String)
|
||||||
|
});
|
||||||
|
return GN_DEVICE_LOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputDevice->outputDevice->fullScreenVertex = [outputDevice->outputDevice->fullScreenShader newFunctionWithName:@"fullscreen_vertex"];
|
||||||
|
outputDevice->outputDevice->fullScreenFragment = [outputDevice->outputDevice->fullScreenShader newFunctionWithName:@"fullscreen_fragment"];
|
||||||
|
|
||||||
|
MTLRenderPipelineDescriptor *pipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
|
pipelineDesc.vertexFunction = outputDevice->outputDevice->fullScreenVertex;
|
||||||
|
pipelineDesc.fragmentFunction = outputDevice->outputDevice->fullScreenFragment;
|
||||||
|
pipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
|
||||||
|
pipelineDesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||||
|
pipelineDesc.stencilAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||||
|
|
||||||
|
outputDevice->outputDevice->fullScreenPipeline = [outputDevice->outputDevice->device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error];
|
||||||
|
if (!outputDevice->outputDevice->fullScreenPipeline) {
|
||||||
|
gnDebuggerSetErrorMessage(instance->debugger, (gnMessageData){
|
||||||
|
.message = gnCombineStrings(gnCreateString("Failed to create graphics pipeline for output device: \n"), error.localizedDescription.UTF8String)
|
||||||
|
});
|
||||||
|
return GN_DEVICE_LOST;
|
||||||
|
}
|
||||||
|
|
||||||
return GN_SUCCESS;
|
return GN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +68,13 @@ void waitForMetalDevice(gnOutputDeviceHandle device) {
|
|||||||
void destroyMetalOutputDevice(gnOutputDeviceHandle device) {
|
void destroyMetalOutputDevice(gnOutputDeviceHandle device) {
|
||||||
[device->outputDevice->transferQueue release];
|
[device->outputDevice->transferQueue release];
|
||||||
[device->outputDevice->device release];
|
[device->outputDevice->device release];
|
||||||
|
|
||||||
|
[device->outputDevice->fullScreenQuadBuffer release];
|
||||||
|
[device->outputDevice->fullScreenShader release];
|
||||||
|
[device->outputDevice->fullScreenVertex release];
|
||||||
|
[device->outputDevice->fullScreenFragment release];
|
||||||
|
[device->outputDevice->fullScreenPipeline release];
|
||||||
|
|
||||||
free(device->outputDevice);
|
free(device->outputDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -14,6 +14,11 @@ struct gnPlatformOutputDevice_t {
|
|||||||
|
|
||||||
id<MTLCommandBuffer> executingCommandBuffer;
|
id<MTLCommandBuffer> executingCommandBuffer;
|
||||||
id<MTLCommandQueue> transferQueue;
|
id<MTLCommandQueue> transferQueue;
|
||||||
|
|
||||||
|
id<MTLBuffer> fullScreenQuadBuffer;
|
||||||
|
id<MTLLibrary> fullScreenShader;
|
||||||
|
id<MTLFunction> fullScreenVertex, fullScreenFragment;
|
||||||
|
id<MTLRenderPipelineState> fullScreenPipeline;
|
||||||
} gnPlatformOutputDevice;
|
} gnPlatformOutputDevice;
|
||||||
|
|
||||||
gnPhysicalDevice* getMetalDevices(gnInstanceHandle instance, uint32_t* deviceCount);
|
gnPhysicalDevice* getMetalDevices(gnInstanceHandle instance, uint32_t* deviceCount);
|
||||||
|
26
projects/apis/metal/src/devices/metal_shader.msl
Normal file
26
projects/apis/metal/src/devices/metal_shader.msl
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const char* shader_source =
|
||||||
|
"using namespace metal;"
|
||||||
|
""
|
||||||
|
"struct Vertex {"
|
||||||
|
" float2 position;"
|
||||||
|
" float2 texcoord;"
|
||||||
|
"};"
|
||||||
|
""
|
||||||
|
"struct VertexOut {"
|
||||||
|
" float4 position [[position]];"
|
||||||
|
" float2 texcoord;"
|
||||||
|
"};"
|
||||||
|
""
|
||||||
|
"vertex VertexOut fullscreen_vertex(const device Vertex* vertices [[buffer(0)]],"
|
||||||
|
" uint vid [[vertex_id]]) {"
|
||||||
|
" VertexOut out;"
|
||||||
|
" out.position = float4(vertices[vid].position, 0.0, 1.0);"
|
||||||
|
" out.texcoord = vertices[vid].texcoord;"
|
||||||
|
" return out;"
|
||||||
|
"}"
|
||||||
|
""
|
||||||
|
"fragment float4 fullscreen_fragment(VertexOut in [[stage_in]],"
|
||||||
|
" texture2d<float> tex [[texture(0)]]) {"
|
||||||
|
" constexpr sampler s(address::clamp_to_edge, filter::linear);"
|
||||||
|
" return tex.sample(s, in.texcoord);"
|
||||||
|
"}";
|
@@ -65,8 +65,9 @@ gnReturnCode createMetalGraphicsPipeline(gnGraphicsPipeline graphicsPipeline, gn
|
|||||||
|
|
||||||
if (subpass.depthAttachment != NULL) {
|
if (subpass.depthAttachment != NULL) {
|
||||||
descriptor.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
descriptor.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||||
descriptor.depthAttachmentPixelFormat = info.renderPassDescriptor->renderPassDescriptor->subpasses[info.subpassIndex].depthAttachment.texture.pixelFormat;
|
descriptor.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||||
descriptor.stencilAttachmentPixelFormat = info.renderPassDescriptor->renderPassDescriptor->subpasses[info.subpassIndex].stencilAttachment.texture.pixelFormat;
|
// descriptor.depthAttachmentPixelFormat = info.renderPassDescriptor->renderPassDescriptor->subpasses[info.subpassIndex].depthAttachment.texture.pixelFormat;
|
||||||
|
// descriptor.stencilAttachmentPixelFormat = info.renderPassDescriptor->renderPassDescriptor->subpasses[info.subpassIndex].stencilAttachment.texture.pixelFormat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,6 +53,7 @@ gnReturnCode metalPresent(gnOutputDeviceHandle device, gnPresentInfo info) {
|
|||||||
gnReturnCode metalPresentSync(gnOutputDeviceHandle device, gnPresentSyncInfo info) {
|
gnReturnCode metalPresentSync(gnOutputDeviceHandle device, gnPresentSyncInfo info) {
|
||||||
for (uint32_t i = 0; i < info.presentationQueueCount; i++) {
|
for (uint32_t i = 0; i < info.presentationQueueCount; i++) {
|
||||||
if (info.presentationQueues[i]->info.surface->windowSurface->layer.device == nil) info.presentationQueues[i]->info.surface->windowSurface->layer.device = device->outputDevice->device;
|
if (info.presentationQueues[i]->info.surface->windowSurface->layer.device == nil) info.presentationQueues[i]->info.surface->windowSurface->layer.device = device->outputDevice->device;
|
||||||
|
info.presentationQueues[i]->info.surface->windowSurface->layer.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
|
||||||
id<CAMetalDrawable> drawable = [info.presentationQueues[i]->info.surface->windowSurface->layer nextDrawable];
|
id<CAMetalDrawable> drawable = [info.presentationQueues[i]->info.surface->windowSurface->layer nextDrawable];
|
||||||
if (drawable == nil) return GN_UNKNOWN_ERROR;
|
if (drawable == nil) return GN_UNKNOWN_ERROR;
|
||||||
|
|
||||||
@@ -68,29 +69,30 @@ gnReturnCode metalPresentSync(gnOutputDeviceHandle device, gnPresentSyncInfo inf
|
|||||||
mtlAddImageBackToQueue(presentationQueue, imageIndex);
|
mtlAddImageBackToQueue(presentationQueue, imageIndex);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
id<MTLBlitCommandEncoder> blit = [commandBuffer blitCommandEncoder];
|
MTLRenderPassDescriptor *desc = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
[blit copyFromTexture:info.presentationQueues[i]->images[info.imageIndices[i]]->texture->texture
|
desc.colorAttachments[0].texture = drawable.texture;
|
||||||
sourceSlice:0
|
desc.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||||
sourceLevel:0
|
desc.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||||
sourceOrigin:(MTLOrigin){0, 0, 0}
|
desc.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||||
sourceSize:(MTLSize){info.presentationQueues[i]->info.imageSize.x, info.presentationQueues[i]->info.imageSize.y, 1}
|
|
||||||
toTexture:drawable.texture
|
|
||||||
destinationSlice:0
|
|
||||||
destinationLevel:0
|
|
||||||
destinationOrigin:(MTLOrigin){0, 0, 0}];
|
|
||||||
|
|
||||||
[blit endEncoding];
|
id<MTLRenderCommandEncoder> enc = [commandBuffer renderCommandEncoderWithDescriptor:desc];
|
||||||
|
|
||||||
[commandBuffer presentDrawable:drawable];
|
[enc setRenderPipelineState:device->outputDevice->fullScreenPipeline];
|
||||||
[commandBuffer commit];
|
[enc setVertexBuffer:device->outputDevice->fullScreenQuadBuffer offset:0 atIndex:0];
|
||||||
device->outputDevice->executingCommandBuffer = commandBuffer;
|
[enc setFragmentTexture:info.presentationQueues[i]->images[info.imageIndices[i]]->texture->texture atIndex:0];
|
||||||
|
[enc drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||||
|
[enc endEncoding];
|
||||||
|
|
||||||
|
[commandBuffer presentDrawable:drawable];
|
||||||
|
[commandBuffer commit];
|
||||||
|
device->outputDevice->executingCommandBuffer = commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < info.presentationQueueCount; i++) {
|
||||||
|
if (info.presentationQueues[i]->info.imageSize.x != info.presentationQueues[i]->info.surface->windowSurface->layer.drawableSize.width ||
|
||||||
|
info.presentationQueues[i]->info.imageSize.y != info.presentationQueues[i]->info.surface->windowSurface->layer.drawableSize.height) {
|
||||||
|
return GN_SUBOPTIMAL_PRESENTATION_QUEUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < info.presentationQueueCount; i++) {
|
|
||||||
if (info.presentationQueues[i]->info.imageSize.x != info.presentationQueues[i]->info.surface->windowSurface->layer.drawableSize.width ||
|
|
||||||
info.presentationQueues[i]->info.imageSize.y != info.presentationQueues[i]->info.surface->windowSurface->layer.drawableSize.height) {
|
|
||||||
return GN_SUBOPTIMAL_PRESENTATION_QUEUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GN_SUCCESS;
|
return GN_SUCCESS;
|
||||||
|
Reference in New Issue
Block a user