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 "src/gpu/GrGpu.h"
10 
11 #include "include/gpu/GrBackendSemaphore.h"
12 #include "include/gpu/GrBackendSurface.h"
13 #include "include/gpu/GrContext.h"
14 #include "src/core/SkMathPriv.h"
15 #include "src/core/SkMipMap.h"
16 #include "src/gpu/GrAuditTrail.h"
17 #include "src/gpu/GrCaps.h"
18 #include "src/gpu/GrContextPriv.h"
19 #include "src/gpu/GrDataUtils.h"
20 #include "src/gpu/GrGpuResourcePriv.h"
21 #include "src/gpu/GrMesh.h"
22 #include "src/gpu/GrNativeRect.h"
23 #include "src/gpu/GrPathRendering.h"
24 #include "src/gpu/GrPipeline.h"
25 #include "src/gpu/GrRenderTargetPriv.h"
26 #include "src/gpu/GrResourceCache.h"
27 #include "src/gpu/GrResourceProvider.h"
28 #include "src/gpu/GrSemaphore.h"
29 #include "src/gpu/GrStencilAttachment.h"
30 #include "src/gpu/GrStencilSettings.h"
31 #include "src/gpu/GrSurfacePriv.h"
32 #include "src/gpu/GrTexturePriv.h"
33 #include "src/gpu/GrTextureProxyPriv.h"
34 #include "src/gpu/GrTracing.h"
35 #include "src/utils/SkJSONWriter.h"
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 
GrGpu(GrContext * context)39 GrGpu::GrGpu(GrContext* context) : fResetBits(kAll_GrBackendState), fContext(context) {}
40 
~GrGpu()41 GrGpu::~GrGpu() {}
42 
disconnect(DisconnectType)43 void GrGpu::disconnect(DisconnectType) {}
44 
45 ////////////////////////////////////////////////////////////////////////////////
46 
IsACopyNeededForRepeatWrapMode(const GrCaps * caps,GrTextureProxy * texProxy,int width,int height,GrSamplerState::Filter filter,GrTextureProducer::CopyParams * copyParams,SkScalar scaleAdjust[2])47 bool GrGpu::IsACopyNeededForRepeatWrapMode(const GrCaps* caps, GrTextureProxy* texProxy,
48                                            int width, int height,
49                                            GrSamplerState::Filter filter,
50                                            GrTextureProducer::CopyParams* copyParams,
51                                            SkScalar scaleAdjust[2]) {
52     if (!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 (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 
73     if (texProxy) {
74         // If the texture format itself doesn't support repeat wrap mode or mipmapping (and
75         // those capabilities are required) force a copy.
76         if (texProxy->hasRestrictedSampling()) {
77             copyParams->fFilter = GrSamplerState::Filter::kNearest;
78             copyParams->fWidth = texProxy->width();
79             copyParams->fHeight = texProxy->height();
80             return true;
81         }
82     }
83 
84     return false;
85 }
86 
IsACopyNeededForMips(const GrCaps * caps,const GrTextureProxy * texProxy,GrSamplerState::Filter filter,GrTextureProducer::CopyParams * copyParams)87 bool GrGpu::IsACopyNeededForMips(const GrCaps* caps, const GrTextureProxy* texProxy,
88                                  GrSamplerState::Filter filter,
89                                  GrTextureProducer::CopyParams* copyParams) {
90     SkASSERT(texProxy);
91     bool willNeedMips = GrSamplerState::Filter::kMipMap == filter && caps->mipMapSupport();
92     // If the texture format itself doesn't support mipmapping (and those capabilities are required)
93     // force a copy.
94     if (willNeedMips && texProxy->mipMapped() == GrMipMapped::kNo) {
95         copyParams->fFilter = GrSamplerState::Filter::kNearest;
96         copyParams->fWidth = texProxy->width();
97         copyParams->fHeight = texProxy->height();
98         return true;
99     }
100 
101     return false;
102 }
103 
validate_texel_levels(int w,int h,GrColorType texelColorType,const GrMipLevel * texels,int mipLevelCount,const GrCaps * caps)104 static bool validate_texel_levels(int w, int h, GrColorType texelColorType,
105                                   const GrMipLevel* texels, int mipLevelCount, const GrCaps* caps) {
106     SkASSERT(mipLevelCount > 0);
107     bool hasBasePixels = texels[0].fPixels;
108     int levelsWithPixelsCnt = 0;
109     auto bpp = GrColorTypeBytesPerPixel(texelColorType);
110     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; ++currentMipLevel) {
111         if (texels[currentMipLevel].fPixels) {
112             const size_t minRowBytes = w * bpp;
113             if (caps->writePixelsRowBytesSupport()) {
114                 if (texels[currentMipLevel].fRowBytes < minRowBytes) {
115                     return false;
116                 }
117                 if (texels[currentMipLevel].fRowBytes % bpp) {
118                     return false;
119                 }
120             } else {
121                 if (texels[currentMipLevel].fRowBytes != minRowBytes) {
122                     return false;
123                 }
124             }
125             ++levelsWithPixelsCnt;
126         }
127         if (w == 1 && h == 1) {
128             if (currentMipLevel != mipLevelCount - 1) {
129                 return false;
130             }
131         } else {
132             w = std::max(w / 2, 1);
133             h = std::max(h / 2, 1);
134         }
135     }
136     // Either just a base layer or a full stack is required.
137     if (mipLevelCount != 1 && (w != 1 || h != 1)) {
138         return false;
139     }
140     // Can specify just the base, all levels, or no levels.
141     if (!hasBasePixels) {
142         return levelsWithPixelsCnt == 0;
143     }
144     return levelsWithPixelsCnt == 1 || levelsWithPixelsCnt == mipLevelCount;
145 }
146 
createTextureCommon(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,int mipLevelCount,uint32_t levelClearMask)147 sk_sp<GrTexture> GrGpu::createTextureCommon(const GrSurfaceDesc& desc,
148                                             const GrBackendFormat& format,
149                                             GrRenderable renderable,
150                                             int renderTargetSampleCnt,
151                                             SkBudgeted budgeted,
152                                             GrProtected isProtected,
153                                             int mipLevelCount,
154                                             uint32_t levelClearMask) {
155     if (this->caps()->isFormatCompressed(format)) {
156         // Call GrGpu::createCompressedTexture.
157         return nullptr;
158     }
159 
160     GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
161     if (!this->caps()->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
162                                              renderable, renderTargetSampleCnt, mipMapped)) {
163         return nullptr;
164     }
165 
166     if (renderable == GrRenderable::kYes) {
167         renderTargetSampleCnt =
168                 this->caps()->getRenderTargetSampleCount(renderTargetSampleCnt, format);
169     }
170     // Attempt to catch un- or wrongly initialized sample counts.
171     SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64);
172     this->handleDirtyContext();
173     auto tex = this->onCreateTexture(desc,
174                                      format,
175                                      renderable,
176                                      renderTargetSampleCnt,
177                                      budgeted,
178                                      isProtected,
179                                      mipLevelCount,
180                                      levelClearMask);
181     if (tex) {
182         SkASSERT(tex->backendFormat() == format);
183         SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
184         if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
185             tex->resourcePriv().removeScratchKey();
186         }
187         fStats.incTextureCreates();
188         if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
189             SkASSERT(GrRenderable::kYes == renderable);
190             tex->asRenderTarget()->setRequiresManualMSAAResolve();
191         }
192     }
193     return tex;
194 }
195 
createTexture(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,GrMipMapped mipMapped,SkBudgeted budgeted,GrProtected isProtected)196 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
197                                       const GrBackendFormat& format,
198                                       GrRenderable renderable,
199                                       int renderTargetSampleCnt,
200                                       GrMipMapped mipMapped,
201                                       SkBudgeted budgeted,
202                                       GrProtected isProtected) {
203     int mipLevelCount = 1;
204     if (mipMapped == GrMipMapped::kYes) {
205         mipLevelCount = 32 - SkCLZ(static_cast<uint32_t>(SkTMax(desc.fWidth, desc.fHeight)));
206     }
207     uint32_t levelClearMask =
208             this->caps()->shouldInitializeTextures() ? (1 << mipLevelCount) - 1 : 0;
209     auto tex = this->createTextureCommon(desc, format, renderable, renderTargetSampleCnt, budgeted,
210                                          isProtected, mipLevelCount, levelClearMask);
211     if (tex && mipMapped == GrMipMapped::kYes && levelClearMask) {
212         tex->texturePriv().markMipMapsClean();
213     }
214     return tex;
215 }
216 
createTexture(const GrSurfaceDesc & desc,const GrBackendFormat & format,GrRenderable renderable,int renderTargetSampleCnt,SkBudgeted budgeted,GrProtected isProtected,GrColorType textureColorType,GrColorType srcColorType,const GrMipLevel texels[],int texelLevelCount)217 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
218                                       const GrBackendFormat& format,
219                                       GrRenderable renderable,
220                                       int renderTargetSampleCnt,
221                                       SkBudgeted budgeted,
222                                       GrProtected isProtected,
223                                       GrColorType textureColorType,
224                                       GrColorType srcColorType,
225                                       const GrMipLevel texels[],
226                                       int texelLevelCount) {
227     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
228     if (texelLevelCount) {
229         if (!validate_texel_levels(desc.fWidth, desc.fHeight, srcColorType, texels, texelLevelCount,
230                                    this->caps())) {
231             return nullptr;
232         }
233     }
234 
235     int mipLevelCount = SkTMax(1, texelLevelCount);
236     uint32_t levelClearMask = 0;
237     if (this->caps()->shouldInitializeTextures()) {
238         if (texelLevelCount) {
239             for (int i = 0; i < mipLevelCount; ++i) {
240                 if (!texels->fPixels) {
241                     levelClearMask |= static_cast<uint32_t>(1 << i);
242                 }
243             }
244         } else {
245             levelClearMask = static_cast<uint32_t>((1 << mipLevelCount) - 1);
246         }
247     }
248 
249     auto tex = this->createTextureCommon(desc, format, renderable, renderTargetSampleCnt, budgeted,
250                                          isProtected, texelLevelCount, levelClearMask);
251     if (tex) {
252         bool markMipLevelsClean = false;
253         // Currently if level 0 does not have pixels then no other level may, as enforced by
254         // validate_texel_levels.
255         if (texelLevelCount && texels[0].fPixels) {
256             if (!this->writePixels(tex.get(), 0, 0, desc.fWidth, desc.fHeight, textureColorType,
257                                    srcColorType, texels, texelLevelCount)) {
258                 return nullptr;
259             }
260             // Currently if level[1] of mip map has pixel data then so must all other levels.
261             // as enforced by validate_texel_levels.
262             markMipLevelsClean = (texelLevelCount > 1 && !levelClearMask && texels[1].fPixels);
263             fStats.incTextureUploads();
264         } else if (levelClearMask && mipLevelCount > 1) {
265             markMipLevelsClean = true;
266         }
267         if (markMipLevelsClean) {
268             tex->texturePriv().markMipMapsClean();
269         }
270     }
271     return tex;
272 }
273 
createCompressedTexture(int width,int height,const GrBackendFormat & format,SkImage::CompressionType compressionType,SkBudgeted budgeted,const void * data,size_t dataSize)274 sk_sp<GrTexture> GrGpu::createCompressedTexture(int width, int height,
275                                                 const GrBackendFormat& format,
276                                                 SkImage::CompressionType compressionType,
277                                                 SkBudgeted budgeted, const void* data,
278                                                 size_t dataSize) {
279     // If we ever add a new CompressionType, we should add a check here to make sure the
280     // GrBackendFormat and CompressionType are compatible with eachother.
281     SkASSERT(compressionType == SkImage::kETC1_CompressionType);
282 
283     this->handleDirtyContext();
284     if (width  < 1 || width  > this->caps()->maxTextureSize() ||
285         height < 1 || height > this->caps()->maxTextureSize()) {
286         return nullptr;
287     }
288     // Note if we relax the requirement that data must be provided then we must check
289     // caps()->shouldInitializeTextures() here.
290     if (!data) {
291         return nullptr;
292     }
293     if (!this->caps()->isFormatTexturable(format)) {
294         return nullptr;
295     }
296     if (dataSize < GrCompressedDataSize(compressionType, width, height)) {
297         return nullptr;
298     }
299     return this->onCreateCompressedTexture(width, height, format, compressionType, budgeted, data);
300 }
301 
wrapBackendTexture(const GrBackendTexture & backendTex,GrColorType colorType,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)302 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex,
303                                            GrColorType colorType,
304                                            GrWrapOwnership ownership, GrWrapCacheable cacheable,
305                                            GrIOType ioType) {
306     SkASSERT(ioType != kWrite_GrIOType);
307     this->handleDirtyContext();
308 
309     const GrCaps* caps = this->caps();
310     SkASSERT(caps);
311 
312     if (!caps->isFormatTexturable(backendTex.getBackendFormat())) {
313         return nullptr;
314     }
315     if (backendTex.width() > caps->maxTextureSize() ||
316         backendTex.height() > caps->maxTextureSize()) {
317         return nullptr;
318     }
319 
320     return this->onWrapBackendTexture(backendTex, colorType, ownership, cacheable, ioType);
321 }
322 
wrapRenderableBackendTexture(const GrBackendTexture & backendTex,int sampleCnt,GrColorType colorType,GrWrapOwnership ownership,GrWrapCacheable cacheable)323 sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex,
324                                                      int sampleCnt, GrColorType colorType,
325                                                      GrWrapOwnership ownership,
326                                                      GrWrapCacheable cacheable) {
327     this->handleDirtyContext();
328     if (sampleCnt < 1) {
329         return nullptr;
330     }
331 
332     const GrCaps* caps = this->caps();
333 
334     if (!caps->isFormatTexturable(backendTex.getBackendFormat()) ||
335         !caps->isFormatRenderable(backendTex.getBackendFormat(), sampleCnt)) {
336         return nullptr;
337     }
338 
339     if (backendTex.width() > caps->maxRenderTargetSize() ||
340         backendTex.height() > caps->maxRenderTargetSize()) {
341         return nullptr;
342     }
343     sk_sp<GrTexture> tex = this->onWrapRenderableBackendTexture(backendTex, sampleCnt, colorType,
344                                                                 ownership, cacheable);
345     SkASSERT(!tex || tex->asRenderTarget());
346     if (tex && sampleCnt > 1 && !caps->msaaResolvesAutomatically()) {
347         tex->asRenderTarget()->setRequiresManualMSAAResolve();
348     }
349     return tex;
350 }
351 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT,GrColorType colorType)352 sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT,
353                                                      GrColorType colorType) {
354     this->handleDirtyContext();
355 
356     const GrCaps* caps = this->caps();
357 
358     if (!caps->isFormatRenderable(backendRT.getBackendFormat(), backendRT.sampleCnt())) {
359         return nullptr;
360     }
361 
362     return this->onWrapBackendRenderTarget(backendRT, colorType);
363 }
364 
wrapBackendTextureAsRenderTarget(const GrBackendTexture & backendTex,int sampleCnt,GrColorType colorType)365 sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& backendTex,
366                                                               int sampleCnt,
367                                                               GrColorType colorType) {
368     this->handleDirtyContext();
369 
370     const GrCaps* caps = this->caps();
371 
372     int maxSize = caps->maxTextureSize();
373     if (backendTex.width() > maxSize || backendTex.height() > maxSize) {
374         return nullptr;
375     }
376 
377     if (!caps->isFormatRenderable(backendTex.getBackendFormat(), sampleCnt)) {
378         return nullptr;
379     }
380 
381     auto rt = this->onWrapBackendTextureAsRenderTarget(backendTex, sampleCnt, colorType);
382     if (rt && sampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
383         rt->setRequiresManualMSAAResolve();
384     }
385     return rt;
386 }
387 
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)388 sk_sp<GrRenderTarget> GrGpu::wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
389                                                                  const GrVkDrawableInfo& vkInfo) {
390     return this->onWrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo);
391 }
392 
onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)393 sk_sp<GrRenderTarget> GrGpu::onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
394                                                                    const GrVkDrawableInfo& vkInfo) {
395     // This is only supported on Vulkan so we default to returning nullptr here
396     return nullptr;
397 }
398 
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)399 sk_sp<GrGpuBuffer> GrGpu::createBuffer(size_t size, GrGpuBufferType intendedType,
400                                        GrAccessPattern accessPattern, const void* data) {
401     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
402     this->handleDirtyContext();
403     sk_sp<GrGpuBuffer> buffer = this->onCreateBuffer(size, intendedType, accessPattern, data);
404     if (!this->caps()->reuseScratchBuffers()) {
405         buffer->resourcePriv().removeScratchKey();
406     }
407     return buffer;
408 }
409 
copySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)410 bool GrGpu::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
411                         const SkIPoint& dstPoint) {
412     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
413     SkASSERT(dst && src);
414 
415     if (dst->readOnly()) {
416         return false;
417     }
418 
419     this->handleDirtyContext();
420 
421     return this->onCopySurface(dst, src, srcRect, dstPoint);
422 }
423 
readPixels(GrSurface * surface,int left,int top,int width,int height,GrColorType surfaceColorType,GrColorType dstColorType,void * buffer,size_t rowBytes)424 bool GrGpu::readPixels(GrSurface* surface, int left, int top, int width, int height,
425                        GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
426                        size_t rowBytes) {
427     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
428     SkASSERT(surface);
429     SkASSERT(this->caps()->isFormatTexturable(surface->backendFormat()));
430 
431     auto subRect = SkIRect::MakeXYWH(left, top, width, height);
432     auto bounds  = SkIRect::MakeWH(surface->width(), surface->height());
433     if (!bounds.contains(subRect)) {
434         return false;
435     }
436 
437     size_t minRowBytes = SkToSizeT(GrColorTypeBytesPerPixel(dstColorType) * width);
438     if (!this->caps()->readPixelsRowBytesSupport()) {
439         if (rowBytes != minRowBytes) {
440             return false;
441         }
442     } else {
443         if (rowBytes < minRowBytes) {
444             return false;
445         }
446         if (rowBytes % GrColorTypeBytesPerPixel(dstColorType)) {
447             return false;
448         }
449     }
450 
451     if (this->caps()->isFormatCompressed(surface->backendFormat())) {
452         return false;
453     }
454 
455     this->handleDirtyContext();
456 
457     return this->onReadPixels(surface, left, top, width, height, surfaceColorType, dstColorType,
458                               buffer, rowBytes);
459 }
460 
writePixels(GrSurface * surface,int left,int top,int width,int height,GrColorType surfaceColorType,GrColorType srcColorType,const GrMipLevel texels[],int mipLevelCount,bool prepForTexSampling)461 bool GrGpu::writePixels(GrSurface* surface, int left, int top, int width, int height,
462                         GrColorType surfaceColorType, GrColorType srcColorType,
463                         const GrMipLevel texels[], int mipLevelCount, bool prepForTexSampling) {
464     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
465     SkASSERT(surface);
466     SkASSERT(this->caps()->isFormatTexturableAndUploadable(surfaceColorType,
467                                                            surface->backendFormat()));
468 
469     if (surface->readOnly()) {
470         return false;
471     }
472 
473     if (mipLevelCount == 0) {
474         return false;
475     } else if (mipLevelCount == 1) {
476         // We require that if we are not mipped, then the write region is contained in the surface
477         auto subRect = SkIRect::MakeXYWH(left, top, width, height);
478         auto bounds  = SkIRect::MakeWH(surface->width(), surface->height());
479         if (!bounds.contains(subRect)) {
480             return false;
481         }
482     } else if (0 != left || 0 != top || width != surface->width() || height != surface->height()) {
483         // We require that if the texels are mipped, than the write region is the entire surface
484         return false;
485     }
486 
487     if (!validate_texel_levels(width, height, srcColorType, texels, mipLevelCount, this->caps())) {
488         return false;
489     }
490 
491     this->handleDirtyContext();
492     if (this->onWritePixels(surface, left, top, width, height, surfaceColorType, srcColorType,
493                             texels, mipLevelCount, prepForTexSampling)) {
494         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
495         this->didWriteToSurface(surface, kTopLeft_GrSurfaceOrigin, &rect, mipLevelCount);
496         fStats.incTextureUploads();
497         return true;
498     }
499     return false;
500 }
501 
transferPixelsTo(GrTexture * texture,int left,int top,int width,int height,GrColorType textureColorType,GrColorType bufferColorType,GrGpuBuffer * transferBuffer,size_t offset,size_t rowBytes)502 bool GrGpu::transferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
503                              GrColorType textureColorType, GrColorType bufferColorType,
504                              GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) {
505     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
506     SkASSERT(texture);
507     SkASSERT(transferBuffer);
508     SkASSERT(this->caps()->isFormatTexturableAndUploadable(textureColorType,
509                                                            texture->backendFormat()));
510 
511     if (texture->readOnly()) {
512         return false;
513     }
514 
515     // We require that the write region is contained in the texture
516     SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
517     SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
518     if (!bounds.contains(subRect)) {
519         return false;
520     }
521 
522     size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
523     if (this->caps()->writePixelsRowBytesSupport()) {
524         if (rowBytes < SkToSizeT(bpp * width)) {
525             return false;
526         }
527         if (rowBytes % bpp) {
528             return false;
529         }
530     } else {
531         if (rowBytes != SkToSizeT(bpp * width)) {
532             return false;
533         }
534     }
535 
536     this->handleDirtyContext();
537     if (this->onTransferPixelsTo(texture, left, top, width, height, textureColorType,
538                                  bufferColorType, transferBuffer, offset, rowBytes)) {
539         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
540         this->didWriteToSurface(texture, kTopLeft_GrSurfaceOrigin, &rect);
541         fStats.incTransfersToTexture();
542 
543         return true;
544     }
545     return false;
546 }
547 
transferPixelsFrom(GrSurface * surface,int left,int top,int width,int height,GrColorType surfaceColorType,GrColorType bufferColorType,GrGpuBuffer * transferBuffer,size_t offset)548 bool GrGpu::transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
549                                GrColorType surfaceColorType, GrColorType bufferColorType,
550                                GrGpuBuffer* transferBuffer, size_t offset) {
551     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
552     SkASSERT(surface);
553     SkASSERT(transferBuffer);
554     SkASSERT(this->caps()->isFormatTexturable(surface->backendFormat()));
555 
556 #ifdef SK_DEBUG
557     auto supportedRead = this->caps()->supportedReadPixelsColorType(
558             surfaceColorType, surface->backendFormat(), bufferColorType);
559     SkASSERT(supportedRead.fOffsetAlignmentForTransferBuffer);
560     SkASSERT(offset % supportedRead.fOffsetAlignmentForTransferBuffer == 0);
561 #endif
562 
563     // We require that the write region is contained in the texture
564     SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
565     SkIRect bounds = SkIRect::MakeWH(surface->width(), surface->height());
566     if (!bounds.contains(subRect)) {
567         return false;
568     }
569 
570     this->handleDirtyContext();
571     if (this->onTransferPixelsFrom(surface, left, top, width, height, surfaceColorType,
572                                    bufferColorType, transferBuffer, offset)) {
573         fStats.incTransfersFromSurface();
574         return true;
575     }
576     return false;
577 }
578 
regenerateMipMapLevels(GrTexture * texture)579 bool GrGpu::regenerateMipMapLevels(GrTexture* texture) {
580     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
581     SkASSERT(texture);
582     SkASSERT(this->caps()->mipMapSupport());
583     SkASSERT(texture->texturePriv().mipMapped() == GrMipMapped::kYes);
584     if (!texture->texturePriv().mipMapsAreDirty()) {
585         // This can happen when the proxy expects mipmaps to be dirty, but they are not dirty on the
586         // actual target. This may be caused by things that the drawingManager could not predict,
587         // i.e., ops that don't draw anything, aborting a draw for exceptional circumstances, etc.
588         // NOTE: This goes away once we quit tracking mipmap state on the actual texture.
589         return true;
590     }
591     if (texture->readOnly()) {
592         return false;
593     }
594     if (this->onRegenerateMipMapLevels(texture)) {
595         texture->texturePriv().markMipMapsClean();
596         return true;
597     }
598     return false;
599 }
600 
resetTextureBindings()601 void GrGpu::resetTextureBindings() {
602     this->handleDirtyContext();
603     this->onResetTextureBindings();
604 }
605 
resolveRenderTarget(GrRenderTarget * target,const SkIRect & resolveRect,GrSurfaceOrigin origin,ForExternalIO forExternalIO)606 void GrGpu::resolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
607                                 GrSurfaceOrigin origin, ForExternalIO forExternalIO) {
608     SkASSERT(target);
609     this->handleDirtyContext();
610     this->onResolveRenderTarget(target, resolveRect, origin, forExternalIO);
611 }
612 
didWriteToSurface(GrSurface * surface,GrSurfaceOrigin origin,const SkIRect * bounds,uint32_t mipLevels) const613 void GrGpu::didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds,
614                               uint32_t mipLevels) const {
615     SkASSERT(surface);
616     SkASSERT(!surface->readOnly());
617     // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds.
618     if (nullptr == bounds || !bounds->isEmpty()) {
619         GrTexture* texture = surface->asTexture();
620         if (texture && 1 == mipLevels) {
621             texture->texturePriv().markMipMapsDirty();
622         }
623     }
624 }
625 
findOrAssignSamplePatternKey(GrRenderTarget * renderTarget)626 int GrGpu::findOrAssignSamplePatternKey(GrRenderTarget* renderTarget) {
627     SkASSERT(this->caps()->sampleLocationsSupport());
628     SkASSERT(renderTarget->numSamples() > 1 ||
629              (renderTarget->renderTargetPriv().getStencilAttachment() &&
630               renderTarget->renderTargetPriv().getStencilAttachment()->numSamples() > 1));
631 
632     SkSTArray<16, SkPoint> sampleLocations;
633     this->querySampleLocations(renderTarget, &sampleLocations);
634     return fSamplePatternDictionary.findOrAssignSamplePatternKey(sampleLocations);
635 }
636 
finishFlush(GrSurfaceProxy * proxies[],int n,SkSurface::BackendSurfaceAccess access,const GrFlushInfo & info,const GrPrepareForExternalIORequests & externalRequests)637 GrSemaphoresSubmitted GrGpu::finishFlush(GrSurfaceProxy* proxies[],
638                                          int n,
639                                          SkSurface::BackendSurfaceAccess access,
640                                          const GrFlushInfo& info,
641                                          const GrPrepareForExternalIORequests& externalRequests) {
642     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
643     this->stats()->incNumFinishFlushes();
644     GrResourceProvider* resourceProvider = fContext->priv().resourceProvider();
645 
646     if (this->caps()->semaphoreSupport()) {
647         for (int i = 0; i < info.fNumSemaphores; ++i) {
648             sk_sp<GrSemaphore> semaphore;
649             if (info.fSignalSemaphores[i].isInitialized()) {
650                 semaphore = resourceProvider->wrapBackendSemaphore(
651                         info.fSignalSemaphores[i],
652                         GrResourceProvider::SemaphoreWrapType::kWillSignal,
653                         kBorrow_GrWrapOwnership);
654             } else {
655                 semaphore = resourceProvider->makeSemaphore(false);
656             }
657             this->insertSemaphore(semaphore);
658 
659             if (!info.fSignalSemaphores[i].isInitialized()) {
660                 info.fSignalSemaphores[i] = semaphore->backendSemaphore();
661             }
662         }
663     }
664     this->onFinishFlush(proxies, n, access, info, externalRequests);
665     return this->caps()->semaphoreSupport() ? GrSemaphoresSubmitted::kYes
666                                             : GrSemaphoresSubmitted::kNo;
667 }
668 
669 #ifdef SK_ENABLE_DUMP_GPU
dumpJSON(SkJSONWriter * writer) const670 void GrGpu::dumpJSON(SkJSONWriter* writer) const {
671     writer->beginObject();
672 
673     // TODO: Is there anything useful in the base class to dump here?
674 
675     this->onDumpJSON(writer);
676 
677     writer->endObject();
678 }
679 #else
dumpJSON(SkJSONWriter * writer) const680 void GrGpu::dumpJSON(SkJSONWriter* writer) const { }
681 #endif
682 
683 #if GR_TEST_UTILS
684 
685 #if GR_GPU_STATS
dump(SkString * out)686 void GrGpu::Stats::dump(SkString* out) {
687     out->appendf("Render Target Binds: %d\n", fRenderTargetBinds);
688     out->appendf("Shader Compilations: %d\n", fShaderCompilations);
689     out->appendf("Textures Created: %d\n", fTextureCreates);
690     out->appendf("Texture Uploads: %d\n", fTextureUploads);
691     out->appendf("Transfers to Texture: %d\n", fTransfersToTexture);
692     out->appendf("Transfers from Surface: %d\n", fTransfersFromSurface);
693     out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates);
694     out->appendf("Number of draws: %d\n", fNumDraws);
695     out->appendf("Number of Scratch Textures reused %d\n", fNumScratchTexturesReused);
696 }
697 
dumpKeyValuePairs(SkTArray<SkString> * keys,SkTArray<double> * values)698 void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) {
699     keys->push_back(SkString("render_target_binds")); values->push_back(fRenderTargetBinds);
700     keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations);
701 }
702 
703 #endif // GR_GPU_STATS
704 #endif // GR_TEST_UTILS
705 
706 
MipMapsAreCorrect(int baseWidth,int baseHeight,GrMipMapped mipMapped,const SkPixmap srcData[],int numMipLevels)707 bool GrGpu::MipMapsAreCorrect(int baseWidth, int baseHeight, GrMipMapped mipMapped,
708                               const SkPixmap srcData[], int numMipLevels) {
709     if (!srcData) {
710         return true;
711     }
712 
713     if (baseWidth != srcData[0].width() || baseHeight != srcData[0].height()) {
714         return false;
715     }
716 
717     if (mipMapped == GrMipMapped::kYes) {
718         if (numMipLevels != SkMipMap::ComputeLevelCount(baseWidth, baseHeight) + 1) {
719             return false;
720         }
721 
722         SkColorType colorType = srcData[0].colorType();
723 
724         int currentWidth = baseWidth;
725         int currentHeight = baseHeight;
726         for (int i = 1; i < numMipLevels; ++i) {
727             currentWidth = SkTMax(1, currentWidth / 2);
728             currentHeight = SkTMax(1, currentHeight / 2);
729 
730             if (srcData[i].colorType() != colorType) { // all levels must have same colorType
731                 return false;
732             }
733 
734             if (srcData[i].width() != currentWidth || srcData[i].height() != currentHeight) {
735                 return false;
736             }
737         }
738     } else if (numMipLevels != 1) {
739         return false;
740     }
741 
742     return true;
743 }
744 
createBackendTexture(int w,int h,const GrBackendFormat & format,GrMipMapped mipMapped,GrRenderable renderable,const SkPixmap srcData[],int numMipLevels,const SkColor4f * color,GrProtected isProtected)745 GrBackendTexture GrGpu::createBackendTexture(int w, int h, const GrBackendFormat& format,
746                                              GrMipMapped mipMapped, GrRenderable renderable,
747                                              const SkPixmap srcData[], int numMipLevels,
748                                              const SkColor4f* color, GrProtected isProtected) {
749     const GrCaps* caps = this->caps();
750 
751     if (!format.isValid()) {
752         return {};
753     }
754 
755     if (caps->isFormatCompressed(format)) {
756         // Compressed formats must go through the createCompressedBackendTexture API
757         return {};
758     }
759 
760     if (w < 1 || w > caps->maxTextureSize() || h < 1 || h > caps->maxTextureSize()) {
761         return {};
762     }
763 
764     // TODO: maybe just ignore the mipMapped parameter in this case
765     if (mipMapped == GrMipMapped::kYes && !this->caps()->mipMapSupport()) {
766         return {};
767     }
768 
769     if (!MipMapsAreCorrect(w, h, mipMapped, srcData, numMipLevels)) {
770         return {};
771     }
772 
773     return this->onCreateBackendTexture(w, h, format, mipMapped, renderable,
774                                         srcData, numMipLevels, color, isProtected);
775 }
776