ebiten/internal/graphicsdriver/metal/mtl/mtl_darwin.m

444 lines
18 KiB
Objective-C

// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "mtl_darwin.h"
#import <Metal/Metal.h>
#include <stdlib.h>
struct Device CreateSystemDefaultDevice() {
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if (!device) {
struct Device d;
d.Device = NULL;
return d;
}
struct Device d;
d.Device = device;
#if !TARGET_OS_IPHONE
d.Headless = device.headless;
d.LowPower = device.lowPower;
#else
d.Headless = 0;
d.LowPower = 0;
#endif
d.Name = device.name.UTF8String;
return d;
}
uint8_t Device_SupportsFeatureSet(void *device, uint16_t featureSet) {
return [(id<MTLDevice>)device supportsFeatureSet:featureSet];
}
void *Device_MakeCommandQueue(void *device) {
return [(id<MTLDevice>)device newCommandQueue];
}
struct Library Device_MakeLibrary(void *device, const char *source,
size_t sourceLength) {
NSError *error;
MTLCompileOptions* options = [[MTLCompileOptions alloc] init];
if (@available(macOS 10.14, iOS 12.0, *)) {
options.languageVersion = MTLLanguageVersion2_1;
}
id<MTLLibrary> library = [(id<MTLDevice>)device
newLibraryWithSource:[[NSString alloc] initWithBytes:source
length:sourceLength
encoding:NSUTF8StringEncoding]
options:options
error:&error];
struct Library l;
l.Library = library;
if (!library) {
l.Error = error.localizedDescription.UTF8String;
}
return l;
}
struct RenderPipelineState
Device_MakeRenderPipelineState(void *device,
struct RenderPipelineDescriptor descriptor) {
MTLRenderPipelineDescriptor *renderPipelineDescriptor =
[[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDescriptor.vertexFunction = descriptor.VertexFunction;
renderPipelineDescriptor.fragmentFunction = descriptor.FragmentFunction;
renderPipelineDescriptor.colorAttachments[0].pixelFormat =
descriptor.ColorAttachment0PixelFormat;
renderPipelineDescriptor.colorAttachments[0].blendingEnabled =
descriptor.ColorAttachment0BlendingEnabled;
renderPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor =
descriptor.ColorAttachment0DestinationAlphaBlendFactor;
renderPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor =
descriptor.ColorAttachment0DestinationRGBBlendFactor;
renderPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor =
descriptor.ColorAttachment0SourceAlphaBlendFactor;
renderPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor =
descriptor.ColorAttachment0SourceRGBBlendFactor;
renderPipelineDescriptor.colorAttachments[0].writeMask =
descriptor.ColorAttachment0WriteMask;
renderPipelineDescriptor.stencilAttachmentPixelFormat =
descriptor.StencilAttachmentPixelFormat;
NSError *error;
id<MTLRenderPipelineState> renderPipelineState = [(id<MTLDevice>)device
newRenderPipelineStateWithDescriptor:renderPipelineDescriptor
error:&error];
[renderPipelineDescriptor release];
struct RenderPipelineState rps;
rps.RenderPipelineState = renderPipelineState;
if (!renderPipelineState) {
rps.Error = error.localizedDescription.UTF8String;
}
return rps;
}
void *Device_MakeBufferWithBytes(void *device, const void *bytes, size_t length,
uint16_t options) {
return [(id<MTLDevice>)device newBufferWithBytes:(const void *)bytes
length:(NSUInteger)length
options:(MTLResourceOptions)options];
}
void *Device_MakeBufferWithLength(void *device, size_t length,
uint16_t options) {
return
[(id<MTLDevice>)device newBufferWithLength:(NSUInteger)length
options:(MTLResourceOptions)options];
}
void *Device_MakeTexture(void *device, struct TextureDescriptor descriptor) {
MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];
textureDescriptor.textureType = descriptor.TextureType;
textureDescriptor.pixelFormat = descriptor.PixelFormat;
textureDescriptor.width = descriptor.Width;
textureDescriptor.height = descriptor.Height;
textureDescriptor.storageMode = descriptor.StorageMode;
textureDescriptor.usage = descriptor.Usage;
id<MTLTexture> texture =
[(id<MTLDevice>)device newTextureWithDescriptor:textureDescriptor];
[textureDescriptor release];
return texture;
}
void *Device_MakeDepthStencilState(void *device,
struct DepthStencilDescriptor descriptor) {
MTLDepthStencilDescriptor *depthStencilDescriptor =
[[MTLDepthStencilDescriptor alloc] init];
depthStencilDescriptor.backFaceStencil.stencilFailureOperation =
descriptor.BackFaceStencilStencilFailureOperation;
depthStencilDescriptor.backFaceStencil.depthFailureOperation =
descriptor.BackFaceStencilDepthFailureOperation;
depthStencilDescriptor.backFaceStencil.depthStencilPassOperation =
descriptor.BackFaceStencilDepthStencilPassOperation;
depthStencilDescriptor.backFaceStencil.stencilCompareFunction =
descriptor.BackFaceStencilStencilCompareFunction;
depthStencilDescriptor.frontFaceStencil.stencilFailureOperation =
descriptor.FrontFaceStencilStencilFailureOperation;
depthStencilDescriptor.frontFaceStencil.depthFailureOperation =
descriptor.FrontFaceStencilDepthFailureOperation;
depthStencilDescriptor.frontFaceStencil.depthStencilPassOperation =
descriptor.FrontFaceStencilDepthStencilPassOperation;
depthStencilDescriptor.frontFaceStencil.stencilCompareFunction =
descriptor.FrontFaceStencilStencilCompareFunction;
id<MTLDepthStencilState> depthStencilState = [(id<MTLDevice>)device
newDepthStencilStateWithDescriptor:depthStencilDescriptor];
[depthStencilDescriptor release];
return depthStencilState;
}
void CommandQueue_Release(void *commandQueue) {
[(id<MTLCommandQueue>)commandQueue release];
}
void *CommandQueue_MakeCommandBuffer(void *commandQueue) {
return [(id<MTLCommandQueue>)commandQueue commandBuffer];
}
void CommandBuffer_Retain(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer retain];
}
void CommandBuffer_Release(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer release];
}
uint8_t CommandBuffer_Status(void *commandBuffer) {
return [(id<MTLCommandBuffer>)commandBuffer status];
}
void CommandBuffer_PresentDrawable(void *commandBuffer, void *drawable) {
[(id<MTLCommandBuffer>)commandBuffer
presentDrawable:(id<MTLDrawable>)drawable];
}
void CommandBuffer_Commit(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer commit];
}
void CommandBuffer_WaitUntilCompleted(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer waitUntilCompleted];
}
void CommandBuffer_WaitUntilScheduled(void *commandBuffer) {
[(id<MTLCommandBuffer>)commandBuffer waitUntilScheduled];
}
void *
CommandBuffer_MakeRenderCommandEncoder(void *commandBuffer,
struct RenderPassDescriptor descriptor) {
MTLRenderPassDescriptor *renderPassDescriptor =
[[MTLRenderPassDescriptor alloc] init];
renderPassDescriptor.colorAttachments[0].loadAction =
descriptor.ColorAttachment0LoadAction;
renderPassDescriptor.colorAttachments[0].storeAction =
descriptor.ColorAttachment0StoreAction;
renderPassDescriptor.colorAttachments[0].clearColor =
MTLClearColorMake(descriptor.ColorAttachment0ClearColor.Red,
descriptor.ColorAttachment0ClearColor.Green,
descriptor.ColorAttachment0ClearColor.Blue,
descriptor.ColorAttachment0ClearColor.Alpha);
renderPassDescriptor.colorAttachments[0].texture =
(id<MTLTexture>)descriptor.ColorAttachment0Texture;
renderPassDescriptor.stencilAttachment.loadAction =
descriptor.StencilAttachmentLoadAction;
renderPassDescriptor.stencilAttachment.storeAction =
descriptor.StencilAttachmentStoreAction;
renderPassDescriptor.stencilAttachment.texture =
(id<MTLTexture>)descriptor.StencilAttachmentTexture;
id<MTLRenderCommandEncoder> rce = [(id<MTLCommandBuffer>)commandBuffer
renderCommandEncoderWithDescriptor:renderPassDescriptor];
[renderPassDescriptor release];
return rce;
}
void *CommandBuffer_MakeBlitCommandEncoder(void *commandBuffer) {
return [(id<MTLCommandBuffer>)commandBuffer blitCommandEncoder];
}
void CommandEncoder_EndEncoding(void *commandEncoder) {
[(id<MTLCommandEncoder>)commandEncoder endEncoding];
}
void RenderCommandEncoder_Release(void *renderCommandEncoder) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder release];
}
void RenderCommandEncoder_SetRenderPipelineState(void *renderCommandEncoder,
void *renderPipelineState) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setRenderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState];
}
void RenderCommandEncoder_SetViewport(void *renderCommandEncoder,
struct Viewport viewport) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setViewport:(MTLViewport){
.originX = viewport.OriginX,
.originY = viewport.OriginY,
.width = viewport.Width,
.height = viewport.Height,
.znear = viewport.ZNear,
.zfar = viewport.ZFar,
}];
}
void RenderCommandEncoder_SetScissorRect(void *renderCommandEncoder,
struct ScissorRect scissorRect) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setScissorRect:(MTLScissorRect){
.x = scissorRect.X,
.y = scissorRect.Y,
.width = scissorRect.Width,
.height = scissorRect.Height,
}];
}
void RenderCommandEncoder_SetVertexBuffer(void *renderCommandEncoder,
void *buffer, uint_t offset,
uint_t index) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setVertexBuffer:(id<MTLBuffer>)buffer
offset:(NSUInteger)offset
atIndex:(NSUInteger)index];
}
void RenderCommandEncoder_SetVertexBytes(void *renderCommandEncoder,
const void *bytes, size_t length,
uint_t index) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setVertexBytes:bytes
length:(NSUInteger)length
atIndex:(NSUInteger)index];
}
void RenderCommandEncoder_SetFragmentBytes(void *renderCommandEncoder,
const void *bytes, size_t length,
uint_t index) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setFragmentBytes:bytes
length:(NSUInteger)length
atIndex:(NSUInteger)index];
}
void RenderCommandEncoder_SetFragmentTexture(void *renderCommandEncoder,
void *texture, uint_t index) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setFragmentTexture:(id<MTLTexture>)texture
atIndex:(NSUInteger)index];
}
void RenderCommandEncoder_SetBlendColor(void *renderCommandEncoder, float red,
float green, float blue, float alpha) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder setBlendColorRed:red
green:green
blue:blue
alpha:alpha];
}
void RenderCommandEncoder_SetDepthStencilState(void *renderCommandEncoder,
void *depthStencilState) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
setDepthStencilState:(id<MTLDepthStencilState>)depthStencilState];
}
void RenderCommandEncoder_DrawPrimitives(void *renderCommandEncoder,
uint8_t primitiveType,
uint_t vertexStart,
uint_t vertexCount) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
drawPrimitives:(MTLPrimitiveType)primitiveType
vertexStart:(NSUInteger)vertexStart
vertexCount:(NSUInteger)vertexCount];
}
void RenderCommandEncoder_DrawIndexedPrimitives(
void *renderCommandEncoder, uint8_t primitiveType, uint_t indexCount,
uint8_t indexType, void *indexBuffer, uint_t indexBufferOffset) {
[(id<MTLRenderCommandEncoder>)renderCommandEncoder
drawIndexedPrimitives:(MTLPrimitiveType)primitiveType
indexCount:(NSUInteger)indexCount
indexType:(MTLIndexType)indexType
indexBuffer:(id<MTLBuffer>)indexBuffer
indexBufferOffset:(NSUInteger)indexBufferOffset];
}
void BlitCommandEncoder_Synchronize(void *blitCommandEncoder, void *resource) {
#if !TARGET_OS_IPHONE
[(id<MTLBlitCommandEncoder>)blitCommandEncoder
synchronizeResource:(id<MTLResource>)resource];
#endif
}
void BlitCommandEncoder_SynchronizeTexture(void *blitCommandEncoder,
void *texture, uint_t slice,
uint_t level) {
#if !TARGET_OS_IPHONE
[(id<MTLBlitCommandEncoder>)blitCommandEncoder
synchronizeTexture:(id<MTLTexture>)texture
slice:(NSUInteger)slice
level:(NSUInteger)level];
#endif
}
void BlitCommandEncoder_CopyFromTexture(
void *blitCommandEncoder, void *sourceTexture, uint_t sourceSlice,
uint_t sourceLevel, struct Origin sourceOrigin, struct Size sourceSize,
void *destinationTexture, uint_t destinationSlice, uint_t destinationLevel,
struct Origin destinationOrigin) {
[(id<MTLBlitCommandEncoder>)blitCommandEncoder
copyFromTexture:(id<MTLTexture>)sourceTexture
sourceSlice:(NSUInteger)sourceSlice
sourceLevel:(NSUInteger)sourceLevel
sourceOrigin:(MTLOrigin){.x = sourceOrigin.X,
.y = sourceOrigin.Y,
.z = sourceOrigin.Z}
sourceSize:(MTLSize){.width = sourceSize.Width,
.height = sourceSize.Height,
.depth = sourceSize.Depth}
toTexture:(id<MTLTexture>)destinationTexture
destinationSlice:(NSUInteger)destinationSlice
destinationLevel:(NSUInteger)destinationLevel
destinationOrigin:(MTLOrigin){.x = destinationOrigin.X,
.y = destinationOrigin.Y,
.z = destinationOrigin.Z}];
}
void *Library_MakeFunction(void *library, const char *name) {
return [(id<MTLLibrary>)library
newFunctionWithName:[NSString stringWithUTF8String:name]];
}
void Texture_Release(void *texture) { [(id<MTLTexture>)texture release]; }
void Texture_GetBytes(void *texture, void *pixelBytes, size_t bytesPerRow,
struct Region region, uint_t level) {
[(id<MTLTexture>)texture getBytes:(void *)pixelBytes
bytesPerRow:(NSUInteger)bytesPerRow
fromRegion:(MTLRegion) {
.origin = {.x = region.Origin.X,
.y = region.Origin.Y,
.z = region.Origin.Z},
.size = {
.width = region.Size.Width,
.height = region.Size.Height,
.depth = region.Size.Depth
}
}
mipmapLevel:(NSUInteger)level];
}
void Texture_ReplaceRegion(void *texture, struct Region region, uint_t level,
void *bytes, uint_t bytesPerRow) {
[(id<MTLTexture>)texture replaceRegion:(MTLRegion) {
.origin = {.x = region.Origin.X,
.y = region.Origin.Y,
.z = region.Origin.Z},
.size = {
.width = region.Size.Width,
.height = region.Size.Height,
.depth = region.Size.Depth
}
}
mipmapLevel:(NSUInteger)level
withBytes:bytes
bytesPerRow:(NSUInteger)bytesPerRow];
}
int Texture_Width(void *texture) { return [(id<MTLTexture>)texture width]; }
int Texture_Height(void *texture) { return [(id<MTLTexture>)texture height]; }
size_t Buffer_Length(void *buffer) { return [(id<MTLBuffer>)buffer length]; }
void Buffer_CopyToContents(void *buffer, void *data, size_t lengthInBytes) {
memcpy(((id<MTLBuffer>)buffer).contents, data, lengthInBytes);
#if !TARGET_OS_IPHONE
[(id<MTLBuffer>)buffer didModifyRange:NSMakeRange(0, lengthInBytes)];
#endif
}
void Buffer_Retain(void *buffer) { [(id<MTLBuffer>)buffer retain]; }
void Buffer_Release(void *buffer) { [(id<MTLBuffer>)buffer release]; }
void Function_Release(void *function) { [(id<MTLFunction>)function release]; }
void RenderPipelineState_Release(void *renderPipelineState) {
[(id<MTLRenderPipelineState>)renderPipelineState release];
}
void DepthStencilState_Release(void *depthStencilState) {
[(id<MTLDepthStencilState>)depthStencilState release];
}