xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrGpu.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 #include "src/gpu/ganesh/GrGpu.h"
8 
9 #include "include/core/SkSize.h"
10 #include "include/core/SkString.h"
11 #include "include/core/SkSurface.h"
12 #include "include/core/SkTextureCompressionType.h"
13 #include "include/gpu/ganesh/GrBackendSemaphore.h"
14 #include "include/gpu/ganesh/GrBackendSurface.h"
15 #include "include/gpu/ganesh/GrDirectContext.h"
16 #include "include/private/base/SkTo.h"
17 #include "src/base/SkMathPriv.h"
18 #include "src/core/SkCompressedDataUtils.h"
19 #include "src/core/SkTraceEvent.h"
20 #include "src/gpu/RefCntedCallback.h"
21 #include "src/gpu/ganesh/GrBackendUtils.h"
22 #include "src/gpu/ganesh/GrCaps.h"
23 #include "src/gpu/ganesh/GrDirectContextPriv.h"
24 #include "src/gpu/ganesh/GrGpuBuffer.h"
25 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
26 #include "src/gpu/ganesh/GrRenderTarget.h"
27 #include "src/gpu/ganesh/GrResourceProvider.h"
28 #include "src/gpu/ganesh/GrRingBuffer.h"
29 #include "src/gpu/ganesh/GrSemaphore.h"
30 #include "src/gpu/ganesh/GrStagingBufferManager.h"
31 #include "src/gpu/ganesh/GrSurface.h"
32 #include "src/gpu/ganesh/GrTexture.h"
33 
34 #include <algorithm>
35 #include <utility>
36 
37 using namespace skia_private;
38 
39 ////////////////////////////////////////////////////////////////////////////////
40 
GrGpu(GrDirectContext * direct)41 GrGpu::GrGpu(GrDirectContext* direct) : fResetBits(kAll_GrBackendState), fContext(direct) {}
42 
~GrGpu()43 GrGpu::~GrGpu() {
44     this->callSubmittedProcs(false);
45 }
46 
initCaps(sk_sp<const GrCaps> caps)47 void GrGpu::initCaps(sk_sp<const GrCaps> caps) {
48     fCaps = std::move(caps);
49 }
50 
disconnect(DisconnectType type)51 void GrGpu::disconnect(DisconnectType type) {}
52 
53 ////////////////////////////////////////////////////////////////////////////////
54 
validate_texel_levels(SkISize dimensions,GrColorType texelColorType,const GrMipLevel * texels,int mipLevelCount,const GrCaps * caps)55 static bool validate_texel_levels(SkISize dimensions, GrColorType texelColorType,
56                                   const GrMipLevel* texels, int mipLevelCount, const GrCaps* caps) {
57     SkASSERT(mipLevelCount > 0);
58     bool hasBasePixels = texels[0].fPixels;
59     int levelsWithPixelsCnt = 0;
60     auto bpp = GrColorTypeBytesPerPixel(texelColorType);
61     int w = dimensions.fWidth;
62     int h = dimensions.fHeight;
63     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; ++currentMipLevel) {
64         if (texels[currentMipLevel].fPixels) {
65             const size_t minRowBytes = w * bpp;
66             if (caps->writePixelsRowBytesSupport()) {
67                 if (texels[currentMipLevel].fRowBytes < minRowBytes) {
68                     return false;
69                 }
70                 if (texels[currentMipLevel].fRowBytes % bpp) {
71                     return false;
72                 }
73             } else {
74                 if (texels[currentMipLevel].fRowBytes != minRowBytes) {
75                     return false;
76                 }
77             }
78             ++levelsWithPixelsCnt;
79         }
80         if (w == 1 && h == 1) {
81             if (currentMipLevel != mipLevelCount - 1) {
82                 return false;
83             }
84         } else {
85             w = std::max(w / 2, 1);
86             h = std::max(h / 2, 1);
87         }
88     }
89     // Either just a base layer or a full stack is required.
90     if (mipLevelCount != 1 && (w != 1 || h != 1)) {
91         return false;
92     }
93     // Can specify just the base, all levels, or no levels.
94     if (!hasBasePixels) {
95         return levelsWithPixelsCnt == 0;
96     }
97     return levelsWithPixelsCnt == 1 || levelsWithPixelsCnt == mipLevelCount;
98 }
99 
createTextureCommon(SkISize dimensions,const GrBackendFormat & format,GrTextureType textureType,GrRenderable renderable,int renderTargetSampleCnt,skgpu::Budgeted budgeted,GrProtected isProtected,int mipLevelCount,uint32_t levelClearMask,std::string_view label)100 sk_sp<GrTexture> GrGpu::createTextureCommon(SkISize dimensions,
101                                             const GrBackendFormat& format,
102                                             GrTextureType textureType,
103                                             GrRenderable renderable,
104                                             int renderTargetSampleCnt,
105                                             skgpu::Budgeted budgeted,
106                                             GrProtected isProtected,
107                                             int mipLevelCount,
108                                             uint32_t levelClearMask,
109                                             std::string_view label) {
110     if (this->caps()->isFormatCompressed(format)) {
111         // Call GrGpu::createCompressedTexture.
112         return nullptr;
113     }
114 
115     skgpu::Mipmapped mipmapped = mipLevelCount > 1 ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
116     if (!this->caps()->validateSurfaceParams(dimensions,
117                                              format,
118                                              renderable,
119                                              renderTargetSampleCnt,
120                                              mipmapped,
121                                              textureType)) {
122         return nullptr;
123     }
124 
125     if (renderable == GrRenderable::kYes) {
126         renderTargetSampleCnt =
127                 this->caps()->getRenderTargetSampleCount(renderTargetSampleCnt, format);
128     }
129     // Attempt to catch un- or wrongly initialized sample counts.
130     SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64);
131     this->handleDirtyContext();
132     auto tex = this->onCreateTexture(dimensions,
133                                      format,
134                                      renderable,
135                                      renderTargetSampleCnt,
136                                      budgeted,
137                                      isProtected,
138                                      mipLevelCount,
139                                      levelClearMask,
140                                      label);
141     if (tex) {
142         SkASSERT(tex->backendFormat() == format);
143         SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
144         if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
145             tex->resourcePriv().removeScratchKey();
146         }
147         fStats.incTextureCreates();
148         if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
149             SkASSERT(GrRenderable::kYes == renderable);
150             tex->asRenderTarget()->setRequiresManualMSAAResolve();
151         }
152     }
153     return tex;
154 }
155 
createTexture(SkISize dimensions,const GrBackendFormat & format,GrTextureType textureType,GrRenderable renderable,int renderTargetSampleCnt,skgpu::Mipmapped mipmapped,skgpu::Budgeted budgeted,GrProtected isProtected,std::string_view label)156 sk_sp<GrTexture> GrGpu::createTexture(SkISize dimensions,
157                                       const GrBackendFormat& format,
158                                       GrTextureType textureType,
159                                       GrRenderable renderable,
160                                       int renderTargetSampleCnt,
161                                       skgpu::Mipmapped mipmapped,
162                                       skgpu::Budgeted budgeted,
163                                       GrProtected isProtected,
164                                       std::string_view label) {
165     int mipLevelCount = 1;
166     if (mipmapped == skgpu::Mipmapped::kYes) {
167         mipLevelCount =
168                 32 - SkCLZ(static_cast<uint32_t>(std::max(dimensions.fWidth, dimensions.fHeight)));
169     }
170     uint32_t levelClearMask =
171             this->caps()->shouldInitializeTextures() ? (1 << mipLevelCount) - 1 : 0;
172     auto tex = this->createTextureCommon(dimensions,
173                                          format,
174                                          textureType,
175                                          renderable,
176                                          renderTargetSampleCnt,
177                                          budgeted,
178                                          isProtected,
179                                          mipLevelCount,
180                                          levelClearMask,
181                                          label);
182     if (tex && mipmapped == skgpu::Mipmapped::kYes && levelClearMask) {
183         tex->markMipmapsClean();
184     }
185 
186     return tex;
187 }
188 
createTexture(SkISize dimensions,const GrBackendFormat & format,GrTextureType textureType,GrRenderable renderable,int renderTargetSampleCnt,skgpu::Budgeted budgeted,GrProtected isProtected,GrColorType textureColorType,GrColorType srcColorType,const GrMipLevel texels[],int texelLevelCount,std::string_view label)189 sk_sp<GrTexture> GrGpu::createTexture(SkISize dimensions,
190                                       const GrBackendFormat& format,
191                                       GrTextureType textureType,
192                                       GrRenderable renderable,
193                                       int renderTargetSampleCnt,
194                                       skgpu::Budgeted budgeted,
195                                       GrProtected isProtected,
196                                       GrColorType textureColorType,
197                                       GrColorType srcColorType,
198                                       const GrMipLevel texels[],
199                                       int texelLevelCount,
200                                       std::string_view label) {
201     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
202     if (texelLevelCount) {
203         if (!validate_texel_levels(dimensions, srcColorType, texels, texelLevelCount,
204                                    this->caps())) {
205             return nullptr;
206         }
207     }
208 
209     int mipLevelCount = std::max(1, texelLevelCount);
210     uint32_t levelClearMask = 0;
211     if (this->caps()->shouldInitializeTextures()) {
212         if (texelLevelCount) {
213             for (int i = 0; i < mipLevelCount; ++i) {
214                 if (!texels->fPixels) {
215                     levelClearMask |= static_cast<uint32_t>(1 << i);
216                 }
217             }
218         } else {
219             levelClearMask = static_cast<uint32_t>((1 << mipLevelCount) - 1);
220         }
221     }
222 
223     auto tex = this->createTextureCommon(dimensions,
224                                          format,
225                                          textureType,
226                                          renderable,
227                                          renderTargetSampleCnt,
228                                          budgeted,
229                                          isProtected,
230                                          texelLevelCount,
231                                          levelClearMask,
232                                          label);
233     if (tex) {
234         bool markMipLevelsClean = false;
235         // Currently if level 0 does not have pixels then no other level may, as enforced by
236         // validate_texel_levels.
237         if (texelLevelCount && texels[0].fPixels) {
238             if (!this->writePixels(tex.get(),
239                                    SkIRect::MakeSize(dimensions),
240                                    textureColorType,
241                                    srcColorType,
242                                    texels,
243                                    texelLevelCount)) {
244                 return nullptr;
245             }
246             // Currently if level[1] of mip map has pixel data then so must all other levels.
247             // as enforced by validate_texel_levels.
248             markMipLevelsClean = (texelLevelCount > 1 && !levelClearMask && texels[1].fPixels);
249             fStats.incTextureUploads();
250         } else if (levelClearMask && mipLevelCount > 1) {
251             markMipLevelsClean = true;
252         }
253         if (markMipLevelsClean) {
254             tex->markMipmapsClean();
255         }
256     }
257     return tex;
258 }
259 
createCompressedTexture(SkISize dimensions,const GrBackendFormat & format,skgpu::Budgeted budgeted,skgpu::Mipmapped mipmapped,GrProtected isProtected,const void * data,size_t dataSize)260 sk_sp<GrTexture> GrGpu::createCompressedTexture(SkISize dimensions,
261                                                 const GrBackendFormat& format,
262                                                 skgpu::Budgeted budgeted,
263                                                 skgpu::Mipmapped mipmapped,
264                                                 GrProtected isProtected,
265                                                 const void* data,
266                                                 size_t dataSize) {
267     this->handleDirtyContext();
268     if (dimensions.width()  < 1 || dimensions.width()  > this->caps()->maxTextureSize() ||
269         dimensions.height() < 1 || dimensions.height() > this->caps()->maxTextureSize()) {
270         return nullptr;
271     }
272     // Note if we relax the requirement that data must be provided then we must check
273     // caps()->shouldInitializeTextures() here.
274     if (!data) {
275         return nullptr;
276     }
277 
278     // TODO: expand CompressedDataIsCorrect to work here too
279     SkTextureCompressionType compressionType = GrBackendFormatToCompressionType(format);
280     if (compressionType == SkTextureCompressionType::kNone) {
281         return nullptr;
282     }
283 
284     if (!this->caps()->isFormatTexturable(format, GrTextureType::k2D)) {
285         return nullptr;
286     }
287 
288     if (dataSize <
289         SkCompressedDataSize(
290                 compressionType, dimensions, nullptr, mipmapped == skgpu::Mipmapped::kYes)) {
291         return nullptr;
292     }
293     return this->onCreateCompressedTexture(dimensions, format, budgeted, mipmapped, isProtected,
294                                            data, dataSize);
295 }
296 
wrapBackendTexture(const GrBackendTexture & backendTex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)297 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex,
298                                            GrWrapOwnership ownership,
299                                            GrWrapCacheable cacheable,
300                                            GrIOType ioType) {
301     SkASSERT(ioType != kWrite_GrIOType);
302     this->handleDirtyContext();
303 
304     const GrCaps* caps = this->caps();
305     SkASSERT(caps);
306 
307     if (!caps->isFormatTexturable(backendTex.getBackendFormat(), backendTex.textureType())) {
308         return nullptr;
309     }
310     if (backendTex.width() > caps->maxTextureSize() ||
311         backendTex.height() > caps->maxTextureSize()) {
312         return nullptr;
313     }
314 
315     return this->onWrapBackendTexture(backendTex, ownership, cacheable, ioType);
316 }
317 
wrapCompressedBackendTexture(const GrBackendTexture & backendTex,GrWrapOwnership ownership,GrWrapCacheable cacheable)318 sk_sp<GrTexture> GrGpu::wrapCompressedBackendTexture(const GrBackendTexture& backendTex,
319                                                      GrWrapOwnership ownership,
320                                                      GrWrapCacheable cacheable) {
321     this->handleDirtyContext();
322 
323     const GrCaps* caps = this->caps();
324     SkASSERT(caps);
325 
326     if (!caps->isFormatTexturable(backendTex.getBackendFormat(), backendTex.textureType())) {
327         return nullptr;
328     }
329     if (backendTex.width() > caps->maxTextureSize() ||
330         backendTex.height() > caps->maxTextureSize()) {
331         return nullptr;
332     }
333 
334     return this->onWrapCompressedBackendTexture(backendTex, ownership, cacheable);
335 }
336 
wrapRenderableBackendTexture(const GrBackendTexture & backendTex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)337 sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex,
338                                                      int sampleCnt,
339                                                      GrWrapOwnership ownership,
340                                                      GrWrapCacheable cacheable) {
341     this->handleDirtyContext();
342     if (sampleCnt < 1) {
343         return nullptr;
344     }
345 
346     const GrCaps* caps = this->caps();
347 
348     if (!caps->isFormatTexturable(backendTex.getBackendFormat(), backendTex.textureType()) ||
349         !caps->isFormatRenderable(backendTex.getBackendFormat(), sampleCnt)) {
350         return nullptr;
351     }
352 
353     if (backendTex.width() > caps->maxRenderTargetSize() ||
354         backendTex.height() > caps->maxRenderTargetSize()) {
355         return nullptr;
356     }
357     sk_sp<GrTexture> tex =
358             this->onWrapRenderableBackendTexture(backendTex, sampleCnt, ownership, cacheable);
359     SkASSERT(!tex || tex->asRenderTarget());
360     if (tex && sampleCnt > 1 && !caps->msaaResolvesAutomatically()) {
361         tex->asRenderTarget()->setRequiresManualMSAAResolve();
362     }
363     return tex;
364 }
365 
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)366 sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
367     this->handleDirtyContext();
368 
369     const GrCaps* caps = this->caps();
370 
371     if (!caps->isFormatRenderable(backendRT.getBackendFormat(), backendRT.sampleCnt())) {
372         return nullptr;
373     }
374 
375     sk_sp<GrRenderTarget> rt = this->onWrapBackendRenderTarget(backendRT);
376     if (backendRT.isFramebufferOnly()) {
377         rt->setFramebufferOnly();
378     }
379     return rt;
380 }
381 
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)382 sk_sp<GrRenderTarget> GrGpu::wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
383                                                                  const GrVkDrawableInfo& vkInfo) {
384     return this->onWrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo);
385 }
386 
onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)387 sk_sp<GrRenderTarget> GrGpu::onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
388                                                                    const GrVkDrawableInfo& vkInfo) {
389     // This is only supported on Vulkan so we default to returning nullptr here
390     return nullptr;
391 }
392 
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern)393 sk_sp<GrGpuBuffer> GrGpu::createBuffer(size_t size,
394                                        GrGpuBufferType intendedType,
395                                        GrAccessPattern accessPattern) {
396     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
397     this->handleDirtyContext();
398     if ((intendedType == GrGpuBufferType::kXferCpuToGpu ||
399          intendedType == GrGpuBufferType::kXferGpuToCpu) &&
400         accessPattern == kStatic_GrAccessPattern) {
401         return nullptr;
402     }
403     sk_sp<GrGpuBuffer> buffer = this->onCreateBuffer(size, intendedType, accessPattern);
404     if (buffer && !this->caps()->reuseScratchBuffers()) {
405         buffer->resourcePriv().removeScratchKey();
406     }
407     return buffer;
408 }
409 
copySurface(GrSurface * dst,const SkIRect & dstRect,GrSurface * src,const SkIRect & srcRect,GrSamplerState::Filter filter)410 bool GrGpu::copySurface(GrSurface* dst, const SkIRect& dstRect,
411                         GrSurface* src, const SkIRect& srcRect,
412                         GrSamplerState::Filter filter) {
413     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
414     SkASSERT(dst && src);
415     SkASSERT(!src->framebufferOnly());
416 
417     if (dst->readOnly()) {
418         return false;
419     }
420 
421     this->handleDirtyContext();
422 
423     return this->onCopySurface(dst, dstRect, src, srcRect, filter);
424 }
425 
readPixels(GrSurface * surface,SkIRect rect,GrColorType surfaceColorType,GrColorType dstColorType,void * buffer,size_t rowBytes)426 bool GrGpu::readPixels(GrSurface* surface,
427                        SkIRect rect,
428                        GrColorType surfaceColorType,
429                        GrColorType dstColorType,
430                        void* buffer,
431                        size_t rowBytes) {
432     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
433     SkASSERT(surface);
434     SkASSERT(!surface->framebufferOnly());
435     SkASSERT(this->caps()->areColorTypeAndFormatCompatible(surfaceColorType,
436                                                            surface->backendFormat()));
437     SkASSERT(dstColorType != GrColorType::kUnknown);
438 
439     if (!SkIRect::MakeSize(surface->dimensions()).contains(rect)) {
440         return false;
441     }
442 
443     size_t minRowBytes = SkToSizeT(GrColorTypeBytesPerPixel(dstColorType) * rect.width());
444     if (!this->caps()->readPixelsRowBytesSupport()) {
445         if (rowBytes != minRowBytes) {
446             return false;
447         }
448     } else {
449         if (rowBytes < minRowBytes) {
450             return false;
451         }
452         if (rowBytes % GrColorTypeBytesPerPixel(dstColorType)) {
453             return false;
454         }
455     }
456 
457     this->handleDirtyContext();
458 
459     return this->onReadPixels(surface, rect, surfaceColorType, dstColorType, buffer, rowBytes);
460 }
461 
writePixels(GrSurface * surface,SkIRect rect,GrColorType surfaceColorType,GrColorType srcColorType,const GrMipLevel texels[],int mipLevelCount,bool prepForTexSampling)462 bool GrGpu::writePixels(GrSurface* surface,
463                         SkIRect rect,
464                         GrColorType surfaceColorType,
465                         GrColorType srcColorType,
466                         const GrMipLevel texels[],
467                         int mipLevelCount,
468                         bool prepForTexSampling) {
469     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
470     ATRACE_ANDROID_FRAMEWORK_ALWAYS("Texture upload(%u) %ix%i",
471                                     surface->uniqueID().asUInt(), rect.width(), rect.height());
472     SkASSERT(surface);
473     SkASSERT(!surface->framebufferOnly());
474 
475     if (surface->readOnly()) {
476         return false;
477     }
478 
479     if (mipLevelCount == 0) {
480         return false;
481     } else if (mipLevelCount == 1) {
482         // We require that if we are not mipped, then the write region is contained in the surface
483         if (!SkIRect::MakeSize(surface->dimensions()).contains(rect)) {
484             return false;
485         }
486     } else if (rect != SkIRect::MakeSize(surface->dimensions())) {
487         // We require that if the texels are mipped, than the write region is the entire surface
488         return false;
489     }
490 
491     if (!validate_texel_levels(rect.size(), srcColorType, texels, mipLevelCount, this->caps())) {
492         return false;
493     }
494 
495     this->handleDirtyContext();
496     if (!this->onWritePixels(surface,
497                              rect,
498                              surfaceColorType,
499                              srcColorType,
500                              texels,
501                              mipLevelCount,
502                              prepForTexSampling)) {
503         return false;
504     }
505 
506     this->didWriteToSurface(surface, kTopLeft_GrSurfaceOrigin, &rect, mipLevelCount);
507     fStats.incTextureUploads();
508 
509     return true;
510 }
511 
transferFromBufferToBuffer(sk_sp<GrGpuBuffer> src,size_t srcOffset,sk_sp<GrGpuBuffer> dst,size_t dstOffset,size_t size)512 bool GrGpu::transferFromBufferToBuffer(sk_sp<GrGpuBuffer> src,
513                                        size_t srcOffset,
514                                        sk_sp<GrGpuBuffer> dst,
515                                        size_t dstOffset,
516                                        size_t size) {
517     SkASSERT(src);
518     SkASSERT(dst);
519     SkASSERT(srcOffset % this->caps()->transferFromBufferToBufferAlignment() == 0);
520     SkASSERT(dstOffset % this->caps()->transferFromBufferToBufferAlignment() == 0);
521     SkASSERT(size      % this->caps()->transferFromBufferToBufferAlignment() == 0);
522     SkASSERT(srcOffset + size <= src->size());
523     SkASSERT(dstOffset + size <= dst->size());
524     SkASSERT(src->intendedType() == GrGpuBufferType::kXferCpuToGpu);
525     SkASSERT(dst->intendedType() != GrGpuBufferType::kXferCpuToGpu);
526 
527     this->handleDirtyContext();
528     if (!this->onTransferFromBufferToBuffer(std::move(src),
529                                             srcOffset,
530                                             std::move(dst),
531                                             dstOffset,
532                                             size)) {
533         return false;
534     }
535 
536     fStats.incBufferTransfers();
537 
538     return true;
539 }
540 
transferPixelsTo(GrTexture * texture,SkIRect rect,GrColorType textureColorType,GrColorType bufferColorType,sk_sp<GrGpuBuffer> transferBuffer,size_t offset,size_t rowBytes)541 bool GrGpu::transferPixelsTo(GrTexture* texture,
542                              SkIRect rect,
543                              GrColorType textureColorType,
544                              GrColorType bufferColorType,
545                              sk_sp<GrGpuBuffer> transferBuffer,
546                              size_t offset,
547                              size_t rowBytes) {
548     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
549     SkASSERT(texture);
550     SkASSERT(transferBuffer);
551     SkASSERT(transferBuffer->intendedType() == GrGpuBufferType::kXferCpuToGpu);
552 
553     if (texture->readOnly()) {
554         return false;
555     }
556 
557     // We require that the write region is contained in the texture
558     if (!SkIRect::MakeSize(texture->dimensions()).contains(rect)) {
559         return false;
560     }
561 
562     size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
563     if (this->caps()->writePixelsRowBytesSupport()) {
564         if (rowBytes < SkToSizeT(bpp*rect.width())) {
565             return false;
566         }
567         if (rowBytes % bpp) {
568             return false;
569         }
570     } else {
571         if (rowBytes != SkToSizeT(bpp*rect.width())) {
572             return false;
573         }
574     }
575 
576     this->handleDirtyContext();
577     if (!this->onTransferPixelsTo(texture,
578                                   rect,
579                                   textureColorType,
580                                   bufferColorType,
581                                   std::move(transferBuffer),
582                                   offset,
583                                   rowBytes)) {
584         return false;
585     }
586 
587     this->didWriteToSurface(texture, kTopLeft_GrSurfaceOrigin, &rect);
588     fStats.incTransfersToTexture();
589 
590     return true;
591 }
592 
transferPixelsFrom(GrSurface * surface,SkIRect rect,GrColorType surfaceColorType,GrColorType bufferColorType,sk_sp<GrGpuBuffer> transferBuffer,size_t offset)593 bool GrGpu::transferPixelsFrom(GrSurface* surface,
594                                SkIRect rect,
595                                GrColorType surfaceColorType,
596                                GrColorType bufferColorType,
597                                sk_sp<GrGpuBuffer> transferBuffer,
598                                size_t offset) {
599     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
600     SkASSERT(surface);
601     SkASSERT(transferBuffer);
602     SkASSERT(transferBuffer->intendedType() == GrGpuBufferType::kXferGpuToCpu);
603     SkASSERT(this->caps()->areColorTypeAndFormatCompatible(surfaceColorType,
604                                                            surface->backendFormat()));
605 
606 #ifdef SK_DEBUG
607     auto supportedRead = this->caps()->supportedReadPixelsColorType(
608             surfaceColorType, surface->backendFormat(), bufferColorType);
609     SkASSERT(supportedRead.fOffsetAlignmentForTransferBuffer);
610     SkASSERT(offset % supportedRead.fOffsetAlignmentForTransferBuffer == 0);
611 #endif
612 
613     // We require that the write region is contained in the texture
614     if (!SkIRect::MakeSize(surface->dimensions()).contains(rect)) {
615         return false;
616     }
617 
618     this->handleDirtyContext();
619     if (!this->onTransferPixelsFrom(surface,
620                                     rect,
621                                     surfaceColorType,
622                                     bufferColorType,
623                                     std::move(transferBuffer),
624                                     offset)) {
625         return false;
626     }
627 
628     fStats.incTransfersFromSurface();
629 
630     return true;
631 }
632 
regenerateMipMapLevels(GrTexture * texture)633 bool GrGpu::regenerateMipMapLevels(GrTexture* texture) {
634     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
635     SkASSERT(texture);
636     SkASSERT(this->caps()->mipmapSupport());
637     SkASSERT(texture->mipmapped() == skgpu::Mipmapped::kYes);
638     if (!texture->mipmapsAreDirty()) {
639         // This can happen when the proxy expects mipmaps to be dirty, but they are not dirty on the
640         // actual target. This may be caused by things that the drawingManager could not predict,
641         // i.e., ops that don't draw anything, aborting a draw for exceptional circumstances, etc.
642         // NOTE: This goes away once we quit tracking mipmap state on the actual texture.
643         return true;
644     }
645     if (texture->readOnly()) {
646         return false;
647     }
648     if (this->onRegenerateMipMapLevels(texture)) {
649         texture->markMipmapsClean();
650         return true;
651     }
652     return false;
653 }
654 
resetTextureBindings()655 void GrGpu::resetTextureBindings() {
656     this->handleDirtyContext();
657     this->onResetTextureBindings();
658 }
659 
resolveRenderTarget(GrRenderTarget * target,const SkIRect & resolveRect)660 void GrGpu::resolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect) {
661     SkASSERT(target);
662     this->handleDirtyContext();
663     this->onResolveRenderTarget(target, resolveRect);
664 }
665 
didWriteToSurface(GrSurface * surface,GrSurfaceOrigin origin,const SkIRect * bounds,uint32_t mipLevels) const666 void GrGpu::didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds,
667                               uint32_t mipLevels) const {
668     SkASSERT(surface);
669     SkASSERT(!surface->readOnly());
670     // Mark any MIP chain as dirty if and only if there is a non-empty bounds.
671     if (nullptr == bounds || !bounds->isEmpty()) {
672         GrTexture* texture = surface->asTexture();
673         if (texture) {
674             if (mipLevels == 1) {
675                 texture->markMipmapsDirty();
676             } else {
677                 texture->markMipmapsClean();
678             }
679         }
680     }
681 }
682 
executeFlushInfo(SkSpan<GrSurfaceProxy * > proxies,SkSurfaces::BackendSurfaceAccess access,const GrFlushInfo & info,std::optional<GrTimerQuery> timerQuery,const skgpu::MutableTextureState * newState)683 void GrGpu::executeFlushInfo(SkSpan<GrSurfaceProxy*> proxies,
684                              SkSurfaces::BackendSurfaceAccess access,
685                              const GrFlushInfo& info,
686                              std::optional<GrTimerQuery> timerQuery,
687                              const skgpu::MutableTextureState* newState) {
688     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
689 
690     GrResourceProvider* resourceProvider = fContext->priv().resourceProvider();
691 
692     std::unique_ptr<std::unique_ptr<GrSemaphore>[]> semaphores(
693             new std::unique_ptr<GrSemaphore>[info.fNumSemaphores]);
694     if (this->caps()->backendSemaphoreSupport() && info.fNumSemaphores) {
695         for (size_t i = 0; i < info.fNumSemaphores; ++i) {
696             if (info.fSignalSemaphores[i].isInitialized()) {
697                 semaphores[i] = resourceProvider->wrapBackendSemaphore(
698                     info.fSignalSemaphores[i],
699                     GrSemaphoreWrapType::kWillSignal,
700                     kBorrow_GrWrapOwnership);
701                 // If we failed to wrap the semaphore it means the client didn't give us a valid
702                 // semaphore to begin with. Therefore, it is fine to not signal it.
703                 if (semaphores[i]) {
704                     this->insertSemaphore(semaphores[i].get());
705                 }
706             } else {
707                 semaphores[i] = resourceProvider->makeSemaphore(false);
708                 if (semaphores[i]) {
709                     this->insertSemaphore(semaphores[i].get());
710                     info.fSignalSemaphores[i] = semaphores[i]->backendSemaphore();
711                 }
712             }
713         }
714     }
715 
716     if (timerQuery) {
717         this->endTimerQuery(*timerQuery);
718     }
719 
720     skgpu::AutoCallback callback;
721     if (info.fFinishedWithStatsProc) {
722         callback = skgpu::AutoCallback(info.fFinishedWithStatsProc, info.fFinishedContext);
723     } else {
724         callback = skgpu::AutoCallback(info.fFinishedProc, info.fFinishedContext);
725     }
726     if (callback) {
727         this->addFinishedCallback(std::move(callback), std::move(timerQuery));
728     }
729 
730     if (info.fSubmittedProc) {
731         fSubmittedProcs.emplace_back(info.fSubmittedProc, info.fSubmittedContext);
732     }
733 
734     // We currently don't support passing in new surface state for multiple proxies here. The only
735     // time we have multiple proxies is if we are flushing a yuv SkImage which won't have state
736     // updates anyways.
737     SkASSERT(!newState || proxies.size() == 1);
738     SkASSERT(!newState || access == SkSurfaces::BackendSurfaceAccess::kNoAccess);
739     this->prepareSurfacesForBackendAccessAndStateUpdates(proxies, access, newState);
740 }
741 
getOpsRenderPass(GrRenderTarget * renderTarget,bool useMSAASurface,GrAttachment * stencil,GrSurfaceOrigin origin,const SkIRect & bounds,const GrOpsRenderPass::LoadAndStoreInfo & colorInfo,const GrOpsRenderPass::StencilLoadAndStoreInfo & stencilInfo,const TArray<GrSurfaceProxy *,true> & sampledProxies,GrXferBarrierFlags renderPassXferBarriers)742 GrOpsRenderPass* GrGpu::getOpsRenderPass(
743         GrRenderTarget* renderTarget,
744         bool useMSAASurface,
745         GrAttachment* stencil,
746         GrSurfaceOrigin origin,
747         const SkIRect& bounds,
748         const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
749         const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
750         const TArray<GrSurfaceProxy*, true>& sampledProxies,
751         GrXferBarrierFlags renderPassXferBarriers) {
752 #if SK_HISTOGRAMS_ENABLED
753     fCurrentSubmitRenderPassCount++;
754 #endif
755     fStats.incRenderPasses();
756     return this->onGetOpsRenderPass(renderTarget, useMSAASurface, stencil, origin, bounds,
757                                     colorInfo, stencilInfo, sampledProxies, renderPassXferBarriers);
758 }
759 
submitToGpu(const GrSubmitInfo & info)760 bool GrGpu::submitToGpu(const GrSubmitInfo& info) {
761     this->stats()->incNumSubmitToGpus();
762 
763     if (auto manager = this->stagingBufferManager()) {
764         manager->detachBuffers();
765     }
766 
767     if (auto uniformsBuffer = this->uniformsRingBuffer()) {
768         uniformsBuffer->startSubmit(this);
769     }
770 
771     bool submitted = this->onSubmitToGpu(info);
772 
773     this->callSubmittedProcs(submitted);
774 
775     this->reportSubmitHistograms();
776 
777     return submitted;
778 }
779 
reportSubmitHistograms()780 void GrGpu::reportSubmitHistograms() {
781 #if SK_HISTOGRAMS_ENABLED
782     // The max allowed value for SK_HISTOGRAM_EXACT_LINEAR is 100. If we want to support higher
783     // values we can add SK_HISTOGRAM_CUSTOM_COUNTS but this has a number of buckets that is less
784     // than the number of actual values
785     [[maybe_unused]] static constexpr int kMaxRenderPassBucketValue = 100;
786     SK_HISTOGRAM_EXACT_LINEAR("SubmitRenderPasses",
787                               std::min(fCurrentSubmitRenderPassCount, kMaxRenderPassBucketValue),
788                               kMaxRenderPassBucketValue);
789     fCurrentSubmitRenderPassCount = 0;
790 #endif
791 
792     this->onReportSubmitHistograms();
793 }
794 
checkAndResetOOMed()795 bool GrGpu::checkAndResetOOMed() {
796     if (fOOMed) {
797         fOOMed = false;
798         return true;
799     }
800     return false;
801 }
802 
callSubmittedProcs(bool success)803 void GrGpu::callSubmittedProcs(bool success) {
804     for (int i = 0; i < fSubmittedProcs.size(); ++i) {
805         fSubmittedProcs[i].fProc(fSubmittedProcs[i].fContext, success);
806     }
807     fSubmittedProcs.clear();
808 }
809 
810 #ifdef SK_ENABLE_DUMP_GPU
811 #include "src/utils/SkJSONWriter.h"
812 
dumpJSON(SkJSONWriter * writer) const813 void GrGpu::dumpJSON(SkJSONWriter* writer) const {
814     writer->beginObject();
815 
816     // TODO: Is there anything useful in the base class to dump here?
817 
818     this->onDumpJSON(writer);
819 
820     writer->endObject();
821 }
822 #else
dumpJSON(SkJSONWriter * writer) const823 void GrGpu::dumpJSON(SkJSONWriter* writer) const { }
824 #endif
825 
826 #if defined(GPU_TEST_UTILS)
827 
828 #if GR_GPU_STATS
829 
dump(SkString * out)830 void GrGpu::Stats::dump(SkString* out) {
831     out->appendf("Textures Created: %d\n", fTextureCreates);
832     out->appendf("Texture Uploads: %d\n", fTextureUploads);
833     out->appendf("Transfers to Texture: %d\n", fTransfersToTexture);
834     out->appendf("Transfers from Surface: %d\n", fTransfersFromSurface);
835     out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates);
836     out->appendf("MSAA Attachment Creates: %d\n", fMSAAAttachmentCreates);
837     out->appendf("Number of draws: %d\n", fNumDraws);
838     out->appendf("Number of Scratch Textures reused %d\n", fNumScratchTexturesReused);
839     out->appendf("Number of Scratch MSAA Attachments reused %d\n",
840                  fNumScratchMSAAAttachmentsReused);
841     out->appendf("Number of Render Passes: %d\n", fRenderPasses);
842     out->appendf("Reordered DAGs Over Budget: %d\n", fNumReorderedDAGsOverBudget);
843 
844     // enable this block to output CSV-style stats for program pre-compilation
845 #if 0
846     SkASSERT(fNumInlineCompilationFailures == 0);
847     SkASSERT(fNumPreCompilationFailures == 0);
848     SkASSERT(fNumCompilationFailures == 0);
849     SkASSERT(fNumPartialCompilationSuccesses == 0);
850 
851     SkDebugf("%d, %d, %d, %d, %d\n",
852              fInlineProgramCacheStats[(int) Stats::ProgramCacheResult::kHit],
853              fInlineProgramCacheStats[(int) Stats::ProgramCacheResult::kMiss],
854              fPreProgramCacheStats[(int) Stats::ProgramCacheResult::kHit],
855              fPreProgramCacheStats[(int) Stats::ProgramCacheResult::kMiss],
856              fNumCompilationSuccesses);
857 #endif
858 }
859 
dumpKeyValuePairs(TArray<SkString> * keys,TArray<double> * values)860 void GrGpu::Stats::dumpKeyValuePairs(TArray<SkString>* keys, TArray<double>* values) {
861     keys->push_back(SkString("render_passes"));
862     values->push_back(fRenderPasses);
863     keys->push_back(SkString("reordered_dags_over_budget"));
864     values->push_back(fNumReorderedDAGsOverBudget);
865 }
866 
867 #endif // GR_GPU_STATS
868 #endif // defined(GPU_TEST_UTILS)
869 
CompressedDataIsCorrect(SkISize dimensions,SkTextureCompressionType compressionType,skgpu::Mipmapped mipmapped,const void * data,size_t length)870 bool GrGpu::CompressedDataIsCorrect(SkISize dimensions,
871                                     SkTextureCompressionType compressionType,
872                                     skgpu::Mipmapped mipmapped,
873                                     const void* data,
874                                     size_t length) {
875     size_t computedSize = SkCompressedDataSize(
876             compressionType, dimensions, nullptr, mipmapped == skgpu::Mipmapped::kYes);
877     return computedSize == length;
878 }
879 
createBackendTexture(SkISize dimensions,const GrBackendFormat & format,GrRenderable renderable,skgpu::Mipmapped mipmapped,GrProtected isProtected,std::string_view label)880 GrBackendTexture GrGpu::createBackendTexture(SkISize dimensions,
881                                              const GrBackendFormat& format,
882                                              GrRenderable renderable,
883                                              skgpu::Mipmapped mipmapped,
884                                              GrProtected isProtected,
885                                              std::string_view label) {
886     const GrCaps* caps = this->caps();
887 
888     if (!format.isValid()) {
889         return {};
890     }
891 
892     if (caps->isFormatCompressed(format)) {
893         // Compressed formats must go through the createCompressedBackendTexture API
894         return {};
895     }
896 
897     if (dimensions.isEmpty() || dimensions.width()  > caps->maxTextureSize() ||
898                                 dimensions.height() > caps->maxTextureSize()) {
899         return {};
900     }
901 
902     if (mipmapped == skgpu::Mipmapped::kYes && !this->caps()->mipmapSupport()) {
903         return {};
904     }
905 
906     return this->onCreateBackendTexture(
907             dimensions, format, renderable, mipmapped, isProtected, label);
908 }
909 
clearBackendTexture(const GrBackendTexture & backendTexture,sk_sp<skgpu::RefCntedCallback> finishedCallback,std::array<float,4> color)910 bool GrGpu::clearBackendTexture(const GrBackendTexture& backendTexture,
911                                 sk_sp<skgpu::RefCntedCallback> finishedCallback,
912                                 std::array<float, 4> color) {
913     if (!backendTexture.isValid()) {
914         return false;
915     }
916 
917     if (backendTexture.hasMipmaps() && !this->caps()->mipmapSupport()) {
918         return false;
919     }
920 
921     return this->onClearBackendTexture(backendTexture, std::move(finishedCallback), color);
922 }
923 
createCompressedBackendTexture(SkISize dimensions,const GrBackendFormat & format,skgpu::Mipmapped mipmapped,GrProtected isProtected)924 GrBackendTexture GrGpu::createCompressedBackendTexture(SkISize dimensions,
925                                                        const GrBackendFormat& format,
926                                                        skgpu::Mipmapped mipmapped,
927                                                        GrProtected isProtected) {
928     const GrCaps* caps = this->caps();
929 
930     if (!format.isValid()) {
931         return {};
932     }
933 
934     SkTextureCompressionType compressionType = GrBackendFormatToCompressionType(format);
935     if (compressionType == SkTextureCompressionType::kNone) {
936         // Uncompressed formats must go through the createBackendTexture API
937         return {};
938     }
939 
940     if (dimensions.isEmpty() ||
941         dimensions.width()  > caps->maxTextureSize() ||
942         dimensions.height() > caps->maxTextureSize()) {
943         return {};
944     }
945 
946     if (mipmapped == skgpu::Mipmapped::kYes && !this->caps()->mipmapSupport()) {
947         return {};
948     }
949 
950     return this->onCreateCompressedBackendTexture(dimensions, format, mipmapped, isProtected);
951 }
952 
updateCompressedBackendTexture(const GrBackendTexture & backendTexture,sk_sp<skgpu::RefCntedCallback> finishedCallback,const void * data,size_t length)953 bool GrGpu::updateCompressedBackendTexture(const GrBackendTexture& backendTexture,
954                                            sk_sp<skgpu::RefCntedCallback> finishedCallback,
955                                            const void* data,
956                                            size_t length) {
957     SkASSERT(data);
958 
959     if (!backendTexture.isValid()) {
960         return false;
961     }
962 
963     GrBackendFormat format = backendTexture.getBackendFormat();
964 
965     SkTextureCompressionType compressionType = GrBackendFormatToCompressionType(format);
966     if (compressionType == SkTextureCompressionType::kNone) {
967         // Uncompressed formats must go through the createBackendTexture API
968         return false;
969     }
970 
971     if (backendTexture.hasMipmaps() && !this->caps()->mipmapSupport()) {
972         return false;
973     }
974 
975     skgpu::Mipmapped mipmapped =
976             backendTexture.hasMipmaps() ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
977 
978     if (!CompressedDataIsCorrect(backendTexture.dimensions(),
979                                  compressionType,
980                                  mipmapped,
981                                  data,
982                                  length)) {
983         return false;
984     }
985 
986     return this->onUpdateCompressedBackendTexture(backendTexture,
987                                                   std::move(finishedCallback),
988                                                   data,
989                                                   length);
990 }
991