Files
LNXRNT/Kinc/Backends/Graphics5/Metal/Sources/kinc/backend/graphics5/Metal.m.h
2025-01-29 10:55:49 +01:00

232 lines
7.8 KiB
Objective-C

#include "Metal.h"
#include <kinc/color.h>
#include <kinc/system.h>
#include <kinc/window.h>
#include <kinc/graphics5/commandlist.h>
#include <kinc/graphics5/rendertarget.h>
#import <Metal/Metal.h>
#import <MetalKit/MTKView.h>
id getMetalLayer(void);
id getMetalDevice(void);
id getMetalQueue(void);
int renderTargetWidth;
int renderTargetHeight;
int newRenderTargetWidth;
int newRenderTargetHeight;
id<CAMetalDrawable> drawable;
id<MTLCommandBuffer> commandBuffer;
id<MTLRenderCommandEncoder> commandEncoder;
id<MTLTexture> depthTexture;
int depthBits;
int stencilBits;
static kinc_g5_render_target_t fallback_render_target;
id getMetalEncoder(void) {
return commandEncoder;
}
void kinc_g5_internal_destroy_window(int window) {}
void kinc_g5_internal_destroy(void) {}
extern void kinc_g4_on_g5_internal_resize(int, int, int);
void kinc_internal_resize(int window, int width, int height) {
kinc_g4_on_g5_internal_resize(window, width, height);
}
void kinc_g5_internal_init(void) {}
void kinc_g5_internal_init_window(int window, int depthBufferBits, int stencilBufferBits, bool vsync) {
depthBits = depthBufferBits;
stencilBits = stencilBufferBits;
kinc_g5_render_target_init(&fallback_render_target, 32, 32, KINC_G5_RENDER_TARGET_FORMAT_32BIT, 0, 0);
}
void kinc_g5_flush(void) {}
void kinc_g5_draw_indexed_vertices_instanced(int instanceCount) {}
void kinc_g5_draw_indexed_vertices_instanced_from_to(int instanceCount, int start, int count) {}
bool kinc_internal_metal_has_depth = false;
bool kinc_internal_current_render_target_has_depth(void) {
return kinc_internal_metal_has_depth;
}
void kinc_g5_begin(kinc_g5_render_target_t *renderTarget, int window) {
CAMetalLayer *metalLayer = getMetalLayer();
drawable = [metalLayer nextDrawable];
if (depthBits > 0 && (depthTexture == nil || depthTexture.width != drawable.texture.width || depthTexture.height != drawable.texture.height)) {
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor new];
descriptor.textureType = MTLTextureType2D;
descriptor.width = drawable.texture.width;
descriptor.height = drawable.texture.height;
descriptor.depth = 1;
descriptor.pixelFormat = MTLPixelFormatDepth32Float_Stencil8;
descriptor.arrayLength = 1;
descriptor.mipmapLevelCount = 1;
descriptor.resourceOptions = MTLResourceStorageModePrivate;
descriptor.usage = MTLTextureUsageRenderTarget;
id<MTLDevice> device = getMetalDevice();
depthTexture = [device newTextureWithDescriptor:descriptor];
kinc_internal_metal_has_depth = true;
}
else {
kinc_internal_metal_has_depth = false;
}
id<MTLTexture> texture = drawable.texture;
MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDescriptor.colorAttachments[0].texture = texture;
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
renderPassDescriptor.depthAttachment.clearDepth = 1;
renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;
renderPassDescriptor.depthAttachment.texture = depthTexture;
renderPassDescriptor.stencilAttachment.clearStencil = 0;
renderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionDontCare;
renderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionDontCare;
renderPassDescriptor.stencilAttachment.texture = depthTexture;
if (commandBuffer != nil && commandEncoder != nil) {
[commandEncoder endEncoding];
[commandBuffer commit];
}
id<MTLCommandQueue> commandQueue = getMetalQueue();
commandBuffer = [commandQueue commandBuffer];
commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
}
void kinc_g5_end(int window) {}
bool kinc_g5_swap_buffers(void) {
if (commandBuffer != nil && commandEncoder != nil) {
[commandEncoder endEncoding];
[commandBuffer presentDrawable:drawable];
[commandBuffer commit];
}
drawable = nil;
commandBuffer = nil;
commandEncoder = nil;
return true;
}
bool kinc_window_vsynced(int window) {
return true;
}
void kinc_g5_internal_new_render_pass(kinc_g5_render_target_t **renderTargets, int count, bool wait, unsigned clear_flags, unsigned color, float depth,
int stencil) {
if (commandBuffer != nil && commandEncoder != nil) {
[commandEncoder endEncoding];
[commandBuffer commit];
if (wait) {
[commandBuffer waitUntilCompleted];
}
}
MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
for (int i = 0; i < count; ++i) {
if (renderTargets == NULL) {
if (drawable == nil) {
renderPassDescriptor.colorAttachments[i].texture = (__bridge id<MTLTexture>)fallback_render_target.impl._tex;
renderPassDescriptor.depthAttachment.texture = nil;
renderPassDescriptor.stencilAttachment.texture = nil;
kinc_internal_metal_has_depth = false;
}
else {
renderPassDescriptor.colorAttachments[i].texture = drawable.texture;
renderPassDescriptor.depthAttachment.texture = depthTexture;
renderPassDescriptor.stencilAttachment.texture = depthTexture;
kinc_internal_metal_has_depth = depthTexture != nil;
}
}
else {
renderPassDescriptor.colorAttachments[i].texture = (__bridge id<MTLTexture>)renderTargets[i]->impl._tex;
renderPassDescriptor.depthAttachment.texture = (__bridge id<MTLTexture>)renderTargets[0]->impl._depthTex;
renderPassDescriptor.stencilAttachment.texture = (__bridge id<MTLTexture>)renderTargets[0]->impl._depthTex;
kinc_internal_metal_has_depth = renderTargets[0]->impl._depthTex != nil;
}
if (clear_flags & KINC_G5_CLEAR_COLOR) {
float red, green, blue, alpha;
kinc_color_components(color, &red, &green, &blue, &alpha);
renderPassDescriptor.colorAttachments[i].loadAction = MTLLoadActionClear;
renderPassDescriptor.colorAttachments[i].storeAction = MTLStoreActionStore;
renderPassDescriptor.colorAttachments[i].clearColor = MTLClearColorMake(red, green, blue, alpha);
}
else {
renderPassDescriptor.colorAttachments[i].loadAction = MTLLoadActionLoad;
renderPassDescriptor.colorAttachments[i].storeAction = MTLStoreActionStore;
renderPassDescriptor.colorAttachments[i].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
}
}
if (clear_flags & KINC_G5_CLEAR_DEPTH) {
renderPassDescriptor.depthAttachment.clearDepth = depth;
renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;
}
else {
renderPassDescriptor.depthAttachment.clearDepth = 1;
renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionLoad;
renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;
}
if (clear_flags & KINC_G5_CLEAR_STENCIL) {
renderPassDescriptor.stencilAttachment.clearStencil = stencil;
renderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionClear;
renderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionStore;
}
else {
renderPassDescriptor.stencilAttachment.clearStencil = 0;
renderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionDontCare;
renderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionDontCare;
}
id<MTLCommandQueue> commandQueue = getMetalQueue();
commandBuffer = [commandQueue commandBuffer];
commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
}
bool kinc_g5_supports_raytracing(void) {
return false;
}
bool kinc_g5_supports_instanced_rendering(void) {
return true;
}
bool kinc_g5_supports_compute_shaders(void) {
return true;
}
bool kinc_g5_supports_blend_constants(void) {
return true;
}
bool kinc_g5_supports_non_pow2_textures(void) {
return true;
}
bool kinc_g5_render_targets_inverted_y(void) {
return false;
}
int kinc_g5_max_bound_textures(void) {
return 16;
}