// 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. // +build darwin #include "mtl.h" #import #include struct Device CreateSystemDefaultDevice() { id device = MTLCreateSystemDefaultDevice(); if (!device) { struct Device d; d.Device = NULL; return d; } struct Device d; d.Device = device; d.Headless = device.headless; d.LowPower = device.lowPower; d.Removable = device.removable; d.RegistryID = device.registryID; d.Name = device.name.UTF8String; return d; } // Caller must call free(d.devices). struct Devices CopyAllDevices() { NSArray> *devices = MTLCopyAllDevices(); struct Devices d; d.Devices = malloc(devices.count * sizeof(struct Device)); for (int i = 0; i < devices.count; i++) { d.Devices[i].Device = devices[i]; d.Devices[i].Headless = devices[i].headless; d.Devices[i].LowPower = devices[i].lowPower; d.Devices[i].Removable = devices[i].removable; d.Devices[i].RegistryID = devices[i].registryID; d.Devices[i].Name = devices[i].name.UTF8String; } d.Length = devices.count; return d; } BOOL Device_SupportsFeatureSet(void *device, uint16_t featureSet) { return [(id)device supportsFeatureSet:featureSet]; } void *Device_MakeCommandQueue(void *device) { return [(id)device newCommandQueue]; } struct Library Device_MakeLibrary(void *device, const char *source, size_t sourceLength) { NSError *error; id library = [(id)device newLibraryWithSource:[[NSString alloc] initWithBytes:source length:sourceLength encoding:NSUTF8StringEncoding] options:NULL // TODO. 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; NSError *error; id renderPipelineState = [(id)device newRenderPipelineStateWithDescriptor:renderPipelineDescriptor error:&error]; [renderPipelineDescriptor release]; struct RenderPipelineState rps; rps.RenderPipelineState = renderPipelineState; if (!renderPipelineState) { rps.Error = error.localizedDescription.UTF8String; } return rps; } void *Device_MakeBuffer(void *device, const void *bytes, size_t length, uint16_t options) { return [(id)device newBufferWithBytes:(const void *)bytes length:(NSUInteger)length options:(MTLResourceOptions)options]; } void *Device_MakeTexture(void *device, struct TextureDescriptor descriptor) { MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init]; textureDescriptor.pixelFormat = descriptor.PixelFormat; textureDescriptor.width = descriptor.Width; textureDescriptor.height = descriptor.Height; textureDescriptor.storageMode = descriptor.StorageMode; textureDescriptor.usage = descriptor.Usage; id texture = [(id)device newTextureWithDescriptor:textureDescriptor]; [textureDescriptor release]; return texture; } void CommandQueue_Release(void *commandQueue) { [(id)commandQueue release]; } void *CommandQueue_MakeCommandBuffer(void *commandQueue) { return [(id)commandQueue commandBuffer]; } void CommandBuffer_PresentDrawable(void *commandBuffer, void *drawable) { [(id)commandBuffer presentDrawable:(id)drawable]; } void CommandBuffer_Commit(void *commandBuffer) { [(id)commandBuffer commit]; } void CommandBuffer_WaitUntilCompleted(void *commandBuffer) { [(id)commandBuffer waitUntilCompleted]; } 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)descriptor.ColorAttachment0Texture; id rce = [(id)commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; [renderPassDescriptor release]; return rce; } void *CommandBuffer_MakeBlitCommandEncoder(void *commandBuffer) { return [(id)commandBuffer blitCommandEncoder]; } void CommandEncoder_EndEncoding(void *commandEncoder) { [(id)commandEncoder endEncoding]; } void RenderCommandEncoder_Release(void *renderCommandEncoder) { [(id)renderCommandEncoder release]; } void RenderCommandEncoder_SetRenderPipelineState(void *renderCommandEncoder, void *renderPipelineState) { [(id)renderCommandEncoder setRenderPipelineState:(id)renderPipelineState]; } void RenderCommandEncoder_SetViewport(void *renderCommandEncoder, struct Viewport viewport) { [(id)renderCommandEncoder setViewport:(MTLViewport){ viewport.OriginX, viewport.OriginY, viewport.Width, viewport.Height, viewport.ZNear, viewport.ZFar, }]; } void RenderCommandEncoder_SetVertexBuffer(void *renderCommandEncoder, void *buffer, uint_t offset, uint_t index) { [(id)renderCommandEncoder setVertexBuffer:(id)buffer offset:(NSUInteger)offset atIndex:(NSUInteger)index]; } void RenderCommandEncoder_SetVertexBytes(void *renderCommandEncoder, const void *bytes, size_t length, uint_t index) { [(id)renderCommandEncoder setVertexBytes:bytes length:(NSUInteger)length atIndex:(NSUInteger)index]; } void RenderCommandEncoder_SetFragmentBytes(void *renderCommandEncoder, const void *bytes, size_t length, uint_t index) { [(id)renderCommandEncoder setFragmentBytes:bytes length:(NSUInteger)length atIndex:(NSUInteger)index]; } void RenderCommandEncoder_SetFragmentTexture(void *renderCommandEncoder, void *texture, uint_t index) { [(id)renderCommandEncoder setFragmentTexture:(id)texture atIndex:(NSUInteger)index]; } void RenderCommandEncoder_SetBlendColor(void *renderCommandEncoder, float red, float green, float blue, float alpha) { [(id)renderCommandEncoder setBlendColorRed:red green:green blue:blue alpha:alpha]; } void RenderCommandEncoder_DrawPrimitives(void *renderCommandEncoder, uint8_t primitiveType, uint_t vertexStart, uint_t vertexCount) { [(id)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)renderCommandEncoder drawIndexedPrimitives:(MTLPrimitiveType)primitiveType indexCount:(NSUInteger)indexCount indexType:(MTLIndexType)indexType indexBuffer:(id)indexBuffer indexBufferOffset:(NSUInteger)indexBufferOffset]; } void BlitCommandEncoder_Synchronize(void *blitCommandEncoder, void *resource) { [(id)blitCommandEncoder synchronizeResource:(id)resource]; } void BlitCommandEncoder_SynchronizeTexture(void *blitCommandEncoder, void *texture, uint_t slice, uint_t level) { [(id)blitCommandEncoder synchronizeTexture:(id)texture slice:(NSUInteger)slice level:(NSUInteger)level]; } void *Library_MakeFunction(void *library, const char *name) { return [(id)library newFunctionWithName:[NSString stringWithUTF8String:name]]; } void Texture_Release(void *texture) { [(id)texture release]; } void Texture_GetBytes(void *texture, void *pixelBytes, size_t bytesPerRow, struct Region region, uint_t level) { [(id)texture getBytes:(void *)pixelBytes bytesPerRow:(NSUInteger)bytesPerRow fromRegion:(MTLRegion) { {region.Origin.X, region.Origin.Y, region.Origin.Z}, { region.Size.Width, region.Size.Height, region.Size.Depth } } mipmapLevel:(NSUInteger)level]; } void Texture_ReplaceRegion(void *texture, struct Region region, uint_t level, void *bytes, uint_t bytesPerRow) { [(id)texture replaceRegion:(MTLRegion) { {region.Origin.X, region.Origin.Y, region.Origin.Z}, { region.Size.Width, region.Size.Height, region.Size.Depth } } mipmapLevel:(NSUInteger)level withBytes:bytes bytesPerRow:(NSUInteger)bytesPerRow]; } void Buffer_Release(void *buffer) { [(id)buffer release]; }