blob: 5c4ab9c4577c0288800dc5782f84233921a44c86 [file] [log] [blame]
bsalomoned0bcad2015-05-04 10:36:42 -07001/*
2 * Copyright 2015 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 "GrResourceProvider.h"
9
cdalton397536c2016-03-25 12:15:03 -070010#include "GrBuffer.h"
robertphillips5fa7f302016-07-21 09:21:04 -070011#include "GrCaps.h"
Robert Phillips26c90e02017-03-14 14:39:29 -040012#include "GrContext.h"
Robert Phillipse78b7252017-04-06 07:59:41 -040013#include "GrContextPriv.h"
bsalomoned0bcad2015-05-04 10:36:42 -070014#include "GrGpu.h"
kkinnunencabe20c2015-06-01 01:37:26 -070015#include "GrPathRendering.h"
egdanielec00d942015-09-14 12:56:10 -070016#include "GrRenderTarget.h"
17#include "GrRenderTargetPriv.h"
bsalomoned0bcad2015-05-04 10:36:42 -070018#include "GrResourceCache.h"
19#include "GrResourceKey.h"
Greg Danield85f97d2017-03-07 13:37:21 -050020#include "GrSemaphore.h"
egdanielec00d942015-09-14 12:56:10 -070021#include "GrStencilAttachment.h"
Robert Phillipsb66b42f2017-03-14 08:53:02 -040022#include "GrSurfaceProxyPriv.h"
Brian Osman32342f02017-03-04 08:12:46 -050023#include "GrTexturePriv.h"
24#include "../private/GrSingleOwner.h"
halcanary4dbbd042016-06-07 17:21:10 -070025#include "SkMathPriv.h"
bsalomoned0bcad2015-05-04 10:36:42 -070026
27GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
28
Brian Osman32342f02017-03-04 08:12:46 -050029const int GrResourceProvider::kMinScratchTextureSize = 16;
30
31#define ASSERT_SINGLE_OWNER \
32 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
33
joshualitt6d0872d2016-01-11 08:27:48 -080034GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner)
Brian Osman32342f02017-03-04 08:12:46 -050035 : fCache(cache)
36 , fGpu(gpu)
37#ifdef SK_DEBUG
38 , fSingleOwner(owner)
39#endif
40 {
Robert Phillips26c90e02017-03-14 14:39:29 -040041 fCaps = sk_ref_sp(fGpu->caps());
42
bsalomoned0bcad2015-05-04 10:36:42 -070043 GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
44 fQuadIndexBufferKey = gQuadIndexBufferKey;
45}
46
Robert Phillipsf7a72612017-03-31 10:03:45 -040047bool GrResourceProvider::IsFunctionallyExact(GrSurfaceProxy* proxy) {
Robert Phillipsb66b42f2017-03-14 08:53:02 -040048 return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height()));
49}
Brian Osman32342f02017-03-04 08:12:46 -050050
Robert Phillipse78b7252017-04-06 07:59:41 -040051// MDB TODO: this should probably be a factory on GrSurfaceProxy
52sk_sp<GrTextureProxy> GrResourceProvider::createMipMappedTexture(
53 const GrSurfaceDesc& desc,
54 SkBudgeted budgeted,
55 const GrMipLevel* texels,
56 int mipLevelCount,
57 uint32_t flags,
Robert Phillipsa4c41b32017-03-15 13:02:45 -040058 SkDestinationSurfaceColorMode mipColorMode) {
Brian Osman32342f02017-03-04 08:12:46 -050059 ASSERT_SINGLE_OWNER
60
61 if (this->isAbandoned()) {
62 return nullptr;
63 }
64 if (mipLevelCount && !texels) {
65 return nullptr;
66 }
67 for (int i = 0; i < mipLevelCount; ++i) {
68 if (!texels[i].fPixels) {
69 return nullptr;
70 }
71 }
72 if (mipLevelCount > 1 && GrPixelConfigIsSint(desc.fConfig)) {
73 return nullptr;
74 }
75 if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
76 !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
77 return nullptr;
78 }
79 if (!GrPixelConfigIsCompressed(desc.fConfig)) {
80 if (mipLevelCount < 2) {
81 flags |= kExact_Flag | kNoCreate_Flag;
Robert Phillipse78b7252017-04-06 07:59:41 -040082 sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags));
83 if (tex) {
84 sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeWrapped(tex);
Brian Osman32342f02017-03-04 08:12:46 -050085 if (!mipLevelCount ||
Robert Phillipse78b7252017-04-06 07:59:41 -040086 fGpu->getContext()->contextPriv().writeSurfacePixels(
87 proxy.get(), nullptr, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
88 nullptr, texels[0].fPixels, texels[0].fRowBytes)) {
Brian Osman32342f02017-03-04 08:12:46 -050089 if (SkBudgeted::kNo == budgeted) {
Robert Phillipse78b7252017-04-06 07:59:41 -040090 tex->resourcePriv().makeUnbudgeted();
Brian Osman32342f02017-03-04 08:12:46 -050091 }
Robert Phillipse78b7252017-04-06 07:59:41 -040092 tex->texturePriv().setMipColorMode(mipColorMode);
93 return proxy;
Brian Osman32342f02017-03-04 08:12:46 -050094 }
Brian Osman32342f02017-03-04 08:12:46 -050095 }
96 }
97 }
98
99 SkTArray<GrMipLevel> texelsShallowCopy(mipLevelCount);
100 for (int i = 0; i < mipLevelCount; ++i) {
101 texelsShallowCopy.push_back(texels[i]);
102 }
Robert Phillipse78b7252017-04-06 07:59:41 -0400103 sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted, texelsShallowCopy));
104 if (tex) {
105 tex->texturePriv().setMipColorMode(mipColorMode);
Robert Phillipsa4c41b32017-03-15 13:02:45 -0400106 }
Robert Phillipse78b7252017-04-06 07:59:41 -0400107
108 return GrSurfaceProxy::MakeWrapped(std::move(tex));
Brian Osman32342f02017-03-04 08:12:46 -0500109}
110
Robert Phillipse78b7252017-04-06 07:59:41 -0400111sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
112 uint32_t flags) {
113 ASSERT_SINGLE_OWNER
114
115 if (this->isAbandoned()) {
116 return nullptr;
Brian Osman32342f02017-03-04 08:12:46 -0500117 }
Robert Phillipse78b7252017-04-06 07:59:41 -0400118
119 if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
120 !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
121 return nullptr;
122 }
123
124 if (!GrPixelConfigIsCompressed(desc.fConfig)) {
125 flags |= kExact_Flag | kNoCreate_Flag;
126 sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags));
127 if (tex) {
128 if (SkBudgeted::kNo == budgeted) {
129 tex->resourcePriv().makeUnbudgeted();
130 }
131 return tex;
132 }
133 }
134
135 sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted));
136 return tex;
Brian Osman32342f02017-03-04 08:12:46 -0500137}
138
139GrTexture* GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, uint32_t flags) {
140 ASSERT_SINGLE_OWNER
141 SkASSERT(0 == flags || kNoPendingIO_Flag == flags);
142 return this->internalCreateApproxTexture(desc, flags);
143}
144
145GrTexture* GrResourceProvider::internalCreateApproxTexture(const GrSurfaceDesc& desc,
146 uint32_t scratchFlags) {
147 ASSERT_SINGLE_OWNER
148 if (this->isAbandoned()) {
149 return nullptr;
150 }
151 // Currently we don't recycle compressed textures as scratch.
152 if (GrPixelConfigIsCompressed(desc.fConfig)) {
153 return nullptr;
154 } else {
155 return this->refScratchTexture(desc, scratchFlags);
156 }
157}
158
159GrTexture* GrResourceProvider::refScratchTexture(const GrSurfaceDesc& inDesc,
160 uint32_t flags) {
161 ASSERT_SINGLE_OWNER
162 SkASSERT(!this->isAbandoned());
163 SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
164
165 SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
166
167 if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
168 if (!(kExact_Flag & flags)) {
169 // bin by pow2 with a reasonable min
170 GrSurfaceDesc* wdesc = desc.writable();
171 wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fWidth));
172 wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fHeight));
173 }
174
175 GrScratchKey key;
176 GrTexturePriv::ComputeScratchKey(*desc, &key);
177 uint32_t scratchFlags = 0;
178 if (kNoPendingIO_Flag & flags) {
179 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
180 } else if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
181 // If it is not a render target then it will most likely be populated by
182 // writePixels() which will trigger a flush if the texture has pending IO.
183 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
184 }
185 GrGpuResource* resource = fCache->findAndRefScratchResource(key,
186 GrSurface::WorstCaseSize(*desc),
187 scratchFlags);
188 if (resource) {
189 GrSurface* surface = static_cast<GrSurface*>(resource);
190 GrRenderTarget* rt = surface->asRenderTarget();
191 if (rt && fGpu->caps()->discardRenderTargetSupport()) {
192 rt->discard();
193 }
194 return surface->asTexture();
195 }
196 }
197
198 if (!(kNoCreate_Flag & flags)) {
199 return fGpu->createTexture(*desc, SkBudgeted::kYes);
200 }
201
202 return nullptr;
203}
204
205sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTextureDesc& desc,
206 GrWrapOwnership ownership) {
207 ASSERT_SINGLE_OWNER
208 if (this->isAbandoned()) {
209 return nullptr;
210 }
211 return fGpu->wrapBackendTexture(desc, ownership);
212}
213
214sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
215 const GrBackendRenderTargetDesc& desc)
216{
217 ASSERT_SINGLE_OWNER
Brian Osman0b791f52017-03-10 08:30:22 -0500218 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(desc);
Brian Osman32342f02017-03-04 08:12:46 -0500219}
220
221void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
222 GrGpuResource* resource) {
223 ASSERT_SINGLE_OWNER
224 if (this->isAbandoned() || !resource) {
225 return;
226 }
227 resource->resourcePriv().setUniqueKey(key);
228}
229
230GrGpuResource* GrResourceProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) {
231 ASSERT_SINGLE_OWNER
232 return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key);
233}
234
235GrTexture* GrResourceProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) {
236 ASSERT_SINGLE_OWNER
237 GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key);
238 if (resource) {
239 GrTexture* texture = static_cast<GrSurface*>(resource)->asTexture();
240 SkASSERT(texture);
241 return texture;
242 }
243 return NULL;
244}
245
Robert Phillipsd3749482017-03-14 09:17:43 -0400246// MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
247void GrResourceProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
248 ASSERT_SINGLE_OWNER
249 SkASSERT(key.isValid());
250 if (this->isAbandoned() || !proxy) {
251 return;
252 }
253
254 GrTexture* texture = proxy->instantiate(this);
255 if (!texture) {
256 return;
257 }
258
259 this->assignUniqueKeyToResource(key, texture);
260}
261
262// MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
263sk_sp<GrTextureProxy> GrResourceProvider::findProxyByUniqueKey(const GrUniqueKey& key) {
264 ASSERT_SINGLE_OWNER
265
266 sk_sp<GrTexture> texture(this->findAndRefTextureByUniqueKey(key));
267 if (!texture) {
268 return nullptr;
269 }
270
271 return GrSurfaceProxy::MakeWrapped(std::move(texture));
272}
273
cdalton397536c2016-03-25 12:15:03 -0700274const GrBuffer* GrResourceProvider::createInstancedIndexBuffer(const uint16_t* pattern,
275 int patternSize,
276 int reps,
277 int vertCount,
278 const GrUniqueKey& key) {
bsalomoned0bcad2015-05-04 10:36:42 -0700279 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
280
Brian Salomon09d994e2016-12-21 11:14:46 -0500281 // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO.
cdaltone2e71c22016-04-07 18:13:29 -0700282 GrBuffer* buffer = this->createBuffer(bufferSize, kIndex_GrBufferType, kStatic_GrAccessPattern,
cdalton397536c2016-03-25 12:15:03 -0700283 kNoPendingIO_Flag);
bsalomoned0bcad2015-05-04 10:36:42 -0700284 if (!buffer) {
halcanary96fcdcc2015-08-27 07:41:13 -0700285 return nullptr;
bsalomoned0bcad2015-05-04 10:36:42 -0700286 }
287 uint16_t* data = (uint16_t*) buffer->map();
halcanary96fcdcc2015-08-27 07:41:13 -0700288 bool useTempData = (nullptr == data);
bsalomoned0bcad2015-05-04 10:36:42 -0700289 if (useTempData) {
halcanary385fe4d2015-08-26 13:07:48 -0700290 data = new uint16_t[reps * patternSize];
bsalomoned0bcad2015-05-04 10:36:42 -0700291 }
292 for (int i = 0; i < reps; ++i) {
293 int baseIdx = i * patternSize;
294 uint16_t baseVert = (uint16_t)(i * vertCount);
295 for (int j = 0; j < patternSize; ++j) {
296 data[baseIdx+j] = baseVert + pattern[j];
297 }
298 }
299 if (useTempData) {
300 if (!buffer->updateData(data, bufferSize)) {
301 buffer->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700302 return nullptr;
bsalomoned0bcad2015-05-04 10:36:42 -0700303 }
halcanary385fe4d2015-08-26 13:07:48 -0700304 delete[] data;
bsalomoned0bcad2015-05-04 10:36:42 -0700305 } else {
306 buffer->unmap();
307 }
308 this->assignUniqueKeyToResource(key, buffer);
309 return buffer;
310}
311
cdalton397536c2016-03-25 12:15:03 -0700312const GrBuffer* GrResourceProvider::createQuadIndexBuffer() {
bsalomoned0bcad2015-05-04 10:36:42 -0700313 static const int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1;
314 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
315 static const uint16_t kPattern[] = { 0, 1, 2, 0, 2, 3 };
316
317 return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
318}
319
bsalomon6663acf2016-05-10 09:14:17 -0700320GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
bsalomon706f08f2015-05-22 07:35:58 -0700321 SkASSERT(this->gpu()->pathRendering());
bsalomon6663acf2016-05-10 09:14:17 -0700322 return this->gpu()->pathRendering()->createPath(path, style);
bsalomon706f08f2015-05-22 07:35:58 -0700323}
324
325GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
bsalomon6663acf2016-05-10 09:14:17 -0700326 const GrStyle& style) {
bsalomon706f08f2015-05-22 07:35:58 -0700327 SkASSERT(this->gpu()->pathRendering());
bsalomon6663acf2016-05-10 09:14:17 -0700328 return this->gpu()->pathRendering()->createPathRange(gen, style);
bsalomon706f08f2015-05-22 07:35:58 -0700329}
330
reeda9322c22016-04-12 06:47:05 -0700331GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf,
332 const SkScalerContextEffects& effects,
333 const SkDescriptor* desc,
bsalomon6663acf2016-05-10 09:14:17 -0700334 const GrStyle& style) {
bsalomon706f08f2015-05-22 07:35:58 -0700335
336 SkASSERT(this->gpu()->pathRendering());
bsalomon6663acf2016-05-10 09:14:17 -0700337 return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style);
bsalomon706f08f2015-05-22 07:35:58 -0700338}
339
cdaltone2e71c22016-04-07 18:13:29 -0700340GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
cdalton1bf3e712016-04-19 10:00:02 -0700341 GrAccessPattern accessPattern, uint32_t flags,
342 const void* data) {
robertphillips1b8e1b52015-06-24 06:54:10 -0700343 if (this->isAbandoned()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700344 return nullptr;
robertphillips1b8e1b52015-06-24 06:54:10 -0700345 }
cdaltond37fe762016-04-21 07:41:50 -0700346 if (kDynamic_GrAccessPattern != accessPattern) {
347 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
348 }
csmartdalton485a1202016-07-13 10:16:32 -0700349 if (!(flags & kRequireGpuMemory_Flag) &&
350 this->gpu()->caps()->preferClientSideDynamicBuffers() &&
351 GrBufferTypeIsVertexOrIndex(intendedType) &&
352 kDynamic_GrAccessPattern == accessPattern) {
353 return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data);
354 }
robertphillips1b8e1b52015-06-24 06:54:10 -0700355
cdaltond37fe762016-04-21 07:41:50 -0700356 // bin by pow2 with a reasonable min
Robert Phillips9e380472016-10-28 12:15:03 -0400357 static const size_t MIN_SIZE = 1 << 12;
358 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
robertphillips1b8e1b52015-06-24 06:54:10 -0700359
cdaltond37fe762016-04-21 07:41:50 -0700360 GrScratchKey key;
csmartdalton485a1202016-07-13 10:16:32 -0700361 GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
cdaltond37fe762016-04-21 07:41:50 -0700362 uint32_t scratchFlags = 0;
363 if (flags & kNoPendingIO_Flag) {
364 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
365 } else {
366 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
367 }
368 GrBuffer* buffer = static_cast<GrBuffer*>(
369 this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags));
370 if (!buffer) {
371 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
372 if (!buffer) {
373 return nullptr;
robertphillips1b8e1b52015-06-24 06:54:10 -0700374 }
375 }
cdaltond37fe762016-04-21 07:41:50 -0700376 if (data) {
377 buffer->updateData(data, size);
378 }
csmartdalton485a1202016-07-13 10:16:32 -0700379 SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs.
cdaltond37fe762016-04-21 07:41:50 -0700380 return buffer;
jvanverth17aa0472016-01-05 10:41:27 -0800381}
382
egdanielec00d942015-09-14 12:56:10 -0700383GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
384 SkASSERT(rt);
385 if (rt->renderTargetPriv().getStencilAttachment()) {
386 return rt->renderTargetPriv().getStencilAttachment();
387 }
388
389 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
390 GrUniqueKey sbKey;
391
392 int width = rt->width();
393 int height = rt->height();
394#if 0
395 if (this->caps()->oversizedStencilSupport()) {
396 width = SkNextPow2(width);
397 height = SkNextPow2(height);
398 }
399#endif
400 bool newStencil = false;
401 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
402 rt->numStencilSamples(), &sbKey);
403 GrStencilAttachment* stencil = static_cast<GrStencilAttachment*>(
404 this->findAndRefResourceByUniqueKey(sbKey));
405 if (!stencil) {
406 // Need to try and create a new stencil
407 stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height);
408 if (stencil) {
Robert Phillipsf7cf81a2017-03-02 10:23:52 -0500409 this->assignUniqueKeyToResource(sbKey, stencil);
egdanielec00d942015-09-14 12:56:10 -0700410 newStencil = true;
411 }
412 }
413 if (rt->renderTargetPriv().attachStencilAttachment(stencil)) {
414 if (newStencil) {
415 // Right now we're clearing the stencil attachment here after it is
bsalomon7ea33f52015-11-22 14:51:00 -0800416 // attached to a RT for the first time. When we start matching
egdanielec00d942015-09-14 12:56:10 -0700417 // stencil buffers with smaller color targets this will no longer
418 // be correct because it won't be guaranteed to clear the entire
419 // sb.
420 // We used to clear down in the GL subclass using a special purpose
421 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
422 // FBO status.
423 this->gpu()->clearStencil(rt);
424 }
425 }
426 }
427 return rt->renderTargetPriv().getStencilAttachment();
428}
429
bungeman6bd52842016-10-27 09:30:08 -0700430sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
431 const GrBackendTextureDesc& desc)
432{
ericrkf7b8b8a2016-02-24 14:49:51 -0800433 if (this->isAbandoned()) {
434 return nullptr;
435 }
kkinnunen49c4c222016-04-01 04:50:37 -0700436 return this->gpu()->wrapBackendTextureAsRenderTarget(desc);
ericrkf7b8b8a2016-02-24 14:49:51 -0800437}
Greg Danield85f97d2017-03-07 13:37:21 -0500438
439sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore() {
440 return fGpu->makeSemaphore();
441}
442
443void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
444 semaphore->resetGpu(fGpu);
445}
446
447void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
448 semaphore->resetGpu(nullptr);
449}