// 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; #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)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_MakeBufferWithBytes(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_MakeBufferWithLength(void *device, size_t length, uint16_t options) { return [(id)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 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){ .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)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)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) { #if !TARGET_OS_IPHONE [(id)blitCommandEncoder synchronizeResource:(id)resource]; #endif } void BlitCommandEncoder_SynchronizeTexture(void *blitCommandEncoder, void *texture, uint_t slice, uint_t level) { #if !TARGET_OS_IPHONE [(id)blitCommandEncoder synchronizeTexture:(id)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)blitCommandEncoder copyFromTexture:(id)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)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)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) { .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)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)texture width]; } int Texture_Height(void *texture) { return [(id)texture height]; } void Buffer_CopyToContents(void *buffer, void *data, size_t lengthInBytes) { memcpy(((id)buffer).contents, data, lengthInBytes); } void Buffer_Retain(void *buffer) { [(id)buffer retain]; } void Buffer_Release(void *buffer) { [(id)buffer release]; } void Function_Release(void *function) { [(id)function release]; } void RenderPipelineState_Release(void *renderPipelineState) { [(id)renderPipelineState release]; }