1/* 2 * Copyright 2018 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 8#include "src/gpu/GrDirectContextPriv.h" 9#include "src/gpu/GrResourceProvider.h" 10#include "src/gpu/mtl/GrMtlGpu.h" 11#include "src/gpu/mtl/GrMtlTextureRenderTarget.h" 12#include "src/gpu/mtl/GrMtlUtil.h" 13 14#if !__has_feature(objc_arc) 15#error This file must be compiled with Arc. Use -fobjc-arc flag 16#endif 17 18GR_NORETAIN_BEGIN 19 20GrMtlTextureRenderTarget::GrMtlTextureRenderTarget(GrMtlGpu* gpu, 21 SkBudgeted budgeted, 22 SkISize dimensions, 23 sk_sp<GrMtlAttachment> texture, 24 sk_sp<GrMtlAttachment> colorAttachment, 25 sk_sp<GrMtlAttachment> resolveAttachment, 26 GrMipmapStatus mipmapStatus) 27 : GrSurface(gpu, dimensions, GrProtected::kNo) 28 , GrMtlTexture(gpu, dimensions, std::move(texture), mipmapStatus) 29 , GrMtlRenderTarget(gpu, dimensions, std::move(colorAttachment), 30 std::move(resolveAttachment)) { 31 this->registerWithCache(budgeted); 32} 33 34GrMtlTextureRenderTarget::GrMtlTextureRenderTarget(GrMtlGpu* gpu, 35 SkISize dimensions, 36 sk_sp<GrMtlAttachment> texture, 37 sk_sp<GrMtlAttachment> colorAttachment, 38 sk_sp<GrMtlAttachment> resolveAttachment, 39 GrMipmapStatus mipmapStatus, 40 GrWrapCacheable cacheable) 41 : GrSurface(gpu, dimensions, GrProtected::kNo) 42 , GrMtlTexture(gpu, dimensions, std::move(texture), mipmapStatus) 43 , GrMtlRenderTarget(gpu, dimensions, std::move(colorAttachment), 44 std::move(resolveAttachment)) { 45 this->registerWithCacheWrapped(cacheable); 46} 47 48bool create_rt_attachments(GrMtlGpu* gpu, SkISize dimensions, MTLPixelFormat format, int sampleCnt, 49 sk_sp<GrMtlAttachment> texture, sk_sp<GrMtlAttachment>* colorAttachment, 50 sk_sp<GrMtlAttachment>* resolveAttachment) { 51 if (sampleCnt > 1) { 52 auto rp = gpu->getContext()->priv().resourceProvider(); 53 sk_sp<GrAttachment> msaaAttachment = rp->makeMSAAAttachment( 54 dimensions, GrBackendFormat::MakeMtl(format), sampleCnt, GrProtected::kNo, 55 GrMemoryless::kNo); 56 if (!msaaAttachment) { 57 return false; 58 } 59 *colorAttachment = 60 sk_sp<GrMtlAttachment>(static_cast<GrMtlAttachment*>(msaaAttachment.release())); 61 *resolveAttachment = std::move(texture); 62 } else { 63 *colorAttachment = std::move(texture); 64 } 65 return true; 66} 67 68sk_sp<GrMtlTextureRenderTarget> GrMtlTextureRenderTarget::MakeNewTextureRenderTarget( 69 GrMtlGpu* gpu, 70 SkBudgeted budgeted, 71 SkISize dimensions, 72 int sampleCnt, 73 MTLPixelFormat format, 74 uint32_t mipLevels, 75 GrMipmapStatus mipmapStatus) { 76 sk_sp<GrMtlAttachment> textureAttachment = 77 GrMtlAttachment::MakeTexture(gpu, dimensions, format, mipLevels, GrRenderable::kYes, 78 /*numSamples=*/1, budgeted); 79 if (!textureAttachment) { 80 return nullptr; 81 } 82 if (@available(macOS 10.11, iOS 9.0, *)) { 83 SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & 84 textureAttachment->mtlTexture().usage); 85 } 86 87 sk_sp<GrMtlAttachment> colorAttachment; 88 sk_sp<GrMtlAttachment> resolveAttachment; 89 if (!create_rt_attachments(gpu, dimensions, format, sampleCnt, textureAttachment, 90 &colorAttachment, &resolveAttachment)) { 91 return nullptr; 92 } 93 SkASSERT(colorAttachment); 94 SkASSERT(sampleCnt == 1 || resolveAttachment); 95 96 return sk_sp<GrMtlTextureRenderTarget>(new GrMtlTextureRenderTarget( 97 gpu, budgeted, dimensions, std::move(textureAttachment), std::move(colorAttachment), 98 std::move(resolveAttachment), mipmapStatus)); 99} 100 101sk_sp<GrMtlTextureRenderTarget> GrMtlTextureRenderTarget::MakeWrappedTextureRenderTarget( 102 GrMtlGpu* gpu, 103 SkISize dimensions, 104 int sampleCnt, 105 id<MTLTexture> texture, 106 GrWrapCacheable cacheable) { 107 SkASSERT(nil != texture); 108 if (@available(macOS 10.11, iOS 9.0, *)) { 109 SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & texture.usage); 110 } 111 GrMipmapStatus mipmapStatus = texture.mipmapLevelCount > 1 112 ? GrMipmapStatus::kDirty 113 : GrMipmapStatus::kNotAllocated; 114 GrAttachment::UsageFlags textureUsageFlags = GrAttachment::UsageFlags::kTexture | 115 GrAttachment::UsageFlags::kColorAttachment; 116 sk_sp<GrMtlAttachment> textureAttachment = 117 GrMtlAttachment::MakeWrapped(gpu, dimensions, texture, textureUsageFlags, cacheable); 118 if (!textureAttachment) { 119 return nullptr; 120 } 121 122 sk_sp<GrMtlAttachment> colorAttachment; 123 sk_sp<GrMtlAttachment> resolveAttachment; 124 if (!create_rt_attachments(gpu, dimensions, texture.pixelFormat, sampleCnt, textureAttachment, 125 &colorAttachment, &resolveAttachment)) { 126 return nullptr; 127 } 128 SkASSERT(colorAttachment); 129 SkASSERT(sampleCnt == 1 || resolveAttachment); 130 131 return sk_sp<GrMtlTextureRenderTarget>(new GrMtlTextureRenderTarget( 132 gpu, dimensions, std::move(textureAttachment), std::move(colorAttachment), 133 std::move(resolveAttachment), mipmapStatus, cacheable)); 134} 135 136size_t GrMtlTextureRenderTarget::onGpuMemorySize() const { 137 // The GrTexture[RenderTarget] is built up by a bunch of attachments each of which are their 138 // own GrGpuResource. Ideally the GrRenderTarget would not be a GrGpuResource and the GrTexture 139 // would just merge with the new GrSurface/Attachment world. Then we could just depend on each 140 // attachment to give its own size since we don't have GrGpuResources owning other 141 // GrGpuResources. Until we get to that point we need to live in some hybrid world. We will let 142 // the msaa and stencil attachments track their own size because they do get cached separately. 143 // For all GrTexture* based things we will continue to to use the GrTexture* to report size and 144 // the owned attachments will have no size and be uncached. 145#ifdef SK_DEBUG 146 // The nonMSAA attachment (either color or resolve depending on numSamples should have size of 147 // zero since it is a texture attachment. 148 SkASSERT(this->nonMSAAAttachment()->gpuMemorySize() == 0); 149 if (this->numSamples() > 1) { 150 // Msaa attachment should have a valid size 151 SkASSERT(this->colorAttachment()->gpuMemorySize() == 152 GrSurface::ComputeSize(this->backendFormat(), this->dimensions(), 153 this->numSamples(), GrMipMapped::kNo)); 154 } 155#endif 156 return GrSurface::ComputeSize(this->backendFormat(), this->dimensions(), 157 1 /*colorSamplesPerPixel*/, this->mipmapped()); 158} 159 160GR_NORETAIN_END 161