zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs

mtl.go (36674B)


      1 // Copyright 2018 The Ebiten Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // +build darwin
     16 
     17 // Package mtl provides access to Apple's Metal API (https://developer.apple.com/documentation/metal).
     18 //
     19 // Package mtl requires macOS version 10.13 or newer.
     20 //
     21 // This package is in very early stages of development.
     22 // The API will change when opportunities for improvement are discovered; it is not yet frozen.
     23 // Less than 20% of the Metal API surface is implemented.
     24 // Current functionality is sufficient to render very basic geometry.
     25 package mtl
     26 
     27 import (
     28 	"errors"
     29 	"fmt"
     30 	"unsafe"
     31 )
     32 
     33 // #cgo !ios CFLAGS: -mmacosx-version-min=10.12
     34 // #cgo LDFLAGS: -framework Metal -framework CoreGraphics -framework Foundation
     35 //
     36 // #include "mtl.h"
     37 // #include <stdlib.h>
     38 import "C"
     39 
     40 // FeatureSet defines a specific platform, hardware, and software configuration.
     41 //
     42 // Reference: https://developer.apple.com/documentation/metal/mtlfeatureset.
     43 type FeatureSet uint16
     44 
     45 // The device feature sets that define specific platform, hardware, and software configurations.
     46 const (
     47 	MacOSGPUFamily1V1          FeatureSet = 10000 // The GPU family 1, version 1 feature set for macOS.
     48 	MacOSGPUFamily1V2          FeatureSet = 10001 // The GPU family 1, version 2 feature set for macOS.
     49 	MacOSReadWriteTextureTier2 FeatureSet = 10002 // The read-write texture, tier 2 feature set for macOS.
     50 	MacOSGPUFamily1V3          FeatureSet = 10003 // The GPU family 1, version 3 feature set for macOS.
     51 	MacOSGPUFamily1V4          FeatureSet = 10004 // The GPU family 1, version 4 feature set for macOS.
     52 	MacOSGPUFamily2V1          FeatureSet = 10005 // The GPU family 2, version 1 feature set for macOS.
     53 )
     54 
     55 const (
     56 	FeatureSet_iOS_GPUFamily1_v1           FeatureSet = 0
     57 	FeatureSet_iOS_GPUFamily1_v2           FeatureSet = 2
     58 	FeatureSet_iOS_GPUFamily1_v3           FeatureSet = 5
     59 	FeatureSet_iOS_GPUFamily1_v4           FeatureSet = 8
     60 	FeatureSet_iOS_GPUFamily1_v5           FeatureSet = 12
     61 	FeatureSet_iOS_GPUFamily2_v1           FeatureSet = 1
     62 	FeatureSet_iOS_GPUFamily2_v2           FeatureSet = 3
     63 	FeatureSet_iOS_GPUFamily2_v3           FeatureSet = 6
     64 	FeatureSet_iOS_GPUFamily2_v4           FeatureSet = 9
     65 	FeatureSet_iOS_GPUFamily2_v5           FeatureSet = 13
     66 	FeatureSet_iOS_GPUFamily3_v1           FeatureSet = 4
     67 	FeatureSet_iOS_GPUFamily3_v2           FeatureSet = 7
     68 	FeatureSet_iOS_GPUFamily3_v3           FeatureSet = 10
     69 	FeatureSet_iOS_GPUFamily3_v4           FeatureSet = 14
     70 	FeatureSet_iOS_GPUFamily4_v1           FeatureSet = 11
     71 	FeatureSet_iOS_GPUFamily4_v2           FeatureSet = 15
     72 	FeatureSet_iOS_GPUFamily5_v1           FeatureSet = 16
     73 	FeatureSet_tvOS_GPUFamily1_v1          FeatureSet = 30000
     74 	FeatureSet_tvOS_GPUFamily1_v2          FeatureSet = 30001
     75 	FeatureSet_tvOS_GPUFamily1_v3          FeatureSet = 30002
     76 	FeatureSet_tvOS_GPUFamily1_v4          FeatureSet = 30004
     77 	FeatureSet_tvOS_GPUFamily2_v1          FeatureSet = 30003
     78 	FeatureSet_tvOS_GPUFamily2_v2          FeatureSet = 30005
     79 	FeatureSet_macOS_GPUFamily1_v1         FeatureSet = 10000
     80 	FeatureSet_macOS_GPUFamily1_v2         FeatureSet = 10001
     81 	FeatureSet_macOS_GPUFamily1_v3         FeatureSet = 10003
     82 	FeatureSet_macOS_GPUFamily1_v4         FeatureSet = 10004
     83 	FeatureSet_macOS_GPUFamily2_v1         FeatureSet = 10005
     84 	FeatureSet_macOS_ReadWriteTextureTier2 FeatureSet = 10002
     85 )
     86 
     87 // TextureType defines The dimension of each image, including whether multiple images are arranged into an array or
     88 // a cube.
     89 //
     90 // Reference: https://developer.apple.com/documentation/metal/mtltexturetype
     91 type TextureType uint16
     92 
     93 const (
     94 	TextureType2D TextureType = 2
     95 )
     96 
     97 // PixelFormat defines data formats that describe the organization
     98 // and characteristics of individual pixels in a texture.
     99 //
    100 // Reference: https://developer.apple.com/documentation/metal/mtlpixelformat.
    101 type PixelFormat uint16
    102 
    103 // The data formats that describe the organization and characteristics
    104 // of individual pixels in a texture.
    105 const (
    106 	PixelFormatRGBA8UNorm     PixelFormat = 70 // Ordinary format with four 8-bit normalized unsigned integer components in RGBA order.
    107 	PixelFormatRGBA8UNormSRGB PixelFormat = 71 // Ordinary format with four 8-bit normalized unsigned integer components in RGBA order with conversion between sRGB and linear space.
    108 	PixelFormatBGRA8UNorm     PixelFormat = 80 // Ordinary format with four 8-bit normalized unsigned integer components in BGRA order.
    109 	PixelFormatBGRA8UNormSRGB PixelFormat = 81 // Ordinary format with four 8-bit normalized unsigned integer components in BGRA order with conversion between sRGB and linear space.
    110 )
    111 
    112 // PrimitiveType defines geometric primitive types for drawing commands.
    113 //
    114 // Reference: https://developer.apple.com/documentation/metal/mtlprimitivetype.
    115 type PrimitiveType uint8
    116 
    117 // Geometric primitive types for drawing commands.
    118 const (
    119 	PrimitiveTypePoint         PrimitiveType = 0
    120 	PrimitiveTypeLine          PrimitiveType = 1
    121 	PrimitiveTypeLineStrip     PrimitiveType = 2
    122 	PrimitiveTypeTriangle      PrimitiveType = 3
    123 	PrimitiveTypeTriangleStrip PrimitiveType = 4
    124 )
    125 
    126 // LoadAction defines actions performed at the start of a rendering pass
    127 // for a render command encoder.
    128 //
    129 // Reference: https://developer.apple.com/documentation/metal/mtlloadaction.
    130 type LoadAction uint8
    131 
    132 // Actions performed at the start of a rendering pass for a render command encoder.
    133 const (
    134 	LoadActionDontCare LoadAction = 0
    135 	LoadActionLoad     LoadAction = 1
    136 	LoadActionClear    LoadAction = 2
    137 )
    138 
    139 // StoreAction defines actions performed at the end of a rendering pass
    140 // for a render command encoder.
    141 //
    142 // Reference: https://developer.apple.com/documentation/metal/mtlstoreaction.
    143 type StoreAction uint8
    144 
    145 // Actions performed at the end of a rendering pass for a render command encoder.
    146 const (
    147 	StoreActionDontCare                   StoreAction = 0
    148 	StoreActionStore                      StoreAction = 1
    149 	StoreActionMultisampleResolve         StoreAction = 2
    150 	StoreActionStoreAndMultisampleResolve StoreAction = 3
    151 	StoreActionUnknown                    StoreAction = 4
    152 	StoreActionCustomSampleDepthStore     StoreAction = 5
    153 )
    154 
    155 // StorageMode defines defines the memory location and access permissions of a resource.
    156 //
    157 // Reference: https://developer.apple.com/documentation/metal/mtlstoragemode.
    158 type StorageMode uint8
    159 
    160 const (
    161 	// StorageModeShared indicates that the resource is stored in system memory
    162 	// accessible to both the CPU and the GPU.
    163 	StorageModeShared StorageMode = 0
    164 
    165 	// StorageModeManaged indicates that the resource exists as a synchronized
    166 	// memory pair with one copy stored in system memory accessible to the CPU
    167 	// and another copy stored in video memory accessible to the GPU.
    168 	StorageModeManaged StorageMode = 1
    169 
    170 	// StorageModePrivate indicates that the resource is stored in memory
    171 	// only accessible to the GPU. In iOS and tvOS, the resource is stored in
    172 	// system memory. In macOS, the resource is stored in video memory.
    173 	StorageModePrivate StorageMode = 2
    174 
    175 	// StorageModeMemoryless indicates that the resource is stored in on-tile memory,
    176 	// without CPU or GPU memory backing. The contents of the on-tile memory are undefined
    177 	// and do not persist; the only way to populate the resource is to render into it.
    178 	// Memoryless resources are limited to temporary render targets (i.e., Textures configured
    179 	// with a TextureDescriptor and used with a RenderPassAttachmentDescriptor).
    180 	StorageModeMemoryless StorageMode = 3
    181 )
    182 
    183 // ResourceOptions defines optional arguments used to create
    184 // and influence behavior of buffer and texture objects.
    185 //
    186 // Reference: https://developer.apple.com/documentation/metal/mtlresourceoptions.
    187 type ResourceOptions uint16
    188 
    189 const (
    190 	// ResourceCPUCacheModeDefaultCache is the default CPU cache mode for the resource.
    191 	// Guarantees that read and write operations are executed in the expected order.
    192 	ResourceCPUCacheModeDefaultCache ResourceOptions = ResourceOptions(CPUCacheModeDefaultCache) << resourceCPUCacheModeShift
    193 
    194 	// ResourceCPUCacheModeWriteCombined is a write-combined CPU cache mode for the resource.
    195 	// Optimized for resources that the CPU will write into, but never read.
    196 	ResourceCPUCacheModeWriteCombined ResourceOptions = ResourceOptions(CPUCacheModeWriteCombined) << resourceCPUCacheModeShift
    197 
    198 	// ResourceStorageModeShared indicates that the resource is stored in system memory
    199 	// accessible to both the CPU and the GPU.
    200 	ResourceStorageModeShared ResourceOptions = ResourceOptions(StorageModeShared) << resourceStorageModeShift
    201 
    202 	// ResourceStorageModeManaged indicates that the resource exists as a synchronized
    203 	// memory pair with one copy stored in system memory accessible to the CPU
    204 	// and another copy stored in video memory accessible to the GPU.
    205 	ResourceStorageModeManaged ResourceOptions = ResourceOptions(StorageModeManaged) << resourceStorageModeShift
    206 
    207 	// ResourceStorageModePrivate indicates that the resource is stored in memory
    208 	// only accessible to the GPU. In iOS and tvOS, the resource is stored
    209 	// in system memory. In macOS, the resource is stored in video memory.
    210 	ResourceStorageModePrivate ResourceOptions = ResourceOptions(StorageModePrivate) << resourceStorageModeShift
    211 
    212 	// ResourceStorageModeMemoryless indicates that the resource is stored in on-tile memory,
    213 	// without CPU or GPU memory backing. The contents of the on-tile memory are undefined
    214 	// and do not persist; the only way to populate the resource is to render into it.
    215 	// Memoryless resources are limited to temporary render targets (i.e., Textures configured
    216 	// with a TextureDescriptor and used with a RenderPassAttachmentDescriptor).
    217 	ResourceStorageModeMemoryless ResourceOptions = ResourceOptions(StorageModeMemoryless) << resourceStorageModeShift
    218 
    219 	// ResourceHazardTrackingModeUntracked indicates that the command encoder dependencies
    220 	// for this resource are tracked manually with Fence objects. This value is always set
    221 	// for resources sub-allocated from a Heap object and may optionally be specified for
    222 	// non-heap resources.
    223 	ResourceHazardTrackingModeUntracked ResourceOptions = 1 << resourceHazardTrackingModeShift
    224 )
    225 
    226 const (
    227 	resourceCPUCacheModeShift       = 0
    228 	resourceStorageModeShift        = 4
    229 	resourceHazardTrackingModeShift = 8
    230 )
    231 
    232 // CPUCacheMode is the CPU cache mode that defines the CPU mapping of a resource.
    233 //
    234 // Reference: https://developer.apple.com/documentation/metal/mtlcpucachemode.
    235 type CPUCacheMode uint8
    236 
    237 const (
    238 	// CPUCacheModeDefaultCache is the default CPU cache mode for the resource.
    239 	// Guarantees that read and write operations are executed in the expected order.
    240 	CPUCacheModeDefaultCache CPUCacheMode = 0
    241 
    242 	// CPUCacheModeWriteCombined is a write-combined CPU cache mode for the resource.
    243 	// Optimized for resources that the CPU will write into, but never read.
    244 	CPUCacheModeWriteCombined CPUCacheMode = 1
    245 )
    246 
    247 // IndexType is the index type for an index buffer that references vertices of geometric primitives.
    248 //
    249 // Reference: https://developer.apple.com/documentation/metal/mtlstoragemode
    250 type IndexType uint8
    251 
    252 const (
    253 	// IndexTypeUInt16 is a 16-bit unsigned integer used as a primitive index.
    254 	IndexTypeUInt16 IndexType = 0
    255 
    256 	// IndexTypeUInt32 is a 32-bit unsigned integer used as a primitive index.
    257 	IndexTypeUInt32 IndexType = 1
    258 )
    259 
    260 type TextureUsage uint8
    261 
    262 const (
    263 	TextureUsageUnknown         TextureUsage = 0x0000
    264 	TextureUsageShaderRead      TextureUsage = 0x0001
    265 	TextureUsageShaderWrite     TextureUsage = 0x0002
    266 	TextureUsageRenderTarget    TextureUsage = 0x0004
    267 	TextureUsagePixelFormatView TextureUsage = 0x0008
    268 )
    269 
    270 type BlendFactor uint8
    271 
    272 const (
    273 	BlendFactorZero                     BlendFactor = 0
    274 	BlendFactorOne                      BlendFactor = 1
    275 	BlendFactorSourceColor              BlendFactor = 2
    276 	BlendFactorOneMinusSourceColor      BlendFactor = 3
    277 	BlendFactorSourceAlpha              BlendFactor = 4
    278 	BlendFactorOneMinusSourceAlpha      BlendFactor = 5
    279 	BlendFactorDestinationColor         BlendFactor = 6
    280 	BlendFactorOneMinusDestinationColor BlendFactor = 7
    281 	BlendFactorDestinationAlpha         BlendFactor = 8
    282 	BlendFactorOneMinusDestinationAlpha BlendFactor = 9
    283 	BlendFactorSourceAlphaSaturated     BlendFactor = 10
    284 	BlendFactorBlendColor               BlendFactor = 11
    285 	BlendFactorOneMinusBlendColor       BlendFactor = 12
    286 	BlendFactorBlendAlpha               BlendFactor = 13
    287 	BlendFactorOneMinusBlendAlpha       BlendFactor = 14
    288 	BlendFactorSource1Color             BlendFactor = 15
    289 	BlendFactorOneMinusSource1Color     BlendFactor = 16
    290 	BlendFactorSource1Alpha             BlendFactor = 17
    291 	BlendFactorOneMinusSource1Alpha     BlendFactor = 18
    292 )
    293 
    294 // Resource represents a memory allocation for storing specialized data
    295 // that is accessible to the GPU.
    296 //
    297 // Reference: https://developer.apple.com/documentation/metal/mtlresource.
    298 type Resource interface {
    299 	// resource returns the underlying id<MTLResource> pointer.
    300 	resource() unsafe.Pointer
    301 }
    302 
    303 // RenderPipelineDescriptor configures new RenderPipelineState objects.
    304 //
    305 // Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinedescriptor.
    306 type RenderPipelineDescriptor struct {
    307 	// VertexFunction is a programmable function that processes individual vertices in a rendering pass.
    308 	VertexFunction Function
    309 
    310 	// FragmentFunction is a programmable function that processes individual fragments in a rendering pass.
    311 	FragmentFunction Function
    312 
    313 	// ColorAttachments is an array of attachments that store color data.
    314 	ColorAttachments [1]RenderPipelineColorAttachmentDescriptor
    315 }
    316 
    317 // RenderPipelineColorAttachmentDescriptor describes a color render target that specifies
    318 // the color configuration and color operations associated with a render pipeline.
    319 //
    320 // Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinecolorattachmentdescriptor.
    321 type RenderPipelineColorAttachmentDescriptor struct {
    322 	// PixelFormat is the pixel format of the color attachment's texture.
    323 	PixelFormat PixelFormat
    324 
    325 	BlendingEnabled bool
    326 
    327 	DestinationAlphaBlendFactor BlendFactor
    328 	DestinationRGBBlendFactor   BlendFactor
    329 	SourceAlphaBlendFactor      BlendFactor
    330 	SourceRGBBlendFactor        BlendFactor
    331 }
    332 
    333 // RenderPassDescriptor describes a group of render targets that serve as
    334 // the output destination for pixels generated by a render pass.
    335 //
    336 // Reference: https://developer.apple.com/documentation/metal/mtlrenderpassdescriptor.
    337 type RenderPassDescriptor struct {
    338 	// ColorAttachments is array of state information for attachments that store color data.
    339 	ColorAttachments [1]RenderPassColorAttachmentDescriptor
    340 }
    341 
    342 // RenderPassColorAttachmentDescriptor describes a color render target that serves
    343 // as the output destination for color pixels generated by a render pass.
    344 //
    345 // Reference: https://developer.apple.com/documentation/metal/mtlrenderpasscolorattachmentdescriptor.
    346 type RenderPassColorAttachmentDescriptor struct {
    347 	RenderPassAttachmentDescriptor
    348 	ClearColor ClearColor
    349 }
    350 
    351 // RenderPassAttachmentDescriptor describes a render target that serves
    352 // as the output destination for pixels generated by a render pass.
    353 //
    354 // Reference: https://developer.apple.com/documentation/metal/mtlrenderpassattachmentdescriptor.
    355 type RenderPassAttachmentDescriptor struct {
    356 	LoadAction  LoadAction
    357 	StoreAction StoreAction
    358 	Texture     Texture
    359 }
    360 
    361 // ClearColor is an RGBA value used for a color pixel.
    362 //
    363 // Reference: https://developer.apple.com/documentation/metal/mtlclearcolor.
    364 type ClearColor struct {
    365 	Red, Green, Blue, Alpha float64
    366 }
    367 
    368 // TextureDescriptor configures new Texture objects.
    369 //
    370 // Reference: https://developer.apple.com/documentation/metal/mtltexturedescriptor.
    371 type TextureDescriptor struct {
    372 	TextureType TextureType
    373 	PixelFormat PixelFormat
    374 	Width       int
    375 	Height      int
    376 	StorageMode StorageMode
    377 	Usage       TextureUsage
    378 }
    379 
    380 // Device is abstract representation of the GPU that
    381 // serves as the primary interface for a Metal app.
    382 //
    383 // Reference: https://developer.apple.com/documentation/metal/mtldevice.
    384 type Device struct {
    385 	device unsafe.Pointer
    386 
    387 	// Headless indicates whether a device is configured as headless.
    388 	Headless bool
    389 
    390 	// LowPower indicates whether a device is low-power.
    391 	LowPower bool
    392 
    393 	// Name is the name of the device.
    394 	Name string
    395 }
    396 
    397 // CreateSystemDefaultDevice returns the preferred system default Metal device.
    398 //
    399 // Reference: https://developer.apple.com/documentation/metal/1433401-mtlcreatesystemdefaultdevice.
    400 func CreateSystemDefaultDevice() (Device, error) {
    401 	d := C.CreateSystemDefaultDevice()
    402 	if d.Device == nil {
    403 		return Device{}, errors.New("Metal is not supported on this system")
    404 	}
    405 
    406 	return Device{
    407 		device:   d.Device,
    408 		Headless: d.Headless != 0,
    409 		LowPower: d.LowPower != 0,
    410 		Name:     C.GoString(d.Name),
    411 	}, nil
    412 }
    413 
    414 // Device returns the underlying id<MTLDevice> pointer.
    415 func (d Device) Device() unsafe.Pointer { return d.device }
    416 
    417 // SupportsFeatureSet reports whether device d supports feature set fs.
    418 //
    419 // Reference: https://developer.apple.com/documentation/metal/mtldevice/1433418-supportsfeatureset.
    420 func (d Device) SupportsFeatureSet(fs FeatureSet) bool {
    421 	return C.Device_SupportsFeatureSet(d.device, C.uint16_t(fs)) != 0
    422 }
    423 
    424 // MakeCommandQueue creates a serial command submission queue.
    425 //
    426 // Reference: https://developer.apple.com/documentation/metal/mtldevice/1433388-makecommandqueue.
    427 func (d Device) MakeCommandQueue() CommandQueue {
    428 	return CommandQueue{C.Device_MakeCommandQueue(d.device)}
    429 }
    430 
    431 // MakeLibrary creates a new library that contains
    432 // the functions stored in the specified source string.
    433 //
    434 // Reference: https://developer.apple.com/documentation/metal/mtldevice/1433431-makelibrary.
    435 func (d Device) MakeLibrary(source string, opt CompileOptions) (Library, error) {
    436 	cs := C.CString(source)
    437 	defer C.free(unsafe.Pointer(cs))
    438 
    439 	l := C.Device_MakeLibrary(d.device, cs, C.size_t(len(source)))
    440 	if l.Library == nil {
    441 		return Library{}, errors.New(C.GoString(l.Error))
    442 	}
    443 
    444 	return Library{l.Library}, nil
    445 }
    446 
    447 // MakeRenderPipelineState creates a render pipeline state object.
    448 //
    449 // Reference: https://developer.apple.com/documentation/metal/mtldevice/1433369-makerenderpipelinestate.
    450 func (d Device) MakeRenderPipelineState(rpd RenderPipelineDescriptor) (RenderPipelineState, error) {
    451 	blendingEnabled := 0
    452 	if rpd.ColorAttachments[0].BlendingEnabled {
    453 		blendingEnabled = 1
    454 	}
    455 	c := &rpd.ColorAttachments[0]
    456 	descriptor := C.struct_RenderPipelineDescriptor{
    457 		VertexFunction:                              rpd.VertexFunction.function,
    458 		FragmentFunction:                            rpd.FragmentFunction.function,
    459 		ColorAttachment0PixelFormat:                 C.uint16_t(c.PixelFormat),
    460 		ColorAttachment0BlendingEnabled:             C.uint8_t(blendingEnabled),
    461 		ColorAttachment0DestinationAlphaBlendFactor: C.uint8_t(c.DestinationAlphaBlendFactor),
    462 		ColorAttachment0DestinationRGBBlendFactor:   C.uint8_t(c.DestinationRGBBlendFactor),
    463 		ColorAttachment0SourceAlphaBlendFactor:      C.uint8_t(c.SourceAlphaBlendFactor),
    464 		ColorAttachment0SourceRGBBlendFactor:        C.uint8_t(c.SourceRGBBlendFactor),
    465 	}
    466 	rps := C.Device_MakeRenderPipelineState(d.device, descriptor)
    467 	if rps.RenderPipelineState == nil {
    468 		return RenderPipelineState{}, errors.New(C.GoString(rps.Error))
    469 	}
    470 
    471 	return RenderPipelineState{rps.RenderPipelineState}, nil
    472 }
    473 
    474 // MakeBufferWithBytes allocates a new buffer of a given length
    475 // and initializes its contents by copying existing data into it.
    476 //
    477 // Reference: https://developer.apple.com/documentation/metal/mtldevice/1433429-makebuffer.
    478 func (d Device) MakeBufferWithBytes(bytes unsafe.Pointer, length uintptr, opt ResourceOptions) Buffer {
    479 	return Buffer{C.Device_MakeBufferWithBytes(d.device, bytes, C.size_t(length), C.uint16_t(opt))}
    480 }
    481 
    482 // MakeBufferWithLength allocates a new zero-filled buffer of a given length.
    483 //
    484 // Reference: https://developer.apple.com/documentation/metal/mtldevice/1433375-newbufferwithlength
    485 func (d Device) MakeBufferWithLength(length uintptr, opt ResourceOptions) Buffer {
    486 	return Buffer{C.Device_MakeBufferWithLength(d.device, C.size_t(length), C.uint16_t(opt))}
    487 }
    488 
    489 // MakeTexture creates a texture object with privately owned storage
    490 // that contains texture state.
    491 //
    492 // Reference: https://developer.apple.com/documentation/metal/mtldevice/1433425-maketexture.
    493 func (d Device) MakeTexture(td TextureDescriptor) Texture {
    494 	descriptor := C.struct_TextureDescriptor{
    495 		TextureType: C.uint16_t(td.TextureType),
    496 		PixelFormat: C.uint16_t(td.PixelFormat),
    497 		Width:       C.uint_t(td.Width),
    498 		Height:      C.uint_t(td.Height),
    499 		StorageMode: C.uint8_t(td.StorageMode),
    500 		Usage:       C.uint8_t(td.Usage),
    501 	}
    502 	return Texture{
    503 		texture: C.Device_MakeTexture(d.device, descriptor),
    504 	}
    505 }
    506 
    507 // CompileOptions specifies optional compilation settings for
    508 // the graphics or compute functions within a library.
    509 //
    510 // Reference: https://developer.apple.com/documentation/metal/mtlcompileoptions.
    511 type CompileOptions struct {
    512 	// TODO.
    513 }
    514 
    515 // Drawable is a displayable resource that can be rendered or written to.
    516 //
    517 // Reference: https://developer.apple.com/documentation/metal/mtldrawable.
    518 type Drawable interface {
    519 	// Drawable returns the underlying id<MTLDrawable> pointer.
    520 	Drawable() unsafe.Pointer
    521 }
    522 
    523 // CommandQueue is a queue that organizes the order
    524 // in which command buffers are executed by the GPU.
    525 //
    526 // Reference: https://developer.apple.com/documentation/metal/mtlcommandqueue.
    527 type CommandQueue struct {
    528 	commandQueue unsafe.Pointer
    529 }
    530 
    531 func (c CommandQueue) Release() {
    532 	C.CommandQueue_Release(c.commandQueue)
    533 }
    534 
    535 // MakeCommandBuffer creates a command buffer.
    536 //
    537 // Reference: https://developer.apple.com/documentation/metal/mtlcommandqueue/1508686-makecommandbuffer.
    538 func (cq CommandQueue) MakeCommandBuffer() CommandBuffer {
    539 	return CommandBuffer{C.CommandQueue_MakeCommandBuffer(cq.commandQueue)}
    540 }
    541 
    542 // CommandBuffer is a container that stores encoded commands
    543 // that are committed to and executed by the GPU.
    544 //
    545 // Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer.
    546 type CommandBuffer struct {
    547 	commandBuffer unsafe.Pointer
    548 }
    549 
    550 // PresentDrawable registers a drawable presentation to occur as soon as possible.
    551 //
    552 // Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443029-presentdrawable.
    553 func (cb CommandBuffer) PresentDrawable(d Drawable) {
    554 	C.CommandBuffer_PresentDrawable(cb.commandBuffer, d.Drawable())
    555 }
    556 
    557 // Commit commits this command buffer for execution as soon as possible.
    558 //
    559 // Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443003-commit.
    560 func (cb CommandBuffer) Commit() {
    561 	C.CommandBuffer_Commit(cb.commandBuffer)
    562 }
    563 
    564 // WaitUntilCompleted waits for the execution of this command buffer to complete.
    565 //
    566 // Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443039-waituntilcompleted.
    567 func (cb CommandBuffer) WaitUntilCompleted() {
    568 	C.CommandBuffer_WaitUntilCompleted(cb.commandBuffer)
    569 }
    570 
    571 // MakeRenderCommandEncoder creates an encoder object that can
    572 // encode graphics rendering commands into this command buffer.
    573 //
    574 // Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1442999-makerendercommandencoder.
    575 func (cb CommandBuffer) MakeRenderCommandEncoder(rpd RenderPassDescriptor) RenderCommandEncoder {
    576 	descriptor := C.struct_RenderPassDescriptor{
    577 		ColorAttachment0LoadAction:  C.uint8_t(rpd.ColorAttachments[0].LoadAction),
    578 		ColorAttachment0StoreAction: C.uint8_t(rpd.ColorAttachments[0].StoreAction),
    579 		ColorAttachment0ClearColor: C.struct_ClearColor{
    580 			Red:   C.double(rpd.ColorAttachments[0].ClearColor.Red),
    581 			Green: C.double(rpd.ColorAttachments[0].ClearColor.Green),
    582 			Blue:  C.double(rpd.ColorAttachments[0].ClearColor.Blue),
    583 			Alpha: C.double(rpd.ColorAttachments[0].ClearColor.Alpha),
    584 		},
    585 		ColorAttachment0Texture: rpd.ColorAttachments[0].Texture.texture,
    586 	}
    587 	return RenderCommandEncoder{CommandEncoder{C.CommandBuffer_MakeRenderCommandEncoder(cb.commandBuffer, descriptor)}}
    588 }
    589 
    590 // MakeBlitCommandEncoder creates an encoder object that can encode
    591 // memory operation (blit) commands into this command buffer.
    592 //
    593 // Reference: https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443001-makeblitcommandencoder.
    594 func (cb CommandBuffer) MakeBlitCommandEncoder() BlitCommandEncoder {
    595 	return BlitCommandEncoder{CommandEncoder{C.CommandBuffer_MakeBlitCommandEncoder(cb.commandBuffer)}}
    596 }
    597 
    598 // CommandEncoder is an encoder that writes sequential GPU commands
    599 // into a command buffer.
    600 //
    601 // Reference: https://developer.apple.com/documentation/metal/mtlcommandencoder.
    602 type CommandEncoder struct {
    603 	commandEncoder unsafe.Pointer
    604 }
    605 
    606 // EndEncoding declares that all command generation from this encoder is completed.
    607 //
    608 // Reference: https://developer.apple.com/documentation/metal/mtlcommandencoder/1458038-endencoding.
    609 func (ce CommandEncoder) EndEncoding() {
    610 	C.CommandEncoder_EndEncoding(ce.commandEncoder)
    611 }
    612 
    613 // RenderCommandEncoder is an encoder that specifies graphics-rendering commands
    614 // and executes graphics functions.
    615 //
    616 // Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder.
    617 type RenderCommandEncoder struct {
    618 	CommandEncoder
    619 }
    620 
    621 func (rce RenderCommandEncoder) Release() {
    622 	C.RenderCommandEncoder_Release(rce.commandEncoder)
    623 }
    624 
    625 // SetRenderPipelineState sets the current render pipeline state object.
    626 //
    627 // Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515811-setrenderpipelinestate.
    628 func (rce RenderCommandEncoder) SetRenderPipelineState(rps RenderPipelineState) {
    629 	C.RenderCommandEncoder_SetRenderPipelineState(rce.commandEncoder, rps.renderPipelineState)
    630 }
    631 
    632 func (rce RenderCommandEncoder) SetViewport(viewport Viewport) {
    633 	C.RenderCommandEncoder_SetViewport(rce.commandEncoder, viewport.c())
    634 }
    635 
    636 // SetScissorRect sets the scissor rectangle for a fragment scissor test.
    637 //
    638 // Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515583-setscissorrect
    639 func (rce RenderCommandEncoder) SetScissorRect(scissorRect ScissorRect) {
    640 	C.RenderCommandEncoder_SetScissorRect(rce.commandEncoder, scissorRect.c())
    641 }
    642 
    643 // SetVertexBuffer sets a buffer for the vertex shader function at an index
    644 // in the buffer argument table with an offset that specifies the start of the data.
    645 //
    646 // Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515829-setvertexbuffer.
    647 func (rce RenderCommandEncoder) SetVertexBuffer(buf Buffer, offset, index int) {
    648 	C.RenderCommandEncoder_SetVertexBuffer(rce.commandEncoder, buf.buffer, C.uint_t(offset), C.uint_t(index))
    649 }
    650 
    651 // SetVertexBytes sets a block of data for the vertex function.
    652 //
    653 // Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515846-setvertexbytes.
    654 func (rce RenderCommandEncoder) SetVertexBytes(bytes unsafe.Pointer, length uintptr, index int) {
    655 	C.RenderCommandEncoder_SetVertexBytes(rce.commandEncoder, bytes, C.size_t(length), C.uint_t(index))
    656 }
    657 
    658 func (rce RenderCommandEncoder) SetFragmentBytes(bytes unsafe.Pointer, length uintptr, index int) {
    659 	C.RenderCommandEncoder_SetFragmentBytes(rce.commandEncoder, bytes, C.size_t(length), C.uint_t(index))
    660 }
    661 
    662 // SetFragmentTexture sets a texture for the fragment function at an index in the texture argument table.
    663 //
    664 // Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515390-setfragmenttexture
    665 func (rce RenderCommandEncoder) SetFragmentTexture(texture Texture, index int) {
    666 	C.RenderCommandEncoder_SetFragmentTexture(rce.commandEncoder, texture.texture, C.uint_t(index))
    667 }
    668 
    669 func (rce RenderCommandEncoder) SetBlendColor(red, green, blue, alpha float32) {
    670 	C.RenderCommandEncoder_SetBlendColor(rce.commandEncoder, C.float(red), C.float(green), C.float(blue), C.float(alpha))
    671 }
    672 
    673 // DrawPrimitives renders one instance of primitives using vertex data
    674 // in contiguous array elements.
    675 //
    676 // Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1516326-drawprimitives.
    677 func (rce RenderCommandEncoder) DrawPrimitives(typ PrimitiveType, vertexStart, vertexCount int) {
    678 	C.RenderCommandEncoder_DrawPrimitives(rce.commandEncoder, C.uint8_t(typ), C.uint_t(vertexStart), C.uint_t(vertexCount))
    679 }
    680 
    681 // DrawIndexedPrimitives encodes a command to render one instance of primitives using an index list specified in a buffer.
    682 //
    683 // Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515542-drawindexedprimitives
    684 func (rce RenderCommandEncoder) DrawIndexedPrimitives(typ PrimitiveType, indexCount int, indexType IndexType, indexBuffer Buffer, indexBufferOffset int) {
    685 	C.RenderCommandEncoder_DrawIndexedPrimitives(rce.commandEncoder, C.uint8_t(typ), C.uint_t(indexCount), C.uint8_t(indexType), indexBuffer.buffer, C.uint_t(indexBufferOffset))
    686 }
    687 
    688 // BlitCommandEncoder is an encoder that specifies resource copy
    689 // and resource synchronization commands.
    690 //
    691 // Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder.
    692 type BlitCommandEncoder struct {
    693 	CommandEncoder
    694 }
    695 
    696 // Synchronize flushes any copy of the specified resource from its corresponding
    697 // Device caches and, if needed, invalidates any CPU caches.
    698 //
    699 // Reference: https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400775-synchronize.
    700 func (bce BlitCommandEncoder) Synchronize(resource Resource) {
    701 	C.BlitCommandEncoder_Synchronize(bce.commandEncoder, resource.resource())
    702 }
    703 
    704 func (bce BlitCommandEncoder) SynchronizeTexture(texture Texture, slice int, level int) {
    705 	C.BlitCommandEncoder_SynchronizeTexture(bce.commandEncoder, texture.texture, C.uint_t(slice), C.uint_t(level))
    706 }
    707 
    708 func (bce BlitCommandEncoder) CopyFromTexture(sourceTexture Texture, sourceSlice int, sourceLevel int, sourceOrigin Origin, sourceSize Size, destinationTexture Texture, destinationSlice int, destinationLevel int, destinationOrigin Origin) {
    709 	C.BlitCommandEncoder_CopyFromTexture(bce.commandEncoder, sourceTexture.texture, C.uint_t(sourceSlice), C.uint_t(sourceLevel), sourceOrigin.c(), sourceSize.c(), destinationTexture.texture, C.uint_t(destinationSlice), C.uint_t(destinationLevel), destinationOrigin.c())
    710 }
    711 
    712 // Library is a collection of compiled graphics or compute functions.
    713 //
    714 // Reference: https://developer.apple.com/documentation/metal/mtllibrary.
    715 type Library struct {
    716 	library unsafe.Pointer
    717 }
    718 
    719 // MakeFunction returns a pre-compiled, non-specialized function.
    720 //
    721 // Reference: https://developer.apple.com/documentation/metal/mtllibrary/1515524-makefunction.
    722 func (l Library) MakeFunction(name string) (Function, error) {
    723 	f := C.Library_MakeFunction(l.library, C.CString(name))
    724 	if f == nil {
    725 		return Function{}, fmt.Errorf("function %q not found", name)
    726 	}
    727 
    728 	return Function{f}, nil
    729 }
    730 
    731 // Texture is a memory allocation for storing formatted
    732 // image data that is accessible to the GPU.
    733 //
    734 // Reference: https://developer.apple.com/documentation/metal/mtltexture.
    735 type Texture struct {
    736 	texture unsafe.Pointer
    737 }
    738 
    739 // NewTexture returns a Texture that wraps an existing id<MTLTexture> pointer.
    740 func NewTexture(texture unsafe.Pointer) Texture {
    741 	return Texture{texture: texture}
    742 }
    743 
    744 // resource implements the Resource interface.
    745 func (t Texture) resource() unsafe.Pointer { return t.texture }
    746 
    747 func (t Texture) Release() {
    748 	C.Texture_Release(t.texture)
    749 }
    750 
    751 // GetBytes copies a block of pixels from the storage allocation of texture
    752 // slice zero into system memory at a specified address.
    753 //
    754 // Reference: https://developer.apple.com/documentation/metal/mtltexture/1515751-getbytes.
    755 func (t Texture) GetBytes(pixelBytes *byte, bytesPerRow uintptr, region Region, level int) {
    756 	r := region.c()
    757 	C.Texture_GetBytes(t.texture, unsafe.Pointer(pixelBytes), C.size_t(bytesPerRow), r, C.uint_t(level))
    758 }
    759 
    760 // ReplaceRegion copies a block of pixels from the caller's pointer into the storage allocation for slice 0 of a texture.
    761 //
    762 // Reference: https://developer.apple.com/documentation/metal/mtltexture/1515464-replaceregion
    763 func (t Texture) ReplaceRegion(region Region, level int, pixelBytes unsafe.Pointer, bytesPerRow int) {
    764 	r := region.c()
    765 	C.Texture_ReplaceRegion(t.texture, r, C.uint_t(level), pixelBytes, C.uint_t(bytesPerRow))
    766 }
    767 
    768 // Width is the width of the texture image for the base level mipmap, in pixels.
    769 //
    770 // Reference: https://developer.apple.com/documentation/metal/mtltexture/1515339-width
    771 func (t Texture) Width() int {
    772 	return int(C.Texture_Width(t.texture))
    773 }
    774 
    775 // Height is the height of the texture image for the base level mipmap, in pixels.
    776 //
    777 // Reference: https://developer.apple.com/documentation/metal/mtltexture/1515938-height
    778 func (t Texture) Height() int {
    779 	return int(C.Texture_Height(t.texture))
    780 }
    781 
    782 // Buffer is a memory allocation for storing unformatted data
    783 // that is accessible to the GPU.
    784 //
    785 // Reference: https://developer.apple.com/documentation/metal/mtlbuffer.
    786 type Buffer struct {
    787 	buffer unsafe.Pointer
    788 }
    789 
    790 func (b Buffer) CopyToContents(data unsafe.Pointer, lengthInBytes uintptr) {
    791 	C.Buffer_CopyToContents(b.buffer, data, C.size_t(lengthInBytes))
    792 }
    793 
    794 func (b Buffer) Retain() {
    795 	C.Buffer_Retain(b.buffer)
    796 }
    797 
    798 func (b Buffer) Release() {
    799 	C.Buffer_Release(b.buffer)
    800 }
    801 
    802 func (b Buffer) Native() unsafe.Pointer {
    803 	return b.buffer
    804 }
    805 
    806 // Function represents a programmable graphics or compute function executed by the GPU.
    807 //
    808 // Reference: https://developer.apple.com/documentation/metal/mtlfunction.
    809 type Function struct {
    810 	function unsafe.Pointer
    811 }
    812 
    813 func (f Function) Release() {
    814 	C.Function_Release(f.function)
    815 }
    816 
    817 // RenderPipelineState contains the graphics functions
    818 // and configuration state used in a render pass.
    819 //
    820 // Reference: https://developer.apple.com/documentation/metal/mtlrenderpipelinestate.
    821 type RenderPipelineState struct {
    822 	renderPipelineState unsafe.Pointer
    823 }
    824 
    825 func (r RenderPipelineState) Release() {
    826 	C.RenderPipelineState_Release(r.renderPipelineState)
    827 }
    828 
    829 // Region is a rectangular block of pixels in an image or texture,
    830 // defined by its upper-left corner and its size.
    831 //
    832 // Reference: https://developer.apple.com/documentation/metal/mtlregion.
    833 type Region struct {
    834 	Origin Origin // The location of the upper-left corner of the block.
    835 	Size   Size   // The size of the block.
    836 }
    837 
    838 func (r *Region) c() C.struct_Region {
    839 	return C.struct_Region{
    840 		Origin: r.Origin.c(),
    841 		Size:   r.Size.c(),
    842 	}
    843 }
    844 
    845 // Origin represents the location of a pixel in an image or texture relative
    846 // to the upper-left corner, whose coordinates are (0, 0).
    847 //
    848 // Reference: https://developer.apple.com/documentation/metal/mtlorigin.
    849 type Origin struct{ X, Y, Z int }
    850 
    851 func (o *Origin) c() C.struct_Origin {
    852 	return C.struct_Origin{
    853 		X: C.uint_t(o.X),
    854 		Y: C.uint_t(o.Y),
    855 		Z: C.uint_t(o.Z),
    856 	}
    857 }
    858 
    859 // Size represents the set of dimensions that declare the size of an object,
    860 // such as an image, texture, threadgroup, or grid.
    861 //
    862 // Reference: https://developer.apple.com/documentation/metal/mtlsize.
    863 type Size struct{ Width, Height, Depth int }
    864 
    865 func (s *Size) c() C.struct_Size {
    866 	return C.struct_Size{
    867 		Width:  C.uint_t(s.Width),
    868 		Height: C.uint_t(s.Height),
    869 		Depth:  C.uint_t(s.Depth),
    870 	}
    871 }
    872 
    873 // RegionMake2D returns a 2D, rectangular region for image or texture data.
    874 //
    875 // Reference: https://developer.apple.com/documentation/metal/1515675-mtlregionmake2d.
    876 func RegionMake2D(x, y, width, height int) Region {
    877 	return Region{
    878 		Origin: Origin{x, y, 0},
    879 		Size:   Size{width, height, 1},
    880 	}
    881 }
    882 
    883 type Viewport struct {
    884 	OriginX float64
    885 	OriginY float64
    886 	Width   float64
    887 	Height  float64
    888 	ZNear   float64
    889 	ZFar    float64
    890 }
    891 
    892 func (v *Viewport) c() C.struct_Viewport {
    893 	return C.struct_Viewport{
    894 		OriginX: C.double(v.OriginX),
    895 		OriginY: C.double(v.OriginY),
    896 		Width:   C.double(v.Width),
    897 		Height:  C.double(v.Height),
    898 		ZNear:   C.double(v.ZNear),
    899 		ZFar:    C.double(v.ZFar),
    900 	}
    901 }
    902 
    903 // ScissorRect represents a rectangle for the scissor fragment test.
    904 //
    905 // Reference: https://developer.apple.com/documentation/metal/mtlscissorrect
    906 type ScissorRect struct {
    907 	X      int
    908 	Y      int
    909 	Width  int
    910 	Height int
    911 }
    912 
    913 func (s *ScissorRect) c() C.struct_ScissorRect {
    914 	return C.struct_ScissorRect{
    915 		X:      C.uint_t(s.X),
    916 		Y:      C.uint_t(s.Y),
    917 		Width:  C.uint_t(s.Width),
    918 		Height: C.uint_t(s.Height),
    919 	}
    920 }