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