blob: 0eca48993ec619c7553856fc0e1361b6b2e48f95 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00006 */
7
epoger@google.comec3ed6a2011-07-28 14:26:00 +00008
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "src/gpu/GrGpu.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000010
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/gpu/GrBackendSemaphore.h"
12#include "include/gpu/GrBackendSurface.h"
13#include "include/gpu/GrContext.h"
Robert Phillips99dead92020-01-27 16:11:57 -050014#include "src/core/SkCompressedDataUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/core/SkMathPriv.h"
Robert Phillips57ef6802019-09-23 10:12:47 -040016#include "src/core/SkMipMap.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040017#include "src/gpu/GrAuditTrail.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrCaps.h"
19#include "src/gpu/GrContextPriv.h"
Brian Salomonbb8dde82019-06-27 10:52:13 -040020#include "src/gpu/GrDataUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/GrGpuResourcePriv.h"
22#include "src/gpu/GrMesh.h"
Chris Dalton16a33c62019-09-24 22:19:17 -060023#include "src/gpu/GrNativeRect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/GrPathRendering.h"
25#include "src/gpu/GrPipeline.h"
26#include "src/gpu/GrRenderTargetPriv.h"
27#include "src/gpu/GrResourceCache.h"
28#include "src/gpu/GrResourceProvider.h"
29#include "src/gpu/GrSemaphore.h"
30#include "src/gpu/GrStencilAttachment.h"
31#include "src/gpu/GrStencilSettings.h"
32#include "src/gpu/GrSurfacePriv.h"
33#include "src/gpu/GrTexturePriv.h"
34#include "src/gpu/GrTextureProxyPriv.h"
35#include "src/gpu/GrTracing.h"
36#include "src/utils/SkJSONWriter.h"
bsalomoncb8979d2015-05-05 09:51:38 -070037
bsalomon@google.comd302f142011-03-03 13:54:13 +000038////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000039
Brian Salomone2826ab2019-06-04 15:58:31 -040040GrGpu::GrGpu(GrContext* context) : fResetBits(kAll_GrBackendState), fContext(context) {}
reed@google.comac10a2d2010-12-22 21:39:39 +000041
bsalomoned0bcad2015-05-04 10:36:42 -070042GrGpu::~GrGpu() {}
bsalomon1d89ddc2014-08-19 14:20:58 -070043
bsalomon6e2aad42016-04-01 11:54:31 -070044void GrGpu::disconnect(DisconnectType) {}
reed@google.comac10a2d2010-12-22 21:39:39 +000045
bsalomon@google.comd302f142011-03-03 13:54:13 +000046////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000047
Robert Phillipsbf5cb0f2020-02-21 13:46:38 +000048bool GrGpu::IsACopyNeededForMips(const GrCaps* caps, const GrTextureProxy* texProxy,
Brian Salomonc8d092a2020-02-24 10:14:21 -050049 GrSamplerState::Filter filter) {
Robert Phillipsbf5cb0f2020-02-21 13:46:38 +000050 SkASSERT(texProxy);
Brian Salomonc8d092a2020-02-24 10:14:21 -050051 if (filter != GrSamplerState::Filter::kMipMap || texProxy->mipMapped() == GrMipMapped::kYes ||
52 !caps->mipMapSupport()) {
53 return false;
Robert Phillipsbf5cb0f2020-02-21 13:46:38 +000054 }
Brian Salomonc8d092a2020-02-24 10:14:21 -050055 return SkMipMap::ComputeLevelCount(texProxy->width(), texProxy->height()) > 0;
Greg Daniel8f5bbda2018-06-08 17:22:23 -040056}
57
Brian Salomona56a7462020-02-07 14:17:25 -050058static bool validate_texel_levels(SkISize dimensions, GrColorType texelColorType,
Brian Salomona90382f2019-09-17 09:01:56 -040059 const GrMipLevel* texels, int mipLevelCount, const GrCaps* caps) {
Brian Salomon1047a492019-07-02 12:25:21 -040060 SkASSERT(mipLevelCount > 0);
61 bool hasBasePixels = texels[0].fPixels;
62 int levelsWithPixelsCnt = 0;
Brian Salomona90382f2019-09-17 09:01:56 -040063 auto bpp = GrColorTypeBytesPerPixel(texelColorType);
Brian Salomona56a7462020-02-07 14:17:25 -050064 int w = dimensions.fWidth;
65 int h = dimensions.fHeight;
Brian Salomon1047a492019-07-02 12:25:21 -040066 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; ++currentMipLevel) {
67 if (texels[currentMipLevel].fPixels) {
68 const size_t minRowBytes = w * bpp;
69 if (caps->writePixelsRowBytesSupport()) {
70 if (texels[currentMipLevel].fRowBytes < minRowBytes) {
71 return false;
72 }
73 if (texels[currentMipLevel].fRowBytes % bpp) {
74 return false;
75 }
76 } else {
77 if (texels[currentMipLevel].fRowBytes != minRowBytes) {
78 return false;
79 }
80 }
81 ++levelsWithPixelsCnt;
82 }
83 if (w == 1 && h == 1) {
84 if (currentMipLevel != mipLevelCount - 1) {
85 return false;
86 }
87 } else {
88 w = std::max(w / 2, 1);
89 h = std::max(h / 2, 1);
90 }
91 }
92 // Either just a base layer or a full stack is required.
93 if (mipLevelCount != 1 && (w != 1 || h != 1)) {
94 return false;
95 }
96 // Can specify just the base, all levels, or no levels.
97 if (!hasBasePixels) {
98 return levelsWithPixelsCnt == 0;
99 }
Brian Salomond2a8ae22019-09-10 16:03:59 -0400100 return levelsWithPixelsCnt == 1 || levelsWithPixelsCnt == mipLevelCount;
Brian Salomon1047a492019-07-02 12:25:21 -0400101}
102
Brian Salomona56a7462020-02-07 14:17:25 -0500103sk_sp<GrTexture> GrGpu::createTextureCommon(SkISize dimensions,
Brian Salomona90382f2019-09-17 09:01:56 -0400104 const GrBackendFormat& format,
105 GrRenderable renderable,
106 int renderTargetSampleCnt,
107 SkBudgeted budgeted,
108 GrProtected isProtected,
109 int mipLevelCount,
110 uint32_t levelClearMask) {
Brian Salomon81536f22019-08-08 16:30:49 -0400111 if (this->caps()->isFormatCompressed(format)) {
Brian Salomonbb8dde82019-06-27 10:52:13 -0400112 // Call GrGpu::createCompressedTexture.
113 return nullptr;
114 }
cblume55f2d2d2016-02-26 13:20:48 -0800115
Brian Salomona90382f2019-09-17 09:01:56 -0400116 GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
Brian Salomona56a7462020-02-07 14:17:25 -0500117 if (!this->caps()->validateSurfaceParams(dimensions, format, renderable, renderTargetSampleCnt,
118 mipMapped)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700119 return nullptr;
egdaniel8c9b6f12015-05-12 13:36:30 -0700120 }
121
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400122 if (renderable == GrRenderable::kYes) {
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400123 renderTargetSampleCnt =
Greg Daniel6fa62e22019-08-07 15:52:37 -0400124 this->caps()->getRenderTargetSampleCount(renderTargetSampleCnt, format);
Brian Salomonbdecacf2018-02-02 20:32:49 -0500125 }
Brian Salomond17b4a62017-05-23 16:53:47 -0400126 // Attempt to catch un- or wrongly initialized sample counts.
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400127 SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64);
Brian Salomona90382f2019-09-17 09:01:56 -0400128 this->handleDirtyContext();
Brian Salomona56a7462020-02-07 14:17:25 -0500129 auto tex = this->onCreateTexture(dimensions,
Brian Salomona90382f2019-09-17 09:01:56 -0400130 format,
131 renderable,
132 renderTargetSampleCnt,
133 budgeted,
134 isProtected,
135 mipLevelCount,
136 levelClearMask);
137 if (tex) {
138 SkASSERT(tex->backendFormat() == format);
139 SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
140 if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
141 tex->resourcePriv().removeScratchKey();
142 }
143 fStats.incTextureCreates();
144 if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
145 SkASSERT(GrRenderable::kYes == renderable);
146 tex->asRenderTarget()->setRequiresManualMSAAResolve();
147 }
148 }
149 return tex;
150}
151
Brian Salomona56a7462020-02-07 14:17:25 -0500152sk_sp<GrTexture> GrGpu::createTexture(SkISize dimensions,
Brian Salomona90382f2019-09-17 09:01:56 -0400153 const GrBackendFormat& format,
154 GrRenderable renderable,
155 int renderTargetSampleCnt,
156 GrMipMapped mipMapped,
157 SkBudgeted budgeted,
158 GrProtected isProtected) {
159 int mipLevelCount = 1;
160 if (mipMapped == GrMipMapped::kYes) {
Brian Salomona56a7462020-02-07 14:17:25 -0500161 mipLevelCount =
162 32 - SkCLZ(static_cast<uint32_t>(std::max(dimensions.fWidth, dimensions.fHeight)));
Brian Salomona90382f2019-09-17 09:01:56 -0400163 }
164 uint32_t levelClearMask =
165 this->caps()->shouldInitializeTextures() ? (1 << mipLevelCount) - 1 : 0;
Brian Salomona56a7462020-02-07 14:17:25 -0500166 auto tex = this->createTextureCommon(dimensions, format, renderable, renderTargetSampleCnt,
167 budgeted, isProtected, mipLevelCount, levelClearMask);
Brian Salomona90382f2019-09-17 09:01:56 -0400168 if (tex && mipMapped == GrMipMapped::kYes && levelClearMask) {
169 tex->texturePriv().markMipMapsClean();
170 }
171 return tex;
172}
173
Brian Salomona56a7462020-02-07 14:17:25 -0500174sk_sp<GrTexture> GrGpu::createTexture(SkISize dimensions,
Brian Salomona90382f2019-09-17 09:01:56 -0400175 const GrBackendFormat& format,
176 GrRenderable renderable,
177 int renderTargetSampleCnt,
178 SkBudgeted budgeted,
179 GrProtected isProtected,
180 GrColorType textureColorType,
181 GrColorType srcColorType,
182 const GrMipLevel texels[],
183 int texelLevelCount) {
184 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomond2a8ae22019-09-10 16:03:59 -0400185 if (texelLevelCount) {
Brian Salomona56a7462020-02-07 14:17:25 -0500186 if (!validate_texel_levels(dimensions, srcColorType, texels, texelLevelCount,
Brian Salomond2a8ae22019-09-10 16:03:59 -0400187 this->caps())) {
Brian Salomon1047a492019-07-02 12:25:21 -0400188 return nullptr;
189 }
Brian Salomond2a8ae22019-09-10 16:03:59 -0400190 }
191
Brian Osman788b9162020-02-07 10:36:46 -0500192 int mipLevelCount = std::max(1, texelLevelCount);
Brian Salomond2a8ae22019-09-10 16:03:59 -0400193 uint32_t levelClearMask = 0;
194 if (this->caps()->shouldInitializeTextures()) {
195 if (texelLevelCount) {
196 for (int i = 0; i < mipLevelCount; ++i) {
197 if (!texels->fPixels) {
198 levelClearMask |= static_cast<uint32_t>(1 << i);
199 }
200 }
201 } else {
202 levelClearMask = static_cast<uint32_t>((1 << mipLevelCount) - 1);
203 }
Brian Salomond17b4a62017-05-23 16:53:47 -0400204 }
205
Brian Salomona56a7462020-02-07 14:17:25 -0500206 auto tex = this->createTextureCommon(dimensions, format, renderable, renderTargetSampleCnt,
207 budgeted, isProtected, texelLevelCount, levelClearMask);
bsalomonb12ea412015-02-02 21:19:50 -0800208 if (tex) {
Brian Salomond2a8ae22019-09-10 16:03:59 -0400209 bool markMipLevelsClean = false;
210 // Currently if level 0 does not have pixels then no other level may, as enforced by
211 // validate_texel_levels.
212 if (texelLevelCount && texels[0].fPixels) {
Brian Salomona56a7462020-02-07 14:17:25 -0500213 if (!this->writePixels(tex.get(), 0, 0, dimensions.fWidth, dimensions.fHeight,
214 textureColorType, srcColorType, texels, texelLevelCount)) {
Brian Salomond2a8ae22019-09-10 16:03:59 -0400215 return nullptr;
cblume55f2d2d2016-02-26 13:20:48 -0800216 }
Brian Salomond2a8ae22019-09-10 16:03:59 -0400217 // Currently if level[1] of mip map has pixel data then so must all other levels.
218 // as enforced by validate_texel_levels.
219 markMipLevelsClean = (texelLevelCount > 1 && !levelClearMask && texels[1].fPixels);
220 fStats.incTextureUploads();
221 } else if (levelClearMask && mipLevelCount > 1) {
222 markMipLevelsClean = true;
bsalomonb12ea412015-02-02 21:19:50 -0800223 }
Brian Salomond2a8ae22019-09-10 16:03:59 -0400224 if (markMipLevelsClean) {
225 tex->texturePriv().markMipMapsClean();
226 }
bsalomonb12ea412015-02-02 21:19:50 -0800227 }
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000228 return tex;
229}
230
Robert Phillips9f744f72019-12-19 19:14:33 -0500231sk_sp<GrTexture> GrGpu::createCompressedTexture(SkISize dimensions,
Greg Daniel7bfc9132019-08-14 14:23:53 -0400232 const GrBackendFormat& format,
Robert Phillips42716d42019-12-16 12:19:54 -0500233 SkBudgeted budgeted,
Robert Phillipse4720c62020-01-14 14:33:24 -0500234 GrMipMapped mipMapped,
Robert Phillips3a833922020-01-21 15:25:58 -0500235 GrProtected isProtected,
Robert Phillips42716d42019-12-16 12:19:54 -0500236 const void* data,
Brian Salomonbb8dde82019-06-27 10:52:13 -0400237 size_t dataSize) {
238 this->handleDirtyContext();
Robert Phillips9f744f72019-12-19 19:14:33 -0500239 if (dimensions.width() < 1 || dimensions.width() > this->caps()->maxTextureSize() ||
240 dimensions.height() < 1 || dimensions.height() > this->caps()->maxTextureSize()) {
Brian Salomonbb8dde82019-06-27 10:52:13 -0400241 return nullptr;
242 }
Brian Salomona3e29962019-07-16 11:52:08 -0400243 // Note if we relax the requirement that data must be provided then we must check
244 // caps()->shouldInitializeTextures() here.
Brian Salomonbb8dde82019-06-27 10:52:13 -0400245 if (!data) {
246 return nullptr;
247 }
Greg Daniel7bfc9132019-08-14 14:23:53 -0400248 if (!this->caps()->isFormatTexturable(format)) {
Brian Salomonbb8dde82019-06-27 10:52:13 -0400249 return nullptr;
250 }
Robert Phillips9f744f72019-12-19 19:14:33 -0500251
252 // TODO: expand CompressedDataIsCorrect to work here too
253 SkImage::CompressionType compressionType = this->caps()->compressionType(format);
254
Robert Phillips99dead92020-01-27 16:11:57 -0500255 if (dataSize < SkCompressedDataSize(compressionType, dimensions, nullptr,
256 mipMapped == GrMipMapped::kYes)) {
Brian Salomonbb8dde82019-06-27 10:52:13 -0400257 return nullptr;
258 }
Robert Phillips3a833922020-01-21 15:25:58 -0500259 return this->onCreateCompressedTexture(dimensions, format, budgeted, mipMapped, isProtected,
260 data, dataSize);
Brian Salomonbb8dde82019-06-27 10:52:13 -0400261}
262
Greg Daniel7ef28f32017-04-20 16:41:55 +0000263sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex,
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400264 GrColorType colorType,
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500265 GrWrapOwnership ownership, GrWrapCacheable cacheable,
266 GrIOType ioType) {
Brian Salomonc67c31c2018-12-06 10:00:03 -0500267 SkASSERT(ioType != kWrite_GrIOType);
bsalomon@google.come269f212011-11-07 13:29:52 +0000268 this->handleDirtyContext();
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400269
270 const GrCaps* caps = this->caps();
271 SkASSERT(caps);
272
Greg Daniel7bfc9132019-08-14 14:23:53 -0400273 if (!caps->isFormatTexturable(backendTex.getBackendFormat())) {
bsalomon5b30c6f2015-12-17 14:17:34 -0800274 return nullptr;
275 }
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400276 if (backendTex.width() > caps->maxTextureSize() ||
277 backendTex.height() > caps->maxTextureSize()) {
bsalomon5b30c6f2015-12-17 14:17:34 -0800278 return nullptr;
279 }
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400280
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400281 return this->onWrapBackendTexture(backendTex, colorType, ownership, cacheable, ioType);
Brian Salomond17f6582017-07-19 18:28:58 -0400282}
Eric Karl5c779752017-05-08 12:02:07 -0700283
Robert Phillipsb915c942019-12-17 14:44:37 -0500284sk_sp<GrTexture> GrGpu::wrapCompressedBackendTexture(const GrBackendTexture& backendTex,
285 GrWrapOwnership ownership,
286 GrWrapCacheable cacheable) {
287 this->handleDirtyContext();
288
289 const GrCaps* caps = this->caps();
290 SkASSERT(caps);
291
292 if (!caps->isFormatTexturable(backendTex.getBackendFormat())) {
293 return nullptr;
294 }
295 if (backendTex.width() > caps->maxTextureSize() ||
296 backendTex.height() > caps->maxTextureSize()) {
297 return nullptr;
298 }
299
300 return this->onWrapCompressedBackendTexture(backendTex, ownership, cacheable);
301}
302
303
Brian Salomond17f6582017-07-19 18:28:58 -0400304sk_sp<GrTexture> GrGpu::wrapRenderableBackendTexture(const GrBackendTexture& backendTex,
Robert Phillips0902c982019-07-16 07:47:56 -0400305 int sampleCnt, GrColorType colorType,
306 GrWrapOwnership ownership,
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500307 GrWrapCacheable cacheable) {
Brian Salomond17f6582017-07-19 18:28:58 -0400308 this->handleDirtyContext();
Brian Salomonbdecacf2018-02-02 20:32:49 -0500309 if (sampleCnt < 1) {
310 return nullptr;
311 }
Robert Phillips0902c982019-07-16 07:47:56 -0400312
313 const GrCaps* caps = this->caps();
314
Greg Daniel7bfc9132019-08-14 14:23:53 -0400315 if (!caps->isFormatTexturable(backendTex.getBackendFormat()) ||
Greg Daniel6fa62e22019-08-07 15:52:37 -0400316 !caps->isFormatRenderable(backendTex.getBackendFormat(), sampleCnt)) {
Brian Salomond17f6582017-07-19 18:28:58 -0400317 return nullptr;
318 }
319
Robert Phillips0902c982019-07-16 07:47:56 -0400320 if (backendTex.width() > caps->maxRenderTargetSize() ||
321 backendTex.height() > caps->maxRenderTargetSize()) {
Brian Salomond17f6582017-07-19 18:28:58 -0400322 return nullptr;
323 }
Robert Phillips0902c982019-07-16 07:47:56 -0400324 sk_sp<GrTexture> tex = this->onWrapRenderableBackendTexture(backendTex, sampleCnt, colorType,
325 ownership, cacheable);
Greg Daniele3204862018-04-16 11:24:10 -0400326 SkASSERT(!tex || tex->asRenderTarget());
Chris Dalton3f7932e2019-08-19 00:39:13 -0600327 if (tex && sampleCnt > 1 && !caps->msaaResolvesAutomatically()) {
328 tex->asRenderTarget()->setRequiresManualMSAAResolve();
329 }
bungeman6bd52842016-10-27 09:30:08 -0700330 return tex;
bsalomon@google.come269f212011-11-07 13:29:52 +0000331}
332
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400333sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT,
334 GrColorType colorType) {
335 this->handleDirtyContext();
336
337 const GrCaps* caps = this->caps();
338
Greg Daniel6fa62e22019-08-07 15:52:37 -0400339 if (!caps->isFormatRenderable(backendRT.getBackendFormat(), backendRT.sampleCnt())) {
bsalomon5b30c6f2015-12-17 14:17:34 -0800340 return nullptr;
341 }
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400342
Stephen White3c0a50f2020-01-16 18:19:54 -0500343 sk_sp<GrRenderTarget> rt = this->onWrapBackendRenderTarget(backendRT, colorType);
344 if (backendRT.isFramebufferOnly()) {
345 rt->setFramebufferOnly();
346 }
347 return rt;
bsalomon@google.come269f212011-11-07 13:29:52 +0000348}
349
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400350sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& backendTex,
351 int sampleCnt,
352 GrColorType colorType) {
Brian Salomonbdecacf2018-02-02 20:32:49 -0500353 this->handleDirtyContext();
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400354
355 const GrCaps* caps = this->caps();
356
357 int maxSize = caps->maxTextureSize();
358 if (backendTex.width() > maxSize || backendTex.height() > maxSize) {
359 return nullptr;
360 }
361
Greg Daniel6fa62e22019-08-07 15:52:37 -0400362 if (!caps->isFormatRenderable(backendTex.getBackendFormat(), sampleCnt)) {
Robert Phillipsc80b0e92019-07-23 10:27:09 -0400363 return nullptr;
364 }
Robert Phillips1cd1ed82019-07-23 13:21:01 -0400365
Chris Dalton3f7932e2019-08-19 00:39:13 -0600366 auto rt = this->onWrapBackendTextureAsRenderTarget(backendTex, sampleCnt, colorType);
367 if (rt && sampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
368 rt->setRequiresManualMSAAResolve();
369 }
370 return rt;
ericrkf7b8b8a2016-02-24 14:49:51 -0800371}
372
Greg Danielb46add82019-01-02 14:51:29 -0500373sk_sp<GrRenderTarget> GrGpu::wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
374 const GrVkDrawableInfo& vkInfo) {
375 return this->onWrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo);
376}
377
378sk_sp<GrRenderTarget> GrGpu::onWrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
379 const GrVkDrawableInfo& vkInfo) {
380 // This is only supported on Vulkan so we default to returning nullptr here
381 return nullptr;
382}
383
Brian Salomondbf70722019-02-07 11:31:24 -0500384sk_sp<GrGpuBuffer> GrGpu::createBuffer(size_t size, GrGpuBufferType intendedType,
385 GrAccessPattern accessPattern, const void* data) {
Brian Salomone39526b2019-06-24 16:35:53 -0400386 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000387 this->handleDirtyContext();
Brian Salomondbf70722019-02-07 11:31:24 -0500388 sk_sp<GrGpuBuffer> buffer = this->onCreateBuffer(size, intendedType, accessPattern, data);
robertphillips1b8e1b52015-06-24 06:54:10 -0700389 if (!this->caps()->reuseScratchBuffers()) {
cdalton397536c2016-03-25 12:15:03 -0700390 buffer->resourcePriv().removeScratchKey();
robertphillips1b8e1b52015-06-24 06:54:10 -0700391 }
cdalton397536c2016-03-25 12:15:03 -0700392 return buffer;
jvanverth73063dc2015-12-03 09:15:47 -0800393}
394
Greg Daniel46cfbc62019-06-07 11:43:30 -0400395bool GrGpu::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
Greg Daniele227fe42019-08-21 13:52:24 -0400396 const SkIPoint& dstPoint) {
Brian Salomone39526b2019-06-24 16:35:53 -0400397 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
joshualitt1cbdcde2015-08-21 11:53:29 -0700398 SkASSERT(dst && src);
Stephen White3c0a50f2020-01-16 18:19:54 -0500399 SkASSERT(!src->framebufferOnly());
Brian Salomonc67c31c2018-12-06 10:00:03 -0500400
401 if (dst->readOnly()) {
402 return false;
403 }
404
joshualitt1cbdcde2015-08-21 11:53:29 -0700405 this->handleDirtyContext();
Brian Salomonc67c31c2018-12-06 10:00:03 -0500406
Greg Daniele227fe42019-08-21 13:52:24 -0400407 return this->onCopySurface(dst, src, srcRect, dstPoint);
joshualitt1cbdcde2015-08-21 11:53:29 -0700408}
409
Brian Salomona6948702018-06-01 15:33:20 -0400410bool GrGpu::readPixels(GrSurface* surface, int left, int top, int width, int height,
Brian Salomonf77c1462019-08-01 15:19:29 -0400411 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
412 size_t rowBytes) {
Brian Salomone39526b2019-06-24 16:35:53 -0400413 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomonbf7b6202016-11-11 16:08:03 -0500414 SkASSERT(surface);
Stephen White3c0a50f2020-01-16 18:19:54 -0500415 SkASSERT(!surface->framebufferOnly());
Greg Daniel7bfc9132019-08-14 14:23:53 -0400416 SkASSERT(this->caps()->isFormatTexturable(surface->backendFormat()));
Brian Salomonbf7b6202016-11-11 16:08:03 -0500417
Brian Salomon1d435302019-07-01 13:05:28 -0400418 auto subRect = SkIRect::MakeXYWH(left, top, width, height);
419 auto bounds = SkIRect::MakeWH(surface->width(), surface->height());
420 if (!bounds.contains(subRect)) {
egdaniel6d901da2015-07-30 12:02:15 -0700421 return false;
422 }
423
Brian Salomon1047a492019-07-02 12:25:21 -0400424 size_t minRowBytes = SkToSizeT(GrColorTypeBytesPerPixel(dstColorType) * width);
425 if (!this->caps()->readPixelsRowBytesSupport()) {
426 if (rowBytes != minRowBytes) {
427 return false;
428 }
429 } else {
430 if (rowBytes < minRowBytes) {
431 return false;
432 }
433 if (rowBytes % GrColorTypeBytesPerPixel(dstColorType)) {
434 return false;
435 }
436 }
437
Brian Salomonbf7b6202016-11-11 16:08:03 -0500438 this->handleDirtyContext();
439
Brian Salomonf77c1462019-08-01 15:19:29 -0400440 return this->onReadPixels(surface, left, top, width, height, surfaceColorType, dstColorType,
441 buffer, rowBytes);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000442}
443
Brian Salomona9b04b92018-06-01 15:04:28 -0400444bool GrGpu::writePixels(GrSurface* surface, int left, int top, int width, int height,
Brian Salomonf77c1462019-08-01 15:19:29 -0400445 GrColorType surfaceColorType, GrColorType srcColorType,
Greg Danielb20d7e52019-09-03 13:54:39 -0400446 const GrMipLevel texels[], int mipLevelCount, bool prepForTexSampling) {
Brian Salomone39526b2019-06-24 16:35:53 -0400447 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomonbf7b6202016-11-11 16:08:03 -0500448 SkASSERT(surface);
Stephen White3c0a50f2020-01-16 18:19:54 -0500449 SkASSERT(!surface->framebufferOnly());
Greg Daniel7bfc9132019-08-14 14:23:53 -0400450 SkASSERT(this->caps()->isFormatTexturableAndUploadable(surfaceColorType,
451 surface->backendFormat()));
Brian Salomonc67c31c2018-12-06 10:00:03 -0500452
453 if (surface->readOnly()) {
454 return false;
455 }
456
Brian Salomon1047a492019-07-02 12:25:21 -0400457 if (mipLevelCount == 0) {
458 return false;
459 } else if (mipLevelCount == 1) {
Greg Daniel660cc992017-06-26 14:55:05 -0400460 // We require that if we are not mipped, then the write region is contained in the surface
Brian Salomon1d435302019-07-01 13:05:28 -0400461 auto subRect = SkIRect::MakeXYWH(left, top, width, height);
462 auto bounds = SkIRect::MakeWH(surface->width(), surface->height());
Greg Daniel660cc992017-06-26 14:55:05 -0400463 if (!bounds.contains(subRect)) {
464 return false;
465 }
466 } else if (0 != left || 0 != top || width != surface->width() || height != surface->height()) {
467 // We require that if the texels are mipped, than the write region is the entire surface
468 return false;
469 }
Robert Phillipsb7b7e5f2017-05-22 13:23:19 -0400470
Brian Salomona56a7462020-02-07 14:17:25 -0500471 if (!validate_texel_levels({width, height}, srcColorType, texels, mipLevelCount,
472 this->caps())) {
Brian Salomon1047a492019-07-02 12:25:21 -0400473 return false;
cblume55f2d2d2016-02-26 13:20:48 -0800474 }
jvanverth2dc29942015-09-01 07:16:46 -0700475
bsalomon@google.com6f379512011-11-16 20:36:03 +0000476 this->handleDirtyContext();
Brian Salomonf77c1462019-08-01 15:19:29 -0400477 if (this->onWritePixels(surface, left, top, width, height, surfaceColorType, srcColorType,
Greg Danielb20d7e52019-09-03 13:54:39 -0400478 texels, mipLevelCount, prepForTexSampling)) {
jvanverth900bd4a2016-04-29 13:53:12 -0700479 SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
Brian Salomona9b04b92018-06-01 15:04:28 -0400480 this->didWriteToSurface(surface, kTopLeft_GrSurfaceOrigin, &rect, mipLevelCount);
bsalomonb12ea412015-02-02 21:19:50 -0800481 fStats.incTextureUploads();
482 return true;
483 }
484 return false;
bsalomon@google.com6f379512011-11-16 20:36:03 +0000485}
486
Brian Salomone05ba5a2019-04-08 11:59:07 -0400487bool GrGpu::transferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
Brian Salomonf77c1462019-08-01 15:19:29 -0400488 GrColorType textureColorType, GrColorType bufferColorType,
489 GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) {
Brian Salomone39526b2019-06-24 16:35:53 -0400490 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomonc67c31c2018-12-06 10:00:03 -0500491 SkASSERT(texture);
cdalton397536c2016-03-25 12:15:03 -0700492 SkASSERT(transferBuffer);
Greg Daniel7bfc9132019-08-14 14:23:53 -0400493 SkASSERT(this->caps()->isFormatTexturableAndUploadable(textureColorType,
494 texture->backendFormat()));
jvanverth17aa0472016-01-05 10:41:27 -0800495
Brian Salomonc67c31c2018-12-06 10:00:03 -0500496 if (texture->readOnly()) {
497 return false;
498 }
499
Greg Daniel660cc992017-06-26 14:55:05 -0400500 // We require that the write region is contained in the texture
501 SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
502 SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
503 if (!bounds.contains(subRect)) {
504 return false;
505 }
506
Brian Salomonb28cb682019-07-26 12:48:47 -0400507 size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
Brian Salomon1047a492019-07-02 12:25:21 -0400508 if (this->caps()->writePixelsRowBytesSupport()) {
509 if (rowBytes < SkToSizeT(bpp * width)) {
510 return false;
511 }
512 if (rowBytes % bpp) {
513 return false;
514 }
515 } else {
516 if (rowBytes != SkToSizeT(bpp * width)) {
517 return false;
518 }
519 }
520
jvanverth17aa0472016-01-05 10:41:27 -0800521 this->handleDirtyContext();
Brian Salomonf77c1462019-08-01 15:19:29 -0400522 if (this->onTransferPixelsTo(texture, left, top, width, height, textureColorType,
523 bufferColorType, transferBuffer, offset, rowBytes)) {
jvanverth900bd4a2016-04-29 13:53:12 -0700524 SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
Brian Salomon1fabd512018-02-09 09:54:25 -0500525 this->didWriteToSurface(texture, kTopLeft_GrSurfaceOrigin, &rect);
jvanverth17aa0472016-01-05 10:41:27 -0800526 fStats.incTransfersToTexture();
jvanverth84741b32016-09-30 08:39:02 -0700527
jvanverth17aa0472016-01-05 10:41:27 -0800528 return true;
529 }
530 return false;
531}
532
Brian Salomon26de56e2019-04-10 12:14:26 -0400533bool GrGpu::transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
Brian Salomonf77c1462019-08-01 15:19:29 -0400534 GrColorType surfaceColorType, GrColorType bufferColorType,
535 GrGpuBuffer* transferBuffer, size_t offset) {
Brian Salomone39526b2019-06-24 16:35:53 -0400536 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400537 SkASSERT(surface);
538 SkASSERT(transferBuffer);
Greg Daniel7bfc9132019-08-14 14:23:53 -0400539 SkASSERT(this->caps()->isFormatTexturable(surface->backendFormat()));
Brian Salomonf77c1462019-08-01 15:19:29 -0400540
Greg Danielba88ab62019-07-26 09:14:01 -0400541#ifdef SK_DEBUG
Brian Salomon1c53a9f2019-08-12 14:10:12 -0400542 auto supportedRead = this->caps()->supportedReadPixelsColorType(
543 surfaceColorType, surface->backendFormat(), bufferColorType);
Greg Danielba88ab62019-07-26 09:14:01 -0400544 SkASSERT(supportedRead.fOffsetAlignmentForTransferBuffer);
545 SkASSERT(offset % supportedRead.fOffsetAlignmentForTransferBuffer == 0);
546#endif
Brian Salomone05ba5a2019-04-08 11:59:07 -0400547
548 // We require that the write region is contained in the texture
549 SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
550 SkIRect bounds = SkIRect::MakeWH(surface->width(), surface->height());
551 if (!bounds.contains(subRect)) {
552 return false;
553 }
554
555 this->handleDirtyContext();
Brian Salomonf77c1462019-08-01 15:19:29 -0400556 if (this->onTransferPixelsFrom(surface, left, top, width, height, surfaceColorType,
557 bufferColorType, transferBuffer, offset)) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400558 fStats.incTransfersFromSurface();
Brian Salomon26de56e2019-04-10 12:14:26 -0400559 return true;
Brian Salomone05ba5a2019-04-08 11:59:07 -0400560 }
Brian Salomon26de56e2019-04-10 12:14:26 -0400561 return false;
Brian Salomone05ba5a2019-04-08 11:59:07 -0400562}
563
Brian Salomon930f9392018-06-20 16:25:26 -0400564bool GrGpu::regenerateMipMapLevels(GrTexture* texture) {
Brian Salomone39526b2019-06-24 16:35:53 -0400565 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Brian Salomon930f9392018-06-20 16:25:26 -0400566 SkASSERT(texture);
567 SkASSERT(this->caps()->mipMapSupport());
568 SkASSERT(texture->texturePriv().mipMapped() == GrMipMapped::kYes);
Chris Dalton16a33c62019-09-24 22:19:17 -0600569 if (!texture->texturePriv().mipMapsAreDirty()) {
570 // This can happen when the proxy expects mipmaps to be dirty, but they are not dirty on the
571 // actual target. This may be caused by things that the drawingManager could not predict,
572 // i.e., ops that don't draw anything, aborting a draw for exceptional circumstances, etc.
573 // NOTE: This goes away once we quit tracking mipmap state on the actual texture.
574 return true;
575 }
Brian Salomonc67c31c2018-12-06 10:00:03 -0500576 if (texture->readOnly()) {
577 return false;
578 }
Brian Salomon930f9392018-06-20 16:25:26 -0400579 if (this->onRegenerateMipMapLevels(texture)) {
580 texture->texturePriv().markMipMapsClean();
581 return true;
582 }
583 return false;
584}
585
Brian Salomon1f05d452019-02-08 12:33:08 -0500586void GrGpu::resetTextureBindings() {
587 this->handleDirtyContext();
588 this->onResetTextureBindings();
589}
590
Chris Dalton16a33c62019-09-24 22:19:17 -0600591void GrGpu::resolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect,
Greg Daniel242536f2020-02-13 14:12:46 -0500592 ForExternalIO forExternalIO) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000593 SkASSERT(target);
bsalomon@google.com75f9f252012-01-31 13:35:56 +0000594 this->handleDirtyContext();
Greg Daniel242536f2020-02-13 14:12:46 -0500595 this->onResolveRenderTarget(target, resolveRect, forExternalIO);
bsalomon@google.com75f9f252012-01-31 13:35:56 +0000596}
597
Brian Salomon1fabd512018-02-09 09:54:25 -0500598void GrGpu::didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds,
599 uint32_t mipLevels) const {
jvanverth900bd4a2016-04-29 13:53:12 -0700600 SkASSERT(surface);
Brian Salomonc67c31c2018-12-06 10:00:03 -0500601 SkASSERT(!surface->readOnly());
jvanverth900bd4a2016-04-29 13:53:12 -0700602 // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds.
603 if (nullptr == bounds || !bounds->isEmpty()) {
jvanverth900bd4a2016-04-29 13:53:12 -0700604 GrTexture* texture = surface->asTexture();
605 if (texture && 1 == mipLevels) {
Greg Daniel0fc4d2d2017-10-12 11:23:36 -0400606 texture->texturePriv().markMipMapsDirty();
jvanverth900bd4a2016-04-29 13:53:12 -0700607 }
608 }
609}
610
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600611int GrGpu::findOrAssignSamplePatternKey(GrRenderTarget* renderTarget) {
Chris Daltond7291ba2019-03-07 14:17:03 -0700612 SkASSERT(this->caps()->sampleLocationsSupport());
Chris Daltoneffee202019-07-01 22:28:03 -0600613 SkASSERT(renderTarget->numSamples() > 1 ||
614 (renderTarget->renderTargetPriv().getStencilAttachment() &&
615 renderTarget->renderTargetPriv().getStencilAttachment()->numSamples() > 1));
Chris Daltond7291ba2019-03-07 14:17:03 -0700616
617 SkSTArray<16, SkPoint> sampleLocations;
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600618 this->querySampleLocations(renderTarget, &sampleLocations);
Chris Daltond7291ba2019-03-07 14:17:03 -0700619 return fSamplePatternDictionary.findOrAssignSamplePatternKey(sampleLocations);
620}
621
Brian Salomonf9a1fdf2019-05-09 10:30:12 -0400622GrSemaphoresSubmitted GrGpu::finishFlush(GrSurfaceProxy* proxies[],
623 int n,
Greg Danielbae71212019-03-01 15:24:35 -0500624 SkSurface::BackendSurfaceAccess access,
Greg Daniel797efca2019-05-09 14:04:20 -0400625 const GrFlushInfo& info,
626 const GrPrepareForExternalIORequests& externalRequests) {
Brian Salomone39526b2019-06-24 16:35:53 -0400627 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
Greg Danield2073452018-12-07 11:20:33 -0500628 this->stats()->incNumFinishFlushes();
Robert Phillips9da87e02019-02-04 13:26:26 -0500629 GrResourceProvider* resourceProvider = fContext->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -0500630
Greg Daniel30a35e82019-11-19 14:12:25 -0500631 struct SemaphoreInfo {
632 std::unique_ptr<GrSemaphore> fSemaphore;
633 bool fDidCreate = false;
634 };
635
636 bool failedSemaphoreCreation = false;
637 std::unique_ptr<SemaphoreInfo[]> semaphoreInfos(new SemaphoreInfo[info.fNumSemaphores]);
638 if (this->caps()->semaphoreSupport() && info.fNumSemaphores) {
639 for (int i = 0; i < info.fNumSemaphores && !failedSemaphoreCreation; ++i) {
Greg Daniele6bfb7d2019-04-17 15:26:11 -0400640 if (info.fSignalSemaphores[i].isInitialized()) {
Greg Daniel30a35e82019-11-19 14:12:25 -0500641 semaphoreInfos[i].fSemaphore = resourceProvider->wrapBackendSemaphore(
Greg Daniele6bfb7d2019-04-17 15:26:11 -0400642 info.fSignalSemaphores[i],
643 GrResourceProvider::SemaphoreWrapType::kWillSignal,
Greg Daniel17b7c052018-01-09 13:55:33 -0500644 kBorrow_GrWrapOwnership);
Greg Daniel51316782017-08-02 15:10:09 +0000645 } else {
Greg Daniel30a35e82019-11-19 14:12:25 -0500646 semaphoreInfos[i].fSemaphore = resourceProvider->makeSemaphore(false);
647 semaphoreInfos[i].fDidCreate = true;
Greg Daniel51316782017-08-02 15:10:09 +0000648 }
Greg Daniel30a35e82019-11-19 14:12:25 -0500649 if (!semaphoreInfos[i].fSemaphore) {
650 semaphoreInfos[i].fDidCreate = false;
651 failedSemaphoreCreation = true;
652 }
653 }
654 if (!failedSemaphoreCreation) {
655 for (int i = 0; i < info.fNumSemaphores && !failedSemaphoreCreation; ++i) {
656 this->insertSemaphore(semaphoreInfos[i].fSemaphore.get());
Greg Daniel51316782017-08-02 15:10:09 +0000657 }
658 }
659 }
Greg Daniel30a35e82019-11-19 14:12:25 -0500660
661 // We always want to try flushing, so do that before checking if we failed semaphore creation.
662 if (!this->onFinishFlush(proxies, n, access, info, externalRequests) ||
663 failedSemaphoreCreation) {
664 // If we didn't do the flush or failed semaphore creations then none of the semaphores were
665 // submitted. Therefore the client can't wait on any of the semaphores. Additionally any
666 // semaphores we created here the client is not responsible for deleting so we must make
667 // sure they get deleted. We do this by changing the ownership from borrowed to owned.
668 for (int i = 0; i < info.fNumSemaphores; ++i) {
669 if (semaphoreInfos[i].fDidCreate) {
670 SkASSERT(semaphoreInfos[i].fSemaphore);
671 semaphoreInfos[i].fSemaphore->setIsOwned();
672 }
673 }
674 return GrSemaphoresSubmitted::kNo;
675 }
676
677 for (int i = 0; i < info.fNumSemaphores; ++i) {
678 if (!info.fSignalSemaphores[i].isInitialized()) {
679 SkASSERT(semaphoreInfos[i].fSemaphore);
680 info.fSignalSemaphores[i] = semaphoreInfos[i].fSemaphore->backendSemaphore();
681 }
682 }
683
Brian Salomon9ff5acb2019-05-08 09:04:47 -0400684 return this->caps()->semaphoreSupport() ? GrSemaphoresSubmitted::kYes
Greg Daniel51316782017-08-02 15:10:09 +0000685 : GrSemaphoresSubmitted::kNo;
686}
Brian Osman71a18892017-08-10 10:23:25 -0400687
Kevin Lubickf4def342018-10-04 12:52:50 -0400688#ifdef SK_ENABLE_DUMP_GPU
Brian Osman71a18892017-08-10 10:23:25 -0400689void GrGpu::dumpJSON(SkJSONWriter* writer) const {
690 writer->beginObject();
691
692 // TODO: Is there anything useful in the base class to dump here?
693
694 this->onDumpJSON(writer);
695
696 writer->endObject();
697}
Kevin Lubickf4def342018-10-04 12:52:50 -0400698#else
699void GrGpu::dumpJSON(SkJSONWriter* writer) const { }
700#endif
Robert Phillips646f6372018-09-25 09:31:10 -0400701
Robert Phillipsf0ced622019-05-16 09:06:25 -0400702#if GR_TEST_UTILS
703
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500704#if GR_GPU_STATS
705void GrGpu::Stats::dump(SkString* out) {
706 out->appendf("Render Target Binds: %d\n", fRenderTargetBinds);
707 out->appendf("Shader Compilations: %d\n", fShaderCompilations);
708 out->appendf("Textures Created: %d\n", fTextureCreates);
709 out->appendf("Texture Uploads: %d\n", fTextureUploads);
710 out->appendf("Transfers to Texture: %d\n", fTransfersToTexture);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400711 out->appendf("Transfers from Surface: %d\n", fTransfersFromSurface);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500712 out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates);
713 out->appendf("Number of draws: %d\n", fNumDraws);
Robert Phillipsf9fcf7f2019-07-11 09:03:27 -0400714 out->appendf("Number of Scratch Textures reused %d\n", fNumScratchTexturesReused);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500715}
716
717void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) {
718 keys->push_back(SkString("render_target_binds")); values->push_back(fRenderTargetBinds);
719 keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations);
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500720}
721
Robert Phillips57ef6802019-09-23 10:12:47 -0400722#endif // GR_GPU_STATS
723#endif // GR_TEST_UTILS
Robert Phillipsdbaf3172019-02-06 15:12:53 -0500724
Robert Phillipsba5c7ad2020-01-24 11:03:33 -0500725bool GrGpu::MipMapsAreCorrect(SkISize dimensions,
726 GrMipMapped mipMapped,
727 const BackendTextureData* data) {
728 int numMipLevels = 1;
729 if (mipMapped == GrMipMapped::kYes) {
730 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
Brian Salomon85c3d682019-11-04 15:04:54 -0500731 }
Robert Phillips57ef6802019-09-23 10:12:47 -0400732
Robert Phillips42716d42019-12-16 12:19:54 -0500733 if (!data || data->type() == BackendTextureData::Type::kColor) {
Robert Phillips57ef6802019-09-23 10:12:47 -0400734 return true;
735 }
736
Robert Phillips42716d42019-12-16 12:19:54 -0500737 if (data->type() == BackendTextureData::Type::kCompressed) {
Robert Phillipsba5c7ad2020-01-24 11:03:33 -0500738 return false; // This should be going through CompressedDataIsCorrect
Robert Phillips42716d42019-12-16 12:19:54 -0500739 }
740
741 SkASSERT(data->type() == BackendTextureData::Type::kPixmaps);
742
Brian Salomon85c3d682019-11-04 15:04:54 -0500743 if (data->pixmap(0).dimensions() != dimensions) {
Robert Phillips57ef6802019-09-23 10:12:47 -0400744 return false;
745 }
746
Brian Salomon85c3d682019-11-04 15:04:54 -0500747 SkColorType colorType = data->pixmap(0).colorType();
Robert Phillipsba5c7ad2020-01-24 11:03:33 -0500748 for (int i = 1; i < numMipLevels; ++i) {
Brian Osman788b9162020-02-07 10:36:46 -0500749 dimensions = {std::max(1, dimensions.width()/2), std::max(1, dimensions.height()/2)};
Brian Salomon85c3d682019-11-04 15:04:54 -0500750 if (dimensions != data->pixmap(i).dimensions()) {
Robert Phillips57ef6802019-09-23 10:12:47 -0400751 return false;
752 }
Brian Salomon85c3d682019-11-04 15:04:54 -0500753 if (colorType != data->pixmap(i).colorType()) {
754 return false;
Robert Phillips57ef6802019-09-23 10:12:47 -0400755 }
Robert Phillips57ef6802019-09-23 10:12:47 -0400756 }
Robert Phillips57ef6802019-09-23 10:12:47 -0400757 return true;
758}
759
Robert Phillipsb915c942019-12-17 14:44:37 -0500760bool GrGpu::CompressedDataIsCorrect(SkISize dimensions, SkImage::CompressionType compressionType,
761 GrMipMapped mipMapped, const BackendTextureData* data) {
762
763 if (!data || data->type() == BackendTextureData::Type::kColor) {
764 return true;
765 }
766
767 if (data->type() == BackendTextureData::Type::kPixmaps) {
768 return false;
769 }
770
771 SkASSERT(data->type() == BackendTextureData::Type::kCompressed);
772
Robert Phillips99dead92020-01-27 16:11:57 -0500773 size_t computedSize = SkCompressedDataSize(compressionType, dimensions,
774 nullptr, mipMapped == GrMipMapped::kYes);
Robert Phillipsb915c942019-12-17 14:44:37 -0500775
776 return computedSize == data->compressedSize();
777}
778
Brian Salomon85c3d682019-11-04 15:04:54 -0500779GrBackendTexture GrGpu::createBackendTexture(SkISize dimensions,
780 const GrBackendFormat& format,
781 GrRenderable renderable,
Robert Phillipsba5c7ad2020-01-24 11:03:33 -0500782 GrMipMapped mipMapped,
Robert Phillips4277f012020-01-21 14:28:34 -0500783 GrProtected isProtected,
784 const BackendTextureData* data) {
Robert Phillips57ef6802019-09-23 10:12:47 -0400785 const GrCaps* caps = this->caps();
786
787 if (!format.isValid()) {
788 return {};
789 }
790
Robert Phillipsd34691b2019-09-24 13:38:43 -0400791 if (caps->isFormatCompressed(format)) {
792 // Compressed formats must go through the createCompressedBackendTexture API
793 return {};
794 }
Robert Phillips57ef6802019-09-23 10:12:47 -0400795
Brian Salomon85c3d682019-11-04 15:04:54 -0500796 if (data && data->type() == BackendTextureData::Type::kPixmaps) {
797 auto ct = SkColorTypeToGrColorType(data->pixmap(0).colorType());
798 if (!caps->areColorTypeAndFormatCompatible(ct, format)) {
799 return {};
800 }
801 }
802
803 if (dimensions.isEmpty() || dimensions.width() > caps->maxTextureSize() ||
804 dimensions.height() > caps->maxTextureSize()) {
Robert Phillips57ef6802019-09-23 10:12:47 -0400805 return {};
806 }
807
Robert Phillipsba5c7ad2020-01-24 11:03:33 -0500808 if (mipMapped == GrMipMapped::kYes && !this->caps()->mipMapSupport()) {
Robert Phillips57ef6802019-09-23 10:12:47 -0400809 return {};
810 }
811
Robert Phillipsba5c7ad2020-01-24 11:03:33 -0500812 if (!MipMapsAreCorrect(dimensions, mipMapped, data)) {
Robert Phillips57ef6802019-09-23 10:12:47 -0400813 return {};
814 }
815
Robert Phillipsba5c7ad2020-01-24 11:03:33 -0500816 return this->onCreateBackendTexture(dimensions, format, renderable, mipMapped,
Robert Phillips4277f012020-01-21 14:28:34 -0500817 isProtected, data);
Robert Phillips57ef6802019-09-23 10:12:47 -0400818}
Robert Phillipsb915c942019-12-17 14:44:37 -0500819
820GrBackendTexture GrGpu::createCompressedBackendTexture(SkISize dimensions,
821 const GrBackendFormat& format,
Robert Phillipsb915c942019-12-17 14:44:37 -0500822 GrMipMapped mipMapped,
Robert Phillips4277f012020-01-21 14:28:34 -0500823 GrProtected isProtected,
824 const BackendTextureData* data) {
Robert Phillipsb915c942019-12-17 14:44:37 -0500825 const GrCaps* caps = this->caps();
826
827 if (!format.isValid()) {
828 return {};
829 }
830
831 SkImage::CompressionType compressionType = caps->compressionType(format);
832 if (compressionType == SkImage::CompressionType::kNone) {
833 // Uncompressed formats must go through the createBackendTexture API
834 return {};
835 }
836
837 if (dimensions.isEmpty() ||
838 dimensions.width() > caps->maxTextureSize() ||
839 dimensions.height() > caps->maxTextureSize()) {
840 return {};
841 }
842
843 if (mipMapped == GrMipMapped::kYes && !this->caps()->mipMapSupport()) {
844 return {};
845 }
846
847 if (!CompressedDataIsCorrect(dimensions, compressionType, mipMapped, data)) {
848 return {};
849 }
850
Robert Phillips4277f012020-01-21 14:28:34 -0500851 return this->onCreateCompressedBackendTexture(dimensions, format, mipMapped,
852 isProtected, data);
Robert Phillipsb915c942019-12-17 14:44:37 -0500853}