xref: /aosp_15_r20/external/skia/tests/GrSurfaceTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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