GrMtlGpu.mm 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. /*
  2. * Copyright 2017 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/gpu/mtl/GrMtlGpu.h"
  8. #include "src/core/SkConvertPixels.h"
  9. #include "src/gpu/GrRenderTargetPriv.h"
  10. #include "src/gpu/GrTexturePriv.h"
  11. #include "src/gpu/mtl/GrMtlBuffer.h"
  12. #include "src/gpu/mtl/GrMtlCommandBuffer.h"
  13. #include "src/gpu/mtl/GrMtlGpuCommandBuffer.h"
  14. #include "src/gpu/mtl/GrMtlTexture.h"
  15. #include "src/gpu/mtl/GrMtlTextureRenderTarget.h"
  16. #include "src/gpu/mtl/GrMtlUtil.h"
  17. #include "src/sksl/SkSLCompiler.h"
  18. #import <simd/simd.h>
  19. #if !__has_feature(objc_arc)
  20. #error This file must be compiled with Arc. Use -fobjc-arc flag
  21. #endif
  22. static bool get_feature_set(id<MTLDevice> device, MTLFeatureSet* featureSet) {
  23. // Mac OSX
  24. #ifdef SK_BUILD_FOR_MAC
  25. if ([device supportsFeatureSet:MTLFeatureSet_OSX_GPUFamily1_v2]) {
  26. *featureSet = MTLFeatureSet_OSX_GPUFamily1_v2;
  27. return true;
  28. }
  29. if ([device supportsFeatureSet:MTLFeatureSet_OSX_GPUFamily1_v1]) {
  30. *featureSet = MTLFeatureSet_OSX_GPUFamily1_v1;
  31. return true;
  32. }
  33. #endif
  34. // iOS Family group 3
  35. #ifdef SK_BUILD_FOR_IOS
  36. if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2]) {
  37. *featureSet = MTLFeatureSet_iOS_GPUFamily3_v2;
  38. return true;
  39. }
  40. if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
  41. *featureSet = MTLFeatureSet_iOS_GPUFamily3_v1;
  42. return true;
  43. }
  44. // iOS Family group 2
  45. if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v3]) {
  46. *featureSet = MTLFeatureSet_iOS_GPUFamily2_v3;
  47. return true;
  48. }
  49. if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2]) {
  50. *featureSet = MTLFeatureSet_iOS_GPUFamily2_v2;
  51. return true;
  52. }
  53. if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1]) {
  54. *featureSet = MTLFeatureSet_iOS_GPUFamily2_v1;
  55. return true;
  56. }
  57. // iOS Family group 1
  58. if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v3]) {
  59. *featureSet = MTLFeatureSet_iOS_GPUFamily1_v3;
  60. return true;
  61. }
  62. if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
  63. *featureSet = MTLFeatureSet_iOS_GPUFamily1_v2;
  64. return true;
  65. }
  66. if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v1]) {
  67. *featureSet = MTLFeatureSet_iOS_GPUFamily1_v1;
  68. return true;
  69. }
  70. #endif
  71. // No supported feature sets were found
  72. return false;
  73. }
  74. sk_sp<GrGpu> GrMtlGpu::Make(GrContext* context, const GrContextOptions& options,
  75. id<MTLDevice> device, id<MTLCommandQueue> queue) {
  76. if (!device || !queue) {
  77. return nullptr;
  78. }
  79. MTLFeatureSet featureSet;
  80. if (!get_feature_set(device, &featureSet)) {
  81. return nullptr;
  82. }
  83. return sk_sp<GrGpu>(new GrMtlGpu(context, options, device, queue, featureSet));
  84. }
  85. GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options,
  86. id<MTLDevice> device, id<MTLCommandQueue> queue, MTLFeatureSet featureSet)
  87. : INHERITED(context)
  88. , fDevice(device)
  89. , fQueue(queue)
  90. , fCmdBuffer(nullptr)
  91. , fCompiler(new SkSL::Compiler())
  92. , fResourceProvider(this)
  93. , fDisconnected(false) {
  94. fMtlCaps.reset(new GrMtlCaps(options, fDevice, featureSet));
  95. fCaps = fMtlCaps;
  96. }
  97. GrMtlGpu::~GrMtlGpu() {
  98. if (!fDisconnected) {
  99. this->destroyResources();
  100. }
  101. }
  102. void GrMtlGpu::disconnect(DisconnectType type) {
  103. INHERITED::disconnect(type);
  104. if (DisconnectType::kCleanup == type) {
  105. this->destroyResources();
  106. } else {
  107. delete fCmdBuffer;
  108. fCmdBuffer = nullptr;
  109. fResourceProvider.destroyResources();
  110. fQueue = nil;
  111. fDevice = nil;
  112. fDisconnected = true;
  113. }
  114. }
  115. void GrMtlGpu::destroyResources() {
  116. // Will implicitly delete the command buffer
  117. this->submitCommandBuffer(SyncQueue::kForce_SyncQueue);
  118. fResourceProvider.destroyResources();
  119. fQueue = nil;
  120. fDevice = nil;
  121. }
  122. GrGpuRTCommandBuffer* GrMtlGpu::getCommandBuffer(
  123. GrRenderTarget* renderTarget, GrSurfaceOrigin origin, const SkRect& bounds,
  124. const GrGpuRTCommandBuffer::LoadAndStoreInfo& colorInfo,
  125. const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo& stencilInfo) {
  126. return new GrMtlGpuRTCommandBuffer(this, renderTarget, origin, bounds, colorInfo, stencilInfo);
  127. }
  128. GrGpuTextureCommandBuffer* GrMtlGpu::getCommandBuffer(GrTexture* texture,
  129. GrSurfaceOrigin origin) {
  130. return new GrMtlGpuTextureCommandBuffer(this, texture, origin);
  131. }
  132. void GrMtlGpu::submit(GrGpuCommandBuffer* buffer) {
  133. GrMtlGpuRTCommandBuffer* mtlRTCmdBuffer =
  134. reinterpret_cast<GrMtlGpuRTCommandBuffer*>(buffer->asRTCommandBuffer());
  135. if (mtlRTCmdBuffer) {
  136. mtlRTCmdBuffer->submit();
  137. }
  138. delete buffer;
  139. }
  140. GrMtlCommandBuffer* GrMtlGpu::commandBuffer() {
  141. if (!fCmdBuffer) {
  142. fCmdBuffer = GrMtlCommandBuffer::Create(fQueue);
  143. }
  144. return fCmdBuffer;
  145. }
  146. void GrMtlGpu::submitCommandBuffer(SyncQueue sync) {
  147. if (fCmdBuffer) {
  148. fResourceProvider.addBufferCompletionHandler(fCmdBuffer);
  149. fCmdBuffer->commit(SyncQueue::kForce_SyncQueue == sync);
  150. delete fCmdBuffer;
  151. fCmdBuffer = nullptr;
  152. }
  153. }
  154. sk_sp<GrGpuBuffer> GrMtlGpu::onCreateBuffer(size_t size, GrGpuBufferType type,
  155. GrAccessPattern accessPattern, const void* data) {
  156. return GrMtlBuffer::Make(this, size, type, accessPattern, data);
  157. }
  158. static bool check_max_blit_width(int widthInPixels) {
  159. if (widthInPixels > 32767) {
  160. SkASSERT(false); // surfaces should not be this wide anyway
  161. return false;
  162. }
  163. return true;
  164. }
  165. bool GrMtlGpu::uploadToTexture(GrMtlTexture* tex, int left, int top, int width, int height,
  166. GrColorType dataColorType, const GrMipLevel texels[],
  167. int mipLevelCount) {
  168. SkASSERT(this->caps()->isConfigTexturable(tex->config()));
  169. // The assumption is either that we have no mipmaps, or that our rect is the entire texture
  170. SkASSERT(1 == mipLevelCount ||
  171. (0 == left && 0 == top && width == tex->width() && height == tex->height()));
  172. // We assume that if the texture has mip levels, we either upload to all the levels or just the
  173. // first.
  174. SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
  175. if (!check_max_blit_width(width)) {
  176. return false;
  177. }
  178. if (width == 0 || height == 0) {
  179. return false;
  180. }
  181. if (GrPixelConfigToColorType(tex->config()) != dataColorType) {
  182. return false;
  183. }
  184. id<MTLTexture> mtlTexture = tex->mtlTexture();
  185. SkASSERT(mtlTexture);
  186. // Either upload only the first miplevel or all miplevels
  187. SkASSERT(1 == mipLevelCount || mipLevelCount == (int)mtlTexture.mipmapLevelCount);
  188. // TODO: implement some way of reusing transfer buffers?
  189. size_t bpp = GrColorTypeBytesPerPixel(dataColorType);
  190. SkTArray<size_t> individualMipOffsets(mipLevelCount);
  191. individualMipOffsets.push_back(0);
  192. size_t combinedBufferSize = width * bpp * height;
  193. int currentWidth = width;
  194. int currentHeight = height;
  195. if (!texels[0].fPixels) {
  196. combinedBufferSize = 0;
  197. }
  198. // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
  199. // config. This works with the assumption that the bytes in pixel config is always a power of 2.
  200. SkASSERT((bpp & (bpp - 1)) == 0);
  201. const size_t alignmentMask = 0x3 | (bpp - 1);
  202. for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; currentMipLevel++) {
  203. currentWidth = SkTMax(1, currentWidth/2);
  204. currentHeight = SkTMax(1, currentHeight/2);
  205. if (texels[currentMipLevel].fPixels) {
  206. const size_t trimmedSize = currentWidth * bpp * currentHeight;
  207. const size_t alignmentDiff = combinedBufferSize & alignmentMask;
  208. if (alignmentDiff != 0) {
  209. combinedBufferSize += alignmentMask - alignmentDiff + 1;
  210. }
  211. individualMipOffsets.push_back(combinedBufferSize);
  212. combinedBufferSize += trimmedSize;
  213. } else {
  214. individualMipOffsets.push_back(0);
  215. }
  216. }
  217. if (0 == combinedBufferSize) {
  218. // We don't actually have any data to upload so just return success
  219. return true;
  220. }
  221. sk_sp<GrMtlBuffer> transferBuffer = GrMtlBuffer::Make(this, combinedBufferSize,
  222. GrGpuBufferType::kXferCpuToGpu,
  223. kStream_GrAccessPattern);
  224. if (!transferBuffer) {
  225. return false;
  226. }
  227. char* buffer = (char*) transferBuffer->map();
  228. size_t bufferOffset = transferBuffer->offset();
  229. currentWidth = width;
  230. currentHeight = height;
  231. int layerHeight = tex->height();
  232. MTLOrigin origin = MTLOriginMake(left, top, 0);
  233. id<MTLBlitCommandEncoder> blitCmdEncoder = this->commandBuffer()->getBlitCommandEncoder();
  234. for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
  235. if (texels[currentMipLevel].fPixels) {
  236. SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
  237. const size_t trimRowBytes = currentWidth * bpp;
  238. const size_t rowBytes = texels[currentMipLevel].fRowBytes;
  239. // copy data into the buffer, skipping the trailing bytes
  240. char* dst = buffer + individualMipOffsets[currentMipLevel];
  241. const char* src = (const char*)texels[currentMipLevel].fPixels;
  242. SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight);
  243. [blitCmdEncoder copyFromBuffer: transferBuffer->mtlBuffer()
  244. sourceOffset: bufferOffset + individualMipOffsets[currentMipLevel]
  245. sourceBytesPerRow: trimRowBytes
  246. sourceBytesPerImage: trimRowBytes*currentHeight
  247. sourceSize: MTLSizeMake(currentWidth, currentHeight, 1)
  248. toTexture: mtlTexture
  249. destinationSlice: 0
  250. destinationLevel: currentMipLevel
  251. destinationOrigin: origin];
  252. }
  253. currentWidth = SkTMax(1, currentWidth/2);
  254. currentHeight = SkTMax(1, currentHeight/2);
  255. layerHeight = currentHeight;
  256. }
  257. transferBuffer->unmap();
  258. if (mipLevelCount < (int) tex->mtlTexture().mipmapLevelCount) {
  259. tex->texturePriv().markMipMapsDirty();
  260. }
  261. return true;
  262. }
  263. bool GrMtlGpu::clearTexture(GrMtlTexture* tex, GrColorType dataColorType, uint32_t levelMask) {
  264. SkASSERT(this->caps()->isConfigTexturable(tex->config()));
  265. if (!levelMask) {
  266. return true;
  267. }
  268. id<MTLTexture> mtlTexture = tex->mtlTexture();
  269. SkASSERT(mtlTexture);
  270. // Either upload only the first miplevel or all miplevels
  271. int mipLevelCount = (int)mtlTexture.mipmapLevelCount;
  272. // TODO: implement some way of reusing transfer buffers?
  273. size_t bpp = GrColorTypeBytesPerPixel(dataColorType);
  274. SkTArray<size_t> individualMipOffsets(mipLevelCount);
  275. size_t combinedBufferSize = 0;
  276. int currentWidth = tex->width();
  277. int currentHeight = tex->height();
  278. // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
  279. // config. This works with the assumption that the bytes in pixel config is always a power of 2.
  280. // TODO: can we just copy from a single buffer the size of the largest cleared level w/o a perf
  281. // penalty?
  282. SkASSERT((bpp & (bpp - 1)) == 0);
  283. const size_t alignmentMask = 0x3 | (bpp - 1);
  284. for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
  285. if (levelMask & (1 << currentMipLevel)) {
  286. const size_t trimmedSize = currentWidth * bpp * currentHeight;
  287. const size_t alignmentDiff = combinedBufferSize & alignmentMask;
  288. if (alignmentDiff != 0) {
  289. combinedBufferSize += alignmentMask - alignmentDiff + 1;
  290. }
  291. individualMipOffsets.push_back(combinedBufferSize);
  292. combinedBufferSize += trimmedSize;
  293. }
  294. currentWidth = SkTMax(1, currentWidth/2);
  295. currentHeight = SkTMax(1, currentHeight/2);
  296. }
  297. SkASSERT(combinedBufferSize > 0 && !individualMipOffsets.empty());
  298. // TODO: Create GrMtlTransferBuffer
  299. id<MTLBuffer> transferBuffer = [fDevice newBufferWithLength: combinedBufferSize
  300. options: MTLResourceStorageModePrivate];
  301. if (nil == transferBuffer) {
  302. return false;
  303. }
  304. id<MTLBlitCommandEncoder> blitCmdEncoder = this->commandBuffer()->getBlitCommandEncoder();
  305. // clear the buffer to transparent black
  306. NSRange clearRange;
  307. clearRange.location = 0;
  308. clearRange.length = combinedBufferSize;
  309. [blitCmdEncoder fillBuffer: transferBuffer
  310. range: clearRange
  311. value: 0];
  312. // now copy buffer to texture
  313. currentWidth = tex->width();
  314. currentHeight = tex->height();
  315. MTLOrigin origin = MTLOriginMake(0, 0, 0);
  316. for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
  317. if (levelMask & (1 << currentMipLevel)) {
  318. const size_t rowBytes = currentWidth * bpp;
  319. [blitCmdEncoder copyFromBuffer: transferBuffer
  320. sourceOffset: individualMipOffsets[currentMipLevel]
  321. sourceBytesPerRow: rowBytes
  322. sourceBytesPerImage: rowBytes * currentHeight
  323. sourceSize: MTLSizeMake(currentWidth, currentHeight, 1)
  324. toTexture: mtlTexture
  325. destinationSlice: 0
  326. destinationLevel: currentMipLevel
  327. destinationOrigin: origin];
  328. }
  329. currentWidth = SkTMax(1, currentWidth/2);
  330. currentHeight = SkTMax(1, currentHeight/2);
  331. }
  332. if (mipLevelCount < (int) tex->mtlTexture().mipmapLevelCount) {
  333. tex->texturePriv().markMipMapsDirty();
  334. }
  335. return true;
  336. }
  337. GrStencilAttachment* GrMtlGpu::createStencilAttachmentForRenderTarget(
  338. const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
  339. SkASSERT(numStencilSamples == rt->numSamples());
  340. SkASSERT(width >= rt->width());
  341. SkASSERT(height >= rt->height());
  342. int samples = rt->numSamples();
  343. const GrMtlCaps::StencilFormat& sFmt = this->mtlCaps().preferredStencilFormat();
  344. GrMtlStencilAttachment* stencil(GrMtlStencilAttachment::Create(this,
  345. width,
  346. height,
  347. samples,
  348. sFmt));
  349. fStats.incStencilAttachmentCreates();
  350. return stencil;
  351. }
  352. sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc, GrRenderable renderable,
  353. int renderTargetSampleCnt, SkBudgeted budgeted,
  354. GrProtected isProtected, const GrMipLevel texels[],
  355. int mipLevelCount) {
  356. // We don't support protected textures in Metal.
  357. if (isProtected == GrProtected::kYes) {
  358. return nullptr;
  359. }
  360. int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
  361. if (!fMtlCaps->isConfigTexturable(desc.fConfig)) {
  362. return nullptr;
  363. }
  364. MTLPixelFormat format;
  365. if (!GrPixelConfigToMTLFormat(desc.fConfig, &format)) {
  366. return nullptr;
  367. }
  368. if (GrPixelConfigIsCompressed(desc.fConfig)) {
  369. return nullptr; // TODO: add compressed texture support
  370. }
  371. sk_sp<GrMtlTexture> tex;
  372. // This TexDesc refers to the texture that will be read by the client. Thus even if msaa is
  373. // requested, this TexDesc describes the resolved texture. Therefore we always have samples
  374. // set to 1.
  375. MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
  376. texDesc.textureType = MTLTextureType2D;
  377. texDesc.pixelFormat = format;
  378. texDesc.width = desc.fWidth;
  379. texDesc.height = desc.fHeight;
  380. texDesc.depth = 1;
  381. texDesc.mipmapLevelCount = mipLevels;
  382. texDesc.sampleCount = 1;
  383. texDesc.arrayLength = 1;
  384. // Make all textures have private gpu only access. We can use transfer buffers or textures
  385. // to copy to them.
  386. texDesc.storageMode = MTLStorageModePrivate;
  387. texDesc.usage = MTLTextureUsageShaderRead;
  388. texDesc.usage |= (renderable == GrRenderable::kYes) ? MTLTextureUsageRenderTarget : 0;
  389. GrMipMapsStatus mipMapsStatus = GrMipMapsStatus::kNotAllocated;
  390. if (mipLevels > 1) {
  391. mipMapsStatus = GrMipMapsStatus::kValid;
  392. for (int i = 0; i < mipLevels; ++i) {
  393. if (!texels[i].fPixels) {
  394. mipMapsStatus = GrMipMapsStatus::kDirty;
  395. break;
  396. }
  397. }
  398. }
  399. if (renderable == GrRenderable::kYes) {
  400. tex = GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(this, budgeted,
  401. desc, renderTargetSampleCnt,
  402. texDesc, mipMapsStatus);
  403. } else {
  404. tex = GrMtlTexture::MakeNewTexture(this, budgeted, desc, texDesc, mipMapsStatus);
  405. }
  406. if (!tex) {
  407. return nullptr;
  408. }
  409. auto colorType = GrPixelConfigToColorType(desc.fConfig);
  410. if (mipLevelCount && texels[0].fPixels) {
  411. if (!this->uploadToTexture(tex.get(), 0, 0, desc.fWidth, desc.fHeight, colorType, texels,
  412. mipLevelCount)) {
  413. tex->unref();
  414. return nullptr;
  415. }
  416. }
  417. if (this->caps()->shouldInitializeTextures()) {
  418. uint32_t levelMask = ~0;
  419. SkASSERT(mipLevelCount < 32);
  420. for (int i = 0; i < mipLevelCount; ++i) {
  421. if (!texels[i].fPixels) {
  422. levelMask &= ~(1 << i);
  423. }
  424. }
  425. this->clearTexture(tex.get(), colorType, levelMask);
  426. }
  427. return std::move(tex);
  428. }
  429. static id<MTLTexture> get_texture_from_backend(const GrBackendTexture& backendTex) {
  430. GrMtlTextureInfo textureInfo;
  431. if (!backendTex.getMtlTextureInfo(&textureInfo)) {
  432. return nil;
  433. }
  434. return GrGetMTLTexture(textureInfo.fTexture.get());
  435. }
  436. static id<MTLTexture> get_texture_from_backend(const GrBackendRenderTarget& backendRT) {
  437. GrMtlTextureInfo textureInfo;
  438. if (!backendRT.getMtlTextureInfo(&textureInfo)) {
  439. return nil;
  440. }
  441. return GrGetMTLTexture(textureInfo.fTexture.get());
  442. }
  443. static inline void init_surface_desc(GrSurfaceDesc* surfaceDesc, id<MTLTexture> mtlTexture,
  444. GrRenderable renderable, GrPixelConfig config) {
  445. if (renderable == GrRenderable::kYes) {
  446. SkASSERT(MTLTextureUsageRenderTarget & mtlTexture.usage);
  447. }
  448. surfaceDesc->fWidth = mtlTexture.width;
  449. surfaceDesc->fHeight = mtlTexture.height;
  450. surfaceDesc->fConfig = config;
  451. }
  452. sk_sp<GrTexture> GrMtlGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
  453. GrColorType grColorType,
  454. GrWrapOwnership,
  455. GrWrapCacheable cacheable, GrIOType ioType) {
  456. id<MTLTexture> mtlTexture = get_texture_from_backend(backendTex);
  457. if (!mtlTexture) {
  458. return nullptr;
  459. }
  460. GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendTex.getBackendFormat(),
  461. grColorType);
  462. SkASSERT(kUnknown_GrPixelConfig != config);
  463. GrSurfaceDesc surfDesc;
  464. init_surface_desc(&surfDesc, mtlTexture, GrRenderable::kNo, config);
  465. return GrMtlTexture::MakeWrappedTexture(this, surfDesc, mtlTexture, cacheable, ioType);
  466. }
  467. sk_sp<GrTexture> GrMtlGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
  468. int sampleCnt,
  469. GrColorType colorType,
  470. GrWrapOwnership,
  471. GrWrapCacheable cacheable) {
  472. id<MTLTexture> mtlTexture = get_texture_from_backend(backendTex);
  473. if (!mtlTexture) {
  474. return nullptr;
  475. }
  476. const GrCaps* caps = this->caps();
  477. GrPixelConfig config = caps->getConfigFromBackendFormat(backendTex.getBackendFormat(),
  478. colorType);
  479. SkASSERT(kUnknown_GrPixelConfig != config);
  480. GrSurfaceDesc surfDesc;
  481. init_surface_desc(&surfDesc, mtlTexture, GrRenderable::kYes, config);
  482. sampleCnt = caps->getRenderTargetSampleCount(sampleCnt, colorType,
  483. backendTex.getBackendFormat());
  484. if (!sampleCnt) {
  485. return nullptr;
  486. }
  487. return GrMtlTextureRenderTarget::MakeWrappedTextureRenderTarget(this, surfDesc, sampleCnt,
  488. mtlTexture, cacheable);
  489. }
  490. sk_sp<GrRenderTarget> GrMtlGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT,
  491. GrColorType grColorType) {
  492. // TODO: Revisit this when the Metal backend is completed. It may support MSAA render targets.
  493. if (backendRT.sampleCnt() > 1) {
  494. return nullptr;
  495. }
  496. id<MTLTexture> mtlTexture = get_texture_from_backend(backendRT);
  497. if (!mtlTexture) {
  498. return nullptr;
  499. }
  500. GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendRT.getBackendFormat(),
  501. grColorType);
  502. SkASSERT(kUnknown_GrPixelConfig != config);
  503. GrSurfaceDesc surfDesc;
  504. init_surface_desc(&surfDesc, mtlTexture, GrRenderable::kYes, config);
  505. return GrMtlRenderTarget::MakeWrappedRenderTarget(this, surfDesc, backendRT.sampleCnt(),
  506. mtlTexture);
  507. }
  508. sk_sp<GrRenderTarget> GrMtlGpu::onWrapBackendTextureAsRenderTarget(
  509. const GrBackendTexture& backendTex, int sampleCnt, GrColorType grColorType) {
  510. id<MTLTexture> mtlTexture = get_texture_from_backend(backendTex);
  511. if (!mtlTexture) {
  512. return nullptr;
  513. }
  514. GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendTex.getBackendFormat(),
  515. grColorType);
  516. SkASSERT(kUnknown_GrPixelConfig != config);
  517. GrSurfaceDesc surfDesc;
  518. init_surface_desc(&surfDesc, mtlTexture, GrRenderable::kYes, config);
  519. sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, grColorType,
  520. backendTex.getBackendFormat());
  521. if (!sampleCnt) {
  522. return nullptr;
  523. }
  524. return GrMtlRenderTarget::MakeWrappedRenderTarget(this, surfDesc, sampleCnt, mtlTexture);
  525. }
  526. bool GrMtlGpu::onRegenerateMipMapLevels(GrTexture* texture) {
  527. GrMtlTexture* grMtlTexture = static_cast<GrMtlTexture*>(texture);
  528. id<MTLTexture> mtlTexture = grMtlTexture->mtlTexture();
  529. // Automatic mipmap generation is only supported by color-renderable formats
  530. if (!fMtlCaps->isConfigRenderable(texture->config()) &&
  531. // We have pixel configs marked as textureable-only that use RGBA8 as the internal format
  532. MTLPixelFormatRGBA8Unorm != mtlTexture.pixelFormat) {
  533. return false;
  534. }
  535. id<MTLBlitCommandEncoder> blitCmdEncoder = this->commandBuffer()->getBlitCommandEncoder();
  536. [blitCmdEncoder generateMipmapsForTexture: mtlTexture];
  537. return true;
  538. }
  539. bool GrMtlGpu::createTestingOnlyMtlTextureInfo(GrPixelConfig config, MTLPixelFormat format,
  540. int w, int h, bool texturable,
  541. bool renderable, GrMipMapped mipMapped,
  542. const void* srcData, size_t srcRowBytes,
  543. GrMtlTextureInfo* info) {
  544. SkASSERT(texturable || renderable);
  545. if (!texturable) {
  546. SkASSERT(GrMipMapped::kNo == mipMapped);
  547. SkASSERT(!srcData);
  548. }
  549. if (texturable && !fMtlCaps->isConfigTexturable(config)) {
  550. return false;
  551. }
  552. if (renderable && !fMtlCaps->isConfigRenderable(config)) {
  553. return false;
  554. }
  555. // Currently we don't support uploading pixel data when mipped.
  556. if (srcData && GrMipMapped::kYes == mipMapped) {
  557. return false;
  558. }
  559. if(!check_max_blit_width(w)) {
  560. return false;
  561. }
  562. bool mipmapped = mipMapped == GrMipMapped::kYes ? true : false;
  563. MTLTextureDescriptor* desc =
  564. [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: format
  565. width: w
  566. height: h
  567. mipmapped: mipmapped];
  568. desc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
  569. desc.storageMode = MTLStorageModePrivate;
  570. desc.usage = texturable ? MTLTextureUsageShaderRead : 0;
  571. desc.usage |= renderable ? MTLTextureUsageRenderTarget : 0;
  572. id<MTLTexture> testTexture = [fDevice newTextureWithDescriptor: desc];
  573. size_t bpp = GrBytesPerPixel(config);
  574. if (!srcRowBytes) {
  575. srcRowBytes = w * bpp;
  576. #ifdef SK_BUILD_FOR_MAC
  577. if (!srcData) {
  578. // On MacOS, the fillBuffer command needs a range with a multiple of 4 bytes
  579. srcRowBytes = ((srcRowBytes + 3) & (~3));
  580. }
  581. #endif
  582. }
  583. size_t bufferSize = srcRowBytes * h;
  584. NSUInteger options = 0; // TODO: consider other options here
  585. #ifdef SK_BUILD_FOR_MAC
  586. options |= MTLResourceStorageModeManaged;
  587. #else
  588. options |= MTLResourceStorageModeShared;
  589. #endif
  590. // TODO: Create GrMtlTransferBuffer
  591. id<MTLBuffer> transferBuffer;
  592. if (0 == bufferSize) {
  593. return false;
  594. }
  595. if (srcData) {
  596. transferBuffer = [fDevice newBufferWithBytes: srcData
  597. length: bufferSize
  598. options: options];
  599. } else {
  600. transferBuffer = [fDevice newBufferWithLength: bufferSize
  601. options: options];
  602. }
  603. if (nil == transferBuffer) {
  604. return false;
  605. }
  606. id<MTLCommandBuffer> cmdBuffer = [fQueue commandBuffer];
  607. id<MTLBlitCommandEncoder> blitCmdEncoder = [cmdBuffer blitCommandEncoder];
  608. if (!srcData) {
  609. [blitCmdEncoder fillBuffer: transferBuffer
  610. range: NSMakeRange(0, bufferSize)
  611. value: 0];
  612. }
  613. [blitCmdEncoder copyFromBuffer: transferBuffer
  614. sourceOffset: 0
  615. sourceBytesPerRow: srcRowBytes
  616. sourceBytesPerImage: bufferSize
  617. sourceSize: MTLSizeMake(w, h, 1)
  618. toTexture: testTexture
  619. destinationSlice: 0
  620. destinationLevel: 0
  621. destinationOrigin: MTLOriginMake(0, 0, 0)];
  622. [blitCmdEncoder endEncoding];
  623. [cmdBuffer commit];
  624. [cmdBuffer waitUntilCompleted];
  625. transferBuffer = nil;
  626. info->fTexture.reset(GrRetainPtrFromId(testTexture));
  627. return true;
  628. }
  629. static bool mtl_format_to_pixel_config(MTLPixelFormat format, GrPixelConfig* config) {
  630. GrPixelConfig dontCare;
  631. if (!config) {
  632. config = &dontCare;
  633. }
  634. switch (format) {
  635. case MTLPixelFormatInvalid:
  636. *config = kUnknown_GrPixelConfig;
  637. return false;
  638. case MTLPixelFormatRGBA8Unorm:
  639. *config = kRGBA_8888_GrPixelConfig;
  640. return true;
  641. case MTLPixelFormatRG8Unorm:
  642. *config = kRG_88_GrPixelConfig;
  643. return true;
  644. case MTLPixelFormatBGRA8Unorm:
  645. *config = kBGRA_8888_GrPixelConfig;
  646. return true;
  647. case MTLPixelFormatRGBA8Unorm_sRGB:
  648. *config = kSRGBA_8888_GrPixelConfig;
  649. return true;
  650. case MTLPixelFormatRGB10A2Unorm:
  651. *config = kRGBA_1010102_GrPixelConfig;
  652. return true;
  653. #ifdef SK_BUILD_FOR_IOS
  654. case MTLPixelFormatB5G6R5Unorm:
  655. *config = kRGB_565_GrPixelConfig;
  656. return true;
  657. case MTLPixelFormatABGR4Unorm:
  658. *config = kRGBA_4444_GrPixelConfig;
  659. return true;
  660. #endif
  661. case MTLPixelFormatR8Unorm:
  662. *config = kAlpha_8_GrPixelConfig;
  663. return true;
  664. case MTLPixelFormatRGBA32Float:
  665. *config = kRGBA_float_GrPixelConfig;
  666. return true;
  667. case MTLPixelFormatRGBA16Float:
  668. *config = kRGBA_half_GrPixelConfig;
  669. return true;
  670. case MTLPixelFormatR16Float:
  671. *config = kAlpha_half_GrPixelConfig;
  672. return true;
  673. #ifdef SK_BUILD_FOR_IOS
  674. case MTLPixelFormatETC2_RGB8:
  675. *config = kRGB_ETC1_GrPixelConfig;
  676. return true;
  677. #endif
  678. case MTLPixelFormatR16Unorm:
  679. *config = kR_16_GrPixelConfig;
  680. return true;
  681. case MTLPixelFormatRG16Unorm:
  682. *config = kRG_1616_GrPixelConfig;
  683. return true;
  684. // Experimental (for Y416 and mutant P016/P010)
  685. case MTLPixelFormatRGBA16Unorm:
  686. *config = kRGBA_16161616_GrPixelConfig;
  687. return true;
  688. case MTLPixelFormatRG16Float:
  689. *config = kRG_half_GrPixelConfig;
  690. return true;
  691. default:
  692. return false;
  693. }
  694. SK_ABORT("Unexpected config");
  695. return false;
  696. }
  697. GrBackendTexture GrMtlGpu::createBackendTexture(int w, int h,
  698. const GrBackendFormat& format,
  699. GrMipMapped mipMapped,
  700. GrRenderable renderable,
  701. const void* pixels, size_t rowBytes,
  702. const SkColor4f* color, GrProtected isProtected) {
  703. if (w > this->caps()->maxTextureSize() || h > this->caps()->maxTextureSize()) {
  704. return GrBackendTexture();
  705. }
  706. const GrMTLPixelFormat* mtlFormat = format.getMtlFormat();
  707. if (!mtlFormat) {
  708. return GrBackendTexture();
  709. }
  710. GrPixelConfig config;
  711. if (!mtl_format_to_pixel_config(static_cast<MTLPixelFormat>(*mtlFormat), &config)) {
  712. return GrBackendTexture();
  713. }
  714. GrMtlTextureInfo info;
  715. if (!this->createTestingOnlyMtlTextureInfo(config, static_cast<MTLPixelFormat>(*mtlFormat),
  716. w, h, true,
  717. GrRenderable::kYes == renderable, mipMapped,
  718. pixels, rowBytes, &info)) {
  719. return {};
  720. }
  721. GrBackendTexture backendTex(w, h, mipMapped, info);
  722. backendTex.fConfig = config;
  723. return backendTex;
  724. }
  725. void GrMtlGpu::deleteBackendTexture(const GrBackendTexture& tex) {
  726. SkASSERT(GrBackendApi::kMetal == tex.fBackend);
  727. // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
  728. }
  729. #if GR_TEST_UTILS
  730. bool GrMtlGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
  731. SkASSERT(GrBackendApi::kMetal == tex.backend());
  732. GrMtlTextureInfo info;
  733. if (!tex.getMtlTextureInfo(&info)) {
  734. return false;
  735. }
  736. id<MTLTexture> mtlTexture = GrGetMTLTexture(info.fTexture.get());
  737. if (!mtlTexture) {
  738. return false;
  739. }
  740. return mtlTexture.usage & MTLTextureUsageShaderRead;
  741. }
  742. GrBackendRenderTarget GrMtlGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType ct) {
  743. if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
  744. return GrBackendRenderTarget();
  745. }
  746. GrPixelConfig config = GrColorTypeToPixelConfig(ct);
  747. MTLPixelFormat format;
  748. if (!GrPixelConfigToMTLFormat(config, &format)) {
  749. return GrBackendRenderTarget();
  750. }
  751. GrMtlTextureInfo info;
  752. if (!this->createTestingOnlyMtlTextureInfo(config, format, w, h, false, true,
  753. GrMipMapped::kNo, nullptr, 0, &info)) {
  754. return {};
  755. }
  756. GrBackendRenderTarget backendRT(w, h, 1, info);
  757. backendRT.fConfig = config;
  758. return backendRT;
  759. }
  760. void GrMtlGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
  761. SkASSERT(GrBackendApi::kMetal == rt.fBackend);
  762. GrMtlTextureInfo info;
  763. if (rt.getMtlTextureInfo(&info)) {
  764. this->testingOnly_flushGpuAndSync();
  765. // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
  766. // is deleted.
  767. }
  768. }
  769. void GrMtlGpu::testingOnly_flushGpuAndSync() {
  770. this->submitCommandBuffer(kForce_SyncQueue);
  771. }
  772. #endif // GR_TEST_UTILS
  773. static int get_surface_sample_cnt(GrSurface* surf) {
  774. if (const GrRenderTarget* rt = surf->asRenderTarget()) {
  775. return rt->numSamples();
  776. }
  777. return 0;
  778. }
  779. void GrMtlGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src) {
  780. // TODO: Add support for subrectangles
  781. GrMtlRenderTarget* srcRT = static_cast<GrMtlRenderTarget*>(src->asRenderTarget());
  782. GrRenderTarget* dstRT = dst->asRenderTarget();
  783. id<MTLTexture> dstTexture;
  784. if (dstRT) {
  785. GrMtlRenderTarget* mtlRT = static_cast<GrMtlRenderTarget*>(dstRT);
  786. dstTexture = mtlRT->mtlColorTexture();
  787. } else {
  788. SkASSERT(dst->asTexture());
  789. dstTexture = static_cast<GrMtlTexture*>(dst->asTexture())->mtlTexture();
  790. }
  791. this->resolveTexture(dstTexture, srcRT->mtlColorTexture());
  792. }
  793. void GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
  794. const SkIPoint& dstPoint) {
  795. #ifdef SK_DEBUG
  796. int dstSampleCnt = get_surface_sample_cnt(dst);
  797. int srcSampleCnt = get_surface_sample_cnt(src);
  798. SkASSERT(this->mtlCaps().canCopyAsBlit(dst->config(), dstSampleCnt, src->config(), srcSampleCnt,
  799. srcRect, dstPoint, dst == src));
  800. #endif
  801. id<MTLTexture> dstTex = GrGetMTLTextureFromSurface(dst);
  802. id<MTLTexture> srcTex = GrGetMTLTextureFromSurface(src);
  803. id<MTLBlitCommandEncoder> blitCmdEncoder = this->commandBuffer()->getBlitCommandEncoder();
  804. [blitCmdEncoder copyFromTexture: srcTex
  805. sourceSlice: 0
  806. sourceLevel: 0
  807. sourceOrigin: MTLOriginMake(srcRect.x(), srcRect.y(), 0)
  808. sourceSize: MTLSizeMake(srcRect.width(), srcRect.height(), 1)
  809. toTexture: dstTex
  810. destinationSlice: 0
  811. destinationLevel: 0
  812. destinationOrigin: MTLOriginMake(dstPoint.fX, dstPoint.fY, 0)];
  813. }
  814. bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
  815. const SkIPoint& dstPoint, bool canDiscardOutsideDstRect) {
  816. SkASSERT(!src->isProtected() && !dst->isProtected());
  817. GrPixelConfig dstConfig = dst->config();
  818. GrPixelConfig srcConfig = src->config();
  819. int dstSampleCnt = get_surface_sample_cnt(dst);
  820. int srcSampleCnt = get_surface_sample_cnt(src);
  821. bool success = false;
  822. if (this->mtlCaps().canCopyAsResolve(dst, dstSampleCnt, src, srcSampleCnt, srcRect, dstPoint)) {
  823. this->copySurfaceAsResolve(dst, src);
  824. success = true;
  825. } else if (this->mtlCaps().canCopyAsBlit(dstConfig, dstSampleCnt, srcConfig, srcSampleCnt,
  826. srcRect, dstPoint, dst == src)) {
  827. this->copySurfaceAsBlit(dst, src, srcRect, dstPoint);
  828. success = true;
  829. }
  830. if (success) {
  831. SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.x(), dstPoint.y(),
  832. srcRect.width(), srcRect.height());
  833. // The rect is already in device space so we pass in kTopLeft so no flip is done.
  834. this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
  835. }
  836. return success;
  837. }
  838. bool GrMtlGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
  839. GrColorType srcColorType, const GrMipLevel texels[],
  840. int mipLevelCount) {
  841. GrMtlTexture* mtlTexture = static_cast<GrMtlTexture*>(surface->asTexture());
  842. // TODO: In principle we should be able to support pure rendertargets as well, but
  843. // until we find a use case we'll only support texture rendertargets.
  844. if (!mtlTexture) {
  845. return false;
  846. }
  847. if (!mipLevelCount) {
  848. return false;
  849. }
  850. #ifdef SK_DEBUG
  851. for (int i = 0; i < mipLevelCount; i++) {
  852. SkASSERT(texels[i].fPixels);
  853. }
  854. #endif
  855. return this->uploadToTexture(mtlTexture, left, top, width, height, srcColorType, texels,
  856. mipLevelCount);
  857. }
  858. bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
  859. GrColorType dstColorType, void* buffer, size_t rowBytes) {
  860. SkASSERT(surface);
  861. if (!check_max_blit_width(width)) {
  862. return false;
  863. }
  864. if (GrPixelConfigToColorType(surface->config()) != dstColorType) {
  865. return false;
  866. }
  867. int bpp = GrColorTypeBytesPerPixel(dstColorType);
  868. size_t transBufferRowBytes = bpp * width;
  869. id<MTLTexture> mtlTexture;
  870. GrMtlRenderTarget* rt = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget());
  871. if (rt) {
  872. // resolve the render target if necessary
  873. switch (rt->getResolveType()) {
  874. case GrMtlRenderTarget::kCantResolve_ResolveType:
  875. return false;
  876. case GrMtlRenderTarget::kAutoResolves_ResolveType:
  877. mtlTexture = rt->mtlColorTexture();
  878. break;
  879. case GrMtlRenderTarget::kCanResolve_ResolveType:
  880. this->resolveRenderTargetNoFlush(rt);
  881. mtlTexture = rt->mtlResolveTexture();
  882. break;
  883. default:
  884. SK_ABORT("Unknown resolve type");
  885. }
  886. } else {
  887. GrMtlTexture* texture = static_cast<GrMtlTexture*>(surface->asTexture());
  888. if (texture) {
  889. mtlTexture = texture->mtlTexture();
  890. }
  891. }
  892. if (!mtlTexture) {
  893. return false;
  894. }
  895. size_t transBufferImageBytes = transBufferRowBytes * height;
  896. // TODO: implement some way of reusing buffers instead of making a new one every time.
  897. NSUInteger options = 0;
  898. #ifdef SK_BUILD_FOR_MAC
  899. options |= MTLResourceStorageModeManaged;
  900. #else
  901. options |= MTLResourceStorageModeShared;
  902. #endif
  903. id<MTLBuffer> transferBuffer = [fDevice newBufferWithLength: transBufferImageBytes
  904. options: options];
  905. id<MTLBlitCommandEncoder> blitCmdEncoder = this->commandBuffer()->getBlitCommandEncoder();
  906. [blitCmdEncoder copyFromTexture: mtlTexture
  907. sourceSlice: 0
  908. sourceLevel: 0
  909. sourceOrigin: MTLOriginMake(left, top, 0)
  910. sourceSize: MTLSizeMake(width, height, 1)
  911. toBuffer: transferBuffer
  912. destinationOffset: 0
  913. destinationBytesPerRow: transBufferRowBytes
  914. destinationBytesPerImage: transBufferImageBytes];
  915. #ifdef SK_BUILD_FOR_MAC
  916. // Sync GPU data back to the CPU
  917. [blitCmdEncoder synchronizeResource: transferBuffer];
  918. #endif
  919. this->submitCommandBuffer(kForce_SyncQueue);
  920. const void* mappedMemory = transferBuffer.contents;
  921. SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, transBufferRowBytes, height);
  922. return true;
  923. }
  924. void GrMtlGpu::internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit) {
  925. if (target->needsResolve()) {
  926. this->resolveTexture(static_cast<GrMtlRenderTarget*>(target)->mtlResolveTexture(),
  927. static_cast<GrMtlRenderTarget*>(target)->mtlColorTexture());
  928. target->flagAsResolved();
  929. if (requiresSubmit) {
  930. this->submitCommandBuffer(kSkip_SyncQueue);
  931. }
  932. }
  933. }
  934. void GrMtlGpu::resolveTexture(id<MTLTexture> resolveTexture, id<MTLTexture> colorTexture) {
  935. auto renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
  936. renderPassDesc.colorAttachments[0].texture = colorTexture;
  937. renderPassDesc.colorAttachments[0].slice = 0;
  938. renderPassDesc.colorAttachments[0].level = 0;
  939. renderPassDesc.colorAttachments[0].resolveTexture = resolveTexture;
  940. renderPassDesc.colorAttachments[0].slice = 0;
  941. renderPassDesc.colorAttachments[0].level = 0;
  942. renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionLoad;
  943. renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
  944. id<MTLRenderCommandEncoder> cmdEncoder =
  945. this->commandBuffer()->getRenderCommandEncoder(renderPassDesc, nullptr, nullptr);
  946. SkASSERT(nil != cmdEncoder);
  947. cmdEncoder.label = @"resolveTexture";
  948. }