rename to projects (DOES NOT COMPILE)
This commit is contained in:
28
projects/apis/metal/CMakeLists.txt
Normal file
28
projects/apis/metal/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS on)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
project(GryphnMetalImpl)
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS
|
||||
"src/*.c" "src/*.h" "src/*.m"
|
||||
)
|
||||
add_library(GryphnMetalImpl STATIC ${SOURCE_FILES})
|
||||
target_include_directories(GryphnMetalImpl PUBLIC
|
||||
${CMAKE_SOURCE_DIR}/gryphn/include/
|
||||
${CMAKE_SOURCE_DIR}/gryphn/src/
|
||||
${CMAKE_SOURCE_DIR}/gryphn/src/utils/
|
||||
src/
|
||||
depends/SPIRV-Cross/
|
||||
)
|
||||
add_compile_definitions(GN_REVEAL_IMPL)
|
||||
add_subdirectory(depends/SPIRV-Cross)
|
||||
|
||||
target_link_libraries(GryphnMetalImpl spirv-cross-core spirv-cross-msl spirv-cross-c)
|
||||
|
||||
target_link_libraries(GryphnMetalImpl
|
||||
"-framework IOKit"
|
||||
"-framework CoreFoundation"
|
||||
"-framework CoreGraphics"
|
||||
"-framework Foundation"
|
||||
"-framework Metal"
|
||||
"-framework QuartzCore"
|
||||
)
|
7
projects/apis/metal/src/buffer/metal_buffer.h
Normal file
7
projects/apis/metal/src/buffer/metal_buffer.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
struct gnPlatformBuffer_t {
|
||||
id<MTLBuffer> buffer, stagingBuffer;
|
||||
bool useStagingBuffer;
|
||||
};
|
40
projects/apis/metal/src/buffer/metal_buffer.m
Normal file
40
projects/apis/metal/src/buffer/metal_buffer.m
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "metal_buffer.h"
|
||||
#include "core/buffers/gryphn_buffer.h"
|
||||
#include "core/output_device/gryphn_output_device.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
|
||||
gnReturnCode gnCreateBufferFn(gnBufferHandle buffer, gnOutputDeviceHandle device, gnBufferInfo info) {
|
||||
buffer->buffer = malloc(sizeof(struct gnPlatformBuffer_t));
|
||||
MTLResourceOptions option;
|
||||
buffer->buffer->useStagingBuffer = (info.usage == GN_DYNAMIC_DRAW) ? NO : YES;
|
||||
if (info.usage == GN_DYNAMIC_DRAW)
|
||||
option = MTLResourceStorageModeShared;
|
||||
else {
|
||||
option = MTLResourceStorageModePrivate;
|
||||
buffer->buffer->stagingBuffer = [device->outputDevice->device newBufferWithLength:info.size options:MTLResourceStorageModeShared];
|
||||
}
|
||||
buffer->buffer->buffer = [device->outputDevice->device newBufferWithLength:info.size options:option];
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
void gnBufferDataFn(gnBufferHandle buffer, size_t dataSize, void* data) {
|
||||
void* bufferData;
|
||||
if (buffer->buffer->useStagingBuffer) {
|
||||
memcpy(buffer->buffer->stagingBuffer.contents, data, dataSize);
|
||||
id<MTLCommandBuffer> commandBuffer = [buffer->device->outputDevice->transferQueue commandBuffer];
|
||||
id<MTLBlitCommandEncoder> encoder = [commandBuffer blitCommandEncoder];
|
||||
[encoder copyFromBuffer:buffer->buffer->stagingBuffer sourceOffset:0 toBuffer:buffer->buffer->buffer destinationOffset:0 size:dataSize];
|
||||
[encoder endEncoding];
|
||||
[commandBuffer commit];
|
||||
[commandBuffer waitUntilCompleted];
|
||||
} else
|
||||
memcpy(buffer->buffer->buffer.contents, data, dataSize);
|
||||
}
|
||||
void* gnMapBufferFn(gnBufferHandle buffer) {
|
||||
return buffer->buffer->buffer.contents;
|
||||
}
|
||||
void gnDestroyBufferFn(gnBufferHandle buffer) {
|
||||
if (buffer->buffer->useStagingBuffer)
|
||||
[buffer->buffer->stagingBuffer release];
|
||||
[buffer->buffer->buffer release];
|
||||
free(buffer->buffer);
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "core/command/command_buffer/gryphn_command_buffer.h"
|
||||
#include "core/pipelines/graphics_pipeline/gryphn_graphics_pipeline.h"
|
||||
#import <Metal/MTLCommandBuffer.h>
|
||||
#import <Metal/MTLCommandEncoder.h>
|
||||
|
||||
typedef struct gnPlatformCommandBuffer_t {
|
||||
id<MTLCommandBuffer> commandBuffer;
|
||||
id<MTLCommandEncoder> encoder;
|
||||
struct gnGraphicsPipeline_t* boundGraphcisPipeline;
|
||||
gnBufferHandle indexBuffer;
|
||||
} gnPlatformCommandBuffer;
|
@@ -0,0 +1,24 @@
|
||||
#include "metal_command_buffer.h"
|
||||
#include "core/commands/command_pool/metal_command_pool.h"
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
gnReturnCode gnCommandPoolAllocateCommandBuffersFn(gnCommandBufferHandle* commandBuffers, uint32_t count, struct gnCommandPool_t* pool) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
commandBuffers[i]->commandBuffer = malloc(sizeof(gnPlatformCommandBuffer));
|
||||
}
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
void gnResetCommandBufferFn(struct gnCommandBuffer_t *commandBuffer) {
|
||||
// do nothing
|
||||
}
|
||||
gnReturnCode gnBeginCommandBufferFn(struct gnCommandBuffer_t* commandBuffer) {
|
||||
commandBuffer->commandBuffer->boundGraphcisPipeline = NULL;
|
||||
commandBuffer->commandBuffer->commandBuffer = [commandBuffer->commandPool->commandPool->commandQueue commandBuffer];
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
gnReturnCode gnEndCommandBufferFn(struct gnCommandBuffer_t* commandBuffer) {
|
||||
// [commandBuffer->commandBuffer->commandBuffer commit];
|
||||
return GN_SUCCESS;
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#import <Metal/Metal.h>
|
||||
#include "core/command/command_pool/gryphn_command_pool.h"
|
||||
|
||||
typedef struct gnPlatformCommandPool_t {
|
||||
id<MTLCommandQueue> commandQueue;
|
||||
} gnPlatformCommandPool;
|
@@ -0,0 +1,14 @@
|
||||
#include "metal_command_pool.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
|
||||
gnReturnCode gnCreateCommandPoolFn(struct gnCommandPool_t* commandPool, struct gnOutputDevice_t* device, struct gnCommandPoolInfo_t info) {
|
||||
commandPool->commandPool = malloc(sizeof(struct gnPlatformCommandPool_t));
|
||||
commandPool->commandPool->commandQueue = [device->outputDevice->device newCommandQueue];
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnDestroyCommandPoolFn(struct gnCommandPool_t* commandPool) {
|
||||
[commandPool->commandPool->commandQueue release];
|
||||
free(commandPool->commandPool);
|
||||
}
|
127
projects/apis/metal/src/commands/commands/metal_commands.m
Normal file
127
projects/apis/metal/src/commands/commands/metal_commands.m
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "core/command/commands/gryphn_command.h"
|
||||
#include "core/framebuffers/metal_framebuffer.h"
|
||||
#include "core/commands/command_buffer/metal_command_buffer.h"
|
||||
#include "core/pipelines/graphics_pipeline/metal_graphics_pipeline.h"
|
||||
#include "core/buffer/metal_buffer.h"
|
||||
#include "core/uniforms/metal_uniform.h"
|
||||
#import <Metal/MTLRenderCommandEncoder.h>
|
||||
|
||||
void gnCommandBeginRenderPassFn(struct gnCommandBuffer_t* buffer, struct gnRenderPassInfo_t passInfo) {
|
||||
int currentColorAttachment = 0;
|
||||
for (int i = 0; i < passInfo.clearValueCount; i++) {
|
||||
gnBool wasDepthStencil = gnFalse;
|
||||
if (isDepthFormat(passInfo.renderPassDescriptor->info.attachmentInfos[i].format)) {
|
||||
wasDepthStencil = gnTrue;
|
||||
}
|
||||
if (isStencilFormat(passInfo.renderPassDescriptor->info.attachmentInfos[i].format)) {
|
||||
wasDepthStencil = gnTrue;
|
||||
}
|
||||
|
||||
if(!wasDepthStencil) {
|
||||
MTLRenderPassColorAttachmentDescriptor* color = passInfo.framebuffer->framebuffer->framebuffer.colorAttachments[i];
|
||||
color.clearColor = MTLClearColorMake(
|
||||
passInfo.clearValues[i].red,
|
||||
passInfo.clearValues[i].green,
|
||||
passInfo.clearValues[i].blue,
|
||||
passInfo.clearValues[i].alpha
|
||||
);
|
||||
}
|
||||
}
|
||||
buffer->commandBuffer->encoder = [buffer->commandBuffer->commandBuffer renderCommandEncoderWithDescriptor:passInfo.framebuffer->framebuffer->framebuffer];
|
||||
MTLViewport vp = {(double)passInfo.offset.x, (double)passInfo.offset.y, (double)passInfo.size.x, (double)passInfo.size.y, 0.0f, 1.0f};
|
||||
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>)buffer->commandBuffer->encoder;
|
||||
[encoder setViewport:vp];
|
||||
}
|
||||
void gnCommandEndRenderPassFn(struct gnCommandBuffer_t* buffer) {
|
||||
[buffer->commandBuffer->encoder endEncoding];
|
||||
}
|
||||
void gnCommandBindGraphicsPipelineFn(struct gnCommandBuffer_t* buffer, struct gnGraphicsPipeline_t* graphicsPipeline) {
|
||||
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>)buffer->commandBuffer->encoder;
|
||||
[encoder setRenderPipelineState:graphicsPipeline->graphicsPipeline->graphicsPipeline];
|
||||
|
||||
if (graphicsPipeline->info.cullMode.face == GN_CULL_FACE_BACK)
|
||||
[encoder setCullMode:MTLCullModeBack];
|
||||
else if (graphicsPipeline->info.cullMode.face == GN_CULL_FACE_FRONT)
|
||||
[encoder setCullMode:MTLCullModeFront];
|
||||
else if (graphicsPipeline->info.cullMode.face == GN_CULL_FACE_NONE)
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
if (graphicsPipeline->info.cullMode.direction == GN_DIRECTION_CLOCK_WISE)
|
||||
[encoder setFrontFacingWinding:MTLWindingCounterClockwise];
|
||||
if (graphicsPipeline->info.cullMode.direction == GN_DIRECTION_COUNTER_CLOCK_WISE)
|
||||
[encoder setFrontFacingWinding:MTLWindingClockwise];
|
||||
|
||||
if (graphicsPipeline->info.fillMode == GN_FILL_MODE_POINT)
|
||||
[encoder setTriangleFillMode:MTLTriangleFillModeFill];
|
||||
if (graphicsPipeline->info.fillMode == GN_FILL_MODE_LINE)
|
||||
[encoder setTriangleFillMode:MTLTriangleFillModeLines];
|
||||
if (graphicsPipeline->info.fillMode == GN_FILL_MODE_FILL)
|
||||
[encoder setTriangleFillMode:MTLTriangleFillModeFill];
|
||||
|
||||
buffer->commandBuffer->boundGraphcisPipeline = graphicsPipeline;
|
||||
}
|
||||
void gnCommandSetViewportFn(struct gnCommandBuffer_t* buffer, struct gnViewport_t viewport) {
|
||||
MTLViewport vp = {(double)viewport.position.x, (double)viewport.position.y, (double)viewport.size.x, (double)viewport.size.y, viewport.minDepth, viewport.maxDepth};
|
||||
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>)buffer->commandBuffer->encoder;
|
||||
[encoder setViewport:vp];
|
||||
}
|
||||
void gnCommandSetScissorFn(struct gnCommandBuffer_t* buffer, struct gnScissor_t scissor) {
|
||||
MTLScissorRect scissorRect = { scissor.position.x, scissor.position.y, scissor.size.x, scissor.size.y };
|
||||
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>)buffer->commandBuffer->encoder;
|
||||
[encoder setScissorRect:scissorRect];
|
||||
}
|
||||
void gnCommandBindBufferFn(gnCommandBufferHandle buffer, gnBufferHandle bufferToBind, gnBufferType type) {
|
||||
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>)buffer->commandBuffer->encoder;
|
||||
if (type == GN_VERTEX_BUFFER)
|
||||
[encoder setVertexBuffer:bufferToBind->buffer->buffer offset:0 atIndex:0];
|
||||
else if (type == GN_INDEX_BUFFER)
|
||||
buffer->commandBuffer->indexBuffer = bufferToBind;
|
||||
}
|
||||
void gnCommandDrawFn(struct gnCommandBuffer_t* buffer, int vertexCount, int firstVertex, int instanceCount, int firstInstance) {
|
||||
if (buffer->commandBuffer->boundGraphcisPipeline != NULL) {
|
||||
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>)buffer->commandBuffer->encoder;
|
||||
if (buffer->commandBuffer->boundGraphcisPipeline->info.primitiveType == GN_PRIMITIVE_POINTS)
|
||||
[encoder drawPrimitives:MTLPrimitiveTypePoint vertexStart:firstVertex vertexCount:vertexCount instanceCount:instanceCount baseInstance:firstInstance];
|
||||
else if (buffer->commandBuffer->boundGraphcisPipeline->info.primitiveType == GN_PRIMITIVE_LINES)
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:firstVertex vertexCount:vertexCount instanceCount:instanceCount baseInstance:firstInstance];
|
||||
else if (buffer->commandBuffer->boundGraphcisPipeline->info.primitiveType == GN_PRIMITIVE_LINE_STRIP)
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:firstVertex vertexCount:vertexCount instanceCount:instanceCount baseInstance:firstInstance];
|
||||
else if (buffer->commandBuffer->boundGraphcisPipeline->info.primitiveType == GN_PRIMITIVE_TRIANGLES)
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:firstVertex vertexCount:vertexCount instanceCount:instanceCount baseInstance:firstInstance];
|
||||
else if (buffer->commandBuffer->boundGraphcisPipeline->info.primitiveType == GN_PRIMITIVE_TRIANGLE_STRIP)
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:firstVertex vertexCount:vertexCount instanceCount:instanceCount baseInstance:firstInstance];
|
||||
}
|
||||
}
|
||||
void gnCommandDrawIndexedFn(gnCommandBufferHandle buffer, gnIndexType type, int indexCount, int firstIndex, int vertexOffset, int instanceCount, int firstInstance) {
|
||||
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>)buffer->commandBuffer->encoder;
|
||||
MTLPrimitiveType primative;
|
||||
switch (buffer->commandBuffer->boundGraphcisPipeline->info.primitiveType) {
|
||||
case GN_PRIMITIVE_POINTS: primative = MTLPrimitiveTypePoint; break;
|
||||
case GN_PRIMITIVE_LINE_STRIP: primative = MTLPrimitiveTypeLineStrip; break;
|
||||
case GN_PRIMITIVE_LINES: primative = MTLPrimitiveTypeLine; break;
|
||||
case GN_PRIMITIVE_TRIANGLE_STRIP: primative = MTLPrimitiveTypeTriangleStrip; break;
|
||||
case GN_PRIMITIVE_TRIANGLES: primative = MTLPrimitiveTypeTriangle; break;
|
||||
}
|
||||
[encoder
|
||||
drawIndexedPrimitives:primative
|
||||
indexCount:indexCount
|
||||
indexType:((type == GN_UINT32) ? MTLIndexTypeUInt32 : MTLIndexTypeUInt16)
|
||||
indexBuffer:buffer->commandBuffer->indexBuffer->buffer->buffer
|
||||
indexBufferOffset:0
|
||||
instanceCount:instanceCount
|
||||
baseVertex:vertexOffset
|
||||
baseInstance:firstInstance
|
||||
];
|
||||
}
|
||||
|
||||
void gnCommandBindUniformFn(gnCommandBufferHandle buffer, gnUniform uniform, uint32_t set) {
|
||||
id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>)buffer->commandBuffer->encoder;
|
||||
if (uniform->uniform->type == GN_UNIFORM_BUFFER_DESCRIPTOR) {
|
||||
gnBufferUniformInfo info = *(gnBufferUniformInfo*)uniform->uniform->data;
|
||||
|
||||
[encoder setVertexBuffer:info.buffer->buffer->buffer
|
||||
offset:info.offset
|
||||
atIndex:(info.binding + 1)
|
||||
];
|
||||
}
|
||||
}
|
9
projects/apis/metal/src/debugger/metal_debugger.m
Normal file
9
projects/apis/metal/src/debugger/metal_debugger.m
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <core/debugger/gryphn_debugger.h>
|
||||
|
||||
// these do nothing because I am too lazy to write a debugger for metal at this point in time
|
||||
gnReturnCode gnCreateDebuggerFn(gnDebuggerHandle debugger, gnInstanceHandle instance, const struct gnDebuggerInfo_t info) {
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
void gnDestroyDebuggerFn(gnDebuggerHandle instance) {
|
||||
|
||||
}
|
37
projects/apis/metal/src/devices/metal_output_device.m
Normal file
37
projects/apis/metal/src/devices/metal_output_device.m
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <core/output_device/gryphn_physical_output_device.h>
|
||||
#include <Metal/Metal.h>
|
||||
#include "metal_output_devices.h"
|
||||
#include "core/instance/metal_instance.h"
|
||||
#include "core/instance/gryphn_instance.h"
|
||||
#include <core/debugger/gryphn_debugger.h>
|
||||
|
||||
gnReturnCode gnCreateOutputDeviceFn(gnOutputDeviceHandle outputDevice, gnInstanceHandle instance, struct gnOutputDeviceInfo_t deviceInfo) {
|
||||
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<MTLCommandQueue>) * deviceInfo.queueInfoCount);
|
||||
// for (int i = 0; i < deviceInfo.queueInfoCount; i++) {
|
||||
// outputDevice->outputDevice->queues[i] = outputDevice->outputDevice->device.newCommandQueue;
|
||||
// }
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnWaitForDeviceFn(gnOutputDeviceHandle device) {
|
||||
[device->outputDevice->executingCommandBuffer waitUntilCompleted];
|
||||
}
|
||||
|
||||
void gnDestroyOutputDeviceFn(gnOutputDeviceHandle device) {
|
||||
// for (int i = 0; i < device->outputDevice->queueCount; i++) {
|
||||
// [device->outputDevice->queues[i] release];
|
||||
// }
|
||||
[device->outputDevice->transferQueue release];
|
||||
[device->outputDevice->device release];
|
||||
free(device->outputDevice);
|
||||
}
|
||||
|
||||
// struct mtlFramebufferVertex {
|
||||
// float x, y;
|
||||
// float u, v;
|
||||
// };
|
18
projects/apis/metal/src/devices/metal_output_devices.h
Normal file
18
projects/apis/metal/src/devices/metal_output_devices.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "core/instance/gryphn_instance.h"
|
||||
#include "core/output_device/gryphn_output_device.h"
|
||||
#include <Metal/Metal.h>
|
||||
#include <MetalKit/MetalKit.h>
|
||||
|
||||
struct gnPlatformPhysicalDevice_t {
|
||||
id<MTLDevice> device;
|
||||
} gnPlatformPhysicalDevice;
|
||||
|
||||
struct gnPlatformOutputDevice_t {
|
||||
id<MTLDevice> device;
|
||||
MTKView* contentView;
|
||||
|
||||
id<MTLCommandBuffer> executingCommandBuffer;
|
||||
id<MTLCommandQueue> transferQueue;
|
||||
// id<MTLRenderPipelineState> framebuffer;
|
||||
} gnPlatformOutputDevice;
|
39
projects/apis/metal/src/devices/metal_physical_device.m
Normal file
39
projects/apis/metal/src/devices/metal_physical_device.m
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <core/output_device/gryphn_physical_output_device.h>
|
||||
#include <Metal/Metal.h>
|
||||
#include "metal_output_devices.h"
|
||||
#include "core/window_surface/gryphn_surface.h"
|
||||
|
||||
gnPhysicalDevice* gnGetPhysicalDevicesFn(gnInstanceHandle instance, uint32_t* deviceCount) {
|
||||
NSArray *devices = MTLCopyAllDevices();
|
||||
*deviceCount = [devices count];
|
||||
gnPhysicalDevice* devicesList = (gnPhysicalDevice*)malloc(sizeof(gnPhysicalDevice) * *deviceCount);
|
||||
for (int i = 0; i < *deviceCount; i++) {
|
||||
devicesList[i].physicalDevice = malloc(sizeof(gnPlatformPhysicalDevice));
|
||||
devicesList[i].physicalDevice->device = [devices objectAtIndex:0];
|
||||
|
||||
|
||||
id<MTLDevice> device = [devices objectAtIndex:0];
|
||||
devicesList[i].properties.name = gnCreateString([[device name] cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
MTLDeviceLocation deviceLocation = device.locationNumber;
|
||||
if (deviceLocation == MTLDeviceLocationBuiltIn)
|
||||
devicesList[i].properties.deviceType = GN_INTEGRATED_DEVICE;
|
||||
else if (deviceLocation == MTLDeviceLocationSlot)
|
||||
devicesList[i].properties.deviceType = GN_DEDICATED_DEVICE;
|
||||
else if (deviceLocation == MTLDeviceLocationExternal)
|
||||
devicesList[i].properties.deviceType = GN_EXTERNAL_DEVICE;
|
||||
|
||||
// below I am going to fake that there is one queue that can support graphics, compute, and transfer queues
|
||||
devicesList[i].queueProperties.queueCount = 1;
|
||||
devicesList[i].queueProperties.queueProperties = malloc(sizeof(gnQueueProperties));
|
||||
devicesList[i].queueProperties.queueProperties[0] = (gnQueueProperties){
|
||||
.queueCount = 1,
|
||||
.queueType = GN_QUEUE_GRAPHICS | GN_QUEUE_COMPUTE | GN_QUEUE_TRANSFER
|
||||
};
|
||||
}
|
||||
[devices release];
|
||||
return devicesList;
|
||||
}
|
||||
|
||||
gnBool gnQueueCanPresentToSurfaceFn(const struct gnPhysicalDevice_t device, uint32_t queueIndex, const struct gnWindowSurface_t windowSurface) {
|
||||
return gnTrue; // I belive that a window should always be able to present to a surface in metal
|
||||
}
|
13
projects/apis/metal/src/framebuffers/metal_framebuffer.h
Normal file
13
projects/apis/metal/src/framebuffers/metal_framebuffer.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "core/framebuffer/gryphn_framebuffer.h"
|
||||
#include "utils/gryphn_bool.h"
|
||||
#include "utils/gryphn_image_format.h"
|
||||
#import <Metal/Metal.h>
|
||||
#import <Metal/MTLRenderPass.h>
|
||||
|
||||
typedef struct gnPlatformFramebuffer_t {
|
||||
MTLRenderPassDescriptor* framebuffer;
|
||||
} gnPlatformFramebuffer;
|
||||
|
||||
gnBool isDepthFormat(gnImageFormat format);
|
||||
gnBool isStencilFormat(gnImageFormat format);
|
79
projects/apis/metal/src/framebuffers/metal_framebuffer.m
Normal file
79
projects/apis/metal/src/framebuffers/metal_framebuffer.m
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "metal_framebuffer.h"
|
||||
#include "core/debugger/gryphn_debugger.h"
|
||||
#include "core/texture/metal_texture.h"
|
||||
#include "core/renderpass/gryphn_render_pass_descriptor.h"
|
||||
#include "core/instance/gryphn_instance.h"
|
||||
|
||||
gnBool isDepthFormat(gnImageFormat format) {
|
||||
return gnFalse;
|
||||
}
|
||||
|
||||
gnBool isStencilFormat(gnImageFormat format) {
|
||||
return gnFalse;
|
||||
}
|
||||
|
||||
MTLLoadAction mtlGryphnLoadOperation(enum gnLoadOperation_e loadOperation) {
|
||||
switch(loadOperation) {
|
||||
case GN_LOAD_OPERATION_LOAD: return MTLLoadActionLoad;
|
||||
case GN_LOAD_OPERATION_CLEAR: return MTLLoadActionClear;
|
||||
case GN_LOAD_OPERATION_DONT_CARE: return MTLLoadActionDontCare;
|
||||
}
|
||||
}
|
||||
|
||||
MTLStoreAction mtlGryphnStoreOperation(enum gnStoreOperation_e storeOperation) {
|
||||
switch (storeOperation) {
|
||||
case GN_STORE_OPERATION_STORE: return MTLStoreActionStore;
|
||||
case GN_STORE_OPERATION_DONT_CARE: return MTLStoreActionDontCare;
|
||||
}
|
||||
}
|
||||
|
||||
gnReturnCode gnCreateFramebufferFn(struct gnFramebuffer_t* framebuffer, struct gnOutputDevice_t* device, struct gnFramebufferInfo_t info) {
|
||||
framebuffer->framebuffer = malloc(sizeof(struct gnPlatformFramebuffer_t));
|
||||
if (info.attachmentCount != info.renderPassDescriptor->info.attachmentCount) {
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCreateString("Attachment count on framebuffer does not equal attachment count on render pass descriptor")
|
||||
});
|
||||
return GN_DIVERGENT_RENDERPASS;
|
||||
}
|
||||
|
||||
framebuffer->framebuffer->framebuffer = [[MTLRenderPassDescriptor alloc] init];
|
||||
[framebuffer->framebuffer->framebuffer setRenderTargetWidth:info.size.x];
|
||||
[framebuffer->framebuffer->framebuffer setRenderTargetHeight:info.size.y];
|
||||
|
||||
int colorAttachment = 0;
|
||||
for (int i = 0; i < info.renderPassDescriptor->info.attachmentCount; i++) {
|
||||
gnBool wasDepthStencil = gnFalse;
|
||||
if (isDepthFormat(info.renderPassDescriptor->info.attachmentInfos[i].format)) {
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCreateString("Depth attachments are not currently supported in metal (get on this)")
|
||||
});
|
||||
wasDepthStencil = gnTrue;
|
||||
}
|
||||
if (isStencilFormat(info.renderPassDescriptor->info.attachmentInfos[i].format)) {
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCreateString("Stencil attachments are not currently supported in metal (get on this)")
|
||||
});
|
||||
wasDepthStencil = gnTrue;
|
||||
}
|
||||
|
||||
if(!wasDepthStencil) {
|
||||
MTLRenderPassColorAttachmentDescriptor* color = framebuffer->framebuffer->framebuffer.colorAttachments[colorAttachment];
|
||||
color.texture = info.attachments[i]->texture->texture;
|
||||
|
||||
color.loadAction = mtlGryphnLoadOperation(info.renderPassDescriptor->info.attachmentInfos[i].loadOperation);
|
||||
color.storeAction = mtlGryphnStoreOperation(info.renderPassDescriptor->info.attachmentInfos[i].storeOperation);
|
||||
|
||||
if (color.loadAction == MTLLoadActionClear)
|
||||
color.clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
colorAttachment++;
|
||||
}
|
||||
}
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnDestroyFramebufferFn(struct gnFramebuffer_t* framebuffer) {
|
||||
[framebuffer->framebuffer->framebuffer release];
|
||||
free(framebuffer->framebuffer);
|
||||
}
|
7
projects/apis/metal/src/instance/metal_instance.h
Normal file
7
projects/apis/metal/src/instance/metal_instance.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <Metal/MTLRenderPipeline.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
typedef struct gnPlatformInstance_t {
|
||||
NSView* metalContentView;
|
||||
} gnPlatformInstance;
|
14
projects/apis/metal/src/instance/metal_instance.m
Normal file
14
projects/apis/metal/src/instance/metal_instance.m
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <gryphn/gryphn.h>
|
||||
#include <gryphn/gryphn_utils.h>
|
||||
#include "metal_instance.h"
|
||||
// #include "bridge/metal_bridge.h"
|
||||
|
||||
|
||||
gnReturnCode gnCreateInstanceFn(gnInstanceHandle instance, gnInstanceInfo instanceInfo) {
|
||||
if (instance->instance == NULL) instance->instance = malloc(sizeof(gnPlatformInstance));
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnDestroyInstanceFn(gnInstanceHandle instance) {
|
||||
free(instance->instance);
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "core/pipelines/graphics_pipeline/gryphn_graphics_pipeline.h"
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
typedef struct gnPlatformGraphicsPipeline_t {
|
||||
id<MTLRenderPipelineState> graphicsPipeline;
|
||||
} gnPlatformGraphicsPipeline;
|
@@ -0,0 +1,103 @@
|
||||
#include "metal_graphics_pipeline.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
#include "core/debugger/gryphn_debugger.h"
|
||||
#include "core/shader_module/metal_shader_module.h"
|
||||
#include "core/surface/metal_surface.h"
|
||||
|
||||
MTLBlendFactor vkGryphnBlendFactor(enum gnBlendFactor_e factor) {
|
||||
switch (factor) {
|
||||
case GN_BLEND_FACTOR_ZERO: return MTLBlendFactorZero;
|
||||
case GN_BLEND_FACTOR_ONE: return MTLBlendFactorOne;
|
||||
case GN_BLEND_FACTOR_SRC_ALPHA: return MTLBlendFactorSourceAlpha;
|
||||
case GN_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: return MTLBlendFactorOneMinusSourceAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
MTLBlendOperation vkGryphnBlendOperation(enum gnBlendOperation_e operation) {
|
||||
switch(operation) {
|
||||
case GN_OPERATION_ADD: return MTLBlendOperationAdd;
|
||||
}
|
||||
}
|
||||
|
||||
MTLVertexFormat mtlGryphnVertexFormat(gnVertexFormat format) {
|
||||
switch (format) {
|
||||
case GN_FLOAT2: return MTLVertexFormatFloat2;
|
||||
case GN_FLOAT3: return MTLVertexFormatFloat3;
|
||||
}
|
||||
}
|
||||
|
||||
gnReturnCode gnCreateGraphicsPipelineFn(struct gnGraphicsPipeline_t* graphicsPipeline, struct gnOutputDevice_t* device, struct gnGraphicsPipelineInfo_t info) {
|
||||
graphicsPipeline->graphicsPipeline = malloc(sizeof(struct gnPlatformGraphicsPipeline_t));
|
||||
MTLRenderPipelineDescriptor* descriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
|
||||
if (info.subpassIndex >= info.renderPassDescriptor->info.subpassCount) {
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCreateString("Subpass index is larger then the subpass count in render pass descriptor")
|
||||
});
|
||||
return GN_UNKNOWN_SUBPASS;
|
||||
}
|
||||
|
||||
struct gnSubpassInfo_t subpass = info.renderPassDescriptor->info.subpassInfos[info.subpassIndex];
|
||||
|
||||
for (uint32_t i = 0; i < subpass.colorAttachmentCount; i++) {
|
||||
gnSubpassAttachmentInfo subpassAtt = subpass.colorAttachments[i];
|
||||
|
||||
gnRenderPassAttachmentInfo attInfo = info.renderPassDescriptor->info.attachmentInfos[subpassAtt.index];
|
||||
descriptor.colorAttachments[i].pixelFormat = mtlGryphnFormatToVulkanFormat(attInfo.format);
|
||||
if (info.colorBlending.enable == gnTrue) {
|
||||
[descriptor.colorAttachments objectAtIndexedSubscript:i].blendingEnabled = YES;
|
||||
[descriptor.colorAttachments objectAtIndexedSubscript:i].rgbBlendOperation = vkGryphnBlendOperation(info.colorBlending.colorBlendOperation);
|
||||
[descriptor.colorAttachments objectAtIndexedSubscript:i].alphaBlendOperation = vkGryphnBlendOperation(info.colorBlending.alphaBlendOperation);
|
||||
[descriptor.colorAttachments objectAtIndexedSubscript:i].sourceRGBBlendFactor = vkGryphnBlendFactor(info.colorBlending.sourceColorBlendFactor);
|
||||
[descriptor.colorAttachments objectAtIndexedSubscript:i].sourceAlphaBlendFactor = vkGryphnBlendFactor(info.colorBlending.sourceAlphaBlendFactor);
|
||||
[descriptor.colorAttachments objectAtIndexedSubscript:i].destinationRGBBlendFactor = vkGryphnBlendFactor(info.colorBlending.destinationColorBlendFactor);
|
||||
[descriptor.colorAttachments objectAtIndexedSubscript:i].destinationAlphaBlendFactor = vkGryphnBlendFactor(info.colorBlending.destinationAlphaBlendFactor);
|
||||
} else {
|
||||
[descriptor.colorAttachments objectAtIndexedSubscript:i].blendingEnabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < info.shaderModuleCount; i++) {
|
||||
if (info.shaderModules[i]->info.stage == GN_VERTEX_SHADER_MODULE) {
|
||||
[descriptor setVertexFunction:info.shaderModules[i]->shaderModule->function];
|
||||
} else if (info.shaderModules[i]->info.stage == GN_FRAGMENT_SHADER_MODULE) {
|
||||
[descriptor setFragmentFunction:info.shaderModules[i]->shaderModule->function];
|
||||
} else {
|
||||
return GN_UNSUPPORTED_SHADER_MODULE;
|
||||
}
|
||||
}
|
||||
|
||||
MTLVertexDescriptor* vertexDescriptor = [[MTLVertexDescriptor alloc] init];
|
||||
MTLVertexAttributeDescriptorArray* attributes = vertexDescriptor.attributes;
|
||||
MTLVertexBufferLayoutDescriptorArray* buffers = vertexDescriptor.layouts;
|
||||
|
||||
int k = 0;
|
||||
for (int i = 0; i < info.shaderInputLayout.bufferCount; i++) {
|
||||
[[buffers objectAtIndexedSubscript:info.shaderInputLayout.bufferAttributes[i].binding] setStride:info.shaderInputLayout.bufferAttributes[i].size];
|
||||
for (int j = 0; j < info.shaderInputLayout.bufferAttributes[i].attributeCount; j++) {
|
||||
attributes[k].bufferIndex = i;
|
||||
attributes[k].offset = info.shaderInputLayout.bufferAttributes[i].attributes[j].offset;
|
||||
attributes[k].format = mtlGryphnVertexFormat(info.shaderInputLayout.bufferAttributes[i].attributes[j].format);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
[descriptor setVertexDescriptor:vertexDescriptor];
|
||||
NSError* error = nil;
|
||||
graphicsPipeline->graphicsPipeline->graphicsPipeline = [device->outputDevice->device newRenderPipelineStateWithDescriptor:descriptor error:&error];
|
||||
if (graphicsPipeline->graphicsPipeline->graphicsPipeline == nil) {
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCombineStrings(gnCreateString("Failed to create metal render pipeline descriptor "), error.localizedDescription.UTF8String)
|
||||
});
|
||||
return GN_FAILED_TO_CREATE_GRAPHICS_PIPELINE;
|
||||
}
|
||||
[descriptor release];
|
||||
[vertexDescriptor release];
|
||||
[error release];
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnDestroyGraphicsPipelineFn(struct gnGraphicsPipeline_t *graphicsPipeline) {
|
||||
[graphicsPipeline->graphicsPipeline->graphicsPipeline release];
|
||||
free(graphicsPipeline->graphicsPipeline);
|
||||
}
|
62
projects/apis/metal/src/present/metal_present.m
Normal file
62
projects/apis/metal/src/present/metal_present.m
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "core/present/gryphn_present.h"
|
||||
#include "core/instance/metal_instance.h"
|
||||
#include "core/surface/metal_surface.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
#include "core/sync/semaphore/metal_semaphore.h"
|
||||
#include "core/presentation_queue/metal_presentation_queue.h"
|
||||
#include "core/debugger/gryphn_debugger.h"
|
||||
#include "core/texture/metal_texture.h"
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
gnReturnCode gnPresentFn(gnOutputDeviceHandle device, struct gnPresentInfo_t info) {
|
||||
for (int i = 0; i < info.waitCount; i++) {
|
||||
while (!info.waitSemaphores[i]->semaphore->eventTriggered) {}
|
||||
}
|
||||
|
||||
for (int i =0 ; i < info.presentationQueueCount; i++) {
|
||||
info.presentationQueues[i]->info.surface->windowSurface->layer.device = device->outputDevice->device;
|
||||
id<CAMetalDrawable> drawable = [info.presentationQueues[i]->info.surface->windowSurface->layer nextDrawable];
|
||||
if (drawable == nil) {
|
||||
return GN_FAILED_TO_CREATE_FRAMEBUFFER;
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> commandBuffer = [device->outputDevice->transferQueue commandBuffer];
|
||||
|
||||
MTLRenderPassDescriptor* passDesc = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
passDesc.colorAttachments[0].texture = drawable.texture;
|
||||
passDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
passDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
passDesc.colorAttachments[0].clearColor = MTLClearColorMake(1.0f, 0, 0, 1.0f);
|
||||
id<MTLRenderCommandEncoder> render = [commandBuffer renderCommandEncoderWithDescriptor:passDesc];
|
||||
[render endEncoding];
|
||||
|
||||
id<MTLBlitCommandEncoder> blit = [commandBuffer blitCommandEncoder];
|
||||
|
||||
[blit copyFromTexture:info.presentationQueues[i]->images[info.imageIndices[i]]->texture->texture
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:(MTLOrigin){0, 0, 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];
|
||||
|
||||
[commandBuffer presentDrawable:drawable];
|
||||
[commandBuffer commit];
|
||||
device->outputDevice->executingCommandBuffer = commandBuffer;
|
||||
}
|
||||
|
||||
[device->outputDevice->executingCommandBuffer waitUntilScheduled];
|
||||
|
||||
for (int 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;
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#import <Metal/Metal.h>
|
||||
#include "core/presentation_queue/gryphn_presentation_queue.h"
|
||||
|
||||
typedef struct gnPlatformPresentationQueue_t {
|
||||
int textureCount;
|
||||
id<MTLTexture>* textures;
|
||||
|
||||
uint32_t currentImage;
|
||||
} gnPlatformPresentationQueue;
|
@@ -0,0 +1,64 @@
|
||||
#include "metal_presentation_queue.h"
|
||||
#include "core/surface/metal_surface.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
#include "core/debugger/gryphn_debugger.h"
|
||||
#include "core/texture/metal_texture.h"
|
||||
#include "core/sync/semaphore/metal_semaphore.h"
|
||||
|
||||
gnReturnCode gnCreatePresentationQueueFn(gnPresentationQueueHandle presentationQueue, const gnOutputDeviceHandle device, struct gnPresentationQueueInfo_t presentationInfo) {
|
||||
if (presentationInfo.minImageCount > 3) {
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCreateString("On Metal you cannot have more than 3 images in a presentation queue")
|
||||
});
|
||||
return GN_UNSUPPORTED_IMAGE_COUNT;
|
||||
}
|
||||
|
||||
if (presentationInfo.minImageCount < 2) {
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCreateString("On Metal you cannot have less than 2 images in a presentation queue")
|
||||
});
|
||||
return GN_UNSUPPORTED_IMAGE_COUNT;
|
||||
}
|
||||
|
||||
presentationQueue->presentationQueue = malloc(sizeof(struct gnPlatformPresentationQueue_t));
|
||||
|
||||
MTLPixelFormat convertedFormat = mtlGryphnFormatToVulkanFormat(presentationInfo.format.format);
|
||||
CGColorSpaceRef convertedColorSpace = mtlGryphnColorSpaceToVulkanColorSpace(presentationInfo.format.colorSpace);
|
||||
|
||||
presentationQueue->presentationQueue->textureCount = presentationInfo.minImageCount;
|
||||
presentationQueue->presentationQueue->textures = malloc(sizeof(id<MTLTexture>) * presentationInfo.minImageCount);
|
||||
|
||||
MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init];
|
||||
textureDescriptor.pixelFormat = convertedFormat;
|
||||
textureDescriptor.width = presentationInfo.imageSize.x;
|
||||
textureDescriptor.height = presentationInfo.imageSize.y;
|
||||
textureDescriptor.usage = MTLTextureUsageRenderTarget;
|
||||
textureDescriptor.textureType = MTLTextureType2D;
|
||||
|
||||
presentationQueue->imageCount = presentationInfo.minImageCount;
|
||||
presentationQueue->images = malloc(sizeof(gnTexture) * presentationInfo.minImageCount);
|
||||
for (int i = 0; i < presentationInfo.minImageCount; i++) {
|
||||
presentationQueue->presentationQueue->textures[i] = [device->outputDevice->device newTextureWithDescriptor:textureDescriptor];
|
||||
presentationQueue->images[i] = malloc(sizeof(struct gnTexture_t));
|
||||
presentationQueue->images[i]->texture = malloc(sizeof(gnPlatformTexture));
|
||||
presentationQueue->images[i]->texture->texture = presentationQueue->presentationQueue->textures[i];
|
||||
}
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
gnReturnCode gnPresentationQueueGetImageFn(gnPresentationQueueHandle presentationQueue, uint64_t timeout, struct gnSemaphore_t* semaphore, uint32_t* imageIndex) {
|
||||
semaphore->semaphore->eventTriggered = gnFalse;
|
||||
*imageIndex = presentationQueue->presentationQueue->currentImage;
|
||||
presentationQueue->presentationQueue->currentImage++;
|
||||
presentationQueue->presentationQueue->currentImage %= presentationQueue->imageCount;
|
||||
semaphore->semaphore->eventTriggered = gnTrue;
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnDestroyPresentationQueueFn(gnPresentationQueueHandle presentationQueue) {
|
||||
for (int i = 0; i < presentationQueue->imageCount; i++) {
|
||||
[presentationQueue->presentationQueue->textures[i] release];
|
||||
}
|
||||
free(presentationQueue->presentationQueue);
|
||||
}
|
7
projects/apis/metal/src/renderpass/metal_render_pass.h
Normal file
7
projects/apis/metal/src/renderpass/metal_render_pass.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "core/renderpass/gryphn_render_pass_descriptor.h"
|
||||
#import <Metal/MTLRenderPass.h>
|
||||
|
||||
typedef struct gnPlatformRenderPassDescriptor_t {
|
||||
MTLRenderPassDescriptor* passDescriptor;
|
||||
} gnPlatformRenderPassDescriptor;
|
13
projects/apis/metal/src/renderpass/metal_render_pass.m
Normal file
13
projects/apis/metal/src/renderpass/metal_render_pass.m
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "metal_render_pass.h"
|
||||
|
||||
gnReturnCode gnCreateRenderPassDescriptorFn(struct gnRenderPassDescriptor_t* renderPass, struct gnOutputDevice_t* device, struct gnRenderPassDescriptorInfo_t info) {
|
||||
renderPass->renderPassDescriptor = malloc(sizeof(gnPlatformRenderPassDescriptor));
|
||||
renderPass->renderPassDescriptor->passDescriptor = [[MTLRenderPassDescriptor alloc] init];
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnDestroyRenderPassDescriptorFn(struct gnRenderPassDescriptor_t* renderPass) {
|
||||
[renderPass->renderPassDescriptor->passDescriptor release];
|
||||
free(renderPass->renderPassDescriptor);
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "core/shader_module/gryphn_shader_module.h"
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
typedef struct gnPlatformShaderModule_t {
|
||||
id<MTLFunction> function;
|
||||
} gnPlatformShaderModule;
|
101
projects/apis/metal/src/shader_module/metal_shader_module.m
Normal file
101
projects/apis/metal/src/shader_module/metal_shader_module.m
Normal file
@@ -0,0 +1,101 @@
|
||||
#include "metal_shader_module.h"
|
||||
#include "spirv_cross_c.h"
|
||||
#include "core/debugger/gryphn_debugger.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
void mtlSpirVErrorCallback(void *userdata, const char *error) {
|
||||
struct gnDebugger_t* debugger = (struct gnDebugger_t*)userdata;
|
||||
gnDebuggerSetErrorMessage(debugger, (gnMessageData){
|
||||
.message = gnCreateString(error)
|
||||
});
|
||||
}
|
||||
|
||||
gnReturnCode gnCreateShaderModuleFn(struct gnShaderModule_t *module, struct gnOutputDevice_t *device, struct gnShaderModuleInfo_t shaderModuleInfo) {
|
||||
module->shaderModule = malloc(sizeof(struct gnPlatformShaderModule_t));
|
||||
|
||||
spvc_context context = NULL;
|
||||
spvc_parsed_ir ir = NULL;
|
||||
spvc_compiler compiler = NULL;
|
||||
const char *result = NULL;
|
||||
spvc_resources resources = NULL;
|
||||
const spvc_reflected_resource *list = NULL;
|
||||
spvc_compiler_options options = NULL;
|
||||
size_t count;
|
||||
|
||||
spvc_context_create(&context);
|
||||
spvc_context_set_error_callback(context, mtlSpirVErrorCallback, module->device->instance->debugger);
|
||||
spvc_context_parse_spirv(context, shaderModuleInfo.code, shaderModuleInfo.size / 4, &ir);
|
||||
spvc_context_create_compiler(context, SPVC_BACKEND_MSL, ir, SPVC_CAPTURE_MODE_COPY, &compiler);
|
||||
|
||||
spvc_compiler_create_shader_resources(compiler, &resources);
|
||||
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);
|
||||
|
||||
for (int i = 0; i < count; i++){
|
||||
uint32_t set = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
|
||||
binding = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
||||
|
||||
if ((shaderModuleInfo.stage & GN_VERTEX_SHADER_MODULE) == GN_VERTEX_SHADER_MODULE)
|
||||
binding += 1;
|
||||
spvc_compiler_unset_decoration(compiler, list[i].id, SpvDecorationBinding);
|
||||
spvc_compiler_set_decoration(compiler, list[i].id, SpvDecorationBinding, binding);
|
||||
}
|
||||
|
||||
|
||||
spvc_compiler_create_compiler_options(compiler, &options);
|
||||
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_MSL_VERSION, 200);
|
||||
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING, true);
|
||||
spvc_compiler_install_compiler_options(compiler, options);
|
||||
|
||||
SpvExecutionModel executionModel = SpvExecutionModelVertex;
|
||||
if (shaderModuleInfo.stage == GN_FRAGMENT_SHADER_MODULE) executionModel = SpvExecutionModelFragment;
|
||||
|
||||
spvc_compiler_set_entry_point(compiler, shaderModuleInfo.entryPoint.value, executionModel);
|
||||
spvc_result res = spvc_compiler_compile(compiler, &result);
|
||||
if (res != SPVC_SUCCESS)
|
||||
return GN_FAILED_TO_CONVERT_SHADER_CODE;
|
||||
|
||||
NSError* error = nil;
|
||||
MTLCompileOptions* mtloptions = nil;
|
||||
NSString* sourceCode = [NSString stringWithCString:result encoding:NSUTF8StringEncoding];
|
||||
id<MTLLibrary> shaderLib = [device->outputDevice->device newLibraryWithSource:sourceCode options:mtloptions error:&error];
|
||||
if (!shaderLib) {
|
||||
const char* errorString = error.localizedDescription.UTF8String;
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCombineStrings(gnCreateString("Failed to compile metal library "), errorString)
|
||||
});
|
||||
return GN_FAILED_TO_CREATE_SHADER_MODULE;
|
||||
}
|
||||
|
||||
const char* name = shaderModuleInfo.entryPoint.value;
|
||||
if (strcmp(name, "main") == 0) {
|
||||
name = "main0";
|
||||
}
|
||||
|
||||
gnBool foundFunction = false;
|
||||
for (int i = 0; i < shaderLib.functionNames.count; i++) {
|
||||
if (strcmp([shaderLib.functionNames objectAtIndex:0].UTF8String, name) == 0) {
|
||||
foundFunction = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundFunction) {
|
||||
gnDebuggerSetErrorMessage(device->instance->debugger, (gnMessageData){
|
||||
.message = gnCombineStrings(gnCreateString("Failed to find specified entry point "), name)
|
||||
});
|
||||
return GN_FAILED_TO_FIND_ENTRY_POINT;
|
||||
}
|
||||
|
||||
NSString* functionName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
|
||||
module->shaderModule->function = [shaderLib newFunctionWithName:functionName];
|
||||
|
||||
[shaderLib release];
|
||||
|
||||
spvc_context_destroy(context);
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnDestroyShaderModuleFn(struct gnShaderModule_t* module) {
|
||||
free(module->shaderModule);
|
||||
}
|
30
projects/apis/metal/src/submit/metal_submit.m
Normal file
30
projects/apis/metal/src/submit/metal_submit.m
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "core/submit/gryphn_submit.h"
|
||||
#include "core/sync/semaphore/metal_semaphore.h"
|
||||
#include "core/commands/command_buffer/metal_command_buffer.h"
|
||||
#include "core/debugger/gryphn_debugger.h"
|
||||
#include "core/commands/command_pool/metal_command_pool.h"
|
||||
|
||||
gnReturnCode gnSubmitFn(struct gnOutputDevice_t* device, struct gnSubmitInfo_t info) {
|
||||
for (int i = 0; i < info.waitCount; i++) {
|
||||
while (!info.waitSemaphores[i]->semaphore->eventTriggered) {}
|
||||
}
|
||||
|
||||
|
||||
__block gnSemaphore* semsToSignal = info.signalSemaphores;
|
||||
__block int semsToSignalCount = info.signalCount;
|
||||
__block gnFence fenceToSignal = info.fence;
|
||||
|
||||
for (int i = 0; i < info.commandBufferCount; i++) {
|
||||
id<MTLCommandBuffer> commandBuffer = info.commandBuffers[i]->commandBuffer->commandBuffer;
|
||||
[info.commandBuffers[i]->commandBuffer->commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
||||
for (int c = 0; c < semsToSignalCount; c++) {
|
||||
semsToSignal[c]->semaphore->eventTriggered = gnTrue;
|
||||
}
|
||||
}];
|
||||
fenceToSignal->signaled = gnTrue;
|
||||
|
||||
[commandBuffer commit];
|
||||
}
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
11
projects/apis/metal/src/surface/metal_surface.h
Normal file
11
projects/apis/metal/src/surface/metal_surface.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "core/window_surface/gryphn_surface.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
typedef struct gnPlatformWindowSurface_t {
|
||||
CAMetalLayer* layer;
|
||||
} gnPlatformWindowSurface;
|
||||
|
||||
|
||||
MTLPixelFormat mtlGryphnFormatToVulkanFormat(gnImageFormat format);
|
||||
CGColorSpaceRef mtlGryphnColorSpaceToVulkanColorSpace(gnColorSpace colorSpace);
|
43
projects/apis/metal/src/surface/metal_surface.m
Normal file
43
projects/apis/metal/src/surface/metal_surface.m
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "metal_surface.h"
|
||||
#include "core/window_surface/gryphn_surface_create_functions.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <Metal/Metal.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
gnReturnCode gnCreateMacOSWindowSurfaceFn(struct gnWindowSurface_t* windowSurface, gnInstanceHandle instance, struct gnMacOSWindowSurfaceInfo_t createInfo) {
|
||||
windowSurface->windowSurface = malloc(sizeof(gnPlatformWindowSurface));
|
||||
windowSurface->windowSurface->layer = createInfo.layer;
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
void gnDestroyWindowSurfaceFn(struct gnWindowSurface_t *windowSurface) {
|
||||
free(windowSurface->windowSurface);
|
||||
}
|
||||
|
||||
struct gnSurfaceDetails_t gnGetSurfaceDetailsFn(
|
||||
struct gnWindowSurface_t* windowSurface, struct gnPhysicalDevice_t device
|
||||
) {
|
||||
struct gnSurfaceDetails_t surfaceDetails;
|
||||
surfaceDetails.formatCount = 1;
|
||||
surfaceDetails.formats = (struct gnSurfaceFormat_t[1]){ { GN_FORMAT_BGRA8_SRGB, GN_COLOR_SPACE_SRGB_NONLINEAR } };
|
||||
surfaceDetails.minImageCount = 2;
|
||||
surfaceDetails.maxImageCount = 3;
|
||||
return surfaceDetails;
|
||||
}
|
||||
|
||||
MTLPixelFormat mtlGryphnFormatToVulkanFormat(gnImageFormat format) {
|
||||
switch (format) {
|
||||
case GN_FORMAT_BGRA8_SRGB: { return MTLPixelFormatBGRA8Unorm_sRGB; }
|
||||
default: return MTLPixelFormatInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
CGColorSpaceRef mtlGryphnColorSpaceToVulkanColorSpace(gnColorSpace colorSpace) {
|
||||
switch (colorSpace) {
|
||||
case GN_COLOR_SPACE_SRGB_NONLINEAR: { return CGColorSpaceCreateWithName(kCGColorSpaceSRGB); }
|
||||
}
|
||||
}
|
8
projects/apis/metal/src/sync/fence/metal_fence.h
Normal file
8
projects/apis/metal/src/sync/fence/metal_fence.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "core/sync/fence/gryphn_fence.h"
|
||||
#import <Metal/Metal.h>
|
||||
#import <Metal/MTLEvent.h>
|
||||
|
||||
typedef struct gnPlatformFence_t {
|
||||
|
||||
} gnPlatformFence;
|
33
projects/apis/metal/src/sync/fence/metal_fence.m
Normal file
33
projects/apis/metal/src/sync/fence/metal_fence.m
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "metal_fence.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
|
||||
gnReturnCode gnCreateFenceFn(struct gnFence_t* fence, struct gnOutputDevice_t* device) {
|
||||
// fence->fence = malloc(sizeof(gnPlatformFence));
|
||||
|
||||
// fence->fence->fence = [device->outputDevice->device newSharedEvent];
|
||||
// fence->fence->listener = [[MTLSharedEventListener alloc] init];
|
||||
// fence->fence->semaphore = dispatch_semaphore_create(1);
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
void gnSignalFenceFn(struct gnFence_t* fence) {
|
||||
// dispatch_semaphore_signal(fence->fence->semaphore);
|
||||
}
|
||||
void gnWaitForFenceFn(struct gnFence_t* fence, uint64_t timeout) {
|
||||
// dispatch_semaphore_wait(fence->fence->semaphore, timeout);
|
||||
while (fence->signaled == gnFalse) {}
|
||||
}
|
||||
void gnResetFenceFn(struct gnFence_t* fence) {
|
||||
// dispatch_semaphore_signal(fence->fence->semaphore);
|
||||
// [fence->fence->fence setSignaledValue:0];
|
||||
// [fence->fence->fence notifyListener:fence->fence->listener
|
||||
// atValue:1
|
||||
// block:^(id<MTLSharedEvent> ev, uint64_t val) {
|
||||
// dispatch_semaphore_signal(fence->fence->semaphore);
|
||||
// }];
|
||||
}
|
||||
void gnDestroyFenceFn(struct gnFence_t* fence) {
|
||||
// [fence->fence->fence release];
|
||||
// [fence->fence->listener release];
|
||||
// free(fence->fence);
|
||||
}
|
8
projects/apis/metal/src/sync/semaphore/metal_semaphore.h
Normal file
8
projects/apis/metal/src/sync/semaphore/metal_semaphore.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "core/sync/semaphore/gryphn_semaphore.h"
|
||||
#import <Metal/MTLEvent.h>
|
||||
|
||||
typedef struct gnPlatformSemaphore_t {
|
||||
id<MTLEvent> event;
|
||||
bool eventTriggered;
|
||||
} gnPlatformSemaphore;
|
13
projects/apis/metal/src/sync/semaphore/metal_semaphore.m
Normal file
13
projects/apis/metal/src/sync/semaphore/metal_semaphore.m
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "metal_semaphore.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
|
||||
gnReturnCode gnCreateSemaphoreFn(struct gnSemaphore_t* semaphore, struct gnOutputDevice_t* device) {
|
||||
semaphore->semaphore = malloc(sizeof(gnPlatformSemaphore));
|
||||
semaphore->semaphore->event = [device->outputDevice->device newEvent];
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
void gnDestroySemaphoreFn(struct gnSemaphore_t* semaphore) {
|
||||
[semaphore->semaphore->event release];
|
||||
free(semaphore->semaphore);
|
||||
}
|
7
projects/apis/metal/src/texture/metal_texture.h
Normal file
7
projects/apis/metal/src/texture/metal_texture.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "core/textures/gryphn_texture.h"
|
||||
#import <Metal/MTLTexture.h>
|
||||
|
||||
typedef struct gnPlatformTexture_t {
|
||||
id<MTLTexture> texture;
|
||||
} gnPlatformTexture;
|
7
projects/apis/metal/src/uniforms/metal_uniform.c
Normal file
7
projects/apis/metal/src/uniforms/metal_uniform.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <core/uniforms/gryphn_uniform.h>
|
||||
#include "metal_uniform.h"
|
||||
|
||||
void gnUpdateBufferUniformFn(gnUniform uniform, gnBufferUniformInfo* info) {
|
||||
uniform->uniform->data = malloc(sizeof(gnBufferUniformInfo));
|
||||
memcpy(uniform->uniform->data, info, sizeof(gnBufferUniformInfo));
|
||||
}
|
8
projects/apis/metal/src/uniforms/metal_uniform.h
Normal file
8
projects/apis/metal/src/uniforms/metal_uniform.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "core/uniforms/gryphn_uniform.h"
|
||||
#include <core/uniforms/gryphn_uniform_pool.h>
|
||||
|
||||
typedef struct gnPlatformUniform_t {
|
||||
gnUniformType type;
|
||||
void* data;
|
||||
} gnPlatformUniform;
|
19
projects/apis/metal/src/uniforms/metal_uniform_pool.c
Normal file
19
projects/apis/metal/src/uniforms/metal_uniform_pool.c
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <core/uniforms/gryphn_uniform_pool.h>
|
||||
#include <core/uniforms/gryphn_uniform.h>
|
||||
#include "metal_uniform.h"
|
||||
|
||||
gnReturnCode gnCreateUniformPoolFn(gnUniformPool pool, gnDeviceHandle device) {
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
gnUniform* gnUniformPoolAllocateUniformsFn(gnUniformPool pool, const gnUniformLayout layout) {
|
||||
gnUniform* uniforms = malloc(sizeof(gnUniform) * layout.uniformBindingCount);
|
||||
for (int i = 0; i < layout.uniformBindingCount; i++) {
|
||||
uniforms[i] = malloc(sizeof(struct gnUniform_t));
|
||||
uniforms[i]->uniform = malloc(sizeof(struct gnPlatformUniform_t));
|
||||
uniforms[i]->uniform->type = layout.uniformBindings[i].type;
|
||||
}
|
||||
return uniforms;
|
||||
}
|
||||
|
||||
void gnDestroyUniformPoolFn(gnUniformPool pool) { }
|
6
projects/apis/metal/src/uniforms/metal_uniform_pool.h
Normal file
6
projects/apis/metal/src/uniforms/metal_uniform_pool.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <core/uniforms/gryphn_uniform_pool.h>
|
||||
|
||||
struct gnPlatformUniformPool_t {
|
||||
};
|
Reference in New Issue
Block a user