1 /*
2  * Copyright 2010 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 
9 #include "GrGpu.h"
10 
11 #include "GrBackendSemaphore.h"
12 #include "GrBackendSurface.h"
13 #include "GrBuffer.h"
14 #include "GrCaps.h"
15 #include "GrContext.h"
16 #include "GrContextPriv.h"
17 #include "GrGpuResourcePriv.h"
18 #include "GrMesh.h"
19 #include "GrPathRendering.h"
20 #include "GrPipeline.h"
21 #include "GrRenderTargetPriv.h"
22 #include "GrResourceCache.h"
23 #include "GrResourceProvider.h"
24 #include "GrSemaphore.h"
25 #include "GrStencilAttachment.h"
26 #include "GrStencilSettings.h"
27 #include "GrSurfacePriv.h"
28 #include "GrTexturePriv.h"
29 #include "GrTracing.h"
30 #include "SkJSONWriter.h"
31 #include "SkMathPriv.h"
32 
33 ////////////////////////////////////////////////////////////////////////////////
34 
GrGpu(GrContext * context)35 GrGpu::GrGpu(GrContext* context)
36     : fResetTimestamp(kExpiredTimestamp+1)
37     , fResetBits(kAll_GrBackendState)
38     , fContext(context) {
39 }
40 
~GrGpu()41 GrGpu::~GrGpu() {}
42 
disconnect(DisconnectType)43 void GrGpu::disconnect(DisconnectType) {}
44 
45 ////////////////////////////////////////////////////////////////////////////////
46 
isACopyNeededForTextureParams(int width,int height,const GrSamplerState & textureParams,GrTextureProducer::CopyParams * copyParams,SkScalar scaleAdjust[2]) const47 bool GrGpu::isACopyNeededForTextureParams(int width, int height,
48                                           const GrSamplerState& textureParams,
49                                           GrTextureProducer::CopyParams* copyParams,
50                                           SkScalar scaleAdjust[2]) const {
51     const GrCaps& caps = *this->caps();
52     if (textureParams.isRepeated() && !caps.npotTextureTileSupport() &&
53         (!SkIsPow2(width) || !SkIsPow2(height))) {
54         SkASSERT(scaleAdjust);
55         copyParams->fWidth = GrNextPow2(width);
56         copyParams->fHeight = GrNextPow2(height);
57         scaleAdjust[0] = ((SkScalar) copyParams->fWidth) / width;
58         scaleAdjust[1] = ((SkScalar) copyParams->fHeight) / height;
59         switch (textureParams.filter()) {
60             case GrSamplerState::Filter::kNearest:
61                 copyParams->fFilter = GrSamplerState::Filter::kNearest;
62                 break;
63             case GrSamplerState::Filter::kBilerp:
64             case GrSamplerState::Filter::kMipMap:
65                 // We are only ever scaling up so no reason to ever indicate kMipMap.
66                 copyParams->fFilter = GrSamplerState::Filter::kBilerp;
67                 break;
68         }
69         return true;
70     }
71     return false;
72 }
73 
createTexture(const GrSurfaceDesc & origDesc,SkBudgeted budgeted,const GrMipLevel texels[],int mipLevelCount)74 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted,
75                                       const GrMipLevel texels[], int mipLevelCount) {
76     GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "createTexture", fContext);
77     GrSurfaceDesc desc = origDesc;
78 
79     GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
80     if (!this->caps()->validateSurfaceDesc(desc, mipMapped)) {
81         return nullptr;
82     }
83 
84     bool isRT = desc.fFlags & kRenderTarget_GrSurfaceFlag;
85     if (isRT) {
86         desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(desc.fSampleCnt, desc.fConfig);
87     }
88     // Attempt to catch un- or wrongly initialized sample counts.
89     SkASSERT(desc.fSampleCnt > 0 && desc.fSampleCnt <= 64);
90 
91     if (mipLevelCount && (desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) {
92         return nullptr;
93     }
94 
95     this->handleDirtyContext();
96     sk_sp<GrTexture> tex = this->onCreateTexture(desc, budgeted, texels, mipLevelCount);
97     if (tex) {
98         if (!this->caps()->reuseScratchTextures() && !isRT) {
99             tex->resourcePriv().removeScratchKey();
100         }
101         fStats.incTextureCreates();
102         if (mipLevelCount) {
103             if (texels[0].fPixels) {
104                 fStats.incTextureUploads();
105             }
106         }
107     }
108     return tex;
109 }
110 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted)111 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted) {
112     return this->createTexture(desc, budgeted, nullptr, 0);
113 }
114 
wrapBackendTexture(const GrBackendTexture & backendTex,GrWrapOwnership ownership)115 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex,
116                                            GrWrapOwnership ownership) {
117     this->handleDirtyContext();
118     if (!this->caps()->isConfigTexturable(backendTex.config())) {
119         return nullptr;
120     }
121     if (backendTex.width() > this->caps()->maxTextureSize() ||
122         backendTex.height() > this->caps()->maxTextureSize()) {
123         return nullptr;
124     }
125     sk_sp<GrTexture> tex = this->onWrapBackendTexture(backendTex, ownership);
126     if (!tex) {
127         return nullptr;
128     }
129     return tex;
130 }
131 
wrapRenderableBackendTexture(const GrBackendTexture & backendTex,int sampleCnt,GrWrapOwnership ownership)132 sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex,
133                                                      int sampleCnt, GrWrapOwnership ownership) {
134     this->handleDirtyContext();
135     if (sampleCnt < 1) {
136         return nullptr;
137     }
138     if (!this->caps()->isConfigTexturable(backendTex.config()) ||
139         !this->caps()->getRenderTargetSampleCount(sampleCnt, backendTex.config())) {
140         return nullptr;
141     }
142 
143     if (backendTex.width() > this->caps()->maxRenderTargetSize() ||
144         backendTex.height() > this->caps()->maxRenderTargetSize()) {
145         return nullptr;
146     }
147     sk_sp<GrTexture> tex = this->onWrapRenderableBackendTexture(backendTex, sampleCnt, ownership);
148     if (!tex) {
149         return nullptr;
150     }
151     SkASSERT(tex->asRenderTarget());
152     return tex;
153 }
154 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)155 sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
156     if (0 == this->caps()->getRenderTargetSampleCount(backendRT.sampleCnt(), backendRT.config())) {
157         return nullptr;
158     }
159     this->handleDirtyContext();
160     return this->onWrapBackendRenderTarget(backendRT);
161 }
162 
wrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,int sampleCnt)163 sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
164                                                               int sampleCnt) {
165     if (0 == this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config())) {
166         return nullptr;
167     }
168     int maxSize = this->caps()->maxTextureSize();
169     if (tex.width() > maxSize || tex.height() > maxSize) {
170         return nullptr;
171     }
172     this->handleDirtyContext();
173     return this->onWrapBackendTextureAsRenderTarget(tex, sampleCnt);
174 }
175 
createBuffer(size_t size,GrBufferType intendedType,GrAccessPattern accessPattern,const void * data)176 GrBuffer* GrGpu::createBuffer(size_t size, GrBufferType intendedType,
177                               GrAccessPattern accessPattern, const void* data) {
178     this->handleDirtyContext();
179     GrBuffer* buffer = this->onCreateBuffer(size, intendedType, accessPattern, data);
180     if (!this->caps()->reuseScratchBuffers()) {
181         buffer->resourcePriv().removeScratchKey();
182     }
183     return buffer;
184 }
185 
copySurface(GrSurface * dst,GrSurfaceOrigin dstOrigin,GrSurface * src,GrSurfaceOrigin srcOrigin,const SkIRect & srcRect,const SkIPoint & dstPoint)186 bool GrGpu::copySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
187                         GrSurface* src, GrSurfaceOrigin srcOrigin,
188                         const SkIRect& srcRect, const SkIPoint& dstPoint) {
189     GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "copySurface", fContext);
190     SkASSERT(dst && src);
191     this->handleDirtyContext();
192     return this->onCopySurface(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint);
193 }
194 
getReadPixelsInfo(GrSurface * srcSurface,GrSurfaceOrigin srcOrigin,int width,int height,size_t rowBytes,GrColorType dstColorType,GrSRGBConversion srgbConversion,DrawPreference * drawPreference,ReadPixelTempDrawInfo * tempDrawInfo)195 bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin, int width,
196                               int height, size_t rowBytes, GrColorType dstColorType,
197                               GrSRGBConversion srgbConversion, DrawPreference* drawPreference,
198                               ReadPixelTempDrawInfo* tempDrawInfo) {
199     SkASSERT(drawPreference);
200     SkASSERT(tempDrawInfo);
201     SkASSERT(srcSurface);
202     SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
203 
204     // We currently do not support reading into the packed formats 565 or 4444 as they are not
205     // required to have read back support on all devices and backends.
206     if (GrColorType::kRGB_565 == dstColorType || GrColorType::kABGR_4444 == dstColorType) {
207         return false;
208     }
209 
210     GrPixelConfig tempSurfaceConfig = kUnknown_GrPixelConfig;
211     // GrGpu::readPixels doesn't do any sRGB conversions, so we must draw if there is one.
212     switch (srgbConversion) {
213         case GrSRGBConversion::kNone:
214             // We support reading from RGBA to just A. In that case there is no sRGB version of the
215             // dst format but we still want to succeed.
216             if (GrColorTypeIsAlphaOnly(dstColorType)) {
217                 tempSurfaceConfig = GrColorTypeToPixelConfig(dstColorType, GrSRGBEncoded::kNo);
218             } else {
219                 tempSurfaceConfig = GrColorTypeToPixelConfig(
220                         dstColorType, GrPixelConfigIsSRGBEncoded(srcSurface->config()));
221             }
222             break;
223         case GrSRGBConversion::kLinearToSRGB:
224             SkASSERT(this->caps()->srgbSupport());
225             tempSurfaceConfig = GrColorTypeToPixelConfig(dstColorType, GrSRGBEncoded::kYes);
226             // Currently we don't expect to make a SRGB encoded surface and then read data from it
227             // such that we treat it as though it were linear and is then converted to sRGB.
228             if (GrPixelConfigIsSRGB(srcSurface->config())) {
229                 return false;
230             }
231             ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
232             break;
233         case GrSRGBConversion::kSRGBToLinear:
234             SkASSERT(this->caps()->srgbSupport());
235             tempSurfaceConfig = GrColorTypeToPixelConfig(dstColorType, GrSRGBEncoded::kNo);
236             // We don't currently support reading sRGB encoded data into linear from a surface
237             // unless it is an sRGB-encoded config. That is likely to change when we need to store
238             // sRGB encoded data in 101010102 and F16 textures. We'll have to provoke the caller to
239             // do the conversion in a shader.
240             if (GrSRGBEncoded::kNo == GrPixelConfigIsSRGBEncoded(srcSurface->config())) {
241                 return false;
242             }
243             ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
244             break;
245     }
246     if (kUnknown_GrPixelConfig == tempSurfaceConfig) {
247         return false;
248     }
249 
250     // Default values for intermediate draws. The intermediate texture config matches the dst's
251     // config, is approx sized to the read rect, no swizzling or spoofing of the dst config.
252     tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag;
253     tempDrawInfo->fTempSurfaceDesc.fWidth = width;
254     tempDrawInfo->fTempSurfaceDesc.fHeight = height;
255     tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
256     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin;  // no CPU y-flip for TL.
257     tempDrawInfo->fTempSurfaceDesc.fConfig = tempSurfaceConfig;
258     tempDrawInfo->fTempSurfaceFit = SkBackingFit::kApprox;
259     tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
260     tempDrawInfo->fReadColorType = dstColorType;
261 
262     if (!this->onGetReadPixelsInfo(srcSurface, srcOrigin, width, height, rowBytes, dstColorType,
263                                    drawPreference, tempDrawInfo)) {
264         return false;
265     }
266 
267     // Check to see if we're going to request that the caller draw when drawing is not possible.
268     if (!srcSurface->asTexture() ||
269         !this->caps()->isConfigRenderable(tempDrawInfo->fTempSurfaceDesc.fConfig)) {
270         // If we don't have a fallback to a straight read then fail.
271         if (kRequireDraw_DrawPreference == *drawPreference) {
272             return false;
273         }
274         *drawPreference = kNoDraw_DrawPreference;
275     }
276 
277     return true;
278 }
279 
getWritePixelsInfo(GrSurface * dstSurface,GrSurfaceOrigin dstOrigin,int width,int height,GrColorType srcColorType,GrSRGBConversion srgbConversion,DrawPreference * drawPreference,WritePixelTempDrawInfo * tempDrawInfo)280 bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin, int width,
281                                int height, GrColorType srcColorType,
282                                GrSRGBConversion srgbConversion, DrawPreference* drawPreference,
283                                WritePixelTempDrawInfo* tempDrawInfo) {
284     SkASSERT(drawPreference);
285     SkASSERT(tempDrawInfo);
286     SkASSERT(dstSurface);
287     SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
288 
289     GrPixelConfig tempSurfaceConfig = kUnknown_GrPixelConfig;
290     // GrGpu::writePixels doesn't do any sRGB conversions, so we must draw if there is one.
291     switch (srgbConversion) {
292         case GrSRGBConversion::kNone:
293             // We support writing just A to a RGBA. In that case there is no sRGB version of the
294             // src format but we still want to succeed.
295             if (GrColorTypeIsAlphaOnly(srcColorType)) {
296                 tempSurfaceConfig = GrColorTypeToPixelConfig(srcColorType, GrSRGBEncoded::kNo);
297             } else {
298                 tempSurfaceConfig = GrColorTypeToPixelConfig(
299                         srcColorType, GrPixelConfigIsSRGBEncoded(dstSurface->config()));
300             }
301             break;
302         case GrSRGBConversion::kLinearToSRGB:
303             SkASSERT(this->caps()->srgbSupport());
304             // This assert goes away when we start referring to CPU data using color type.
305             tempSurfaceConfig = GrColorTypeToPixelConfig(srcColorType, GrSRGBEncoded::kNo);
306             // We don't currently support storing sRGB encoded data in a surface unless it is
307             // an SRGB-encoded config. That is likely to change when we need to store sRGB encoded
308             // data in 101010102 and F16 textures. We'll have to provoke the caller to do the
309             // conversion in a shader.
310             if (!GrPixelConfigIsSRGB(dstSurface->config())) {
311                 return false;
312             }
313             ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
314             break;
315         case GrSRGBConversion::kSRGBToLinear:
316             SkASSERT(this->caps()->srgbSupport());
317             tempSurfaceConfig = GrColorTypeToPixelConfig(srcColorType, GrSRGBEncoded::kYes);
318             // Currently we don't expect to make a SRGB encoded surface and then succeed at
319             // treating it as though it were linear and then convert to sRGB.
320             if (GrSRGBEncoded::kYes == GrPixelConfigIsSRGBEncoded(dstSurface->config())) {
321                 return false;
322             }
323             ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
324             break;
325     }
326     if (kUnknown_GrPixelConfig == tempSurfaceConfig) {
327         return false;
328     }
329 
330     // Default values for intermediate draws. The intermediate texture config matches the dst's
331     // config, is approx sized to the write rect, no swizzling or sppofing of the src config.
332     tempDrawInfo->fTempSurfaceDesc.fFlags = kNone_GrSurfaceFlags;
333     tempDrawInfo->fTempSurfaceDesc.fConfig = tempSurfaceConfig;
334     tempDrawInfo->fTempSurfaceDesc.fWidth = width;
335     tempDrawInfo->fTempSurfaceDesc.fHeight = height;
336     tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
337     tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin;  // no CPU y-flip for TL.
338     tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
339     tempDrawInfo->fWriteColorType = srcColorType;
340 
341     if (!this->onGetWritePixelsInfo(dstSurface, dstOrigin, width, height, srcColorType,
342                                     drawPreference, tempDrawInfo)) {
343         return false;
344     }
345 
346     // Check to see if we're going to request that the caller draw when drawing is not possible.
347     if (!dstSurface->asRenderTarget() ||
348         !this->caps()->isConfigTexturable(tempDrawInfo->fTempSurfaceDesc.fConfig)) {
349         // If we don't have a fallback to a straight upload then fail.
350         if (kRequireDraw_DrawPreference == *drawPreference /*TODO ||
351             !this->caps()->isConfigTexturable(srcConfig)*/) {
352             return false;
353         }
354         *drawPreference = kNoDraw_DrawPreference;
355     }
356     return true;
357 }
358 
readPixels(GrSurface * surface,GrSurfaceOrigin origin,int left,int top,int width,int height,GrColorType dstColorType,void * buffer,size_t rowBytes)359 bool GrGpu::readPixels(GrSurface* surface, GrSurfaceOrigin origin, int left, int top, int width,
360                        int height, GrColorType dstColorType, void* buffer, size_t rowBytes) {
361     SkASSERT(surface);
362 
363     int bpp = GrColorTypeBytesPerPixel(dstColorType);
364     if (!GrSurfacePriv::AdjustReadPixelParams(surface->width(), surface->height(), bpp,
365                                               &left, &top, &width, &height,
366                                               &buffer,
367                                               &rowBytes)) {
368         return false;
369     }
370 
371     this->handleDirtyContext();
372 
373     return this->onReadPixels(surface, origin, left, top, width, height, dstColorType, buffer,
374                               rowBytes);
375 }
376 
writePixels(GrSurface * surface,GrSurfaceOrigin origin,int left,int top,int width,int height,GrColorType srcColorType,const GrMipLevel texels[],int mipLevelCount)377 bool GrGpu::writePixels(GrSurface* surface, GrSurfaceOrigin origin, int left, int top, int width,
378                         int height, GrColorType srcColorType, const GrMipLevel texels[],
379                         int mipLevelCount) {
380     SkASSERT(surface);
381     if (1 == mipLevelCount) {
382         // We require that if we are not mipped, then the write region is contained in the surface
383         SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
384         SkIRect bounds = SkIRect::MakeWH(surface->width(), surface->height());
385         if (!bounds.contains(subRect)) {
386             return false;
387         }
388     } else if (0 != left || 0 != top || width != surface->width() || height != surface->height()) {
389         // We require that if the texels are mipped, than the write region is the entire surface
390         return false;
391     }
392 
393     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
394         if (!texels[currentMipLevel].fPixels ) {
395             return false;
396         }
397     }
398 
399     this->handleDirtyContext();
400     if (this->onWritePixels(surface, origin, left, top, width, height, srcColorType, texels,
401                             mipLevelCount)) {
402         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
403         this->didWriteToSurface(surface, origin, &rect, mipLevelCount);
404         fStats.incTextureUploads();
405         return true;
406     }
407     return false;
408 }
409 
writePixels(GrSurface * surface,GrSurfaceOrigin origin,int left,int top,int width,int height,GrColorType srcColorType,const void * buffer,size_t rowBytes)410 bool GrGpu::writePixels(GrSurface* surface, GrSurfaceOrigin origin, int left, int top, int width,
411                         int height, GrColorType srcColorType, const void* buffer, size_t rowBytes) {
412     GrMipLevel mipLevel = { buffer, rowBytes };
413 
414     return this->writePixels(surface, origin, left, top, width, height, srcColorType, &mipLevel, 1);
415 }
416 
transferPixels(GrTexture * texture,int left,int top,int width,int height,GrColorType bufferColorType,GrBuffer * transferBuffer,size_t offset,size_t rowBytes)417 bool GrGpu::transferPixels(GrTexture* texture, int left, int top, int width, int height,
418                            GrColorType bufferColorType, GrBuffer* transferBuffer, size_t offset,
419                            size_t rowBytes) {
420     SkASSERT(transferBuffer);
421 
422     // We require that the write region is contained in the texture
423     SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
424     SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
425     if (!bounds.contains(subRect)) {
426         return false;
427     }
428 
429     this->handleDirtyContext();
430     if (this->onTransferPixels(texture, left, top, width, height, bufferColorType, transferBuffer,
431                                offset, rowBytes)) {
432         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
433         this->didWriteToSurface(texture, kTopLeft_GrSurfaceOrigin, &rect);
434         fStats.incTransfersToTexture();
435 
436         return true;
437     }
438     return false;
439 }
440 
resolveRenderTarget(GrRenderTarget * target)441 void GrGpu::resolveRenderTarget(GrRenderTarget* target) {
442     SkASSERT(target);
443     this->handleDirtyContext();
444     this->onResolveRenderTarget(target);
445 }
446 
didWriteToSurface(GrSurface * surface,GrSurfaceOrigin origin,const SkIRect * bounds,uint32_t mipLevels) const447 void GrGpu::didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds,
448                               uint32_t mipLevels) const {
449     SkASSERT(surface);
450     // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds.
451     if (nullptr == bounds || !bounds->isEmpty()) {
452         if (GrRenderTarget* target = surface->asRenderTarget()) {
453             SkIRect flippedBounds;
454             if (kBottomLeft_GrSurfaceOrigin == origin && bounds) {
455                 flippedBounds = {bounds->fLeft, surface->height() - bounds->fBottom,
456                                  bounds->fRight, surface->height() - bounds->fTop};
457                 bounds = &flippedBounds;
458             }
459             target->flagAsNeedingResolve(bounds);
460         }
461         GrTexture* texture = surface->asTexture();
462         if (texture && 1 == mipLevels) {
463             texture->texturePriv().markMipMapsDirty();
464         }
465     }
466 }
467 
finishFlush(int numSemaphores,GrBackendSemaphore backendSemaphores[])468 GrSemaphoresSubmitted GrGpu::finishFlush(int numSemaphores,
469                                          GrBackendSemaphore backendSemaphores[]) {
470     GrResourceProvider* resourceProvider = fContext->contextPriv().resourceProvider();
471 
472     if (this->caps()->fenceSyncSupport()) {
473         for (int i = 0; i < numSemaphores; ++i) {
474             sk_sp<GrSemaphore> semaphore;
475             if (backendSemaphores[i].isInitialized()) {
476                 semaphore = resourceProvider->wrapBackendSemaphore(
477                         backendSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillSignal,
478                         kBorrow_GrWrapOwnership);
479             } else {
480                 semaphore = resourceProvider->makeSemaphore(false);
481             }
482             this->insertSemaphore(semaphore, false);
483 
484             if (!backendSemaphores[i].isInitialized()) {
485                 semaphore->setBackendSemaphore(&backendSemaphores[i]);
486             }
487         }
488     }
489     this->onFinishFlush((numSemaphores > 0 && this->caps()->fenceSyncSupport()));
490     return this->caps()->fenceSyncSupport() ? GrSemaphoresSubmitted::kYes
491                                             : GrSemaphoresSubmitted::kNo;
492 }
493 
dumpJSON(SkJSONWriter * writer) const494 void GrGpu::dumpJSON(SkJSONWriter* writer) const {
495     writer->beginObject();
496 
497     // TODO: Is there anything useful in the base class to dump here?
498 
499     this->onDumpJSON(writer);
500 
501     writer->endObject();
502 }
503