metal_darwin.go 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  1. // SPDX-License-Identifier: Unlicense OR MIT
  2. package metal
  3. import (
  4. "errors"
  5. "fmt"
  6. "image"
  7. "unsafe"
  8. "gioui.org/gpu/internal/driver"
  9. "gioui.org/shader"
  10. )
  11. /*
  12. #cgo CFLAGS: -Werror -xobjective-c -fobjc-arc
  13. #cgo LDFLAGS: -framework CoreGraphics -framework Metal -framework Foundation
  14. #include <CoreFoundation/CoreFoundation.h>
  15. #include <Metal/Metal.h>
  16. typedef struct {
  17. void *addr;
  18. NSUInteger size;
  19. } slice;
  20. static CFTypeRef queueNewBuffer(CFTypeRef queueRef) {
  21. @autoreleasepool {
  22. id<MTLCommandQueue> queue = (__bridge id<MTLCommandQueue>)queueRef;
  23. return CFBridgingRetain([queue commandBuffer]);
  24. }
  25. }
  26. static void cmdBufferCommit(CFTypeRef cmdBufRef) {
  27. @autoreleasepool {
  28. id<MTLCommandBuffer> cmdBuf = (__bridge id<MTLCommandBuffer>)cmdBufRef;
  29. [cmdBuf commit];
  30. }
  31. }
  32. static void cmdBufferWaitUntilCompleted(CFTypeRef cmdBufRef) {
  33. @autoreleasepool {
  34. id<MTLCommandBuffer> cmdBuf = (__bridge id<MTLCommandBuffer>)cmdBufRef;
  35. [cmdBuf waitUntilCompleted];
  36. }
  37. }
  38. static CFTypeRef cmdBufferRenderEncoder(CFTypeRef cmdBufRef, CFTypeRef textureRef, MTLLoadAction act, float r, float g, float b, float a) {
  39. @autoreleasepool {
  40. id<MTLCommandBuffer> cmdBuf = (__bridge id<MTLCommandBuffer>)cmdBufRef;
  41. MTLRenderPassDescriptor *desc = [MTLRenderPassDescriptor new];
  42. desc.colorAttachments[0].texture = (__bridge id<MTLTexture>)textureRef;
  43. desc.colorAttachments[0].loadAction = act;
  44. desc.colorAttachments[0].clearColor = MTLClearColorMake(r, g, b, a);
  45. return CFBridgingRetain([cmdBuf renderCommandEncoderWithDescriptor:desc]);
  46. }
  47. }
  48. static CFTypeRef cmdBufferComputeEncoder(CFTypeRef cmdBufRef) {
  49. @autoreleasepool {
  50. id<MTLCommandBuffer> cmdBuf = (__bridge id<MTLCommandBuffer>)cmdBufRef;
  51. return CFBridgingRetain([cmdBuf computeCommandEncoder]);
  52. }
  53. }
  54. static CFTypeRef cmdBufferBlitEncoder(CFTypeRef cmdBufRef) {
  55. @autoreleasepool {
  56. id<MTLCommandBuffer> cmdBuf = (__bridge id<MTLCommandBuffer>)cmdBufRef;
  57. return CFBridgingRetain([cmdBuf blitCommandEncoder]);
  58. }
  59. }
  60. static void renderEncEnd(CFTypeRef renderEncRef) {
  61. @autoreleasepool {
  62. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  63. [enc endEncoding];
  64. }
  65. }
  66. static void renderEncViewport(CFTypeRef renderEncRef, MTLViewport viewport) {
  67. @autoreleasepool {
  68. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  69. [enc setViewport:viewport];
  70. }
  71. }
  72. static void renderEncSetFragmentTexture(CFTypeRef renderEncRef, NSUInteger index, CFTypeRef texRef) {
  73. @autoreleasepool {
  74. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  75. id<MTLTexture> tex = (__bridge id<MTLTexture>)texRef;
  76. [enc setFragmentTexture:tex atIndex:index];
  77. }
  78. }
  79. static void renderEncSetFragmentSamplerState(CFTypeRef renderEncRef, NSUInteger index, CFTypeRef samplerRef) {
  80. @autoreleasepool {
  81. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  82. id<MTLSamplerState> sampler = (__bridge id<MTLSamplerState>)samplerRef;
  83. [enc setFragmentSamplerState:sampler atIndex:index];
  84. }
  85. }
  86. static void renderEncSetVertexBuffer(CFTypeRef renderEncRef, CFTypeRef bufRef, NSUInteger idx, NSUInteger offset) {
  87. @autoreleasepool {
  88. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  89. id<MTLBuffer> buf = (__bridge id<MTLBuffer>)bufRef;
  90. [enc setVertexBuffer:buf offset:offset atIndex:idx];
  91. }
  92. }
  93. static void renderEncSetFragmentBuffer(CFTypeRef renderEncRef, CFTypeRef bufRef, NSUInteger idx, NSUInteger offset) {
  94. @autoreleasepool {
  95. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  96. id<MTLBuffer> buf = (__bridge id<MTLBuffer>)bufRef;
  97. [enc setFragmentBuffer:buf offset:offset atIndex:idx];
  98. }
  99. }
  100. static void renderEncSetFragmentBytes(CFTypeRef renderEncRef, const void *bytes, NSUInteger length, NSUInteger idx) {
  101. @autoreleasepool {
  102. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  103. [enc setFragmentBytes:bytes length:length atIndex:idx];
  104. }
  105. }
  106. static void renderEncSetVertexBytes(CFTypeRef renderEncRef, const void *bytes, NSUInteger length, NSUInteger idx) {
  107. @autoreleasepool {
  108. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  109. [enc setVertexBytes:bytes length:length atIndex:idx];
  110. }
  111. }
  112. static void renderEncSetRenderPipelineState(CFTypeRef renderEncRef, CFTypeRef pipeRef) {
  113. @autoreleasepool {
  114. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  115. id<MTLRenderPipelineState> pipe = (__bridge id<MTLRenderPipelineState>)pipeRef;
  116. [enc setRenderPipelineState:pipe];
  117. }
  118. }
  119. static void renderEncDrawPrimitives(CFTypeRef renderEncRef, MTLPrimitiveType type, NSUInteger start, NSUInteger count) {
  120. @autoreleasepool {
  121. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  122. [enc drawPrimitives:type vertexStart:start vertexCount:count];
  123. }
  124. }
  125. static void renderEncDrawIndexedPrimitives(CFTypeRef renderEncRef, MTLPrimitiveType type, CFTypeRef bufRef, NSUInteger offset, NSUInteger count) {
  126. @autoreleasepool {
  127. id<MTLRenderCommandEncoder> enc = (__bridge id<MTLRenderCommandEncoder>)renderEncRef;
  128. id<MTLBuffer> buf = (__bridge id<MTLBuffer>)bufRef;
  129. [enc drawIndexedPrimitives:type indexCount:count indexType:MTLIndexTypeUInt16 indexBuffer:buf indexBufferOffset:offset];
  130. }
  131. }
  132. static void computeEncSetPipeline(CFTypeRef computeEncRef, CFTypeRef pipeRef) {
  133. @autoreleasepool {
  134. id<MTLComputeCommandEncoder> enc = (__bridge id<MTLComputeCommandEncoder>)computeEncRef;
  135. id<MTLComputePipelineState> pipe = (__bridge id<MTLComputePipelineState>)pipeRef;
  136. [enc setComputePipelineState:pipe];
  137. }
  138. }
  139. static void computeEncSetTexture(CFTypeRef computeEncRef, NSUInteger index, CFTypeRef texRef) {
  140. @autoreleasepool {
  141. id<MTLComputeCommandEncoder> enc = (__bridge id<MTLComputeCommandEncoder>)computeEncRef;
  142. id<MTLTexture> tex = (__bridge id<MTLTexture>)texRef;
  143. [enc setTexture:tex atIndex:index];
  144. }
  145. }
  146. static void computeEncEnd(CFTypeRef computeEncRef) {
  147. @autoreleasepool {
  148. id<MTLComputeCommandEncoder> enc = (__bridge id<MTLComputeCommandEncoder>)computeEncRef;
  149. [enc endEncoding];
  150. }
  151. }
  152. static void computeEncSetBuffer(CFTypeRef computeEncRef, NSUInteger index, CFTypeRef bufRef) {
  153. @autoreleasepool {
  154. id<MTLComputeCommandEncoder> enc = (__bridge id<MTLComputeCommandEncoder>)computeEncRef;
  155. id<MTLBuffer> buf = (__bridge id<MTLBuffer>)bufRef;
  156. [enc setBuffer:buf offset:0 atIndex:index];
  157. }
  158. }
  159. static void computeEncDispatch(CFTypeRef computeEncRef, MTLSize threadgroupsPerGrid, MTLSize threadsPerThreadgroup) {
  160. @autoreleasepool {
  161. id<MTLComputeCommandEncoder> enc = (__bridge id<MTLComputeCommandEncoder>)computeEncRef;
  162. [enc dispatchThreadgroups:threadgroupsPerGrid threadsPerThreadgroup:threadsPerThreadgroup];
  163. }
  164. }
  165. static void computeEncSetBytes(CFTypeRef computeEncRef, const void *bytes, NSUInteger length, NSUInteger index) {
  166. @autoreleasepool {
  167. id<MTLComputeCommandEncoder> enc = (__bridge id<MTLComputeCommandEncoder>)computeEncRef;
  168. [enc setBytes:bytes length:length atIndex:index];
  169. }
  170. }
  171. static void blitEncEnd(CFTypeRef blitEncRef) {
  172. @autoreleasepool {
  173. id<MTLBlitCommandEncoder> enc = (__bridge id<MTLBlitCommandEncoder>)blitEncRef;
  174. [enc endEncoding];
  175. }
  176. }
  177. static void blitEncCopyFromTexture(CFTypeRef blitEncRef, CFTypeRef srcRef, MTLOrigin srcOrig, MTLSize srcSize, CFTypeRef dstRef, MTLOrigin dstOrig) {
  178. @autoreleasepool {
  179. id<MTLBlitCommandEncoder> enc = (__bridge id<MTLBlitCommandEncoder>)blitEncRef;
  180. id<MTLTexture> src = (__bridge id<MTLTexture>)srcRef;
  181. id<MTLTexture> dst = (__bridge id<MTLTexture>)dstRef;
  182. [enc copyFromTexture:src
  183. sourceSlice:0
  184. sourceLevel:0
  185. sourceOrigin:srcOrig
  186. sourceSize:srcSize
  187. toTexture:dst
  188. destinationSlice:0
  189. destinationLevel:0
  190. destinationOrigin:dstOrig];
  191. }
  192. }
  193. static void blitEncCopyBufferToTexture(CFTypeRef blitEncRef, CFTypeRef bufRef, CFTypeRef texRef, NSUInteger offset, NSUInteger stride, NSUInteger length, MTLSize dims, MTLOrigin orig) {
  194. @autoreleasepool {
  195. id<MTLBlitCommandEncoder> enc = (__bridge id<MTLBlitCommandEncoder>)blitEncRef;
  196. id<MTLBuffer> src = (__bridge id<MTLBuffer>)bufRef;
  197. id<MTLTexture> dst = (__bridge id<MTLTexture>)texRef;
  198. [enc copyFromBuffer:src
  199. sourceOffset:offset
  200. sourceBytesPerRow:stride
  201. sourceBytesPerImage:length
  202. sourceSize:dims
  203. toTexture:dst
  204. destinationSlice:0
  205. destinationLevel:0
  206. destinationOrigin:orig];
  207. }
  208. }
  209. static void blitEncGenerateMipmapsForTexture(CFTypeRef blitEncRef, CFTypeRef texRef) {
  210. @autoreleasepool {
  211. id<MTLBlitCommandEncoder> enc = (__bridge id<MTLBlitCommandEncoder>)blitEncRef;
  212. id<MTLTexture> tex = (__bridge id<MTLTexture>)texRef;
  213. [enc generateMipmapsForTexture: tex];
  214. }
  215. }
  216. static void blitEncCopyTextureToBuffer(CFTypeRef blitEncRef, CFTypeRef texRef, CFTypeRef bufRef, NSUInteger offset, NSUInteger stride, NSUInteger length, MTLSize dims, MTLOrigin orig) {
  217. @autoreleasepool {
  218. id<MTLBlitCommandEncoder> enc = (__bridge id<MTLBlitCommandEncoder>)blitEncRef;
  219. id<MTLTexture> src = (__bridge id<MTLTexture>)texRef;
  220. id<MTLBuffer> dst = (__bridge id<MTLBuffer>)bufRef;
  221. [enc copyFromTexture:src
  222. sourceSlice:0
  223. sourceLevel:0
  224. sourceOrigin:orig
  225. sourceSize:dims
  226. toBuffer:dst
  227. destinationOffset:offset
  228. destinationBytesPerRow:stride
  229. destinationBytesPerImage:length];
  230. }
  231. }
  232. static void blitEncCopyBufferToBuffer(CFTypeRef blitEncRef, CFTypeRef srcRef, CFTypeRef dstRef, NSUInteger srcOff, NSUInteger dstOff, NSUInteger size) {
  233. @autoreleasepool {
  234. id<MTLBlitCommandEncoder> enc = (__bridge id<MTLBlitCommandEncoder>)blitEncRef;
  235. id<MTLBuffer> src = (__bridge id<MTLBuffer>)srcRef;
  236. id<MTLBuffer> dst = (__bridge id<MTLBuffer>)dstRef;
  237. [enc copyFromBuffer:src
  238. sourceOffset:srcOff
  239. toBuffer:dst
  240. destinationOffset:dstOff
  241. size:size];
  242. }
  243. }
  244. static CFTypeRef newTexture(CFTypeRef devRef, NSUInteger width, NSUInteger height, MTLPixelFormat format, MTLTextureUsage usage, int mipmapped) {
  245. @autoreleasepool {
  246. id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
  247. MTLTextureDescriptor *mtlDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: format
  248. width: width
  249. height: height
  250. mipmapped: mipmapped ? YES : NO];
  251. mtlDesc.usage = usage;
  252. mtlDesc.storageMode = MTLStorageModePrivate;
  253. return CFBridgingRetain([dev newTextureWithDescriptor:mtlDesc]);
  254. }
  255. }
  256. static CFTypeRef newSampler(CFTypeRef devRef, MTLSamplerMinMagFilter minFilter, MTLSamplerMinMagFilter magFilter, MTLSamplerMipFilter mipFilter) {
  257. @autoreleasepool {
  258. id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
  259. MTLSamplerDescriptor *desc = [MTLSamplerDescriptor new];
  260. desc.minFilter = minFilter;
  261. desc.magFilter = magFilter;
  262. desc.mipFilter = mipFilter;
  263. return CFBridgingRetain([dev newSamplerStateWithDescriptor:desc]);
  264. }
  265. }
  266. static CFTypeRef newBuffer(CFTypeRef devRef, NSUInteger size, MTLResourceOptions opts) {
  267. @autoreleasepool {
  268. id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
  269. id<MTLBuffer> buf = [dev newBufferWithLength:size
  270. options:opts];
  271. return CFBridgingRetain(buf);
  272. }
  273. }
  274. static slice bufferContents(CFTypeRef bufRef) {
  275. @autoreleasepool {
  276. id<MTLBuffer> buf = (__bridge id<MTLBuffer>)bufRef;
  277. slice s = {.addr = [buf contents], .size = [buf length]};
  278. return s;
  279. }
  280. }
  281. static CFTypeRef newLibrary(CFTypeRef devRef, char *name, void *mtllib, size_t size) {
  282. @autoreleasepool {
  283. id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
  284. dispatch_data_t data = dispatch_data_create(mtllib, size, DISPATCH_TARGET_QUEUE_DEFAULT, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
  285. id<MTLLibrary> lib = [dev newLibraryWithData:data error:nil];
  286. lib.label = [NSString stringWithUTF8String:name];
  287. return CFBridgingRetain(lib);
  288. }
  289. }
  290. static CFTypeRef libraryNewFunction(CFTypeRef libRef, char *funcName) {
  291. @autoreleasepool {
  292. id<MTLLibrary> lib = (__bridge id<MTLLibrary>)libRef;
  293. NSString *name = [NSString stringWithUTF8String:funcName];
  294. return CFBridgingRetain([lib newFunctionWithName:name]);
  295. }
  296. }
  297. static CFTypeRef newComputePipeline(CFTypeRef devRef, CFTypeRef funcRef) {
  298. @autoreleasepool {
  299. id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
  300. id<MTLFunction> func = (__bridge id<MTLFunction>)funcRef;
  301. return CFBridgingRetain([dev newComputePipelineStateWithFunction:func error:nil]);
  302. }
  303. }
  304. static CFTypeRef newRenderPipeline(CFTypeRef devRef, CFTypeRef vertFunc, CFTypeRef fragFunc, MTLPixelFormat pixelFormat, NSUInteger bufIdx, NSUInteger nverts, MTLVertexFormat *fmts, NSUInteger *offsets, NSUInteger stride, int blend, MTLBlendFactor srcFactor, MTLBlendFactor dstFactor, NSUInteger nvertBufs, NSUInteger nfragBufs) {
  305. @autoreleasepool {
  306. id<MTLDevice> dev = (__bridge id<MTLDevice>)devRef;
  307. id<MTLFunction> vfunc = (__bridge id<MTLFunction>)vertFunc;
  308. id<MTLFunction> ffunc = (__bridge id<MTLFunction>)fragFunc;
  309. MTLVertexDescriptor *vdesc = [MTLVertexDescriptor vertexDescriptor];
  310. vdesc.layouts[bufIdx].stride = stride;
  311. for (NSUInteger i = 0; i < nverts; i++) {
  312. vdesc.attributes[i].format = fmts[i];
  313. vdesc.attributes[i].offset = offsets[i];
  314. vdesc.attributes[i].bufferIndex = bufIdx;
  315. }
  316. MTLRenderPipelineDescriptor *desc = [MTLRenderPipelineDescriptor new];
  317. desc.vertexFunction = vfunc;
  318. desc.fragmentFunction = ffunc;
  319. desc.vertexDescriptor = vdesc;
  320. for (NSUInteger i = 0; i < nvertBufs; i++) {
  321. if (@available(iOS 11.0, *)) {
  322. desc.vertexBuffers[i].mutability = MTLMutabilityImmutable;
  323. }
  324. }
  325. for (NSUInteger i = 0; i < nfragBufs; i++) {
  326. if (@available(iOS 11.0, *)) {
  327. desc.fragmentBuffers[i].mutability = MTLMutabilityImmutable;
  328. }
  329. }
  330. desc.colorAttachments[0].pixelFormat = pixelFormat;
  331. desc.colorAttachments[0].blendingEnabled = blend ? YES : NO;
  332. desc.colorAttachments[0].sourceAlphaBlendFactor = srcFactor;
  333. desc.colorAttachments[0].sourceRGBBlendFactor = srcFactor;
  334. desc.colorAttachments[0].destinationAlphaBlendFactor = dstFactor;
  335. desc.colorAttachments[0].destinationRGBBlendFactor = dstFactor;
  336. return CFBridgingRetain([dev newRenderPipelineStateWithDescriptor:desc
  337. error:nil]);
  338. }
  339. }
  340. */
  341. import "C"
  342. type Backend struct {
  343. dev C.CFTypeRef
  344. queue C.CFTypeRef
  345. pixelFmt C.MTLPixelFormat
  346. cmdBuffer C.CFTypeRef
  347. lastCmdBuffer C.CFTypeRef
  348. renderEnc C.CFTypeRef
  349. computeEnc C.CFTypeRef
  350. blitEnc C.CFTypeRef
  351. prog *Program
  352. topology C.MTLPrimitiveType
  353. stagingBuf C.CFTypeRef
  354. stagingOff int
  355. indexBuf *Buffer
  356. // bufSizes is scratch space for filling out the spvBufferSizeConstants
  357. // that spirv-cross generates for emulating buffer.length expressions in
  358. // shaders.
  359. bufSizes []uint32
  360. }
  361. type Texture struct {
  362. backend *Backend
  363. texture C.CFTypeRef
  364. sampler C.CFTypeRef
  365. width int
  366. height int
  367. mipmap bool
  368. foreign bool
  369. }
  370. type Shader struct {
  371. function C.CFTypeRef
  372. inputs []shader.InputLocation
  373. }
  374. type Program struct {
  375. pipeline C.CFTypeRef
  376. groupSize [3]int
  377. }
  378. type Pipeline struct {
  379. pipeline C.CFTypeRef
  380. topology C.MTLPrimitiveType
  381. }
  382. type Buffer struct {
  383. backend *Backend
  384. size int
  385. buffer C.CFTypeRef
  386. // store is the buffer contents For buffers not allocated on the GPU.
  387. store []byte
  388. }
  389. const (
  390. uniformBufferIndex = 0
  391. attributeBufferIndex = 1
  392. spvBufferSizeConstantsBinding = 25
  393. )
  394. const (
  395. texUnits = 4
  396. bufferUnits = 4
  397. )
  398. func init() {
  399. driver.NewMetalDevice = newMetalDevice
  400. }
  401. func newMetalDevice(api driver.Metal) (driver.Device, error) {
  402. dev := C.CFTypeRef(api.Device)
  403. C.CFRetain(dev)
  404. queue := C.CFTypeRef(api.Queue)
  405. C.CFRetain(queue)
  406. b := &Backend{
  407. dev: dev,
  408. queue: queue,
  409. pixelFmt: C.MTLPixelFormat(api.PixelFormat),
  410. bufSizes: make([]uint32, bufferUnits),
  411. }
  412. return b, nil
  413. }
  414. func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Texture {
  415. if b.lastCmdBuffer != 0 {
  416. C.cmdBufferWaitUntilCompleted(b.lastCmdBuffer)
  417. b.stagingOff = 0
  418. }
  419. if target == nil {
  420. return nil
  421. }
  422. switch t := target.(type) {
  423. case driver.MetalRenderTarget:
  424. texture := C.CFTypeRef(t.Texture)
  425. return &Texture{texture: texture, foreign: true}
  426. case *Texture:
  427. return t
  428. default:
  429. panic(fmt.Sprintf("metal: unsupported render target type: %T", t))
  430. }
  431. }
  432. func (b *Backend) startBlit() C.CFTypeRef {
  433. if b.blitEnc != 0 {
  434. return b.blitEnc
  435. }
  436. b.endEncoder()
  437. b.ensureCmdBuffer()
  438. b.blitEnc = C.cmdBufferBlitEncoder(b.cmdBuffer)
  439. if b.blitEnc == 0 {
  440. panic("metal: [MTLCommandBuffer blitCommandEncoder:] failed")
  441. }
  442. return b.blitEnc
  443. }
  444. func (b *Backend) CopyTexture(dst driver.Texture, dorig image.Point, src driver.Texture, srect image.Rectangle) {
  445. enc := b.startBlit()
  446. dstTex := dst.(*Texture).texture
  447. srcTex := src.(*Texture).texture
  448. ssz := srect.Size()
  449. C.blitEncCopyFromTexture(
  450. enc,
  451. srcTex,
  452. C.MTLOrigin{
  453. x: C.NSUInteger(srect.Min.X),
  454. y: C.NSUInteger(srect.Min.Y),
  455. },
  456. C.MTLSize{
  457. width: C.NSUInteger(ssz.X),
  458. height: C.NSUInteger(ssz.Y),
  459. depth: 1,
  460. },
  461. dstTex,
  462. C.MTLOrigin{
  463. x: C.NSUInteger(dorig.X),
  464. y: C.NSUInteger(dorig.Y),
  465. },
  466. )
  467. }
  468. func (b *Backend) EndFrame() {
  469. b.endCmdBuffer(false)
  470. }
  471. func (b *Backend) endCmdBuffer(wait bool) {
  472. b.endEncoder()
  473. if b.cmdBuffer == 0 {
  474. return
  475. }
  476. C.cmdBufferCommit(b.cmdBuffer)
  477. if wait {
  478. C.cmdBufferWaitUntilCompleted(b.cmdBuffer)
  479. }
  480. if b.lastCmdBuffer != 0 {
  481. C.CFRelease(b.lastCmdBuffer)
  482. }
  483. b.lastCmdBuffer = b.cmdBuffer
  484. b.cmdBuffer = 0
  485. }
  486. func (b *Backend) Caps() driver.Caps {
  487. return driver.Caps{
  488. MaxTextureSize: 8192,
  489. Features: driver.FeatureSRGB | driver.FeatureCompute | driver.FeatureFloatRenderTargets,
  490. }
  491. }
  492. func (b *Backend) NewTimer() driver.Timer {
  493. panic("timers not supported")
  494. }
  495. func (b *Backend) IsTimeContinuous() bool {
  496. panic("timers not supported")
  497. }
  498. func (b *Backend) Release() {
  499. if b.cmdBuffer != 0 {
  500. C.CFRelease(b.cmdBuffer)
  501. }
  502. if b.lastCmdBuffer != 0 {
  503. C.CFRelease(b.lastCmdBuffer)
  504. }
  505. if b.stagingBuf != 0 {
  506. C.CFRelease(b.stagingBuf)
  507. }
  508. C.CFRelease(b.queue)
  509. C.CFRelease(b.dev)
  510. *b = Backend{}
  511. }
  512. func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, minFilter, magFilter driver.TextureFilter, bindings driver.BufferBinding) (driver.Texture, error) {
  513. mformat := pixelFormatFor(format)
  514. var usage C.MTLTextureUsage
  515. if bindings&(driver.BufferBindingTexture|driver.BufferBindingShaderStorageRead) != 0 {
  516. usage |= C.MTLTextureUsageShaderRead
  517. }
  518. if bindings&driver.BufferBindingFramebuffer != 0 {
  519. usage |= C.MTLTextureUsageRenderTarget
  520. }
  521. if bindings&driver.BufferBindingShaderStorageWrite != 0 {
  522. usage |= C.MTLTextureUsageShaderWrite
  523. }
  524. min, mip := samplerFilterFor(minFilter)
  525. max, _ := samplerFilterFor(magFilter)
  526. mipmap := mip != C.MTLSamplerMipFilterNotMipmapped
  527. mipmapped := C.int(0)
  528. if mipmap {
  529. mipmapped = 1
  530. }
  531. tex := C.newTexture(b.dev, C.NSUInteger(width), C.NSUInteger(height), mformat, usage, mipmapped)
  532. if tex == 0 {
  533. return nil, errors.New("metal: [MTLDevice newTextureWithDescriptor:] failed")
  534. }
  535. s := C.newSampler(b.dev, min, max, mip)
  536. if s == 0 {
  537. C.CFRelease(tex)
  538. return nil, errors.New("metal: [MTLDevice newSamplerStateWithDescriptor:] failed")
  539. }
  540. return &Texture{backend: b, texture: tex, sampler: s, width: width, height: height, mipmap: mipmap}, nil
  541. }
  542. func samplerFilterFor(f driver.TextureFilter) (C.MTLSamplerMinMagFilter, C.MTLSamplerMipFilter) {
  543. switch f {
  544. case driver.FilterNearest:
  545. return C.MTLSamplerMinMagFilterNearest, C.MTLSamplerMipFilterNotMipmapped
  546. case driver.FilterLinear:
  547. return C.MTLSamplerMinMagFilterLinear, C.MTLSamplerMipFilterNotMipmapped
  548. case driver.FilterLinearMipmapLinear:
  549. return C.MTLSamplerMinMagFilterLinear, C.MTLSamplerMipFilterLinear
  550. default:
  551. panic("invalid texture filter")
  552. }
  553. }
  554. func (b *Backend) NewPipeline(desc driver.PipelineDesc) (driver.Pipeline, error) {
  555. vsh, fsh := desc.VertexShader.(*Shader), desc.FragmentShader.(*Shader)
  556. layout := desc.VertexLayout.Inputs
  557. if got, exp := len(layout), len(vsh.inputs); got != exp {
  558. return nil, fmt.Errorf("metal: number of input descriptors (%d) doesn't match number of inputs (%d)", got, exp)
  559. }
  560. formats := make([]C.MTLVertexFormat, len(layout))
  561. offsets := make([]C.NSUInteger, len(layout))
  562. for i, inp := range layout {
  563. index := vsh.inputs[i].Location
  564. formats[index] = vertFormatFor(vsh.inputs[i])
  565. offsets[index] = C.NSUInteger(inp.Offset)
  566. }
  567. var (
  568. fmtPtr *C.MTLVertexFormat
  569. offPtr *C.NSUInteger
  570. )
  571. if len(layout) > 0 {
  572. fmtPtr = &formats[0]
  573. offPtr = &offsets[0]
  574. }
  575. srcFactor := blendFactorFor(desc.BlendDesc.SrcFactor)
  576. dstFactor := blendFactorFor(desc.BlendDesc.DstFactor)
  577. blend := C.int(0)
  578. if desc.BlendDesc.Enable {
  579. blend = 1
  580. }
  581. pf := b.pixelFmt
  582. if f := desc.PixelFormat; f != driver.TextureFormatOutput {
  583. pf = pixelFormatFor(f)
  584. }
  585. pipe := C.newRenderPipeline(
  586. b.dev,
  587. vsh.function,
  588. fsh.function,
  589. pf,
  590. attributeBufferIndex,
  591. C.NSUInteger(len(layout)), fmtPtr, offPtr,
  592. C.NSUInteger(desc.VertexLayout.Stride),
  593. blend, srcFactor, dstFactor,
  594. 2, // Number of vertex buffers.
  595. 1, // Number of fragment buffers.
  596. )
  597. if pipe == 0 {
  598. return nil, errors.New("metal: pipeline construction failed")
  599. }
  600. return &Pipeline{pipeline: pipe, topology: primitiveFor(desc.Topology)}, nil
  601. }
  602. func dataTypeSize(d shader.DataType) int {
  603. switch d {
  604. case shader.DataTypeFloat:
  605. return 4
  606. default:
  607. panic("unsupported data type")
  608. }
  609. }
  610. func blendFactorFor(f driver.BlendFactor) C.MTLBlendFactor {
  611. switch f {
  612. case driver.BlendFactorZero:
  613. return C.MTLBlendFactorZero
  614. case driver.BlendFactorOne:
  615. return C.MTLBlendFactorOne
  616. case driver.BlendFactorOneMinusSrcAlpha:
  617. return C.MTLBlendFactorOneMinusSourceAlpha
  618. case driver.BlendFactorDstColor:
  619. return C.MTLBlendFactorDestinationColor
  620. default:
  621. panic("unsupported blend factor")
  622. }
  623. }
  624. func vertFormatFor(f shader.InputLocation) C.MTLVertexFormat {
  625. t := f.Type
  626. s := f.Size
  627. switch {
  628. case t == shader.DataTypeFloat && s == 1:
  629. return C.MTLVertexFormatFloat
  630. case t == shader.DataTypeFloat && s == 2:
  631. return C.MTLVertexFormatFloat2
  632. case t == shader.DataTypeFloat && s == 3:
  633. return C.MTLVertexFormatFloat3
  634. case t == shader.DataTypeFloat && s == 4:
  635. return C.MTLVertexFormatFloat4
  636. default:
  637. panic("unsupported data type")
  638. }
  639. }
  640. func pixelFormatFor(f driver.TextureFormat) C.MTLPixelFormat {
  641. switch f {
  642. case driver.TextureFormatFloat:
  643. return C.MTLPixelFormatR16Float
  644. case driver.TextureFormatRGBA8:
  645. return C.MTLPixelFormatRGBA8Unorm
  646. case driver.TextureFormatSRGBA:
  647. return C.MTLPixelFormatRGBA8Unorm_sRGB
  648. default:
  649. panic("unsupported pixel format")
  650. }
  651. }
  652. func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer, error) {
  653. // Transfer buffer contents in command encoders on every use for
  654. // smaller buffers. The advantage is that buffer re-use during a frame
  655. // won't occur a GPU wait.
  656. // We can't do this for buffers written to by the GPU and read by the client,
  657. // and Metal doesn't require a buffer for indexed draws.
  658. if size <= 4096 && typ&(driver.BufferBindingShaderStorageWrite|driver.BufferBindingIndices) == 0 {
  659. return &Buffer{size: size, store: make([]byte, size)}, nil
  660. }
  661. buf := C.newBuffer(b.dev, C.NSUInteger(size), C.MTLResourceStorageModePrivate)
  662. return &Buffer{backend: b, size: size, buffer: buf}, nil
  663. }
  664. func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (driver.Buffer, error) {
  665. buf, err := b.NewBuffer(typ, len(data))
  666. if err != nil {
  667. return nil, err
  668. }
  669. buf.Upload(data)
  670. return buf, nil
  671. }
  672. func (b *Backend) NewComputeProgram(src shader.Sources) (driver.Program, error) {
  673. sh, err := b.newShader(src)
  674. if err != nil {
  675. return nil, err
  676. }
  677. defer sh.Release()
  678. pipe := C.newComputePipeline(b.dev, sh.function)
  679. if pipe == 0 {
  680. return nil, fmt.Errorf("metal: compute program %q load failed", src.Name)
  681. }
  682. return &Program{pipeline: pipe, groupSize: src.WorkgroupSize}, nil
  683. }
  684. func (b *Backend) NewVertexShader(src shader.Sources) (driver.VertexShader, error) {
  685. return b.newShader(src)
  686. }
  687. func (b *Backend) NewFragmentShader(src shader.Sources) (driver.FragmentShader, error) {
  688. return b.newShader(src)
  689. }
  690. func (b *Backend) newShader(src shader.Sources) (*Shader, error) {
  691. vsrc := []byte(src.MetalLib)
  692. cname := C.CString(src.Name)
  693. defer C.free(unsafe.Pointer(cname))
  694. vlib := C.newLibrary(b.dev, cname, unsafe.Pointer(&vsrc[0]), C.size_t(len(vsrc)))
  695. if vlib == 0 {
  696. return nil, fmt.Errorf("metal: vertex shader %q load failed", src.Name)
  697. }
  698. defer C.CFRelease(vlib)
  699. funcName := C.CString("main0")
  700. defer C.free(unsafe.Pointer(funcName))
  701. f := C.libraryNewFunction(vlib, funcName)
  702. if f == 0 {
  703. return nil, fmt.Errorf("metal: main function not found in %q", src.Name)
  704. }
  705. return &Shader{function: f, inputs: src.Inputs}, nil
  706. }
  707. func (b *Backend) Viewport(x, y, width, height int) {
  708. enc := b.renderEnc
  709. if enc == 0 {
  710. panic("no active render pass")
  711. }
  712. C.renderEncViewport(enc, C.MTLViewport{
  713. originX: C.double(x),
  714. originY: C.double(y),
  715. width: C.double(width),
  716. height: C.double(height),
  717. znear: 0.0,
  718. zfar: 1.0,
  719. })
  720. }
  721. func (b *Backend) DrawArrays(off, count int) {
  722. enc := b.renderEnc
  723. if enc == 0 {
  724. panic("no active render pass")
  725. }
  726. C.renderEncDrawPrimitives(enc, b.topology, C.NSUInteger(off), C.NSUInteger(count))
  727. }
  728. func (b *Backend) DrawElements(off, count int) {
  729. enc := b.renderEnc
  730. if enc == 0 {
  731. panic("no active render pass")
  732. }
  733. C.renderEncDrawIndexedPrimitives(enc, b.topology, b.indexBuf.buffer, C.NSUInteger(off), C.NSUInteger(count))
  734. }
  735. func primitiveFor(mode driver.Topology) C.MTLPrimitiveType {
  736. switch mode {
  737. case driver.TopologyTriangles:
  738. return C.MTLPrimitiveTypeTriangle
  739. case driver.TopologyTriangleStrip:
  740. return C.MTLPrimitiveTypeTriangleStrip
  741. default:
  742. panic("metal: unknown draw mode")
  743. }
  744. }
  745. func (b *Backend) BindImageTexture(unit int, tex driver.Texture) {
  746. b.BindTexture(unit, tex)
  747. }
  748. func (b *Backend) BeginCompute() {
  749. b.endEncoder()
  750. b.ensureCmdBuffer()
  751. for i := range b.bufSizes {
  752. b.bufSizes[i] = 0
  753. }
  754. b.computeEnc = C.cmdBufferComputeEncoder(b.cmdBuffer)
  755. if b.computeEnc == 0 {
  756. panic("metal: [MTLCommandBuffer computeCommandEncoder:] failed")
  757. }
  758. }
  759. func (b *Backend) EndCompute() {
  760. if b.computeEnc == 0 {
  761. panic("no active compute pass")
  762. }
  763. C.computeEncEnd(b.computeEnc)
  764. C.CFRelease(b.computeEnc)
  765. b.computeEnc = 0
  766. }
  767. func (b *Backend) DispatchCompute(x, y, z int) {
  768. enc := b.computeEnc
  769. if enc == 0 {
  770. panic("no active compute pass")
  771. }
  772. C.computeEncSetBytes(enc, unsafe.Pointer(&b.bufSizes[0]), C.NSUInteger(len(b.bufSizes)*4), spvBufferSizeConstantsBinding)
  773. threadgroupsPerGrid := C.MTLSize{
  774. width: C.NSUInteger(x), height: C.NSUInteger(y), depth: C.NSUInteger(z),
  775. }
  776. sz := b.prog.groupSize
  777. threadsPerThreadgroup := C.MTLSize{
  778. width: C.NSUInteger(sz[0]), height: C.NSUInteger(sz[1]), depth: C.NSUInteger(sz[2]),
  779. }
  780. C.computeEncDispatch(enc, threadgroupsPerGrid, threadsPerThreadgroup)
  781. }
  782. func (b *Backend) stagingBuffer(size int) (C.CFTypeRef, int) {
  783. if b.stagingBuf == 0 || b.stagingOff+size > len(bufferStore(b.stagingBuf)) {
  784. if b.stagingBuf != 0 {
  785. C.CFRelease(b.stagingBuf)
  786. }
  787. cap := 2 * (b.stagingOff + size)
  788. b.stagingBuf = C.newBuffer(b.dev, C.NSUInteger(cap), C.MTLResourceStorageModeShared|C.MTLResourceCPUCacheModeWriteCombined)
  789. if b.stagingBuf == 0 {
  790. panic(fmt.Errorf("metal: failed to allocate %d bytes of staging buffer", cap))
  791. }
  792. b.stagingOff = 0
  793. }
  794. off := b.stagingOff
  795. b.stagingOff += size
  796. return b.stagingBuf, off
  797. }
  798. func (t *Texture) Upload(offset, size image.Point, pixels []byte, stride int) {
  799. if len(pixels) == 0 {
  800. return
  801. }
  802. if stride == 0 {
  803. stride = size.X * 4
  804. }
  805. dstStride := size.X * 4
  806. n := size.Y * dstStride
  807. buf, off := t.backend.stagingBuffer(n)
  808. store := bufferSlice(buf, off, n)
  809. var srcOff, dstOff int
  810. for y := 0; y < size.Y; y++ {
  811. srcRow := pixels[srcOff : srcOff+dstStride]
  812. dstRow := store[dstOff : dstOff+dstStride]
  813. copy(dstRow, srcRow)
  814. dstOff += dstStride
  815. srcOff += stride
  816. }
  817. enc := t.backend.startBlit()
  818. orig := C.MTLOrigin{
  819. x: C.NSUInteger(offset.X),
  820. y: C.NSUInteger(offset.Y),
  821. }
  822. msize := C.MTLSize{
  823. width: C.NSUInteger(size.X),
  824. height: C.NSUInteger(size.Y),
  825. depth: 1,
  826. }
  827. C.blitEncCopyBufferToTexture(enc, buf, t.texture, C.NSUInteger(off), C.NSUInteger(dstStride), C.NSUInteger(len(store)), msize, orig)
  828. if t.mipmap {
  829. C.blitEncGenerateMipmapsForTexture(enc, t.texture)
  830. }
  831. }
  832. func (t *Texture) Release() {
  833. if t.foreign {
  834. panic("metal: release of external texture")
  835. }
  836. C.CFRelease(t.texture)
  837. C.CFRelease(t.sampler)
  838. *t = Texture{}
  839. }
  840. func (p *Pipeline) Release() {
  841. C.CFRelease(p.pipeline)
  842. *p = Pipeline{}
  843. }
  844. func (b *Backend) PrepareTexture(tex driver.Texture) {}
  845. func (b *Backend) BindTexture(unit int, tex driver.Texture) {
  846. t := tex.(*Texture)
  847. if enc := b.renderEnc; enc != 0 {
  848. C.renderEncSetFragmentTexture(enc, C.NSUInteger(unit), t.texture)
  849. C.renderEncSetFragmentSamplerState(enc, C.NSUInteger(unit), t.sampler)
  850. } else if enc := b.computeEnc; enc != 0 {
  851. C.computeEncSetTexture(enc, C.NSUInteger(unit), t.texture)
  852. } else {
  853. panic("no active render nor compute pass")
  854. }
  855. }
  856. func (b *Backend) ensureCmdBuffer() {
  857. if b.cmdBuffer != 0 {
  858. return
  859. }
  860. b.cmdBuffer = C.queueNewBuffer(b.queue)
  861. if b.cmdBuffer == 0 {
  862. panic("metal: [MTLCommandQueue cmdBuffer] failed")
  863. }
  864. }
  865. func (b *Backend) BindPipeline(pipe driver.Pipeline) {
  866. p := pipe.(*Pipeline)
  867. enc := b.renderEnc
  868. if enc == 0 {
  869. panic("no active render pass")
  870. }
  871. C.renderEncSetRenderPipelineState(enc, p.pipeline)
  872. b.topology = p.topology
  873. }
  874. func (b *Backend) BindProgram(prog driver.Program) {
  875. enc := b.computeEnc
  876. if enc == 0 {
  877. panic("no active compute pass")
  878. }
  879. p := prog.(*Program)
  880. C.computeEncSetPipeline(enc, p.pipeline)
  881. b.prog = p
  882. }
  883. func (s *Shader) Release() {
  884. C.CFRelease(s.function)
  885. *s = Shader{}
  886. }
  887. func (p *Program) Release() {
  888. C.CFRelease(p.pipeline)
  889. *p = Program{}
  890. }
  891. func (b *Backend) BindStorageBuffer(binding int, buffer driver.Buffer) {
  892. buf := buffer.(*Buffer)
  893. b.bufSizes[binding] = uint32(buf.size)
  894. enc := b.computeEnc
  895. if enc == 0 {
  896. panic("no active compute pass")
  897. }
  898. if buf.buffer != 0 {
  899. C.computeEncSetBuffer(enc, C.NSUInteger(binding), buf.buffer)
  900. } else if buf.size > 0 {
  901. C.computeEncSetBytes(enc, unsafe.Pointer(&buf.store[0]), C.NSUInteger(buf.size), C.NSUInteger(binding))
  902. }
  903. }
  904. func (b *Backend) BindUniforms(buf driver.Buffer) {
  905. bf := buf.(*Buffer)
  906. enc := b.renderEnc
  907. if enc == 0 {
  908. panic("no active render pass")
  909. }
  910. if bf.buffer != 0 {
  911. C.renderEncSetVertexBuffer(enc, bf.buffer, uniformBufferIndex, 0)
  912. C.renderEncSetFragmentBuffer(enc, bf.buffer, uniformBufferIndex, 0)
  913. } else if bf.size > 0 {
  914. C.renderEncSetVertexBytes(enc, unsafe.Pointer(&bf.store[0]), C.NSUInteger(bf.size), uniformBufferIndex)
  915. C.renderEncSetFragmentBytes(enc, unsafe.Pointer(&bf.store[0]), C.NSUInteger(bf.size), uniformBufferIndex)
  916. }
  917. }
  918. func (b *Backend) BindVertexBuffer(buf driver.Buffer, offset int) {
  919. bf := buf.(*Buffer)
  920. enc := b.renderEnc
  921. if enc == 0 {
  922. panic("no active render pass")
  923. }
  924. if bf.buffer != 0 {
  925. C.renderEncSetVertexBuffer(enc, bf.buffer, attributeBufferIndex, C.NSUInteger(offset))
  926. } else if n := bf.size - offset; n > 0 {
  927. C.renderEncSetVertexBytes(enc, unsafe.Pointer(&bf.store[offset]), C.NSUInteger(n), attributeBufferIndex)
  928. }
  929. }
  930. func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
  931. b.indexBuf = buf.(*Buffer)
  932. }
  933. func (b *Buffer) Download(data []byte) error {
  934. if len(data) > b.size {
  935. panic(fmt.Errorf("len(data) (%d) larger than len(content) (%d)", len(data), b.size))
  936. }
  937. buf, off := b.backend.stagingBuffer(len(data))
  938. enc := b.backend.startBlit()
  939. C.blitEncCopyBufferToBuffer(enc, b.buffer, buf, 0, C.NSUInteger(off), C.NSUInteger(len(data)))
  940. b.backend.endCmdBuffer(true)
  941. store := bufferSlice(buf, off, len(data))
  942. copy(data, store)
  943. return nil
  944. }
  945. func (b *Buffer) Upload(data []byte) {
  946. if len(data) > b.size {
  947. panic(fmt.Errorf("len(data) (%d) larger than len(content) (%d)", len(data), b.size))
  948. }
  949. if b.buffer == 0 {
  950. copy(b.store, data)
  951. return
  952. }
  953. buf, off := b.backend.stagingBuffer(len(data))
  954. store := bufferSlice(buf, off, len(data))
  955. copy(store, data)
  956. enc := b.backend.startBlit()
  957. C.blitEncCopyBufferToBuffer(enc, buf, b.buffer, C.NSUInteger(off), 0, C.NSUInteger(len(store)))
  958. }
  959. func bufferStore(buf C.CFTypeRef) []byte {
  960. contents := C.bufferContents(buf)
  961. return (*(*[1 << 30]byte)(contents.addr))[:contents.size:contents.size]
  962. }
  963. func bufferSlice(buf C.CFTypeRef, off, len int) []byte {
  964. store := bufferStore(buf)
  965. return store[off : off+len]
  966. }
  967. func (b *Buffer) Release() {
  968. if b.buffer != 0 {
  969. C.CFRelease(b.buffer)
  970. }
  971. *b = Buffer{}
  972. }
  973. func (t *Texture) ReadPixels(src image.Rectangle, pixels []byte, stride int) error {
  974. if len(pixels) == 0 {
  975. return nil
  976. }
  977. sz := src.Size()
  978. orig := C.MTLOrigin{
  979. x: C.NSUInteger(src.Min.X),
  980. y: C.NSUInteger(src.Min.Y),
  981. }
  982. msize := C.MTLSize{
  983. width: C.NSUInteger(sz.X),
  984. height: C.NSUInteger(sz.Y),
  985. depth: 1,
  986. }
  987. stageStride := sz.X * 4
  988. n := sz.Y * stageStride
  989. buf, off := t.backend.stagingBuffer(n)
  990. enc := t.backend.startBlit()
  991. C.blitEncCopyTextureToBuffer(enc, t.texture, buf, C.NSUInteger(off), C.NSUInteger(stageStride), C.NSUInteger(n), msize, orig)
  992. t.backend.endCmdBuffer(true)
  993. store := bufferSlice(buf, off, n)
  994. var srcOff, dstOff int
  995. for y := 0; y < sz.Y; y++ {
  996. dstRow := pixels[srcOff : srcOff+stageStride]
  997. srcRow := store[dstOff : dstOff+stageStride]
  998. copy(dstRow, srcRow)
  999. dstOff += stageStride
  1000. srcOff += stride
  1001. }
  1002. return nil
  1003. }
  1004. func (b *Backend) BeginRenderPass(tex driver.Texture, d driver.LoadDesc) {
  1005. b.endEncoder()
  1006. b.ensureCmdBuffer()
  1007. f := tex.(*Texture)
  1008. col := d.ClearColor
  1009. var act C.MTLLoadAction
  1010. switch d.Action {
  1011. case driver.LoadActionKeep:
  1012. act = C.MTLLoadActionLoad
  1013. case driver.LoadActionClear:
  1014. act = C.MTLLoadActionClear
  1015. case driver.LoadActionInvalidate:
  1016. act = C.MTLLoadActionDontCare
  1017. }
  1018. b.renderEnc = C.cmdBufferRenderEncoder(b.cmdBuffer, f.texture, act, C.float(col.R), C.float(col.G), C.float(col.B), C.float(col.A))
  1019. if b.renderEnc == 0 {
  1020. panic("metal: [MTLCommandBuffer renderCommandEncoderWithDescriptor:] failed")
  1021. }
  1022. }
  1023. func (b *Backend) EndRenderPass() {
  1024. if b.renderEnc == 0 {
  1025. panic("no active render pass")
  1026. }
  1027. C.renderEncEnd(b.renderEnc)
  1028. C.CFRelease(b.renderEnc)
  1029. b.renderEnc = 0
  1030. }
  1031. func (b *Backend) endEncoder() {
  1032. if b.renderEnc != 0 {
  1033. panic("active render pass")
  1034. }
  1035. if b.computeEnc != 0 {
  1036. panic("active compute pass")
  1037. }
  1038. if b.blitEnc != 0 {
  1039. C.blitEncEnd(b.blitEnc)
  1040. C.CFRelease(b.blitEnc)
  1041. b.blitEnc = 0
  1042. }
  1043. }
  1044. func (f *Texture) ImplementsRenderTarget() {}