1 /*
2 * Copyright 2013 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 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkColorType.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkPixmap.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/core/SkSamplingOptions.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkString.h"
21 #include "include/core/SkTextureCompressionType.h"
22 #include "include/core/SkTypes.h"
23 #include "include/gpu/GpuTypes.h"
24 #include "include/gpu/ganesh/GrBackendSurface.h"
25 #include "include/gpu/ganesh/GrContextOptions.h"
26 #include "include/gpu/ganesh/GrDirectContext.h"
27 #include "include/gpu/ganesh/GrTypes.h"
28 #include "include/private/base/SkTo.h"
29 #include "include/private/gpu/ganesh/GrTypesPriv.h"
30 #include "src/core/SkAutoPixmapStorage.h"
31 #include "src/core/SkCompressedDataUtils.h"
32 #include "src/gpu/DataUtils.h"
33 #include "src/gpu/SkBackingFit.h"
34 #include "src/gpu/Swizzle.h"
35 #include "src/gpu/ganesh/GrBackendUtils.h"
36 #include "src/gpu/ganesh/GrCaps.h"
37 #include "src/gpu/ganesh/GrColorInfo.h"
38 #include "src/gpu/ganesh/GrDataUtils.h"
39 #include "src/gpu/ganesh/GrDirectContextPriv.h"
40 #include "src/gpu/ganesh/GrGpu.h"
41 #include "src/gpu/ganesh/GrImageInfo.h"
42 #include "src/gpu/ganesh/GrProxyProvider.h"
43 #include "src/gpu/ganesh/GrRenderTarget.h"
44 #include "src/gpu/ganesh/GrResourceCache.h"
45 #include "src/gpu/ganesh/GrResourceProvider.h"
46 #include "src/gpu/ganesh/GrSamplerState.h"
47 #include "src/gpu/ganesh/GrSurface.h"
48 #include "src/gpu/ganesh/GrSurfaceProxy.h"
49 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
50 #include "src/gpu/ganesh/GrTexture.h"
51 #include "src/gpu/ganesh/GrTextureProxy.h"
52 #include "src/gpu/ganesh/GrUtil.h"
53 #include "src/gpu/ganesh/SkGr.h"
54 #include "src/gpu/ganesh/SurfaceContext.h"
55 #include "src/gpu/ganesh/TestFormatColorTypeCombination.h"
56 #include "tests/CtsEnforcement.h"
57 #include "tests/Test.h"
58 #include "tools/gpu/ContextType.h"
59 #include "tools/gpu/ManagedBackendTexture.h"
60
61 #include <cstdint>
62 #include <functional>
63 #include <initializer_list>
64 #include <memory>
65 #include <tuple>
66 #include <utility>
67 #include <vector>
68
69 // Tests that GrSurface::asTexture(), GrSurface::asRenderTarget(), and static upcasting of texture
70 // and render targets to GrSurface all work as expected.
DEF_GANESH_TEST_FOR_MOCK_CONTEXT(GrSurface,reporter,ctxInfo)71 DEF_GANESH_TEST_FOR_MOCK_CONTEXT(GrSurface, reporter, ctxInfo) {
72 auto context = ctxInfo.directContext();
73 auto resourceProvider = context->priv().resourceProvider();
74
75 static constexpr SkISize kDesc = {256, 256};
76 auto format = context->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
77 GrRenderable::kYes);
78 sk_sp<GrSurface> texRT1 = resourceProvider->createTexture(kDesc,
79 format,
80 GrTextureType::k2D,
81 GrRenderable::kYes,
82 1,
83 skgpu::Mipmapped::kNo,
84 skgpu::Budgeted::kNo,
85 GrProtected::kNo,
86 /*label=*/{});
87
88 REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asRenderTarget());
89 REPORTER_ASSERT(reporter, texRT1.get() == texRT1->asTexture());
90 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
91 texRT1->asTexture());
92 REPORTER_ASSERT(reporter, texRT1->asRenderTarget() ==
93 static_cast<GrSurface*>(texRT1->asTexture()));
94 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT1->asRenderTarget()) ==
95 static_cast<GrSurface*>(texRT1->asTexture()));
96
97 sk_sp<GrTexture> tex1 = resourceProvider->createTexture(kDesc,
98 format,
99 GrTextureType::k2D,
100 GrRenderable::kNo,
101 1,
102 skgpu::Mipmapped::kNo,
103 skgpu::Budgeted::kNo,
104 GrProtected::kNo,
105 /*label=*/{});
106 REPORTER_ASSERT(reporter, nullptr == tex1->asRenderTarget());
107 REPORTER_ASSERT(reporter, tex1.get() == tex1->asTexture());
108 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(tex1.get()) == tex1->asTexture());
109
110 GrBackendTexture backendTex = context->createBackendTexture(256,
111 256,
112 kRGBA_8888_SkColorType,
113 SkColors::kTransparent,
114 skgpu::Mipmapped::kNo,
115 GrRenderable::kNo,
116 GrProtected::kNo);
117
118 sk_sp<GrSurface> texRT2 = resourceProvider->wrapRenderableBackendTexture(
119 backendTex, 1, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo);
120
121 REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asRenderTarget());
122 REPORTER_ASSERT(reporter, texRT2.get() == texRT2->asTexture());
123 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
124 texRT2->asTexture());
125 REPORTER_ASSERT(reporter, texRT2->asRenderTarget() ==
126 static_cast<GrSurface*>(texRT2->asTexture()));
127 REPORTER_ASSERT(reporter, static_cast<GrSurface*>(texRT2->asRenderTarget()) ==
128 static_cast<GrSurface*>(texRT2->asTexture()));
129
130 context->deleteBackendTexture(backendTex);
131 }
132
133 // This test checks that the isFormatTexturable and isFormatRenderable are
134 // consistent with createTexture's result.
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)135 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability,
136 reporter,
137 ctxInfo,
138 CtsEnforcement::kApiLevel_T) {
139 auto context = ctxInfo.directContext();
140 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
141 GrResourceProvider* resourceProvider = context->priv().resourceProvider();
142 const GrCaps* caps = context->priv().caps();
143
144 // TODO: Should only need format here but need to determine compression type from format
145 // without config.
146 auto createTexture = [](SkISize dimensions, GrColorType colorType,
147 const GrBackendFormat& format, GrRenderable renderable,
148 GrResourceProvider* rp) -> sk_sp<GrTexture> {
149 SkTextureCompressionType compression = GrBackendFormatToCompressionType(format);
150 if (compression != SkTextureCompressionType::kNone) {
151 if (renderable == GrRenderable::kYes) {
152 return nullptr;
153 }
154 auto size = SkCompressedDataSize(compression, dimensions, nullptr, false);
155 auto data = SkData::MakeUninitialized(size);
156 SkColor4f color = {0, 0, 0, 0};
157 skgpu::FillInCompressedData(compression,
158 dimensions,
159 skgpu::Mipmapped::kNo,
160 (char*)data->writable_data(),
161 color);
162 return rp->createCompressedTexture(dimensions,
163 format,
164 skgpu::Budgeted::kNo,
165 skgpu::Mipmapped::kNo,
166 GrProtected::kNo,
167 data.get(),
168 /*label=*/{});
169 } else {
170 return rp->createTexture(dimensions,
171 format,
172 GrTextureType::k2D,
173 renderable,
174 1,
175 skgpu::Mipmapped::kNo,
176 skgpu::Budgeted::kNo,
177 GrProtected::kNo,
178 /*label=*/{});
179 }
180 };
181
182 static constexpr SkISize kDims = {64, 64};
183
184 const std::vector<GrTest::TestFormatColorTypeCombination>& combos =
185 caps->getTestingCombinations();
186
187 for (const GrTest::TestFormatColorTypeCombination& combo : combos) {
188
189 SkASSERT(combo.fColorType != GrColorType::kUnknown);
190 SkASSERT(combo.fFormat.isValid());
191
192 // Right now Vulkan has two backend formats that support ABGR_4444 (R4G4B4A4 and B4G4R4A4).
193 // Until we can create textures directly from the backend format this yields some
194 // ambiguity in what is actually supported and which textures can be created.
195 if (ctxInfo.backend() == kVulkan_GrBackend && combo.fColorType == GrColorType::kABGR_4444) {
196 continue;
197 }
198
199 // Check if 'isFormatTexturable' agrees with 'createTexture' and that the mipmap
200 // support check is working
201 {
202 bool isCompressed = caps->isFormatCompressed(combo.fFormat);
203 bool isTexturable = caps->isFormatTexturable(combo.fFormat, GrTextureType::k2D);
204
205 sk_sp<GrSurface> tex = createTexture(kDims, combo.fColorType, combo.fFormat,
206 GrRenderable::kNo, resourceProvider);
207 REPORTER_ASSERT(reporter, SkToBool(tex) == isTexturable,
208 "ct:%s format:%s, tex:%d, isTexturable:%d",
209 GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
210 SkToBool(tex), isTexturable);
211
212 // Check that the lack of mipmap support blocks the creation of mipmapped
213 // proxies
214 bool expectedMipMapability = isTexturable && caps->mipmapSupport() && !isCompressed;
215
216 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(combo.fFormat,
217 kDims,
218 GrRenderable::kNo,
219 1,
220 skgpu::Mipmapped::kYes,
221 SkBackingFit::kExact,
222 skgpu::Budgeted::kNo,
223 GrProtected::kNo,
224 /*label=*/{});
225 REPORTER_ASSERT(reporter, SkToBool(proxy.get()) == expectedMipMapability,
226 "ct:%s format:%s, tex:%d, expectedMipMapability:%d",
227 GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
228 SkToBool(proxy.get()), expectedMipMapability);
229 }
230
231 // Check if 'isFormatAsColorTypeRenderable' agrees with 'createTexture' (w/o MSAA)
232 {
233 bool isRenderable = caps->isFormatRenderable(combo.fFormat, 1);
234
235 sk_sp<GrSurface> tex = resourceProvider->createTexture(kDims,
236 combo.fFormat,
237 GrTextureType::k2D,
238 GrRenderable::kYes,
239 1,
240 skgpu::Mipmapped::kNo,
241 skgpu::Budgeted::kNo,
242 GrProtected::kNo,
243 /*label=*/{});
244 REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
245 "ct:%s format:%s, tex:%d, isRenderable:%d",
246 GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
247 SkToBool(tex), isRenderable);
248 }
249
250 // Check if 'isFormatAsColorTypeRenderable' agrees with 'createTexture' w/ MSAA
251 {
252 bool isRenderable = caps->isFormatRenderable(combo.fFormat, 2);
253
254 sk_sp<GrSurface> tex = resourceProvider->createTexture(kDims,
255 combo.fFormat,
256 GrTextureType::k2D,
257 GrRenderable::kYes,
258 2,
259 skgpu::Mipmapped::kNo,
260 skgpu::Budgeted::kNo,
261 GrProtected::kNo,
262 /*label=*/{});
263 REPORTER_ASSERT(reporter, SkToBool(tex) == isRenderable,
264 "ct:%s format:%s, tex:%d, isRenderable:%d",
265 GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
266 SkToBool(tex), isRenderable);
267 }
268 }
269 }
270
271 // For each context, set it to always clear the textures and then run through all the
272 // supported formats checking that the textures are actually cleared
DEF_GANESH_TEST(InitialTextureClear,reporter,baseOptions,CtsEnforcement::kApiLevel_T)273 DEF_GANESH_TEST(InitialTextureClear, reporter, baseOptions, CtsEnforcement::kApiLevel_T) {
274 GrContextOptions options = baseOptions;
275 options.fClearAllTextures = true;
276
277 static constexpr int kSize = 100;
278 static constexpr SkColor kClearColor = 0xABABABAB;
279
280 const SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
281 kPremul_SkAlphaType);
282
283 SkAutoPixmapStorage readback;
284 readback.alloc(imageInfo);
285
286 SkISize desc;
287 desc.fWidth = desc.fHeight = kSize;
288
289 for (int ct = 0; ct < skgpu::kContextTypeCount; ++ct) {
290 sk_gpu_test::GrContextFactory factory(options);
291 auto contextType = static_cast<skgpu::ContextType>(ct);
292 if (!skgpu::IsRenderingContext(contextType)) {
293 continue;
294 }
295 auto dContext = factory.get(contextType);
296 if (!dContext) {
297 continue;
298 }
299
300 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
301 const GrCaps* caps = dContext->priv().caps();
302
303 const std::vector<GrTest::TestFormatColorTypeCombination>& combos =
304 caps->getTestingCombinations();
305
306 for (const GrTest::TestFormatColorTypeCombination& combo : combos) {
307
308 SkASSERT(combo.fColorType != GrColorType::kUnknown);
309 SkASSERT(combo.fFormat.isValid());
310
311 if (!caps->isFormatTexturable(combo.fFormat, GrTextureType::k2D)) {
312 continue;
313 }
314
315 auto checkColor = [reporter](const GrTest::TestFormatColorTypeCombination& combo,
316 uint32_t readColor) {
317 // We expect that if there is no alpha in the src color type and we read it to a
318 // color type with alpha that we will get one for alpha rather than zero. We used to
319 // require this but the Intel Iris 6100 on Win 10 test bot doesn't put one in the
320 // alpha channel when reading back from GL_RG16 or GL_RG16F. So now we allow either.
321 uint32_t channels = GrColorTypeChannelFlags(combo.fColorType);
322 bool allowAlphaOne = !(channels & kAlpha_SkColorChannelFlag);
323 if (allowAlphaOne) {
324 if (readColor != 0x00000000 && readColor != 0xFF000000) {
325 ERRORF(reporter,
326 "Failed on ct %s format %s 0x%08x is not 0x00000000 or 0xFF000000",
327 GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
328 readColor);
329 return false;
330 }
331 } else {
332 if (readColor) {
333 ERRORF(reporter, "Failed on ct %s format %s 0x%08x != 0x00000000",
334 GrColorTypeToStr(combo.fColorType), combo.fFormat.toStr().c_str(),
335 readColor);
336 return false;
337 }
338 }
339 return true;
340 };
341
342 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
343 if (renderable == GrRenderable::kYes &&
344 !caps->isFormatAsColorTypeRenderable(combo.fColorType, combo.fFormat)) {
345 continue;
346 }
347
348 for (auto fit : {SkBackingFit::kApprox, SkBackingFit::kExact}) {
349
350 // Does directly allocating a texture clear it?
351 {
352 auto proxy = proxyProvider->testingOnly_createInstantiatedProxy(
353 {kSize, kSize},
354 combo.fFormat,
355 renderable,
356 1,
357 fit,
358 skgpu::Budgeted::kYes,
359 GrProtected::kNo);
360 if (proxy) {
361 skgpu::Swizzle swizzle = caps->getReadSwizzle(combo.fFormat,
362 combo.fColorType);
363 GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin,
364 swizzle);
365 GrColorInfo info(combo.fColorType, kPremul_SkAlphaType, nullptr);
366 auto texCtx = dContext->priv().makeSC(std::move(view), info);
367
368 readback.erase(kClearColor);
369 if (texCtx->readPixels(dContext, readback, {0, 0})) {
370 for (int i = 0; i < kSize * kSize; ++i) {
371 if (!checkColor(combo, readback.addr32()[i])) {
372 break;
373 }
374 }
375 }
376 }
377
378 dContext->priv().getResourceCache()->purgeUnlockedResources(
379 GrPurgeResourceOptions::kAllResources);
380 }
381
382 // Try creating the texture as a deferred proxy.
383 {
384 GrImageInfo info(combo.fColorType,
385 GrColorTypeHasAlpha(combo.fColorType)
386 ? kPremul_SkAlphaType
387 : kOpaque_SkAlphaType,
388 nullptr,
389 {desc.fHeight, desc.fHeight});
390
391 auto sc = dContext->priv().makeSC(info,
392 combo.fFormat,
393 /*label=*/{},
394 fit,
395 kTopLeft_GrSurfaceOrigin,
396 renderable);
397 if (!sc) {
398 continue;
399 }
400
401 readback.erase(kClearColor);
402 if (sc->readPixels(dContext, readback, {0, 0})) {
403 for (int i = 0; i < kSize * kSize; ++i) {
404 if (!checkColor(combo, readback.addr32()[i])) {
405 break;
406 }
407 }
408 }
409 dContext->priv().getResourceCache()->purgeUnlockedResources(
410 GrPurgeResourceOptions::kAllResources);
411 }
412 }
413 }
414 }
415 }
416 }
417
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture,reporter,context_info,CtsEnforcement::kApiLevel_T)418 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture,
419 reporter,
420 context_info,
421 CtsEnforcement::kApiLevel_T) {
422 using namespace skgpu;
423
424 auto fillPixels = [](SkPixmap* p, const std::function<uint32_t(int x, int y)>& f) {
425 for (int y = 0; y < p->height(); ++y) {
426 for (int x = 0; x < p->width(); ++x) {
427 *p->writable_addr32(x, y) = f(x, y);
428 }
429 }
430 };
431
432 auto comparePixels = [](const SkPixmap& p1, const SkPixmap& p2, skiatest::Reporter* reporter) {
433 SkASSERT(p1.info() == p2.info());
434 for (int y = 0; y < p1.height(); ++y) {
435 for (int x = 0; x < p1.width(); ++x) {
436 REPORTER_ASSERT(reporter, p1.getColor(x, y) == p2.getColor(x, y));
437 if (p1.getColor(x, y) != p2.getColor(x, y)) {
438 return;
439 }
440 }
441 }
442 };
443
444 static constexpr int kSize = 100;
445 SkImageInfo ii = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
446 SkAutoPixmapStorage srcPixmap;
447 srcPixmap.alloc(ii);
448 fillPixels(&srcPixmap,
449 [](int x, int y) {
450 return (0xFFU << 24) | (x << 16) | (y << 8) | uint8_t((x * y) & 0xFF);
451 });
452
453 auto dContext = context_info.directContext();
454 GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
455
456 Protected isProtected = Protected(dContext->priv().caps()->supportsProtectedContent());
457
458 // We test both kRW in addition to kRead mostly to ensure that the calls are structured such
459 // that they'd succeed if the texture wasn't kRead. We want to be sure we're failing with
460 // kRead for the right reason.
461 for (auto ioType : {kRead_GrIOType, kRW_GrIOType}) {
462 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithData(dContext,
463 srcPixmap,
464 kTopLeft_GrSurfaceOrigin,
465 GrRenderable::kNo,
466 isProtected);
467 if (!mbet) {
468 ERRORF(reporter, "Could not make texture.");
469 return;
470 }
471 auto proxy = proxyProvider->wrapBackendTexture(mbet->texture(), kBorrow_GrWrapOwnership,
472 GrWrapCacheable::kNo, ioType,
473 mbet->refCountedCallback());
474 Swizzle swizzle = dContext->priv().caps()->getReadSwizzle(proxy->backendFormat(),
475 GrColorType::kRGBA_8888);
476 GrSurfaceProxyView view(proxy, kTopLeft_GrSurfaceOrigin, swizzle);
477 auto surfContext = dContext->priv().makeSC(std::move(view), ii.colorInfo());
478 // Read pixels should work with a read-only texture.
479 {
480 SkAutoPixmapStorage read;
481 read.alloc(srcPixmap.info());
482 auto readResult = surfContext->readPixels(dContext, read, {0, 0});
483 REPORTER_ASSERT(reporter, readResult);
484 if (readResult) {
485 comparePixels(srcPixmap, read, reporter);
486 }
487 }
488
489 // Write pixels should not work with a read-only texture.
490 SkAutoPixmapStorage write;
491 write.alloc(srcPixmap.info());
492 fillPixels(&write, [&srcPixmap](int x, int y) { return ~*srcPixmap.addr32(); });
493 auto writeResult = surfContext->writePixels(dContext, write, {0, 0});
494 REPORTER_ASSERT(reporter, writeResult == (ioType == kRW_GrIOType));
495 // Try the low level write.
496 dContext->flushAndSubmit();
497 auto gpuWriteResult = dContext->priv().getGpu()->writePixels(
498 proxy->peekTexture(),
499 SkIRect::MakeWH(kSize, kSize),
500 GrColorType::kRGBA_8888,
501 GrColorType::kRGBA_8888,
502 write.addr32(),
503 kSize*GrColorTypeBytesPerPixel(GrColorType::kRGBA_8888));
504 REPORTER_ASSERT(reporter, gpuWriteResult == (ioType == kRW_GrIOType));
505
506 SkBitmap copySrcBitmap;
507 copySrcBitmap.installPixels(write);
508 copySrcBitmap.setImmutable();
509
510 auto copySrc = std::get<0>(GrMakeUncachedBitmapProxyView(dContext, copySrcBitmap));
511
512 REPORTER_ASSERT(reporter, copySrc);
513 auto copyResult = surfContext->testCopy(copySrc.refProxy());
514 REPORTER_ASSERT(reporter, copyResult == (ioType == kRW_GrIOType));
515 // Try the low level copy.
516 dContext->flushAndSubmit();
517 auto gpuCopyResult = dContext->priv().getGpu()->copySurface(
518 proxy->peekSurface(),
519 SkIRect::MakeWH(kSize, kSize),
520 copySrc.proxy()->peekSurface(),
521 SkIRect::MakeWH(kSize, kSize),
522 GrSamplerState::Filter::kNearest);
523 REPORTER_ASSERT(reporter, gpuCopyResult == (ioType == kRW_GrIOType));
524
525 // Mip regen should not work with a read only texture.
526 if (dContext->priv().caps()->mipmapSupport()) {
527 mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(dContext,
528 kSize,
529 kSize,
530 kRGBA_8888_SkColorType,
531 Mipmapped::kYes,
532 GrRenderable::kNo,
533 isProtected);
534 proxy = proxyProvider->wrapBackendTexture(mbet->texture(), kBorrow_GrWrapOwnership,
535 GrWrapCacheable::kNo, ioType,
536 mbet->refCountedCallback());
537 dContext->flushAndSubmit();
538 proxy->peekTexture()->markMipmapsDirty(); // avoids assert in GrGpu.
539 auto regenResult =
540 dContext->priv().getGpu()->regenerateMipMapLevels(proxy->peekTexture());
541 REPORTER_ASSERT(reporter, regenResult == (ioType == kRW_GrIOType));
542 }
543 }
544 }
545