first commit
This commit is contained in:
10
rendering_api/metal/src/bridge/info.txt
Normal file
10
rendering_api/metal/src/bridge/info.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
(this file is because I have zero god damn clue what is going on)
|
||||
|
||||
UHHHHHHH I FUCKING HATE APPLE WHY DO I HAVE TO WRITE OBJECTIVE C JUST SO THAT I CAN OPEN A WINDOW
|
||||
AND THAN DRAW SHIT TO IT WHY DONT YOU JUST LET ME DO ALL THIS SHIT IN PLAIN C LIKE ANY OTHER
|
||||
OPERATING SYSTEM EVEN FUCKING MICROSOFT LETS ME DO THIS SHIT IN C YOU ARE A BITCH APPLE
|
||||
NO ONE IN THERE LIFE HAS EVER WANTED TO WRITE OBJECTIVE C BECAUSE IT IS THE BIGGEST
|
||||
PEICE OF SHIT OF ALL TIME BUT THIS IS THE LITTLE OBJECTIVE C THAT I NEEDED TO WRITE TO GET
|
||||
ALL OF THIS TO WORK.
|
||||
|
||||
(please disregard this file this is just for when I forget how this project works and I want to remember why there is objective-c in here)
|
55
rendering_api/metal/src/bridge/metal_bridege.mm
Normal file
55
rendering_api/metal/src/bridge/metal_bridege.mm
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "metal_bridge.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <Metal/Metal.h>
|
||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
|
||||
void mtlObjectCSetContentViewsLayer(void* window, void* layer) {
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
|
||||
NSWindow* nsWindow = (NSWindow*)glfwGetCocoaWindow((GLFWwindow*)window);
|
||||
NSView* contentView = [nsWindow contentView];
|
||||
|
||||
CAMetalLayer* metalLayer = (__bridge CAMetalLayer*)layer;
|
||||
|
||||
[contentView setWantsLayer:YES];
|
||||
[contentView setLayer:metalLayer];
|
||||
|
||||
[CATransaction commit];
|
||||
}
|
||||
|
||||
void* mtlCreateContentView(void* targetWindow) {
|
||||
NSWindow* window = (__bridge NSWindow*)targetWindow;
|
||||
NSRect frame = [[window contentView] frame]; // fallback size
|
||||
NSView* contentView = [[NSView alloc] initWithFrame:frame];
|
||||
[window setContentView:contentView];
|
||||
|
||||
if (contentView == nullptr)
|
||||
frame = NSMakeRect(0, 0, window.frame.size.width, window.frame.size.height);
|
||||
|
||||
return contentView;
|
||||
}
|
||||
|
||||
// void* mtlInitContentView(void* targetView) {
|
||||
// NSView* view = (__bridge NSView*)targetView;
|
||||
|
||||
// CAMetalLayer* metalLayer = [CAMetalLayer layer];
|
||||
// // metalLayer.device = metalDevice;
|
||||
// metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
// metalLayer.contentsScale = [view.window backingScaleFactor];
|
||||
// metalLayer.framebufferOnly = YES;
|
||||
// view.layer = metalLayer;
|
||||
// view.wantsLayer = YES;
|
||||
// return metalLayer;
|
||||
// }
|
||||
|
||||
void mtlInitializeMetalLayer(void* layer, bool vsync) {
|
||||
CAMetalLayer* metalLayer = (__bridge CAMetalLayer*)layer;
|
||||
metalLayer.maximumDrawableCount = 3;
|
||||
metalLayer.displaySyncEnabled = vsync;
|
||||
metalLayer.framebufferOnly = true;
|
||||
}
|
5
rendering_api/metal/src/bridge/metal_bridge.h
Normal file
5
rendering_api/metal/src/bridge/metal_bridge.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void mtlObjectCSetContentViewsLayer(void* window, void* layer);
|
||||
void* mtlCreateContentView(void* targetWindow);
|
||||
void mtlInitializeMetalLayer(void* layer, bool vsync);
|
30
rendering_api/metal/src/core/buffers/metal_buffer.cpp
Normal file
30
rendering_api/metal/src/core/buffers/metal_buffer.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <core/buffers/gryphn_buffer.h>
|
||||
#include <core/devices/metal_output_devices.h>
|
||||
#include "metal_buffer.h"
|
||||
|
||||
GN_EXPORT gnErrorCode gnCreateBufferFn(gnBuffer* buffer, const gnOutputDevice& outputDevice) {
|
||||
if (!buffer->buffer) buffer->buffer = new gnPlatformBuffer();
|
||||
|
||||
buffer->buffer->buffer = outputDevice.outputDevice->device->newBuffer(buffer->size, MTL::ResourceStorageModeShared);
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
GN_EXPORT void gnBufferDataFn(gnBuffer& buffer, void* data) {
|
||||
memcpy(buffer.buffer->buffer->contents(), data, buffer.size);
|
||||
}
|
||||
|
||||
GN_EXPORT void gnBufferSubDataFn(gnBuffer& buffer, gnSize offset, gnSize size, void* data) {
|
||||
memcpy((char*)buffer.buffer->buffer->contents() + offset, data, size);
|
||||
}
|
||||
GN_EXPORT void gnBufferClearDataFn(gnBuffer& buffer) {
|
||||
memcpy(buffer.buffer->buffer->contents(), 0, buffer.size);
|
||||
}
|
||||
|
||||
GN_EXPORT void gnBufferMapDataFn(gnBuffer& buffer, void** data) {
|
||||
*data = buffer.buffer->buffer->contents();
|
||||
}
|
||||
|
||||
GN_EXPORT void gnDestroyBufferFn(gnBuffer& buffer) {
|
||||
buffer.buffer->buffer->release();
|
||||
}
|
6
rendering_api/metal/src/core/buffers/metal_buffer.h
Normal file
6
rendering_api/metal/src/core/buffers/metal_buffer.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformBuffer {
|
||||
MTL::Buffer* buffer;
|
||||
};
|
@@ -0,0 +1,46 @@
|
||||
#include "metal_vertex_description.h"
|
||||
|
||||
// MTL::VertexDescriptor* flatVertexDescriptor = MTL::VertexDescriptor::alloc()->init();
|
||||
// auto attributes = flatVertexDescriptor->attributes();
|
||||
// attributes->object(0)->setFormat(MTL::VertexFormat::VertexFormatFloat2);
|
||||
// attributes->object(0)->setOffset(offsetof(Vertex, position));
|
||||
// attributes->object(0)->setBufferIndex(0);
|
||||
// attributes->object(1)->setFormat(MTL::VertexFormat::VertexFormatFloat3);
|
||||
// attributes->object(1)->setOffset(offsetof(Vertex, uv));
|
||||
// attributes->object(1)->setBufferIndex(0);
|
||||
// flatVertexDescriptor->layouts()->object(0)->setStride(sizeof(Vertex));
|
||||
|
||||
GN_EXPORT void gnVertexDescriptionSetBindingDescriptionFn(gnVertexDescription& vertexDescription, const gnBindingDescription& binding) {
|
||||
if (!vertexDescription.vertexDescription) vertexDescription.vertexDescription = new gnPlatformVertexDescription();
|
||||
|
||||
vertexDescription.vertexDescription->binding = binding.binding;
|
||||
vertexDescription.vertexDescription->vertexDescriptor = MTL::VertexDescriptor::alloc()->init();
|
||||
vertexDescription.vertexDescription->vertexDescriptor->layouts()->object(0)->setStride(binding.stride);
|
||||
// auto attributes = vertexDescriptor->attributes();
|
||||
// attributes->object(0)->setFormat(MTL::VertexFormat::VertexFormatFloat2);
|
||||
// attributes->object(0)->setOffset(offsetof(Vertex, position));
|
||||
// attributes->object(0)->setBufferIndex(0);
|
||||
}
|
||||
|
||||
GN_EXPORT void gnVertexDescriptionSetPropertiesCountFn(gnVertexDescription& vertexDescription, int count) {
|
||||
if (!vertexDescription.vertexDescription) vertexDescription.vertexDescription = new gnPlatformVertexDescription();
|
||||
vertexDescription.vertexDescription->descriptorCount = count;
|
||||
// this does nothing on metal but I guess imma do something with it cuz it exists
|
||||
}
|
||||
|
||||
GN_EXPORT void gnVertexDescriptionSetPropertyFn(gnVertexDescription& vertexDescription, int index, const gnVertexProperty& property) {
|
||||
if (!vertexDescription.vertexDescription) vertexDescription.vertexDescription = new gnPlatformVertexDescription();
|
||||
|
||||
auto attribute = vertexDescription.vertexDescription->vertexDescriptor->attributes()->object(index);
|
||||
attribute->setBufferIndex(0);
|
||||
|
||||
switch(property.format) {
|
||||
case GN_FLOAT: attribute->setFormat(MTL::VertexFormat::VertexFormatFloat); break;
|
||||
case GN_FLOAT2: attribute->setFormat(MTL::VertexFormat::VertexFormatFloat2); break;
|
||||
case GN_FLOAT3: attribute->setFormat(MTL::VertexFormat::VertexFormatFloat3); break;
|
||||
case GN_FLOAT4: attribute->setFormat(MTL::VertexFormat::VertexFormatFloat4); break;
|
||||
case GN_UINT: attribute->setFormat(MTL::VertexFormat::VertexFormatUInt); break;
|
||||
}
|
||||
|
||||
attribute->setOffset(property.offset);
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
#include <core/buffers/vertex_descriptions/gryphn_vertex_description.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformVertexDescription {
|
||||
MTL::VertexDescriptor* vertexDescriptor = nullptr;
|
||||
uint32_t binding;
|
||||
uint32_t descriptorCount;
|
||||
};
|
106
rendering_api/metal/src/core/commands/metal_command.cpp
Normal file
106
rendering_api/metal/src/core/commands/metal_command.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include <core/commands/gryphn_command.h>
|
||||
#include <core/commands/metal_command_buffer.h>
|
||||
#include <core/graphics_pipeline/metal_render_pass_frame.h>
|
||||
#include <core/graphics_pipeline/metal_graphics_pipeline.h>
|
||||
#include <core/framebuffers/metal_framebuffer.h>
|
||||
#include <core/textures/metal_texture.h>
|
||||
#include <core/buffers/metal_buffer.h>
|
||||
#include <core/metal_instance.h>
|
||||
#include <core/shaders/metal_shader_module.h>
|
||||
|
||||
GN_EXPORT gnReturnCode gnCommandBufferStartFn(gnCommandBuffer& commandBuffer) {
|
||||
// do absoluetly nothing
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnCommandBeginRenderPassFn(gnCommandBuffer& commandBuffer, const gnRenderPassFrame& frame) {
|
||||
int currentColorAttachment = 0;
|
||||
for (int i = 0; i < gnListLength(frame.framebuffer->framebufferAttachments); i++) {
|
||||
if (frame.framebuffer->framebufferAttachments[i].bindPoint == GN_COLOR_ATTACHMENT) {
|
||||
frame.framebuffer->framebuffer->framebuffer->colorAttachments()->object(currentColorAttachment)->setClearColor(MTL::ClearColor::Make(frame.clearColor.r / 255.0f, frame.clearColor.g / 255.0f, frame.clearColor.b / 255.0f, frame.clearColor.a));
|
||||
currentColorAttachment++;
|
||||
}
|
||||
}
|
||||
commandBuffer.commandBuffer->renderCommandEncoder = commandBuffer.commandBuffer->commandBuffer->renderCommandEncoder(frame.framebuffer->framebuffer->framebuffer);
|
||||
MTL::Viewport vp = {(double)frame.offset.x, (double)frame.offset.y, (double)frame.area.x, (double)frame.area.y, 0.0, 1.0};
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setViewport(vp);
|
||||
}
|
||||
GN_EXPORT void gnCommandSetGraphicsPipelineFn(gnCommandBuffer& commandBuffer, const gnGraphicsPipeline& graphicsPipeline) {
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setRenderPipelineState(graphicsPipeline.graphicsPipeline->renderPipelineState);
|
||||
if (graphicsPipeline.graphicsPipeline->cullMode == GN_CULL_BACKFACE)
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setCullMode(MTL::CullMode::CullModeBack);
|
||||
else if (graphicsPipeline.graphicsPipeline->cullMode == GN_CULL_FRONTFACE)
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setCullMode(MTL::CullMode::CullModeFront);
|
||||
else if (graphicsPipeline.graphicsPipeline->cullMode == GN_CULL_NONE)
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setCullMode(MTL::CullMode::CullModeNone);
|
||||
|
||||
if (graphicsPipeline.graphicsPipeline->direction == GN_CLOCKWISE)
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setFrontFacingWinding(MTL::WindingCounterClockwise);
|
||||
if (graphicsPipeline.graphicsPipeline->direction == GN_COUNTER_CLOCKWISE)
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setFrontFacingWinding(MTL::WindingClockwise);
|
||||
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setDepthStencilState(graphicsPipeline.graphicsPipeline->depthStencilState);
|
||||
}
|
||||
GN_EXPORT void gnCommandSetViewportFn(const gnCommandBuffer& commandBuffer, gnViewportDescriptionData data) {
|
||||
MTL::Viewport viewport = {
|
||||
data.offset.x, data.offset.y,
|
||||
data.size.x, data.size.y,
|
||||
data.depth.x, data.depth.y
|
||||
};
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setViewport(viewport);
|
||||
}
|
||||
GN_EXPORT void gnCommandSetScissorFn(const gnCommandBuffer& commandBuffer, gnScissorDescriptionData data) {
|
||||
MTL::ScissorRect rect = {
|
||||
data.offset.x, data.offset.y,
|
||||
data.extent.x, data.extent.y
|
||||
};
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setScissorRect(rect);
|
||||
}
|
||||
GN_EXPORT void gnCommandDrawFn(gnCommandBuffer& commandBuffer, int vertexCount, int instanceCount, int firstVertex, int firstInstance) {
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle, firstVertex, vertexCount, instanceCount, firstInstance);
|
||||
}
|
||||
GN_EXPORT void gnCommandDrawIndexedFn(gnCommandBuffer& commandBuffer, gnUInt indexCount, gnUInt instanceCount, gnUInt firstIndex, gnInt vertexOffset, gnUInt firstInstance) {
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->drawIndexedPrimitives(MTL::PrimitiveTypeTriangle, indexCount, MTL::IndexTypeUInt16, commandBuffer.commandBuffer->boundIndexBuffer, vertexOffset, instanceCount);
|
||||
}
|
||||
GN_EXPORT void gnCommandBindBufferFn(gnCommandBuffer& commandBuffer, const gnBuffer& buffer) {
|
||||
if (buffer.bufferType == GN_VERTEX_BUFFER)
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setVertexBuffer(buffer.buffer->buffer, 0, 0);
|
||||
else if (buffer.bufferType == GN_INDEX_BUFFER)
|
||||
commandBuffer.commandBuffer->boundIndexBuffer = buffer.buffer->buffer;
|
||||
}
|
||||
GN_EXPORT void gnCommandBindBufferUniformFn(gnCommandBuffer& commandBuffer, gnGraphicsPipeline& graphicsPipeline, gnBufferUniform& uniformBuffer, gnInt set) {
|
||||
for (int i = 0; i < graphicsPipeline.graphicsPipeline->shaders.size(); i++) {
|
||||
const mtlShaderRepresentation& repr = graphicsPipeline.graphicsPipeline->shaders[i];
|
||||
if (repr.module == GN_VERTEX_SHADER_MODULE) {
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setVertexBuffer(uniformBuffer.buffer->buffer->buffer, 0, uniformBuffer.binding + repr.uniformBufferBinding);
|
||||
} else if (repr.module == GN_FRAGMENT_SHADER_MODULE) {
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setFragmentBuffer(uniformBuffer.buffer->buffer->buffer, 0, uniformBuffer.binding + repr.pushConstantBinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
GN_EXPORT void gnCommandBindSamplerUniformFn(gnCommandBuffer& commandBuffer, const gnGraphicsPipeline& graphicsPipeline, const gnSamplerUniform& sampler, gnInt set) {
|
||||
for (int i = 0; i < graphicsPipeline.graphicsPipeline->shaders.size(); i++) {
|
||||
if (graphicsPipeline.graphicsPipeline->shaders[i].module == GN_FRAGMENT_SHADER_MODULE) {
|
||||
int binding = graphicsPipeline.graphicsPipeline->shaders[i].textureBindings[{(gnUInt)set, sampler.binding}];
|
||||
// std::cout << "Binding: " << binding << "\n";
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setFragmentTexture(sampler.texture->texture->texture, binding);
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setFragmentSamplerState(sampler.texture->texture->sampler, binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
GN_EXPORT void gnCommandPushConstantFn(gnCommandBuffer& commandBuffer, const gnGraphicsPipeline& graphicsPipeline, const gnPushConstant& pushConstant, void* data) {
|
||||
for (int i = 0; i < graphicsPipeline.graphicsPipeline->shaders.size(); i++) {
|
||||
const mtlShaderRepresentation& repr = graphicsPipeline.graphicsPipeline->shaders[i];
|
||||
if (repr.module == GN_VERTEX_SHADER_MODULE) {
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setVertexBytes(data, pushConstant.size, repr.pushConstantBinding);
|
||||
} else if (repr.module == GN_FRAGMENT_SHADER_MODULE) {
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->setFragmentBytes(data, pushConstant.size, repr.pushConstantBinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
GN_EXPORT void gnCommandEndRenderPassFn(gnCommandBuffer& commandBuffer) {
|
||||
commandBuffer.commandBuffer->renderCommandEncoder->endEncoding();
|
||||
}
|
||||
GN_EXPORT gnReturnCode gnCommandBufferEndFn(gnCommandBuffer& commandBuffer) {
|
||||
// commandBuffer.commandBuffer->commandBuffer->commit();
|
||||
return GN_SUCCESS;
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
#include "metal_command_buffer.h"
|
||||
#include <core/devices/metal_output_devices.h>
|
||||
#include <core/output_device/gryphn_output_device.h>
|
||||
#include <core/metal_instance.h>
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreateCommandBufferFn(gnCommandBuffer* commandBuffer, const gnOutputDevice& outputDevice) {
|
||||
commandBuffer->commandBuffer = new gnPlatformCommandBuffer();
|
||||
commandBuffer->commandBuffer->outputDevice = &outputDevice;
|
||||
commandBuffer->commandBuffer->commandBuffer = outputDevice.outputDevice->commandQueue->commandBuffer();
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT gnReturnCode _gnCreateCommandBuffersFn(gnCommandBuffer* commandBuffers, gnUInt commandBufferCount, const gnOutputDevice& outputDevice) {
|
||||
for (int i = 0; i < commandBufferCount; i++) {
|
||||
commandBuffers[i].commandBuffer = new gnPlatformCommandBuffer();
|
||||
commandBuffers[i].commandBuffer->outputDevice = &outputDevice;
|
||||
commandBuffers[i].commandBuffer->commandBuffer = outputDevice.outputDevice->commandQueue->commandBuffer();
|
||||
}
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
// so imma just destroy and recreate the command buffer every frame, fuck you
|
||||
GN_EXPORT void gnCommandBufferResetFn(const gnCommandBuffer& commandBuffer) {
|
||||
commandBuffer.commandBuffer->commandBuffer->release();
|
||||
commandBuffer.commandBuffer->commandBuffer = commandBuffer.commandBuffer->outputDevice->outputDevice->commandQueue->commandBuffer();
|
||||
}
|
||||
GN_EXPORT void gnDestroyCommandBufferFn(const gnCommandBuffer& commandBuffer) {
|
||||
commandBuffer.commandBuffer->commandBuffer->release();
|
||||
}
|
13
rendering_api/metal/src/core/commands/metal_command_buffer.h
Normal file
13
rendering_api/metal/src/core/commands/metal_command_buffer.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <core/commands/gryphn_command_buffer.h>
|
||||
#include <core/graphics_pipeline/gryphn_graphics_pipeline.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformCommandBuffer {
|
||||
MTL::CommandBuffer* commandBuffer;
|
||||
MTL::RenderCommandEncoder* renderCommandEncoder;
|
||||
|
||||
MTL::Buffer* boundIndexBuffer = nullptr;
|
||||
|
||||
const gnOutputDevice* outputDevice;
|
||||
};
|
@@ -0,0 +1,55 @@
|
||||
#include <core/commands/present_command/gryphn_command_present.h>
|
||||
#include "core/sync_objects/metal_semaphore.h"
|
||||
#include "core/presentation_queue/metal_presentation_queue.h"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
#include "core/textures/metal_texture.h"
|
||||
#include "core/metal_instance.h"
|
||||
#include "bridge/metal_bridge.h"
|
||||
|
||||
GN_EXPORT gnPresentationQueueState gnCommandPresentGetValidPresentationQueueFn(gnCommandPresentData& presentCommandData) {
|
||||
return GN_VALID;
|
||||
}
|
||||
GN_EXPORT gnReturnCode gnCommandPresentFn(gnCommandPresentData& presentCommandData) {
|
||||
// dispatch_semaphore_wait(presentCommandData.semaphore->semaphore->semaphore, DISPATCH_TIME_FOREVER);
|
||||
// 2. Create the command buffer
|
||||
gnOutputDevice* outputDevice = mltGetOutputDevice(presentCommandData.presentationQueue->presentationQueue);
|
||||
MTL::CommandBuffer* commandBuffer = outputDevice->outputDevice->commandQueue->commandBuffer();
|
||||
|
||||
// 3. Add a completed handler to signal the semaphore after the GPU has completed rendering.
|
||||
__block dispatch_semaphore_t semToSignal = presentCommandData.semaphore->semaphore->semaphore;
|
||||
commandBuffer->addCompletedHandler(^(MTL::CommandBuffer* buffer) {
|
||||
// Signal the semaphore after GPU work (drawing) is complete
|
||||
dispatch_semaphore_signal(semToSignal);
|
||||
});
|
||||
|
||||
|
||||
gnInstance* instance = outputDevice->outputDevice->instance;
|
||||
MTK::View* view = outputDevice->outputDevice->contentView;
|
||||
CA::MetalDrawable* drawable = presentCommandData.presentationQueue->presentationQueue->currentDrawable;
|
||||
// if (drawable == nullptr) {
|
||||
// GN_RETURN_ERROR("drawable is null");
|
||||
// }
|
||||
|
||||
MTL::RenderPassDescriptor* desc = MTL::RenderPassDescriptor::alloc()->init();
|
||||
desc->colorAttachments()->object(0)->setTexture(drawable->texture());
|
||||
desc->colorAttachments()->object(0)->setLoadAction(MTL::LoadActionClear);
|
||||
desc->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionStore);
|
||||
desc->colorAttachments()->object(0)->setClearColor(MTL::ClearColor::Make(1, 0, 0, 1));
|
||||
|
||||
auto enc = commandBuffer->renderCommandEncoder(desc);
|
||||
|
||||
enc->setRenderPipelineState(instance->instance->framebufferRenderer);
|
||||
enc->setFragmentTexture(presentCommandData.presentationQueue->images[*presentCommandData.imageIndex].texture->texture, 0);
|
||||
enc->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
||||
|
||||
enc->endEncoding();
|
||||
|
||||
commandBuffer->presentDrawable(drawable);
|
||||
|
||||
// // 5. Commit the command buffer
|
||||
commandBuffer->commit();
|
||||
|
||||
// 6. Wait again on the semaphore to ensure the drawable is presented and the GPU work is complete.
|
||||
dispatch_semaphore_wait(semToSignal, DISPATCH_TIME_FOREVER);
|
||||
return GN_SUCCESS;
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
#include "core/commands/submit_command/gryphn_command_submit.h"
|
||||
#include "core/sync_objects/metal_semaphore.h"
|
||||
#include "core/commands/metal_command_buffer.h"
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
GN_EXPORT gnPresentationQueueState gnCommandSubmitGetValidPresentationQueueFn(gnCommandSubmitData& presentCommandData) {
|
||||
return GN_VALID;
|
||||
}
|
||||
GN_EXPORT gnErrorCode gnCommandSubmitFn(gnCommandSubmitData& data, const gnFence& fence) {
|
||||
dispatch_semaphore_wait(data.waitSemaphore->semaphore->semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
__block dispatch_semaphore_t semToSignal = data.signalSemaphore->semaphore->semaphore;
|
||||
data.commandBuffer->commandBuffer->commandBuffer->addCompletedHandler(^void(MTL::CommandBuffer* buffer) {
|
||||
dispatch_semaphore_signal(semToSignal);
|
||||
});
|
||||
data.commandBuffer->commandBuffer->commandBuffer->commit();
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
11
rendering_api/metal/src/core/debugger/metal_debugger.cpp
Normal file
11
rendering_api/metal/src/core/debugger/metal_debugger.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#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
|
||||
GN_EXPORT gnReturnCode gnCreateDebuggerFn(gnDebugger* instance) {
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnDestroyDebuggerFn(gnDebugger& instance) {
|
||||
|
||||
}
|
||||
// I will at some point but if you have chosen the fate of writing this on a mac than you should really
|
||||
// hate yourself
|
6
rendering_api/metal/src/core/debugger/metal_layers.cpp
Normal file
6
rendering_api/metal/src/core/debugger/metal_layers.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <core/debugger/gryphn_layers.h>
|
||||
|
||||
GN_EXPORT gnString gnGetPlatformLayerNameFn(const gnString& gnName) {
|
||||
if (gnStringEquals(gnName, "GN_DEFAULT_DEBUG_LAYER")) return "METAL_DEBUG_LAYER";
|
||||
return "GN_NO_LAYER";
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
#include <core/uniform_descriptor/gryphn_uniform_layout.h>
|
||||
|
||||
struct gnPlatformUniformLayout {
|
||||
|
||||
};
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreateUniformLayoutFn(gnUniformLayout* uniformLayout, gnOutputDevice& device) {
|
||||
if (uniformLayout->uniformLayout == nullptr) uniformLayout->uniformLayout = new gnPlatformUniformLayout();
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnDestroyUniformLayoutFn(gnUniformLayout& uniformLayout) {
|
||||
|
||||
}
|
154
rendering_api/metal/src/core/devices/metal_output_device.cpp
Normal file
154
rendering_api/metal/src/core/devices/metal_output_device.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include <core/output_device/gryphn_physical_output_device.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
// #include
|
||||
#include <core/metal_instance.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include "metal_output_devices.h"
|
||||
|
||||
struct mtlFramebufferVertex {
|
||||
float x, y;
|
||||
float u, v;
|
||||
};
|
||||
|
||||
GN_EXPORT gnReturnCode gnRegisterOutputDeviceFn(gnOutputDevice* outputDevice, const gnInstance& instance, const gnPhysicalOutputDevice& physicalDevice) {
|
||||
if (outputDevice->outputDevice == nullptr) outputDevice->outputDevice = new gnPlatformOutputDevice();
|
||||
outputDevice->physicalOutputDevice = const_cast<gnPhysicalOutputDevice*>(&physicalDevice);
|
||||
|
||||
// instance.instance->metalLayer->setDevice(physicalDevice.physicalOutputDevice->device);
|
||||
|
||||
// outputDevice->outputDevice->contentView = instance.instance->metalContentView->retain();
|
||||
outputDevice->outputDevice->device = physicalDevice.physicalOutputDevice->device->retain();
|
||||
outputDevice->outputDevice->commandQueue = outputDevice->outputDevice->device->newCommandQueue();
|
||||
outputDevice->outputDevice->instance = const_cast<gnInstance*>(&instance);
|
||||
|
||||
{
|
||||
const char* shaderSrc = R"metal(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
vertex VertexOut vs_main(uint vertexID [[vertex_id]]) {
|
||||
float2 positions[4] = {
|
||||
{-1.0, -1.0},
|
||||
{ 1.0, -1.0},
|
||||
{-1.0, 1.0},
|
||||
{ 1.0, 1.0}
|
||||
};
|
||||
float2 uvs[4] = {
|
||||
{0.0, 1.0},
|
||||
{1.0, 1.0},
|
||||
{0.0, 0.0},
|
||||
{1.0, 0.0}
|
||||
};
|
||||
|
||||
VertexOut out;
|
||||
out.position = float4(positions[vertexID], 0.0, 1.0);
|
||||
out.uv = uvs[vertexID];
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 fs_main(VertexOut in [[stage_in]],
|
||||
texture2d<float> colorTex [[texture(0)]],
|
||||
sampler samp [[sampler(0)]]) {
|
||||
return colorTex.sample(samp, in.uv);
|
||||
}
|
||||
)metal";
|
||||
|
||||
NS::Error* error = nullptr;
|
||||
MTL::CompileOptions* options = nullptr;
|
||||
MTL::Library* library = physicalDevice.physicalOutputDevice->device->newLibrary(NS::String::string(shaderSrc, NS::UTF8StringEncoding), options, &error);
|
||||
if (!library) {
|
||||
GN_RETURN_ERROR(error->localizedDescription()->utf8String());
|
||||
}
|
||||
MTL::Function* vs = library->newFunction(NS::String::string("vs_main", NS::UTF8StringEncoding));
|
||||
MTL::Function* fs = library->newFunction(NS::String::string("fs_main", NS::UTF8StringEncoding));
|
||||
|
||||
MTL::RenderPipelineDescriptor* pipelineDesc = MTL::RenderPipelineDescriptor::alloc()->init();
|
||||
pipelineDesc->setVertexFunction(vs);
|
||||
pipelineDesc->setFragmentFunction(fs);
|
||||
pipelineDesc->colorAttachments()->object(0)->setPixelFormat(MTL::PixelFormatBGRA8Unorm);
|
||||
|
||||
instance.instance->framebufferRenderer = outputDevice->outputDevice->device->newRenderPipelineState(pipelineDesc, &error);
|
||||
if (!instance.instance->framebufferRenderer) {
|
||||
GN_RETURN_ERROR(error->localizedDescription()->utf8String());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const char* shaderSrc = R"metal(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct VertexIn {
|
||||
float3 position;
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
};
|
||||
|
||||
vertex VertexOut vs_main(uint vertexID [[vertex_id]]) {
|
||||
float2 positions[6] = {
|
||||
{-0.5, -0.5},
|
||||
{ 0.5, -0.5},
|
||||
{-0.5, 0.5},
|
||||
{ 0.5, -0.5},
|
||||
{-0.5, 0.5},
|
||||
{ 0.5, 0.5}
|
||||
};
|
||||
|
||||
VertexOut out;
|
||||
out.position = float4(positions[vertexID], 0.0, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 fs_main(VertexOut in [[stage_in]]) {
|
||||
return float4(1.0, 1.0, 1.0, 1.0);
|
||||
}
|
||||
)metal";
|
||||
|
||||
NS::Error* error = nullptr;
|
||||
MTL::CompileOptions* options = nullptr;
|
||||
MTL::Library* library = physicalDevice.physicalOutputDevice->device->newLibrary(NS::String::string(shaderSrc, NS::UTF8StringEncoding), options, &error);
|
||||
if (!library) {
|
||||
GN_RETURN_ERROR(error->localizedDescription()->utf8String());
|
||||
}
|
||||
MTL::Function* vs = library->newFunction(NS::String::string("vs_main", NS::UTF8StringEncoding));
|
||||
MTL::Function* fs = library->newFunction(NS::String::string("fs_main", NS::UTF8StringEncoding));
|
||||
|
||||
MTL::RenderPipelineDescriptor* pipelineDesc = MTL::RenderPipelineDescriptor::alloc()->init();
|
||||
pipelineDesc->setVertexFunction(vs);
|
||||
pipelineDesc->setFragmentFunction(fs);
|
||||
pipelineDesc->colorAttachments()->object(0)->setPixelFormat(MTL::PixelFormatBGRA8Unorm);
|
||||
|
||||
instance.instance->testSquareRenderer = outputDevice->outputDevice->device->newRenderPipelineState(pipelineDesc, &error);
|
||||
if (!instance.instance->framebufferRenderer) {
|
||||
GN_RETURN_ERROR(error->localizedDescription()->utf8String());
|
||||
}
|
||||
}
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
GN_EXPORT void gnWaitForDeviceFn(const gnOutputDevice& device) {
|
||||
NS::AutoreleasePool* pool = NS::AutoreleasePool::alloc()->init();
|
||||
|
||||
auto mtlDevice = device.physicalOutputDevice->physicalOutputDevice->device;
|
||||
|
||||
auto commandBuffer = device.outputDevice->commandQueue->commandBuffer();
|
||||
|
||||
commandBuffer->commit();
|
||||
commandBuffer->waitUntilCompleted();
|
||||
|
||||
pool->release();
|
||||
}
|
||||
|
||||
GN_EXPORT void gnDestroyOutputDeviceFn(gnOutputDevice& device) {
|
||||
device.outputDevice->commandQueue->release();
|
||||
device.physicalOutputDevice->physicalOutputDevice->device->release();
|
||||
}
|
16
rendering_api/metal/src/core/devices/metal_output_devices.h
Normal file
16
rendering_api/metal/src/core/devices/metal_output_devices.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <Metal/Metal.hpp>
|
||||
#include <MetalKit/MetalKit.hpp>
|
||||
|
||||
struct gnPlatformPhysicalOutputDevice {
|
||||
MTL::Device* device;
|
||||
};
|
||||
struct gnInstance;
|
||||
|
||||
struct gnPlatformOutputDevice {
|
||||
MTL::Device* device;
|
||||
MTL::CommandQueue* commandQueue;
|
||||
MTK::View* contentView;
|
||||
|
||||
gnInstance* instance;
|
||||
};
|
@@ -0,0 +1,23 @@
|
||||
#include <core/output_device/gryphn_physical_output_device.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
#include "metal_output_devices.h"
|
||||
|
||||
GN_EXPORT gnList<gnPhysicalOutputDevice> gnGetPhysicalOutputDevicesFn(const gnInstance& instance) {
|
||||
gnList<gnPhysicalOutputDevice> physicalOutputDevices = gnCreateList<gnPhysicalOutputDevice>();
|
||||
NS::Array *devices = MTL::CopyAllDevices();
|
||||
for (int i = 0; i < devices->count(); i++) {
|
||||
gnPhysicalOutputDevice physicalOutputDevice;
|
||||
physicalOutputDevice.outputDeviceName = reinterpret_cast<MTL::Device*>(devices->object(0))->name()->cString(NS::StringEncoding::UTF8StringEncoding);
|
||||
physicalOutputDevice.physicalOutputDevice = new gnPlatformPhysicalOutputDevice();
|
||||
physicalOutputDevice.physicalOutputDevice->device = reinterpret_cast<MTL::Device*>(devices->object(0));
|
||||
gnListAdd(physicalOutputDevices, physicalOutputDevice);
|
||||
}
|
||||
return physicalOutputDevices;
|
||||
}
|
||||
|
||||
GN_EXPORT gnBool gnDeviceSupportsAPIFn(const gnPhysicalOutputDevice& device) {
|
||||
// so as far as my understanding goes which is not very far I dont think that the
|
||||
// method I am using to ge the devices would return a list of devices that are not supported on
|
||||
// metal but idk or really care cuz fuck you for using metal
|
||||
return true;
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
#include "metal_framebuffer.h"
|
||||
#include "core/graphics_pipeline/metal_graphics_pipeline.h"
|
||||
#include <core/devices/metal_output_devices.h>
|
||||
#include <core/textures/metal_texture.h>
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreateFramebufferAttachmentFn(gnFramebufferAttachment* attachment, gnPresentationQueue& queue) {
|
||||
attachment->framebufferAttachment = new gnPlatformFramebufferAttachment();
|
||||
// attachment->framebufferAttachment->framebufferAttachment = MTL::RenderPassAttachmentDescriptor::alloc()->init();
|
||||
// MTL::RenderPassAttachmentDescriptor* descriptor = attachment->framebufferAttachment->framebufferAttachment;
|
||||
// attachment->framebufferAttachment->framebufferAttachment->setTexture(attachment->texture->texture->texture->retain());
|
||||
// descriptor->setLoadAction(MTL::LoadActionClear);
|
||||
// descriptor->setStoreAction(MTL::StoreActionStore);
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreateFramebufferFn(gnFramebuffer* framebuffer, const gnRenderPass& renderpass) {
|
||||
framebuffer->framebuffer = new gnPlatformFramebuffer();
|
||||
framebuffer->framebuffer->framebuffer = MTL::RenderPassDescriptor::alloc()->init();
|
||||
framebuffer->framebuffer->framebuffer->setRenderTargetWidth(framebuffer->size.x);
|
||||
framebuffer->framebuffer->framebuffer->setRenderTargetHeight(framebuffer->size.y);
|
||||
framebuffer->framebuffer->framebuffer->setDepthAttachment(nullptr);
|
||||
int currentColorAttachment = 0;
|
||||
for (int i = 0; i < gnListLength(framebuffer->framebufferAttachments); i++) {
|
||||
if (framebuffer->framebufferAttachments[i].bindPoint == GN_COLOR_ATTACHMENT) {
|
||||
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = framebuffer->framebuffer->framebuffer->colorAttachments()->object(currentColorAttachment)->retain();
|
||||
colorAttachment->setTexture(framebuffer->framebufferAttachments[i].texture->texture->texture);
|
||||
colorAttachment->setClearColor(MTL::ClearColor::Make(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
colorAttachment->setLoadAction(MTL::LoadActionClear);
|
||||
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
||||
colorAttachment->release();
|
||||
currentColorAttachment++;
|
||||
} else if (framebuffer->framebufferAttachments[i].bindPoint == GN_DEPTH_STENCIL_ATTACHMENT) {
|
||||
MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = framebuffer->framebuffer->framebuffer->depthAttachment()->retain();
|
||||
depthAttachment->setTexture(framebuffer->framebufferAttachments[i].texture->texture->texture);
|
||||
depthAttachment->setLoadAction(MTL::LoadActionClear);
|
||||
depthAttachment->setStoreAction(MTL::StoreActionStore);
|
||||
depthAttachment->release();
|
||||
|
||||
MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = framebuffer->framebuffer->framebuffer->stencilAttachment()->retain();
|
||||
stencilAttachment->setTexture(framebuffer->framebufferAttachments[i].texture->texture->texture);
|
||||
stencilAttachment->setLoadAction(MTL::LoadActionClear);
|
||||
stencilAttachment->setStoreAction(MTL::StoreActionStore);
|
||||
stencilAttachment->release();
|
||||
} else {
|
||||
GN_RETURN_ERROR("fuck you (line 46 in metal_framebuffer.cpp)");
|
||||
}
|
||||
}
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnDestroyFramebufferFn(const gnFramebuffer& framebuffer) {
|
||||
framebuffer.framebuffer->framebuffer->release();
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
#include <core/framebuffers/gryphn_framebuffer.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformFramebuffer {
|
||||
MTL::RenderPassDescriptor* framebuffer;
|
||||
};
|
||||
|
||||
struct gnPlatformFramebufferAttachment {
|
||||
MTL::RenderPassAttachmentDescriptor* framebufferAttachment;
|
||||
};
|
@@ -0,0 +1,134 @@
|
||||
#include <core/graphics_pipeline/gryphn_graphics_pipeline.h>
|
||||
#include "metal_graphics_pipeline.h"
|
||||
#include <core/devices/metal_output_devices.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
#include <core/buffers/vertex_description/metal_vertex_description.h>
|
||||
#include "core/shaders/metal_shader_module.h"
|
||||
|
||||
void mtlInitGraphicsPipeline(gnGraphicsPipeline& pipeline) {
|
||||
if (pipeline.graphicsPipeline == nullptr) { pipeline.graphicsPipeline = new gnPlatformGraphicsPipeline();
|
||||
pipeline.graphicsPipeline->renderPipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init();
|
||||
}
|
||||
}
|
||||
|
||||
GN_EXPORT void gnGraphicsPipelineSetPrimativeFn(gnGraphicsPipeline& pipeline, gnPrimative primative) {
|
||||
mtlInitGraphicsPipeline(pipeline);
|
||||
pipeline.primative = primative;
|
||||
// this is done at draw time in metal, all this shit it
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineEnableDynamicStatesFn(gnGraphicsPipeline& pipeline, const gnBool enable) {
|
||||
mtlInitGraphicsPipeline(pipeline);
|
||||
pipeline.graphicsPipeline->dynamicStatesEnabled = enable;
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineEnableDynamicStateFn(gnGraphicsPipeline& pipeline, const gnDynamicState state) {
|
||||
mtlInitGraphicsPipeline(pipeline);
|
||||
pipeline.graphicsPipeline->dynamicStates.push_back(state);
|
||||
}
|
||||
GN_EXPORT void _gnGraphicsPipelineSetViewportFn(gnGraphicsPipeline& pipeline, gnUInt2 position, gnUInt2 size, gnFloat minDepth, gnFloat maxDepth) {
|
||||
mtlInitGraphicsPipeline(pipeline);
|
||||
pipeline.graphicsPipeline->position = position;
|
||||
pipeline.graphicsPipeline->size = size;
|
||||
pipeline.graphicsPipeline->minDepth = minDepth;
|
||||
pipeline.graphicsPipeline->maxDepth = maxDepth; // these functions are usless because metal already makes all this shit dynamic
|
||||
} // minDepth = 0.0f, maxDepth = 1.0f
|
||||
GN_EXPORT void gnGraphicsPipelineSetCropFn(gnGraphicsPipeline& graphicsPipeline, gnInt2 position, gnUInt2 size) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
graphicsPipeline.graphicsPipeline->stencil_position = position;
|
||||
graphicsPipeline.graphicsPipeline->stencil_size = size;
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineSetDepthClampFn(gnGraphicsPipeline& graphicsPipeline, gnBool enableDepthClamp) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
graphicsPipeline.graphicsPipeline->enableDepthClamp = true;
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineSetFillModeFn(gnGraphicsPipeline& graphicsPipeline, gnFillMode fillMode) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
graphicsPipeline.graphicsPipeline->fillMode = fillMode;
|
||||
// if fill mode is points than fuck you, I have to write a renderer that is going to just draw the points
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineSetLineWidthFn(gnGraphicsPipeline& graphicsPipeline, gnFloat lineWidth) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
graphicsPipeline.graphicsPipeline->lineWidth = lineWidth;
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineSetCullModeFn(gnGraphicsPipeline& graphicsPipeline, gnCullMode cullMode, gnFrontFaceDirection direction) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
graphicsPipeline.graphicsPipeline->cullMode = cullMode;
|
||||
graphicsPipeline.graphicsPipeline->direction = direction;
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineSetMultisamplingFn(gnGraphicsPipeline& graphicsPipeline, gnBool enableMultisampling) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
if (enableMultisampling) {
|
||||
std::cout << "Fuck you im not doing multisampling";
|
||||
}
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineEnableDepthTestFn(gnGraphicsPipeline& graphicsPipeline, gnBool depthTest) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
graphicsPipeline.graphicsPipeline->depthStateDescriptor = MTL::DepthStencilDescriptor::alloc()->init();
|
||||
if (depthTest) {
|
||||
graphicsPipeline.graphicsPipeline->depthStateDescriptor->setDepthCompareFunction(MTL::CompareFunctionLess);
|
||||
graphicsPipeline.graphicsPipeline->depthStateDescriptor->setDepthWriteEnabled(true);
|
||||
} else {
|
||||
graphicsPipeline.graphicsPipeline->depthStateDescriptor->setDepthCompareFunction(MTL::CompareFunctionAlways);
|
||||
graphicsPipeline.graphicsPipeline->depthStateDescriptor->setDepthWriteEnabled(false);
|
||||
}
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineSetColorBlendFn(gnGraphicsPipeline& graphicsPipeline, gnBool colorBlend) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
graphicsPipeline.graphicsPipeline->colorBlending = colorBlend;
|
||||
|
||||
if (colorBlend) {
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->colorAttachments()->object(0)->setBlendingEnabled(true);
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->colorAttachments()->object(0)->setRgbBlendOperation(MTL::BlendOperation::BlendOperationAdd);
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->colorAttachments()->object(0)->setAlphaBlendOperation(MTL::BlendOperation::BlendOperationAdd);
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->colorAttachments()->object(0)->setSourceRGBBlendFactor(MTL::BlendFactor::BlendFactorSourceAlpha);
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->colorAttachments()->object(0)->setSourceAlphaBlendFactor(MTL::BlendFactor::BlendFactorSourceAlpha);
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->colorAttachments()->object(0)->setDestinationRGBBlendFactor(MTL::BlendFactor::BlendFactorOneMinusSourceAlpha);
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->colorAttachments()->object(0)->setDestinationAlphaBlendFactor(MTL::BlendFactor::BlendFactorOneMinusSourceAlpha);
|
||||
}
|
||||
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineSetVertexDescriptionFn(gnGraphicsPipeline& graphicsPipeline, const gnVertexDescription& vertexDescription) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
// this is one of the only things that is not done at runtime in metal, i dont fucking know why
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->setVertexDescriptor(vertexDescription.vertexDescription->vertexDescriptor);
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineBindShaderFn(gnGraphicsPipeline& graphicsPipeline, const gnShader& shader) {
|
||||
mtlInitGraphicsPipeline(graphicsPipeline);
|
||||
for (int i = 0; i < gnListLength(shader.shaderModules); i++) {
|
||||
if (shader.shaderModules[i].shaderType == GN_VERTEX_SHADER_MODULE)
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->setVertexFunction(shader.shaderModules[i].shaderModule->shaderFunction);
|
||||
else if (shader.shaderModules[i].shaderType == GN_FRAGMENT_SHADER_MODULE)
|
||||
graphicsPipeline.graphicsPipeline->renderPipelineDescriptor->setFragmentFunction(shader.shaderModules[i].shaderModule->shaderFunction);
|
||||
|
||||
graphicsPipeline.graphicsPipeline->shaders.push_back({
|
||||
shader.shaderModules[i].shaderType,
|
||||
shader.shaderModules[i].shaderModule->uniformBufferOffset,
|
||||
shader.shaderModules[i].shaderModule->pushConstantOffset,
|
||||
shader.shaderModules[i].shaderModule->texturesSetBindings
|
||||
});
|
||||
}
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineSetRenderPassFn(gnGraphicsPipeline& graphicsPipeline, gnRenderPass& renderpass) {
|
||||
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineAddUniformLayoutFn(gnGraphicsPipeline& graphicsPipeline, const gnUniformLayout& uniformLayout) {
|
||||
|
||||
}
|
||||
GN_EXPORT void gnGraphicsPipelineAddPushConstantFn(gnGraphicsPipeline& graphicsPipeline, const gnPushConstant& pushConstant) {
|
||||
|
||||
}
|
||||
GN_EXPORT gnReturnCode gnCreateGraphicsPipelineFn(gnGraphicsPipeline* graphicsPipeline, gnOutputDevice& outputDevice) {
|
||||
if (graphicsPipeline->graphicsPipeline == nullptr) GN_RETURN_ERROR("Need to call one gnGraphicsPipeline function to create a graphics pipeline");
|
||||
NS::Error* error = nullptr;
|
||||
graphicsPipeline->graphicsPipeline->renderPipelineDescriptor->colorAttachments()->object(0)->setPixelFormat(MTL::PixelFormatBGRA8Unorm);
|
||||
graphicsPipeline->graphicsPipeline->renderPipelineState = outputDevice.outputDevice->device->newRenderPipelineState(graphicsPipeline->graphicsPipeline->renderPipelineDescriptor, &error);
|
||||
if (!graphicsPipeline->graphicsPipeline->renderPipelineState)
|
||||
GN_RETURN_ERROR(error->localizedDescription()->utf8String());
|
||||
|
||||
graphicsPipeline->graphicsPipeline->depthStencilState = outputDevice.outputDevice->device->newDepthStencilState(graphicsPipeline->graphicsPipeline->depthStateDescriptor);
|
||||
graphicsPipeline->graphicsPipeline->outputDevice = &outputDevice;
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnDestroyGraphicsPipelineFn(gnGraphicsPipeline& graphicsPipeline) {
|
||||
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
#include <core/graphics_pipeline/gryphn_graphics_pipeline.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct mtlShaderRepresentation {
|
||||
gnShaderModuleStage module;
|
||||
int uniformBufferBinding, pushConstantBinding;
|
||||
std::unordered_map<gnUInt2, gnUInt> textureBindings;
|
||||
};
|
||||
|
||||
struct gnPlatformGraphicsPipeline {
|
||||
MTL::RenderPipelineState* renderPipelineState = nullptr;
|
||||
MTL::RenderPipelineDescriptor* renderPipelineDescriptor = nullptr;
|
||||
MTL::DepthStencilDescriptor* depthStateDescriptor = nullptr;
|
||||
gnOutputDevice* outputDevice;
|
||||
std::vector<mtlShaderRepresentation> shaders = {};
|
||||
MTL::DepthStencilState* depthStencilState;
|
||||
|
||||
gnBool dynamicStatesEnabled = false;
|
||||
std::vector<gnDynamicState> dynamicStates = {};
|
||||
|
||||
// for the viewport
|
||||
gnUInt2 position = { 0, 0 };
|
||||
gnUInt2 size = { 100, 100 };
|
||||
gnFloat minDepth = 0.0f, maxDepth = 1.0f;
|
||||
|
||||
// for the stencil
|
||||
gnInt2 stencil_position;
|
||||
gnUInt2 stencil_size;
|
||||
|
||||
gnBool enableDepthClamp;
|
||||
gnFillMode fillMode;
|
||||
gnFloat lineWidth;
|
||||
|
||||
gnCullMode cullMode;
|
||||
gnFrontFaceDirection direction;
|
||||
gnBool colorBlending;
|
||||
};
|
@@ -0,0 +1,36 @@
|
||||
#include <core/graphics_pipeline/gryphn_render_pass.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
// okay so my understanding is that there is no such thing as a MTL::Subpass or any alternative
|
||||
// so instread every render pass is instread going to be an array of render passes and
|
||||
// im going to find a way to implment error handling if the user attempts to to try and access different
|
||||
// resources or something like that
|
||||
struct gnPlatformRenderPass {
|
||||
// MTL::RenderPassDescriptor* renderPassDescriptor = nullptr;
|
||||
};
|
||||
struct gnPlatformSubpass {};
|
||||
struct gnPlatformRenderpassAttachment {};
|
||||
|
||||
// all this function is resposible for is making sure that youre whole render pass will be valid when
|
||||
// created at runtime, I fucking hate you metal more than vulkan, I wish everything was explicit like
|
||||
// vulkan, can I just define everything at compile time please
|
||||
GN_EXPORT gnReturnCode gnCreateRenderPassFn(gnRenderPass* renderPass, const gnOutputDevice& outputDevice) {
|
||||
// renderPass->renderpass = new gnPlatformRenderPass();
|
||||
// renderPass->renderpass->renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
|
||||
for (int i = 0; i < renderPass->attachmentCount; i++) {
|
||||
renderPass->attachments[i].renderpassAttachment = new gnPlatformRenderpassAttachment();
|
||||
if (renderPass->attachments[i].colorMode == GN_RGBA8) {}
|
||||
else if (renderPass->attachments[i].colorMode == GN_DEPTH8_STENCIL24) {}
|
||||
else {
|
||||
std::string return_code = "GN_RENDERPASS_ATTATCHMENT_(" + std::to_string(i) + ")" + "_UNSUPPORTED_COLOR_MODE";
|
||||
GN_RETURN_ERROR(return_code.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnDestroyRenderPassFn(gnRenderPass& renderPass) {
|
||||
//renderPass.renderpass->renderPassDescriptor->release();
|
||||
return;
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
#include <core/graphics_pipeline/gryphn_render_pass_frame.h>
|
||||
#include "metal_render_pass_frame.h"
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
gnPlatformRenderPassFrame::gnPlatformRenderPassFrame() {
|
||||
// renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
}
|
||||
|
||||
GN_EXPORT void gnRenderPassFrameSetRenderPassFn(gnRenderPassFrame& frame, const gnRenderPass& renderPass) {
|
||||
if (frame.renderPassFrame == nullptr) frame.renderPassFrame = new gnPlatformRenderPassFrame();
|
||||
// this is going to do nothing
|
||||
}
|
||||
GN_EXPORT void gnRenderPassFrameSetFramebufferFn(gnRenderPassFrame& frame, const gnFramebuffer& framebuffer) {
|
||||
if (frame.renderPassFrame == nullptr) frame.renderPassFrame = new gnPlatformRenderPassFrame();
|
||||
std::cout << "gnRenderPassFrameSetFramebufferFn on Metal is not implemented, il do this at some point\n";
|
||||
// this will do something with setting the attachment descriptions but im kinda lazy
|
||||
// and by lazy I mean gnFramebuffer_metal_impl has not been created yet
|
||||
}
|
||||
GN_EXPORT void gnRenderPassFrameSetOffsetFn(gnRenderPassFrame& frame, const gnUInt2& offset) {
|
||||
if (frame.renderPassFrame == nullptr) frame.renderPassFrame = new gnPlatformRenderPassFrame();
|
||||
//frame.renderPassFrame->renderPassDescriptor->
|
||||
if (offset.x != 0 || offset.y != 0) std::cout << "gnRenderPassFrameOffsetFn offset must be zero on metal\n";
|
||||
}
|
||||
GN_EXPORT void gnRenderPassFrameSetRenderAreaFn(gnRenderPassFrame& frame, const gnUInt2& area){
|
||||
if (frame.renderPassFrame == nullptr) frame.renderPassFrame = new gnPlatformRenderPassFrame();
|
||||
frame.renderPassFrame->renderPassDescriptor->setRenderTargetWidth(area.x);
|
||||
frame.renderPassFrame->renderPassDescriptor->setRenderTargetHeight(area.y);
|
||||
}
|
||||
GN_EXPORT void gnRenderPassFrameSetClearColorFn(gnRenderPassFrame& frame, gnColor clearColor) {
|
||||
if (frame.renderPassFrame == nullptr) frame.renderPassFrame = new gnPlatformRenderPassFrame();
|
||||
std::cout << "gnRenderPassFrameSetClearColorFn does nothing on metal cuz imma bitch\n";
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
#include <core/graphics_pipeline/gryphn_render_pass_frame.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformRenderPassFrame {
|
||||
// ive been told I can recreate this jazz every frame so im going to do that, screw you
|
||||
MTL::RenderPassDescriptor* renderPassDescriptor = nullptr;
|
||||
MTL::RenderCommandEncoder* renderCommandEncoder = nullptr;
|
||||
|
||||
gnColor clearColor;
|
||||
|
||||
gnPlatformRenderPassFrame();
|
||||
};
|
31
rendering_api/metal/src/core/metal_instance.cpp
Normal file
31
rendering_api/metal/src/core/metal_instance.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <gryphn/gryphn.h>
|
||||
#include <gryphn/gryphn_utils.h>
|
||||
|
||||
#import <GLFW/glfw3.h>
|
||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
#import <GLFW/glfw3native.h>
|
||||
|
||||
#include "bridge/metal_bridge.h"
|
||||
#include "metal_instance.h"
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreateInstanceFn(gnInstance* instance) {
|
||||
if (instance->instance == nullptr) instance->instance = new gnPlatformInstanceData();
|
||||
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
GN_EXPORT void gnDestroyInstanceFn(gnInstance& instance) {
|
||||
|
||||
}
|
||||
|
||||
GN_EXPORT gnReturnCode gnInstanceSetWindowFn(gnInstance& instance, GLFWwindow* window) {
|
||||
if (instance.instance == nullptr) instance.instance = new gnPlatformInstanceData();
|
||||
instance.instance->window = window;
|
||||
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(instance.instance->window, &width, &height);
|
||||
|
||||
instance.instance->metalWindow = reinterpret_cast<NS::Window*>(glfwGetCocoaWindow(window));
|
||||
instance.instance->metalContentView = reinterpret_cast<NS::View*>(glfwGetCocoaView(window));
|
||||
return GN_SUCCESS;
|
||||
}
|
21
rendering_api/metal/src/core/metal_instance.h
Normal file
21
rendering_api/metal/src/core/metal_instance.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#ifndef OBJECT_C_CODE
|
||||
#include <Metal/Metal.hpp>
|
||||
#include <QuartzCore/CAMetalLayer.hpp>
|
||||
#include <QuartzCore/CAMetalLayer.h>
|
||||
#include <QuartzCore/QuartzCore.hpp>
|
||||
|
||||
#include <AppKit/AppKit.hpp>
|
||||
#include <MetalKit/MetalKit.hpp>
|
||||
#include <Foundation/Foundation.hpp>
|
||||
#endif
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
struct gnPlatformInstanceData {
|
||||
NS::Window* metalWindow;
|
||||
NS::View* metalContentView;
|
||||
GLFWwindow* window;
|
||||
|
||||
MTL::RenderPipelineState* framebufferRenderer, *testSquareRenderer;
|
||||
};
|
9
rendering_api/metal/src/core/metal_supports.cpp
Normal file
9
rendering_api/metal/src/core/metal_supports.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <core/gryphn_support.h>
|
||||
|
||||
GN_EXPORT gnBool gnAPISupportsFn(gnFeature feature) {
|
||||
switch (feature) {
|
||||
case GN_DYNAMIC_STATES: return false; // from what I belive eveything is a dynamic state
|
||||
case GN_SYNC_OBJECTS: return true; // from what I belive metal does but i don't feel like supporting them
|
||||
}
|
||||
return false; // we should never get here
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
#define GN_TEXTURE_NO_TEXTURE_ID
|
||||
#include <core/presentation_queue/gryphn_device_presentation_details.h>
|
||||
#include <core/presentation_queue/gryphn_presentation_queue.h>
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
#include "core/metal_instance.h"
|
||||
#include "core/textures/metal_texture.h"
|
||||
#include "QuartzCore/CAMetalLayer.h"
|
||||
#include "core/sync_objects/metal_semaphore.h"
|
||||
#include "bridge/metal_bridge.h"
|
||||
#include "metal_presentation_queue.h"
|
||||
|
||||
gnOutputDevice* mltGetOutputDevice(gnPlatformPresentationQueue* presentaionQueue) {
|
||||
return presentaionQueue->outputDevice;
|
||||
}
|
||||
|
||||
#define MAXIMUM_DRAWABLES 3
|
||||
|
||||
GN_EXPORT gnDevicePresentationDetails gnGetDevicePresentationDetailsFn(const gnPhysicalOutputDevice& physicalOutputDevice) {
|
||||
return { MAXIMUM_DRAWABLES, MAXIMUM_DRAWABLES };
|
||||
}
|
||||
|
||||
GN_EXPORT gnReturnCode gnPresentationQueueGetNextImageAsyncFn(gnPresentationQueue& presentationQueue, const gnSyncSemaphore& semaphore, gnUInt* imageIndex) {
|
||||
mtlObjectCSetContentViewsLayer(
|
||||
presentationQueue.presentationQueue->outputDevice->outputDevice->instance->instance->window,
|
||||
presentationQueue.presentationQueue->layer);
|
||||
|
||||
presentationQueue.presentationQueue->currentDrawableIndex++;
|
||||
presentationQueue.presentationQueue->currentDrawableIndex %= MAXIMUM_DRAWABLES;
|
||||
*imageIndex = presentationQueue.presentationQueue->currentDrawableIndex;
|
||||
|
||||
presentationQueue.presentationQueue->currentDrawable = presentationQueue.presentationQueue->layer->nextDrawable();
|
||||
|
||||
dispatch_semaphore_signal(semaphore.semaphore->semaphore);
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
GN_EXPORT gnPresentationQueueState gnPresentationQueueGetStateFn(gnPresentationQueue& presentationQueue) {
|
||||
return GN_VALID;
|
||||
}
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreatePresentationQueueFn(gnPresentationQueue* presentationQueue, const gnOutputDevice& device, gnPresentationDetails& details) {
|
||||
presentationQueue->presentationQueue = new gnPlatformPresentationQueue();
|
||||
presentationQueue->presentationQueue->outputDevice = const_cast<gnOutputDevice*>(&device);
|
||||
|
||||
presentationQueue->presentationQueue->layer = CA::MetalLayer::layer();
|
||||
presentationQueue->presentationQueue->layer->setPixelFormat(MTL::PixelFormat::PixelFormatBGRA8Unorm_sRGB);
|
||||
presentationQueue->presentationQueue->layer->setFramebufferOnly(true);
|
||||
presentationQueue->presentationQueue->layer->setDrawableSize({ (double)details.ImageSize.x, (double)details.ImageSize.y });
|
||||
presentationQueue->presentationQueue->layer->setDevice(device.outputDevice->device);
|
||||
|
||||
mtlInitializeMetalLayer(presentationQueue->presentationQueue->layer, true);
|
||||
|
||||
mtlObjectCSetContentViewsLayer(
|
||||
device.outputDevice->instance->instance->window,
|
||||
presentationQueue->presentationQueue->layer);
|
||||
|
||||
for (int i = 0; i < details.ImageCount; i++) {
|
||||
MTL::TextureDescriptor* desc = MTL::TextureDescriptor::texture2DDescriptor(
|
||||
MTL::PixelFormat::PixelFormatBGRA8Unorm,
|
||||
details.ImageSize.x,
|
||||
details.ImageSize.y,
|
||||
false
|
||||
);
|
||||
desc->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead);
|
||||
|
||||
gnTexture newImage = gnTexture();
|
||||
newImage.textureColorFormat = GN_BGRA8;
|
||||
newImage.minFilter = GN_FILTER_NEAREST;
|
||||
newImage.magFilter = GN_FILTER_NEAREST;
|
||||
newImage.textureType = GN_TEXTURE_2D;
|
||||
newImage.texture = new gnPlatformTexture();
|
||||
newImage.texture->texture = device.outputDevice->device->newTexture(desc);
|
||||
gnListAdd(presentationQueue->images, newImage);
|
||||
}
|
||||
|
||||
MTL::TextureDescriptor* afsdfsdf = MTL::TextureDescriptor::texture2DDescriptor(
|
||||
MTL::PixelFormat::PixelFormatBGRA8Unorm,
|
||||
2,
|
||||
2,
|
||||
false
|
||||
);
|
||||
afsdfsdf->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead);
|
||||
|
||||
gnTexture newImage = gnTexture();
|
||||
newImage.textureColorFormat = GN_BGRA8;
|
||||
newImage.minFilter = GN_FILTER_NEAREST;
|
||||
newImage.magFilter = GN_FILTER_NEAREST;
|
||||
newImage.textureType = GN_TEXTURE_2D;
|
||||
newImage.texture = new gnPlatformTexture();
|
||||
newImage.texture->texture = device.outputDevice->device->newTexture(afsdfsdf);
|
||||
MTL::Region region = MTL::Region(0, 0, 2, 2);
|
||||
uint32_t data[4] = {
|
||||
0xffffffff, 0xff000000, 0xffff0000, 0xffffff00
|
||||
};
|
||||
newImage.texture->texture->replaceRegion(region, 0, data, 8);
|
||||
|
||||
gnListAdd(presentationQueue->images, newImage);
|
||||
|
||||
// so funny story I have no god damn clue how to implement a presentation queue on metal
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnDestroyPresentationQueueFn(gnPresentationQueue& queue) {
|
||||
/*for (int i = 0; i < gnListLength(queue.images); i++) {
|
||||
gnDestroyTexture(queue.images[i]);
|
||||
}
|
||||
queue.images = gnCreateList<gnTexture>();*/
|
||||
std::cout << "gnDestroyPresentationQueueFn needs fixin\n";
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "QuartzCore/CAMetalLayer.hpp"
|
||||
#include "core/output_device/gryphn_output_device.h"
|
||||
|
||||
struct gnPlatformPresentationQueue {
|
||||
int currentDrawableIndex = 0;
|
||||
gnOutputDevice* outputDevice;
|
||||
CA::MetalLayer* layer;
|
||||
|
||||
CA::MetalDrawable* currentDrawable;
|
||||
};
|
||||
|
||||
struct gnPlatformPresentationQueue;
|
||||
gnOutputDevice* mltGetOutputDevice(gnPlatformPresentationQueue* presentaionQueue);
|
120
rendering_api/metal/src/core/shaders/metal_shader.cpp
Normal file
120
rendering_api/metal/src/core/shaders/metal_shader.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include "metal_shader_module.h"
|
||||
#include "metal_shader.h"
|
||||
#include "spirv_msl.hpp"
|
||||
#include "core/devices/metal_output_devices.h"
|
||||
|
||||
static uint32_t* chars_to_uint32s(const char* chars, size_t num_chars) {
|
||||
if (chars == NULL || num_chars == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Determine the number of uint32_t elements needed.
|
||||
// Round up in case the number of chars isn't a multiple of 4.
|
||||
size_t num_uint32s = (num_chars + 3) / 4;
|
||||
|
||||
// Allocate memory for the uint32_t array.
|
||||
uint32_t* uint32s = (uint32_t*)malloc(num_uint32s * sizeof(uint32_t));
|
||||
if (uint32s == NULL) {
|
||||
return NULL; // Allocation failed
|
||||
}
|
||||
|
||||
// Initialize the uint32_t array to 0.
|
||||
for (size_t i = 0; i < num_uint32s; ++i) {
|
||||
uint32s[i] = 0;
|
||||
}
|
||||
|
||||
// Iterate through the char array and build uint32_t values.
|
||||
for (size_t i = 0; i < num_chars; ++i) {
|
||||
size_t uint32_index = i / 4;
|
||||
int shift = 8 * (i % 4);
|
||||
uint32s[uint32_index] |= (uint32_t)(unsigned char)chars[i] << shift;
|
||||
}
|
||||
return uint32s;
|
||||
}
|
||||
|
||||
GN_EXPORT gnReturnCode gnBuildShaderModuleFn(gnShaderModule* shaderModule, const gnOutputDevice& outputDeviec) {
|
||||
if (shaderModule->shaderModule == nullptr) shaderModule->shaderModule = new gnPlatformShaderModule();
|
||||
|
||||
spirv_cross::CompilerMSL::Options options;
|
||||
options.enable_decoration_binding = true;
|
||||
options.pad_argument_buffer_resources = true;
|
||||
|
||||
std::string shaderSource;
|
||||
uint32_t* data = chars_to_uint32s(shaderModule->shaderData, shaderModule->codeSize);
|
||||
if (shaderModule->shaderType == GN_VERTEX_SHADER_MODULE) {
|
||||
spirv_cross::CompilerMSL vertexMSL(data, (shaderModule->codeSize + 3) / 4);
|
||||
vertexMSL.set_msl_options(options);
|
||||
|
||||
spirv_cross::ShaderResources resources = vertexMSL.get_shader_resources();
|
||||
int largestBinding = 0;
|
||||
for (auto &resource : resources.uniform_buffers) {
|
||||
unsigned binding = vertexMSL.get_decoration(resource.id, spv::DecorationBinding) + 1;
|
||||
vertexMSL.unset_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
vertexMSL.set_decoration(resource.id, spv::DecorationBinding, binding);
|
||||
if (binding > largestBinding) largestBinding = binding;
|
||||
} // bullshit stuff to remap bindings so that metal can not being a whining little baby bitch boy
|
||||
|
||||
for (auto &resource : resources.push_constant_buffers) {
|
||||
unsigned binding = vertexMSL.get_decoration(resource.id, spv::DecorationBinding) + 1;
|
||||
vertexMSL.unset_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
vertexMSL.set_decoration(resource.id, spv::DecorationBinding, largestBinding + binding);
|
||||
} // bullshit stuff to remap push constants for metal because its being a little baby bitch boy
|
||||
shaderSource = vertexMSL.compile();
|
||||
shaderModule->shaderModule->uniformBufferOffset = 1;
|
||||
shaderModule->shaderModule->pushConstantOffset = largestBinding + 1;
|
||||
} else if (shaderModule->shaderType == GN_FRAGMENT_SHADER_MODULE) {
|
||||
spirv_cross::CompilerMSL fragmentMSL(data, (shaderModule->codeSize + 3) / 4);
|
||||
fragmentMSL.set_msl_options(options);
|
||||
|
||||
spirv_cross::ShaderResources resources = fragmentMSL.get_shader_resources();
|
||||
int largestBinding = 0;
|
||||
for (auto &resource : resources.uniform_buffers) {
|
||||
unsigned binding = fragmentMSL.get_decoration(resource.id, spv::DecorationBinding);
|
||||
if (binding > largestBinding) largestBinding = binding;
|
||||
}
|
||||
|
||||
for (auto &resource : resources.push_constant_buffers) {
|
||||
unsigned binding = fragmentMSL.get_decoration(resource.id, spv::DecorationBinding);
|
||||
fragmentMSL.unset_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
fragmentMSL.set_decoration(resource.id, spv::DecorationBinding, (largestBinding + 1) + binding);
|
||||
} // bullshit stuff to remap push constants for metal because its being a little baby bitch boy
|
||||
|
||||
int bindingIndex = 0;
|
||||
for (auto &resource : resources.sampled_images) {
|
||||
unsigned binding = fragmentMSL.get_decoration(resource.id, spv::DecorationBinding);
|
||||
unsigned set = fragmentMSL.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
fragmentMSL.unset_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
fragmentMSL.set_decoration(resource.id, spv::DecorationBinding, bindingIndex);
|
||||
shaderModule->shaderModule->texturesSetBindings[{set, binding}] = bindingIndex;
|
||||
bindingIndex++;
|
||||
}
|
||||
|
||||
shaderSource = fragmentMSL.compile();
|
||||
shaderModule->shaderModule->uniformBufferOffset = 0;
|
||||
shaderModule->shaderModule->pushConstantOffset = largestBinding + 1;
|
||||
} else {
|
||||
GN_RETURN_ERROR("GN_UNKNOWN_SHADER_MODULE_TYPE_(I prolly lazy)");
|
||||
}
|
||||
|
||||
// std::cout << shaderSource << "\n";
|
||||
|
||||
NS::Error* error = nullptr;
|
||||
MTL::CompileOptions* mtloptions = nullptr;
|
||||
NS::String* sourceCode = NS::String::string(shaderSource.c_str(), NS::StringEncoding::UTF8StringEncoding);
|
||||
MTL::Library* shaderLib = outputDeviec.outputDevice->device->newLibrary(sourceCode, mtloptions, &error);
|
||||
if (!shaderLib)
|
||||
GN_RETURN_ERROR(error->localizedDescription()->utf8String());
|
||||
if (shaderLib->functionNames()->count() > 1)
|
||||
GN_RETURN_ERROR("More than one shader function in shader");
|
||||
|
||||
shaderModule->shaderModule->shaderFunction = shaderLib->newFunction(reinterpret_cast<NS::String*>(shaderLib->functionNames()->object(0)));
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
|
||||
GN_EXPORT void gnDestroyShaderModuleFn(gnShaderModule& shaderModule) {
|
||||
shaderModule.shaderModule->shaderFunction->release();
|
||||
}
|
||||
|
||||
GN_EXPORT gnReturnCode gnBuildShaderFn(gnShader* shader) {
|
||||
return GN_SUCCESS;
|
||||
}
|
4
rendering_api/metal/src/core/shaders/metal_shader.h
Normal file
4
rendering_api/metal/src/core/shaders/metal_shader.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <core/shaders/gryphn_shader.h>
|
||||
|
||||
struct gnPlatformShader {};
|
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <core/shaders/gryphn_shader_module.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformShaderModule {
|
||||
MTL::Function* shaderFunction;
|
||||
int uniformBufferOffset = 0, pushConstantOffset = 0;
|
||||
std::unordered_map<gnUInt2, gnUInt> texturesSetBindings;
|
||||
};
|
34
rendering_api/metal/src/core/sync_objects/metal_fence.cpp
Normal file
34
rendering_api/metal/src/core/sync_objects/metal_fence.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <core/sync_objects/gryphn_fence.h>
|
||||
#include <core/devices/metal_output_devices.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformFence {
|
||||
MTL::SharedEvent* fence;
|
||||
MTL::SharedEventListener* listener;
|
||||
dispatch_semaphore_t semaphore;
|
||||
};
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreateFenceFn(gnFence* fence, const gnOutputDevice& device) {
|
||||
fence->fence = new gnPlatformFence();
|
||||
fence->fence->fence = device.outputDevice->device->newSharedEvent();
|
||||
fence->fence->listener = MTL::SharedEventListener::alloc()->init();
|
||||
fence->fence->semaphore = dispatch_semaphore_create(1);
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnWaitForFenceFn(const gnFence& fence) {
|
||||
dispatch_semaphore_wait(fence.fence->semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
GN_EXPORT void gnResetFenceFn(gnFence& fence) {
|
||||
dispatch_semaphore_signal(fence.fence->semaphore);
|
||||
fence.fence->fence->setSignaledValue(0);
|
||||
fence.fence->fence->notifyListener(
|
||||
fence.fence->listener,
|
||||
1,
|
||||
^(MTL::SharedEvent* ev, uint64_t val) {
|
||||
dispatch_semaphore_signal(fence.fence->semaphore);
|
||||
}
|
||||
);
|
||||
}
|
||||
GN_EXPORT void gnDestroyFenceFn(gnFence& fence) {
|
||||
fence.fence->fence->release();
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
#include <core/sync_objects/gryphn_sync_semaphore.h>
|
||||
#include "metal_semaphore.h"
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreateSyncSemaphoreFn(gnSyncSemaphore* semaphore, const gnOutputDevice& device) {
|
||||
semaphore->semaphore = new gnPlatformSyncSemaphore();
|
||||
semaphore->semaphore->semaphore = dispatch_semaphore_create(0);
|
||||
// semaphore->semaphore->semaphore = device.outputDevice->device->newFence();
|
||||
}
|
||||
GN_EXPORT void gnDestroySyncSemaphoreFn(const gnSyncSemaphore& semaphore) {
|
||||
// semaphore.semaphore->semaphore->release();
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformSyncSemaphore {
|
||||
// MTL::Fence* semaphore;
|
||||
dispatch_semaphore_t semaphore;
|
||||
};
|
84
rendering_api/metal/src/core/textures/metal_texture.cpp
Normal file
84
rendering_api/metal/src/core/textures/metal_texture.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "metal_texture.h"
|
||||
|
||||
GN_EXPORT void gnTextureDataFn(gnTexture& texture, gnSize dataSize, const void* data) {
|
||||
if (texture.texture == nullptr) texture.texture = new gnPlatformTexture();
|
||||
|
||||
MTL::Region region = MTL::Region(0, 0, 0, texture.textureExtent.x, texture.textureExtent.y, 1);
|
||||
NS::UInteger bytesPerRow = texture.textureExtent.x;
|
||||
|
||||
if (texture.textureColorFormat == GN_RED)
|
||||
bytesPerRow *= 1;
|
||||
else if (texture.textureColorFormat == GN_RGB8)
|
||||
bytesPerRow *= 3;
|
||||
else if (texture.textureColorFormat == GN_RGBA8)
|
||||
bytesPerRow *= 4;
|
||||
else if (texture.textureColorFormat == GN_BGRA8)
|
||||
bytesPerRow *= 4;
|
||||
else if (texture.textureColorFormat == GN_DEPTH_STENCIL)
|
||||
bytesPerRow *= 32; // this number is straight from my ass and may not work
|
||||
|
||||
texture.texture->texture->replaceRegion(region, 0, data, bytesPerRow);
|
||||
}
|
||||
GN_EXPORT void gnTextureCubeMapDataFn(gnTexture& texture, gnSize imageDataSize, void* face1, void* face2, void* face3, void* face4, void* face5, void* face6) {
|
||||
NS::UInteger bytesPerRow = texture.textureExtent.x;
|
||||
|
||||
if (texture.textureColorFormat == GN_RED)
|
||||
bytesPerRow *= 1;
|
||||
else if (texture.textureColorFormat == GN_RGB8)
|
||||
bytesPerRow *= 3;
|
||||
else if (texture.textureColorFormat == GN_RGBA8)
|
||||
bytesPerRow *= 4;
|
||||
else if (texture.textureColorFormat == GN_BGRA8)
|
||||
bytesPerRow *= 4;
|
||||
else if (texture.textureColorFormat == GN_DEPTH_STENCIL)
|
||||
bytesPerRow *= 32; // this number is straight from my ass and may not work
|
||||
|
||||
MTL::Region region = MTL::Region::Make2D(0, 0, texture.textureExtent.x, texture.textureExtent.y);
|
||||
texture.texture->texture->replaceRegion(region, 0, 0, face1, bytesPerRow, imageDataSize);
|
||||
texture.texture->texture->replaceRegion(region, 0, 1, face2, bytesPerRow, imageDataSize);
|
||||
texture.texture->texture->replaceRegion(region, 0, 2, face3, bytesPerRow, imageDataSize);
|
||||
texture.texture->texture->replaceRegion(region, 0, 3, face4, bytesPerRow, imageDataSize);
|
||||
texture.texture->texture->replaceRegion(region, 0, 4, face5, bytesPerRow, imageDataSize);
|
||||
texture.texture->texture->replaceRegion(region, 0, 5, face6, bytesPerRow, imageDataSize);
|
||||
}
|
||||
GN_EXPORT gnErrorCode gnCreateTextureFn(gnTexture* texture, const gnOutputDevice& outputDevice) {
|
||||
if (texture->texture == nullptr) texture->texture = new gnPlatformTexture();
|
||||
|
||||
MTL::TextureDescriptor* textureDescriptor = MTL::TextureDescriptor::alloc()->init();
|
||||
if (texture->textureType == GN_TEXTURE_CUBE_MAP) textureDescriptor->setTextureType(MTL::TextureType::TextureTypeCube);
|
||||
if (texture->textureColorFormat == GN_RED)
|
||||
textureDescriptor->setPixelFormat(MTL::PixelFormatR8Unorm);
|
||||
else if (texture->textureColorFormat == GN_RGB8)
|
||||
return gnReturnError("GN_RGB8_UNSUPPORTED");
|
||||
else if (texture->textureColorFormat == GN_RGBA8)
|
||||
textureDescriptor->setPixelFormat(MTL::PixelFormatRGBA8Unorm);
|
||||
else if (texture->textureColorFormat == GN_BGRA8)
|
||||
textureDescriptor->setPixelFormat(MTL::PixelFormatBGRA8Unorm);
|
||||
else if (texture->textureColorFormat == GN_DEPTH_STENCIL)
|
||||
textureDescriptor->setPixelFormat(MTL::PixelFormatDepth32Float_Stencil8);
|
||||
else return gnReturnError("GN_UNSUPPORTED_PIXEL_FORMAT");
|
||||
|
||||
textureDescriptor->setWidth(texture->textureExtent.x);
|
||||
textureDescriptor->setHeight(texture->textureExtent.y);
|
||||
// textureDescriptor->setUsage(MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead);
|
||||
|
||||
texture->texture->texture = outputDevice.physicalOutputDevice->physicalOutputDevice->device->newTexture(textureDescriptor);
|
||||
MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();
|
||||
if (texture->minFilter == GN_FILTER_LINEAR)
|
||||
samplerDescriptor->setMinFilter(MTL::SamplerMinMagFilter::SamplerMinMagFilterLinear);
|
||||
else
|
||||
samplerDescriptor->setMinFilter(MTL::SamplerMinMagFilter::SamplerMinMagFilterNearest);
|
||||
|
||||
if (texture->magFilter == GN_FILTER_LINEAR)
|
||||
samplerDescriptor->setMagFilter(MTL::SamplerMinMagFilter::SamplerMinMagFilterLinear);
|
||||
else
|
||||
samplerDescriptor->setMagFilter(MTL::SamplerMinMagFilter::SamplerMinMagFilterNearest);
|
||||
texture->texture->sampler = outputDevice.outputDevice->device->newSamplerState(samplerDescriptor);
|
||||
|
||||
textureDescriptor->release();
|
||||
samplerDescriptor->release();
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnDestroyTextureFn(gnTexture& texture) {
|
||||
texture.texture->texture->release();
|
||||
}
|
9
rendering_api/metal/src/core/textures/metal_texture.h
Normal file
9
rendering_api/metal/src/core/textures/metal_texture.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <core/textures/gryphn_texture.h>
|
||||
#include <core/devices/metal_output_devices.h>
|
||||
#include <Metal/Metal.hpp>
|
||||
|
||||
struct gnPlatformTexture {
|
||||
MTL::Texture* texture;
|
||||
MTL::SamplerState* sampler;
|
||||
};
|
17
rendering_api/metal/src/core/triangle.metal
Normal file
17
rendering_api/metal/src/core/triangle.metal
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
vertex float4
|
||||
vertexShader(uint vertexID [[vertex_id]],
|
||||
constant simd::float3* vertexPositions)
|
||||
{
|
||||
float4 vertexOutPositions = float4(vertexPositions[vertexID][0],
|
||||
vertexPositions[vertexID][1],
|
||||
vertexPositions[vertexID][2],
|
||||
1.0f);
|
||||
return vertexOutPositions;
|
||||
}
|
||||
|
||||
fragment float4 fragmentShader(float4 vertexOutPositions [[stage_in]]) {
|
||||
return float4(182.0f/255.0f, 240.0f/255.0f, 228.0f/255.0f, 1.0f);
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
#include "core/uniform_descriptor/uniform_buffer/gryphn_uniform_buffer.h"
|
||||
|
||||
GN_EXPORT void gnUpdateBufferUniformFn(gnBufferUniform& uniformBuffer, const gnOutputDevice& outputDevice) {
|
||||
if (uniformBuffer.uniform->uniformLayout->bindings[uniformBuffer.binding].type != GN_UNIFORM_BUFFER_DESCRIPTOR) {
|
||||
std::cout << "uniform layout [" << uniformBuffer.binding << "] is of type GN_SAMPLER_DESCRIPTOR but calling gnUpdateBufferUniform\n";
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
#include "core/uniform_descriptor/sampler/gryphn_sampler.h"
|
||||
|
||||
GN_EXPORT void gnUpdateSamplerUniformFn(gnSamplerUniform& samplerUniform, const gnOutputDevice& outputDevice) {
|
||||
if (samplerUniform.uniform->uniformLayout->bindings[samplerUniform.binding].type != GN_SAMPLER_DESCRIPTOR) {
|
||||
std::cout << "uniform layout [" << samplerUniform.binding << "] is of type GN_UNIFORM_BUFFER_DESCRIPTOR but calling gnUpdateSamplerUniform\n";
|
||||
}
|
||||
}
|
8
rendering_api/metal/src/core/uniforms/metal_uniform.cpp
Normal file
8
rendering_api/metal/src/core/uniforms/metal_uniform.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "core/uniform_descriptor/gryphn_uniform.h"
|
||||
|
||||
GN_EXPORT gnReturnCode gnCreateUniformFn(gnUniform* uniform, gnOutputDevice& outputDevice) {
|
||||
return GN_SUCCESS;
|
||||
}
|
||||
GN_EXPORT void gnDestroyUniformFn(gnUniform& uniform) {
|
||||
|
||||
}
|
Reference in New Issue
Block a user