blob: dafa27bcf2562852b4e86c340e6eee82874fec74 [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);
Brian Osman32342f02017-03-04 08:12:46 -0500142
Brian Osman32342f02017-03-04 08:12:46 -0500143 if (this->isAbandoned()) {
144 return nullptr;
145 }
146 // Currently we don't recycle compressed textures as scratch.
147 if (GrPixelConfigIsCompressed(desc.fConfig)) {
148 return nullptr;
149 } else {
Robert Phillipsb9a02a12017-04-06 11:08:40 -0400150 return this->refScratchTexture(desc, flags);
Brian Osman32342f02017-03-04 08:12:46 -0500151 }
152}
153
154GrTexture* GrResourceProvider::refScratchTexture(const GrSurfaceDesc& inDesc,
155 uint32_t flags) {
156 ASSERT_SINGLE_OWNER
157 SkASSERT(!this->isAbandoned());
158 SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
159
160 SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
161
162 if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
163 if (!(kExact_Flag & flags)) {
164 // bin by pow2 with a reasonable min
165 GrSurfaceDesc* wdesc = desc.writable();
166 wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fWidth));
167 wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fHeight));
168 }
169
170 GrScratchKey key;
171 GrTexturePriv::ComputeScratchKey(*desc, &key);
172 uint32_t scratchFlags = 0;
173 if (kNoPendingIO_Flag & flags) {
174 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
175 } else if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
176 // If it is not a render target then it will most likely be populated by
177 // writePixels() which will trigger a flush if the texture has pending IO.
178 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
179 }
180 GrGpuResource* resource = fCache->findAndRefScratchResource(key,
181 GrSurface::WorstCaseSize(*desc),
182 scratchFlags);
183 if (resource) {
184 GrSurface* surface = static_cast<GrSurface*>(resource);
185 GrRenderTarget* rt = surface->asRenderTarget();
186 if (rt && fGpu->caps()->discardRenderTargetSupport()) {
187 rt->discard();
188 }
189 return surface->asTexture();
190 }
191 }
192
193 if (!(kNoCreate_Flag & flags)) {
194 return fGpu->createTexture(*desc, SkBudgeted::kYes);
195 }
196
197 return nullptr;
198}
199
200sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTextureDesc& desc,
201 GrWrapOwnership ownership) {
202 ASSERT_SINGLE_OWNER
203 if (this->isAbandoned()) {
204 return nullptr;
205 }
206 return fGpu->wrapBackendTexture(desc, ownership);
207}
208
209sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
210 const GrBackendRenderTargetDesc& desc)
211{
212 ASSERT_SINGLE_OWNER
Brian Osman0b791f52017-03-10 08:30:22 -0500213 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(desc);
Brian Osman32342f02017-03-04 08:12:46 -0500214}
215
216void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
217 GrGpuResource* resource) {
218 ASSERT_SINGLE_OWNER
219 if (this->isAbandoned() || !resource) {
220 return;
221 }
222 resource->resourcePriv().setUniqueKey(key);
223}
224
225GrGpuResource* GrResourceProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) {
226 ASSERT_SINGLE_OWNER
227 return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key);
228}
229
230GrTexture* GrResourceProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) {
231 ASSERT_SINGLE_OWNER
232 GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key);
233 if (resource) {
234 GrTexture* texture = static_cast<GrSurface*>(resource)->asTexture();
235 SkASSERT(texture);
236 return texture;
237 }
238 return NULL;
239}
240
Robert Phillipsd3749482017-03-14 09:17:43 -0400241// MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
242void GrResourceProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
243 ASSERT_SINGLE_OWNER
244 SkASSERT(key.isValid());
245 if (this->isAbandoned() || !proxy) {
246 return;
247 }
248
249 GrTexture* texture = proxy->instantiate(this);
250 if (!texture) {
251 return;
252 }
253
254 this->assignUniqueKeyToResource(key, texture);
255}
256
257// MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
258sk_sp<GrTextureProxy> GrResourceProvider::findProxyByUniqueKey(const GrUniqueKey& key) {
259 ASSERT_SINGLE_OWNER
260
261 sk_sp<GrTexture> texture(this->findAndRefTextureByUniqueKey(key));
262 if (!texture) {
263 return nullptr;
264 }
265
266 return GrSurfaceProxy::MakeWrapped(std::move(texture));
267}
268
cdalton397536c2016-03-25 12:15:03 -0700269const GrBuffer* GrResourceProvider::createInstancedIndexBuffer(const uint16_t* pattern,
270 int patternSize,
271 int reps,
272 int vertCount,
273 const GrUniqueKey& key) {
bsalomoned0bcad2015-05-04 10:36:42 -0700274 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
275
Brian Salomon09d994e2016-12-21 11:14:46 -0500276 // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO.
cdaltone2e71c22016-04-07 18:13:29 -0700277 GrBuffer* buffer = this->createBuffer(bufferSize, kIndex_GrBufferType, kStatic_GrAccessPattern,
cdalton397536c2016-03-25 12:15:03 -0700278 kNoPendingIO_Flag);
bsalomoned0bcad2015-05-04 10:36:42 -0700279 if (!buffer) {
halcanary96fcdcc2015-08-27 07:41:13 -0700280 return nullptr;
bsalomoned0bcad2015-05-04 10:36:42 -0700281 }
282 uint16_t* data = (uint16_t*) buffer->map();
halcanary96fcdcc2015-08-27 07:41:13 -0700283 bool useTempData = (nullptr == data);
bsalomoned0bcad2015-05-04 10:36:42 -0700284 if (useTempData) {
halcanary385fe4d2015-08-26 13:07:48 -0700285 data = new uint16_t[reps * patternSize];
bsalomoned0bcad2015-05-04 10:36:42 -0700286 }
287 for (int i = 0; i < reps; ++i) {
288 int baseIdx = i * patternSize;
289 uint16_t baseVert = (uint16_t)(i * vertCount);
290 for (int j = 0; j < patternSize; ++j) {
291 data[baseIdx+j] = baseVert + pattern[j];
292 }
293 }
294 if (useTempData) {
295 if (!buffer->updateData(data, bufferSize)) {
296 buffer->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700297 return nullptr;
bsalomoned0bcad2015-05-04 10:36:42 -0700298 }
halcanary385fe4d2015-08-26 13:07:48 -0700299 delete[] data;
bsalomoned0bcad2015-05-04 10:36:42 -0700300 } else {
301 buffer->unmap();
302 }
303 this->assignUniqueKeyToResource(key, buffer);
304 return buffer;
305}
306
cdalton397536c2016-03-25 12:15:03 -0700307const GrBuffer* GrResourceProvider::createQuadIndexBuffer() {
bsalomoned0bcad2015-05-04 10:36:42 -0700308 static const int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1;
309 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
310 static const uint16_t kPattern[] = { 0, 1, 2, 0, 2, 3 };
311
312 return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
313}
314
bsalomon6663acf2016-05-10 09:14:17 -0700315GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
bsalomon706f08f2015-05-22 07:35:58 -0700316 SkASSERT(this->gpu()->pathRendering());
bsalomon6663acf2016-05-10 09:14:17 -0700317 return this->gpu()->pathRendering()->createPath(path, style);
bsalomon706f08f2015-05-22 07:35:58 -0700318}
319
320GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
bsalomon6663acf2016-05-10 09:14:17 -0700321 const GrStyle& style) {
bsalomon706f08f2015-05-22 07:35:58 -0700322 SkASSERT(this->gpu()->pathRendering());
bsalomon6663acf2016-05-10 09:14:17 -0700323 return this->gpu()->pathRendering()->createPathRange(gen, style);
bsalomon706f08f2015-05-22 07:35:58 -0700324}
325
reeda9322c22016-04-12 06:47:05 -0700326GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf,
327 const SkScalerContextEffects& effects,
328 const SkDescriptor* desc,
bsalomon6663acf2016-05-10 09:14:17 -0700329 const GrStyle& style) {
bsalomon706f08f2015-05-22 07:35:58 -0700330
331 SkASSERT(this->gpu()->pathRendering());
bsalomon6663acf2016-05-10 09:14:17 -0700332 return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style);
bsalomon706f08f2015-05-22 07:35:58 -0700333}
334
cdaltone2e71c22016-04-07 18:13:29 -0700335GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
cdalton1bf3e712016-04-19 10:00:02 -0700336 GrAccessPattern accessPattern, uint32_t flags,
337 const void* data) {
robertphillips1b8e1b52015-06-24 06:54:10 -0700338 if (this->isAbandoned()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700339 return nullptr;
robertphillips1b8e1b52015-06-24 06:54:10 -0700340 }
cdaltond37fe762016-04-21 07:41:50 -0700341 if (kDynamic_GrAccessPattern != accessPattern) {
342 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
343 }
csmartdalton485a1202016-07-13 10:16:32 -0700344 if (!(flags & kRequireGpuMemory_Flag) &&
345 this->gpu()->caps()->preferClientSideDynamicBuffers() &&
346 GrBufferTypeIsVertexOrIndex(intendedType) &&
347 kDynamic_GrAccessPattern == accessPattern) {
348 return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data);
349 }
robertphillips1b8e1b52015-06-24 06:54:10 -0700350
cdaltond37fe762016-04-21 07:41:50 -0700351 // bin by pow2 with a reasonable min
Robert Phillips9e380472016-10-28 12:15:03 -0400352 static const size_t MIN_SIZE = 1 << 12;
353 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
robertphillips1b8e1b52015-06-24 06:54:10 -0700354
cdaltond37fe762016-04-21 07:41:50 -0700355 GrScratchKey key;
csmartdalton485a1202016-07-13 10:16:32 -0700356 GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
cdaltond37fe762016-04-21 07:41:50 -0700357 uint32_t scratchFlags = 0;
358 if (flags & kNoPendingIO_Flag) {
359 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
360 } else {
361 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
362 }
363 GrBuffer* buffer = static_cast<GrBuffer*>(
364 this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags));
365 if (!buffer) {
366 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
367 if (!buffer) {
368 return nullptr;
robertphillips1b8e1b52015-06-24 06:54:10 -0700369 }
370 }
cdaltond37fe762016-04-21 07:41:50 -0700371 if (data) {
372 buffer->updateData(data, size);
373 }
csmartdalton485a1202016-07-13 10:16:32 -0700374 SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs.
cdaltond37fe762016-04-21 07:41:50 -0700375 return buffer;
jvanverth17aa0472016-01-05 10:41:27 -0800376}
377
egdanielec00d942015-09-14 12:56:10 -0700378GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
379 SkASSERT(rt);
380 if (rt->renderTargetPriv().getStencilAttachment()) {
381 return rt->renderTargetPriv().getStencilAttachment();
382 }
383
384 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
385 GrUniqueKey sbKey;
386
387 int width = rt->width();
388 int height = rt->height();
389#if 0
390 if (this->caps()->oversizedStencilSupport()) {
391 width = SkNextPow2(width);
392 height = SkNextPow2(height);
393 }
394#endif
395 bool newStencil = false;
396 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
397 rt->numStencilSamples(), &sbKey);
398 GrStencilAttachment* stencil = static_cast<GrStencilAttachment*>(
399 this->findAndRefResourceByUniqueKey(sbKey));
400 if (!stencil) {
401 // Need to try and create a new stencil
402 stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height);
403 if (stencil) {
Robert Phillipsf7cf81a2017-03-02 10:23:52 -0500404 this->assignUniqueKeyToResource(sbKey, stencil);
egdanielec00d942015-09-14 12:56:10 -0700405 newStencil = true;
406 }
407 }
408 if (rt->renderTargetPriv().attachStencilAttachment(stencil)) {
409 if (newStencil) {
410 // Right now we're clearing the stencil attachment here after it is
bsalomon7ea33f52015-11-22 14:51:00 -0800411 // attached to a RT for the first time. When we start matching
egdanielec00d942015-09-14 12:56:10 -0700412 // stencil buffers with smaller color targets this will no longer
413 // be correct because it won't be guaranteed to clear the entire
414 // sb.
415 // We used to clear down in the GL subclass using a special purpose
416 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
417 // FBO status.
418 this->gpu()->clearStencil(rt);
419 }
420 }
421 }
422 return rt->renderTargetPriv().getStencilAttachment();
423}
424
bungeman6bd52842016-10-27 09:30:08 -0700425sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
426 const GrBackendTextureDesc& desc)
427{
ericrkf7b8b8a2016-02-24 14:49:51 -0800428 if (this->isAbandoned()) {
429 return nullptr;
430 }
kkinnunen49c4c222016-04-01 04:50:37 -0700431 return this->gpu()->wrapBackendTextureAsRenderTarget(desc);
ericrkf7b8b8a2016-02-24 14:49:51 -0800432}
Greg Danield85f97d2017-03-07 13:37:21 -0500433
434sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore() {
435 return fGpu->makeSemaphore();
436}
437
438void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
439 semaphore->resetGpu(fGpu);
440}
441
442void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
443 semaphore->resetGpu(nullptr);
444}