1 /*
2  * Copyright 2017 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/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorSpace.h"
14 #include "include/core/SkColorType.h"
15 #include "include/core/SkImage.h"
16 #include "include/core/SkImageGenerator.h"
17 #include "include/core/SkImageInfo.h"
18 #include "include/core/SkMatrix.h"
19 #include "include/core/SkRect.h"
20 #include "include/core/SkRefCnt.h"
21 #include "include/core/SkSamplingOptions.h"
22 #include "include/core/SkSurface.h"
23 #include "include/core/SkSurfaceProps.h"
24 #include "include/core/SkTypes.h"
25 #include "include/gpu/GpuTypes.h"
26 #include "include/gpu/GrBackendSurface.h"
27 #include "include/gpu/GrContextOptions.h"
28 #include "include/gpu/GrDirectContext.h"
29 #include "include/gpu/GrRecordingContext.h"
30 #include "include/gpu/GrTypes.h"
31 #include "include/gpu/mock/GrMockTypes.h"
32 #include "include/private/SkColorData.h"
33 #include "include/private/gpu/ganesh/GrTypesPriv.h"
34 #include "src/gpu/SkBackingFit.h"
35 #include "src/gpu/Swizzle.h"
36 #include "src/gpu/ganesh/Device_v1.h"
37 #include "src/gpu/ganesh/GrBackendTextureImageGenerator.h"
38 #include "src/gpu/ganesh/GrCaps.h"
39 #include "src/gpu/ganesh/GrColorSpaceXform.h"
40 #include "src/gpu/ganesh/GrDirectContextPriv.h"
41 #include "src/gpu/ganesh/GrDrawingManager.h"
42 #include "src/gpu/ganesh/GrProxyProvider.h"
43 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
44 #include "src/gpu/ganesh/GrSamplerState.h"
45 #include "src/gpu/ganesh/GrSemaphore.h"
46 #include "src/gpu/ganesh/GrSurfaceProxy.h"
47 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
48 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
49 #include "src/gpu/ganesh/GrTexture.h"
50 #include "src/gpu/ganesh/GrTextureProxy.h"
51 #include "src/gpu/ganesh/SkGr.h"
52 #include "src/gpu/ganesh/SurfaceDrawContext.h"
53 #include "src/gpu/ganesh/ops/OpsTask.h"
54 #include "src/image/SkSurface_Gpu.h"
55 #include "tests/CtsEnforcement.h"
56 #include "tests/Test.h"
57 #include "tools/gpu/BackendSurfaceFactory.h"
58 #include "tools/gpu/BackendTextureImageFactory.h"
59 #include "tools/gpu/ManagedBackendTexture.h"
60 #include "tools/gpu/ProxyUtils.h"
61 
62 #include <initializer_list>
63 #include <memory>
64 #include <utility>
65 
66 class GrRenderTask;
67 
68 #if defined(SK_DIRECT3D)
69 #include "include/gpu/d3d/GrD3DTypes.h"
70 #endif
71 
72 #if defined(SK_GL)
73 #include "include/gpu/gl/GrGLTypes.h"
74 #endif
75 
76 #if defined(SK_VULKAN)
77 #include "include/gpu/vk/GrVkTypes.h"
78 #endif
79 
80 #if defined(SK_DAWN)
81 #include "include/gpu/dawn/GrDawnTypes.h"
82 #include "dawn/webgpu_cpp.h"
83 #endif
84 
85 static constexpr int kSize = 8;
86 
87 // Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in
88 // SkImages and SkSurfaces
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)89 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest,
90                                        reporter,
91                                        ctxInfo,
92                                        CtsEnforcement::kApiLevel_T) {
93     auto dContext = ctxInfo.directContext();
94     if (!dContext->priv().caps()->mipmapSupport()) {
95         return;
96     }
97 
98     for (auto mipmapped : {GrMipmapped::kNo, GrMipmapped::kYes}) {
99         for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
100             // createBackendTexture currently doesn't support uploading data to mip maps
101             // so we don't send any. However, we pretend there is data for the checks below which is
102             // fine since we are never actually using these textures for any work on the gpu.
103             auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithData(dContext,
104                                                                          kSize,
105                                                                          kSize,
106                                                                          kRGBA_8888_SkColorType,
107                                                                          SkColors::kTransparent,
108                                                                          mipmapped,
109                                                                          renderable,
110                                                                          GrProtected::kNo);
111             if (!mbet) {
112                 ERRORF(reporter, "Could not make texture.");
113                 return;
114             }
115 
116             sk_sp<GrTextureProxy> proxy;
117             sk_sp<SkImage> image;
118             if (renderable == GrRenderable::kYes) {
119                 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
120                         dContext,
121                         mbet->texture(),
122                         kTopLeft_GrSurfaceOrigin,
123                         0,
124                         kRGBA_8888_SkColorType,
125                         /*color space*/ nullptr,
126                         /*surface props*/ nullptr,
127                         sk_gpu_test::ManagedBackendTexture::ReleaseProc,
128                         mbet->releaseContext());
129 
130                 auto device = ((SkSurface_Gpu*)surface.get())->getDevice();
131                 proxy = device->readSurfaceView().asTextureProxyRef();
132             } else {
133                 image = SkImage::MakeFromTexture(dContext,
134                                                  mbet->texture(),
135                                                  kTopLeft_GrSurfaceOrigin,
136                                                  kRGBA_8888_SkColorType,
137                                                  kPremul_SkAlphaType,
138                                                  /* color space */ nullptr,
139                                                  sk_gpu_test::ManagedBackendTexture::ReleaseProc,
140                                                  mbet->releaseContext());
141                 REPORTER_ASSERT(reporter, (mipmapped == GrMipmapped::kYes) == image->hasMipmaps());
142                 proxy = sk_ref_sp(sk_gpu_test::GetTextureImageProxy(image.get(), dContext));
143             }
144             REPORTER_ASSERT(reporter, proxy);
145             if (!proxy) {
146                 continue;
147             }
148 
149             REPORTER_ASSERT(reporter, proxy->isInstantiated());
150 
151             GrTexture* texture = proxy->peekTexture();
152             REPORTER_ASSERT(reporter, texture);
153             if (!texture) {
154                 continue;
155             }
156 
157             if (mipmapped == GrMipmapped::kYes) {
158                 REPORTER_ASSERT(reporter, GrMipmapped::kYes == texture->mipmapped());
159                 if (GrRenderable::kYes == renderable) {
160                     REPORTER_ASSERT(reporter, texture->mipmapsAreDirty());
161                 } else {
162                     REPORTER_ASSERT(reporter, !texture->mipmapsAreDirty());
163                 }
164             } else {
165                 REPORTER_ASSERT(reporter, GrMipmapped::kNo == texture->mipmapped());
166             }
167         }
168     }
169 }
170 
171 // Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator
172 // based on if we will use mips in the draw and the mip status of the GrBackendTexture.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)173 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest,
174                                        reporter,
175                                        ctxInfo,
176                                        CtsEnforcement::kApiLevel_T) {
177     auto dContext = ctxInfo.directContext();
178     if (!dContext->priv().caps()->mipmapSupport()) {
179         return;
180     }
181 
182     for (auto betMipmapped : {GrMipmapped::kNo, GrMipmapped::kYes}) {
183         for (auto requestMipmapped : {GrMipmapped::kNo, GrMipmapped::kYes}) {
184             auto ii =
185                     SkImageInfo::Make({kSize, kSize}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
186             sk_sp<SkImage> image = sk_gpu_test::MakeBackendTextureImage(
187                     dContext, ii, SkColors::kTransparent, betMipmapped);
188             REPORTER_ASSERT(reporter, (betMipmapped == GrMipmapped::kYes) == image->hasMipmaps());
189 
190             GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(), dContext);
191             REPORTER_ASSERT(reporter, proxy);
192             if (!proxy) {
193                 return;
194             }
195 
196             REPORTER_ASSERT(reporter, proxy->isInstantiated());
197 
198             sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
199             REPORTER_ASSERT(reporter, texture);
200             if (!texture) {
201                 return;
202             }
203 
204             std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make(
205                     texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType,
206                     kPremul_SkAlphaType, nullptr);
207             REPORTER_ASSERT(reporter, imageGen);
208             if (!imageGen) {
209                 return;
210             }
211 
212             SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
213                                                       kPremul_SkAlphaType);
214             GrSurfaceProxyView genView = imageGen->generateTexture(
215                     dContext, imageInfo, requestMipmapped, GrImageTexGenPolicy::kDraw);
216             GrSurfaceProxy* genProxy = genView.proxy();
217 
218             REPORTER_ASSERT(reporter, genProxy);
219             if (!genProxy) {
220                 return;
221             }
222 
223             if (genProxy->isLazy()) {
224                 genProxy->priv().doLazyInstantiation(dContext->priv().resourceProvider());
225             } else if (!genProxy->isInstantiated()) {
226                 genProxy->instantiate(dContext->priv().resourceProvider());
227             }
228 
229             REPORTER_ASSERT(reporter, genProxy->isInstantiated());
230             if (!genProxy->isInstantiated()) {
231                 return;
232             }
233 
234             GrTexture* genTexture = genProxy->peekTexture();
235             REPORTER_ASSERT(reporter, genTexture);
236             if (!genTexture) {
237                 return;
238             }
239 
240             GrBackendTexture backendTex = texture->getBackendTexture();
241             GrBackendTexture genBackendTex = genTexture->getBackendTexture();
242 
243             if (GrBackendApi::kOpenGL == genBackendTex.backend()) {
244 #ifdef SK_GL
245                 GrGLTextureInfo genTexInfo;
246                 GrGLTextureInfo origTexInfo;
247                 if (genBackendTex.getGLTextureInfo(&genTexInfo) &&
248                     backendTex.getGLTextureInfo(&origTexInfo)) {
249                     if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) {
250                         // We did a copy so the texture IDs should be different
251                         REPORTER_ASSERT(reporter, origTexInfo.fID != genTexInfo.fID);
252                     } else {
253                         REPORTER_ASSERT(reporter, origTexInfo.fID == genTexInfo.fID);
254                     }
255                 } else {
256                     ERRORF(reporter, "Failed to get GrGLTextureInfo");
257                 }
258 #endif
259 #ifdef SK_VULKAN
260             } else if (GrBackendApi::kVulkan == genBackendTex.backend()) {
261                 GrVkImageInfo genImageInfo;
262                 GrVkImageInfo origImageInfo;
263                 if (genBackendTex.getVkImageInfo(&genImageInfo) &&
264                     backendTex.getVkImageInfo(&origImageInfo)) {
265                     if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) {
266                         // We did a copy so the texture IDs should be different
267                         REPORTER_ASSERT(reporter, origImageInfo.fImage != genImageInfo.fImage);
268                     } else {
269                         REPORTER_ASSERT(reporter, origImageInfo.fImage == genImageInfo.fImage);
270                     }
271                 } else {
272                     ERRORF(reporter, "Failed to get GrVkImageInfo");
273                 }
274 #endif
275 #ifdef SK_METAL
276             } else if (GrBackendApi::kMetal == genBackendTex.backend()) {
277                 GrMtlTextureInfo genImageInfo;
278                 GrMtlTextureInfo origImageInfo;
279                 if (genBackendTex.getMtlTextureInfo(&genImageInfo) &&
280                     backendTex.getMtlTextureInfo(&origImageInfo)) {
281                     if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) {
282                         // We did a copy so the texture IDs should be different
283                         REPORTER_ASSERT(reporter, origImageInfo.fTexture != genImageInfo.fTexture);
284                     } else {
285                         REPORTER_ASSERT(reporter, origImageInfo.fTexture == genImageInfo.fTexture);
286                     }
287                 } else {
288                     ERRORF(reporter, "Failed to get GrMtlTextureInfo");
289                 }
290 #endif
291 #ifdef SK_DIRECT3D
292             } else if (GrBackendApi::kDirect3D == genBackendTex.backend()) {
293                 GrD3DTextureResourceInfo genImageInfo;
294                 GrD3DTextureResourceInfo origImageInfo;
295                 if (genBackendTex.getD3DTextureResourceInfo(&genImageInfo) &&
296                     backendTex.getD3DTextureResourceInfo(&origImageInfo)) {
297                     if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) {
298                         // We did a copy so the texture resources should be different
299                         REPORTER_ASSERT(reporter,
300                                         origImageInfo.fResource != genImageInfo.fResource);
301                     } else {
302                         REPORTER_ASSERT(reporter,
303                                         origImageInfo.fResource == genImageInfo.fResource);
304                     }
305                 } else {
306                     ERRORF(reporter, "Failed to get GrMtlTextureInfo");
307                 }
308 #endif
309 #ifdef SK_DAWN
310             } else if (GrBackendApi::kDawn == genBackendTex.backend()) {
311                 GrDawnTextureInfo genImageInfo;
312                 GrDawnTextureInfo origImageInfo;
313                 if (genBackendTex.getDawnTextureInfo(&genImageInfo) &&
314                     backendTex.getDawnTextureInfo(&origImageInfo)) {
315                     if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) {
316                         // We did a copy so the texture IDs should be different
317                         REPORTER_ASSERT(reporter,
318                             origImageInfo.fTexture.Get() != genImageInfo.fTexture.Get());
319                     } else {
320                         REPORTER_ASSERT(reporter,
321                             origImageInfo.fTexture.Get() == genImageInfo.fTexture.Get());
322                     }
323                 } else {
324                     ERRORF(reporter, "Failed to get GrDawnTextureInfo");
325                 }
326 #endif
327             } else {
328                 REPORTER_ASSERT(reporter, false);
329             }
330         }
331     }
332 }
333 
334 // Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the
335 // resource we took the snapshot of.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)336 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest,
337                                        reporter,
338                                        ctxInfo,
339                                        CtsEnforcement::kApiLevel_T) {
340     auto dContext = ctxInfo.directContext();
341     if (!dContext->priv().caps()->mipmapSupport()) {
342         return;
343     }
344 
345     auto resourceProvider = dContext->priv().resourceProvider();
346 
347     for (auto willUseMips : {false, true}) {
348         for (auto isWrapped : {false, true}) {
349             GrMipmapped mipmapped = willUseMips ? GrMipmapped::kYes : GrMipmapped::kNo;
350             sk_sp<SkSurface> surface;
351             SkImageInfo info =
352                     SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
353             if (isWrapped) {
354                 surface = sk_gpu_test::MakeBackendTextureSurface(dContext,
355                                                                  info,
356                                                                  kTopLeft_GrSurfaceOrigin,
357                                                                  /* sample count */ 1,
358                                                                  mipmapped);
359             } else {
360                 surface = SkSurface::MakeRenderTarget(dContext,
361                                                       skgpu::Budgeted::kYes,
362                                                       info,
363                                                       /* sample count */ 1,
364                                                       kTopLeft_GrSurfaceOrigin,
365                                                       nullptr,
366                                                       willUseMips);
367             }
368             REPORTER_ASSERT(reporter, surface);
369             auto device = ((SkSurface_Gpu*)surface.get())->getDevice();
370             GrTextureProxy* texProxy = device->readSurfaceView().asTextureProxy();
371             REPORTER_ASSERT(reporter, mipmapped == texProxy->mipmapped());
372 
373             texProxy->instantiate(resourceProvider);
374             GrTexture* texture = texProxy->peekTexture();
375             REPORTER_ASSERT(reporter, mipmapped == texture->mipmapped());
376 
377             sk_sp<SkImage> image = surface->makeImageSnapshot();
378             REPORTER_ASSERT(reporter, willUseMips == image->hasMipmaps());
379             REPORTER_ASSERT(reporter, image);
380             texProxy = sk_gpu_test::GetTextureImageProxy(image.get(), dContext);
381             REPORTER_ASSERT(reporter, mipmapped == texProxy->mipmapped());
382 
383             texProxy->instantiate(resourceProvider);
384             texture = texProxy->peekTexture();
385             REPORTER_ASSERT(reporter, mipmapped == texture->mipmapped());
386         }
387     }
388 }
389 
390 // Test that we don't create a mip mapped texture if the size is 1x1 even if the filter mode is set
391 // to use mips. This test passes by not crashing or hitting asserts in code.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)392 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest,
393                                        reporter,
394                                        ctxInfo,
395                                        CtsEnforcement::kApiLevel_T) {
396     auto dContext = ctxInfo.directContext();
397     if (!dContext->priv().caps()->mipmapSupport()) {
398         return;
399     }
400 
401     // Make surface to draw into
402     SkImageInfo info = SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType);
403     sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(dContext, skgpu::Budgeted::kNo, info);
404 
405     // Make 1x1 raster bitmap
406     SkBitmap bmp;
407     bmp.allocN32Pixels(1, 1);
408     SkPMColor* pixel = reinterpret_cast<SkPMColor*>(bmp.getPixels());
409     *pixel = 0;
410 
411     sk_sp<SkImage> bmpImage = bmp.asImage();
412 
413     // Make sure we scale so we don't optimize out the use of mips.
414     surface->getCanvas()->scale(0.5f, 0.5f);
415 
416     // This should upload the image to a non mipped GrTextureProxy.
417     surface->getCanvas()->drawImage(bmpImage, 0, 0);
418     surface->flushAndSubmit();
419 
420     // Now set the filter quality to high so we use mip maps. We should find the non mipped texture
421     // in the cache for the SkImage. Since the texture is 1x1 we should just use that texture
422     // instead of trying to do a copy to a mipped texture.
423     surface->getCanvas()->drawImage(bmpImage, 0, 0, SkSamplingOptions({1.0f/3, 1.0f/3}));
424     surface->flushAndSubmit();
425 }
426 
427 // Create a new render target and draw 'mipmapView' into it using the provided 'filter'.
draw_mipmap_into_new_render_target(GrRecordingContext * rContext,GrColorType colorType,SkAlphaType alphaType,GrSurfaceProxyView mipmapView,GrSamplerState::MipmapMode mm)428 static std::unique_ptr<skgpu::v1::SurfaceDrawContext> draw_mipmap_into_new_render_target(
429         GrRecordingContext* rContext,
430         GrColorType colorType,
431         SkAlphaType alphaType,
432         GrSurfaceProxyView mipmapView,
433         GrSamplerState::MipmapMode mm) {
434     auto proxyProvider = rContext->priv().proxyProvider();
435     sk_sp<GrSurfaceProxy> renderTarget =
436             proxyProvider->createProxy(mipmapView.proxy()->backendFormat(),
437                                        {1, 1},
438                                        GrRenderable::kYes,
439                                        1,
440                                        GrMipmapped::kNo,
441                                        SkBackingFit::kApprox,
442                                        skgpu::Budgeted::kYes,
443                                        GrProtected::kNo,
444                                        /*label=*/"DrawMipMapViewTest");
445 
446     auto sdc = skgpu::v1::SurfaceDrawContext::Make(rContext,
447                                                    colorType,
448                                                    std::move(renderTarget),
449                                                    nullptr,
450                                                    kTopLeft_GrSurfaceOrigin,
451                                                    SkSurfaceProps());
452 
453     sdc->drawTexture(nullptr,
454                      std::move(mipmapView),
455                      alphaType,
456                      GrSamplerState::Filter::kLinear,
457                      mm,
458                      SkBlendMode::kSrcOver,
459                      {1, 1, 1, 1},
460                      SkRect::MakeWH(4, 4),
461                      SkRect::MakeWH(1, 1),
462                      GrQuadAAFlags::kAll,
463                      SkCanvas::kFast_SrcRectConstraint,
464                      SkMatrix::I(),
465                      nullptr);
466     return sdc;
467 }
468 
469 // Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask.
470 DEF_GANESH_TEST(GrManyDependentsMipMappedTest,
471                 reporter,
472                 /* options */,
473                 CtsEnforcement::kApiLevel_T) {
474     using Enable = GrContextOptions::Enable;
475     using MipmapMode = GrSamplerState::MipmapMode;
476 
477     for (auto enableSortingAndReduction : {Enable::kYes, Enable::kNo}) {
478         GrMockOptions mockOptions;
479         mockOptions.fMipmapSupport = true;
480         GrContextOptions ctxOptions;
481         ctxOptions.fReduceOpsTaskSplitting = enableSortingAndReduction;
482         sk_sp<GrDirectContext> dContext = GrDirectContext::MakeMock(&mockOptions, ctxOptions);
483         GrDrawingManager* drawingManager = dContext->priv().drawingManager();
484         if (!dContext) {
485             ERRORF(reporter, "could not create mock dContext with fReduceOpsTaskSplitting %s.",
486                    (Enable::kYes == enableSortingAndReduction) ? "enabled" : "disabled");
487             continue;
488         }
489 
490         SkASSERT(dContext->priv().caps()->mipmapSupport());
491 
492         GrBackendFormat format = dContext->defaultBackendFormat(
493                 kRGBA_8888_SkColorType, GrRenderable::kYes);
494         GrColorType colorType = GrColorType::kRGBA_8888;
495         SkAlphaType alphaType = kPremul_SkAlphaType;
496 
497         GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
498 
499         // Create a mipmapped render target.
500 
501         sk_sp<GrTextureProxy> mipmapProxy =
502                 proxyProvider->createProxy(format,
503                                            {4, 4},
504                                            GrRenderable::kYes,
505                                            1,
506                                            GrMipmapped::kYes,
507                                            SkBackingFit::kExact,
508                                            skgpu::Budgeted::kYes,
509                                            GrProtected::kNo,
510                                            /*label=*/"ManyDependentsMipMappedTest");
511 
512         // Mark the mipmaps clean to ensure things still work properly when they won't be marked
513         // dirty again until GrRenderTask::makeClosed().
514         mipmapProxy->markMipmapsClean();
515 
516         auto mipmapSDC = skgpu::v1::SurfaceDrawContext::Make(
517             dContext.get(), colorType, mipmapProxy, nullptr, kTopLeft_GrSurfaceOrigin,
518             SkSurfaceProps());
519 
520         mipmapSDC->clear(SkPMColor4f{.1f, .2f, .3f, .4f});
521         REPORTER_ASSERT(reporter, drawingManager->getLastRenderTask(mipmapProxy.get()));
522         // mipmapProxy's last render task should now just be the opsTask containing the clear.
523         REPORTER_ASSERT(reporter,
524                 mipmapSDC->testingOnly_PeekLastOpsTask() ==
525                         drawingManager->getLastRenderTask(mipmapProxy.get()));
526 
527         // Mipmaps don't get marked dirty until makeClosed().
528         REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty());
529 
530         skgpu::Swizzle swizzle = dContext->priv().caps()->getReadSwizzle(format, colorType);
531         GrSurfaceProxyView mipmapView(mipmapProxy, kTopLeft_GrSurfaceOrigin, swizzle);
532 
533         // Draw the dirty mipmap texture into a render target.
534         auto sdc1 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType,
535                                                        mipmapView, MipmapMode::kLinear);
536         auto sdc1Task = sk_ref_sp(sdc1->testingOnly_PeekLastOpsTask());
537 
538         // Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as
539         // soon as a GrTextureResolveRenderTask was inserted. The way we know they were resolved is
540         // if mipmapProxy->getLastRenderTask() has switched from the opsTask that drew to it, to the
541         // task that resolved its mips.
542         GrRenderTask* initialMipmapRegenTask = drawingManager->getLastRenderTask(mipmapProxy.get());
543         REPORTER_ASSERT(reporter, initialMipmapRegenTask);
544         REPORTER_ASSERT(reporter,
545                 initialMipmapRegenTask != mipmapSDC->testingOnly_PeekLastOpsTask());
546         REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty());
547 
548         // Draw the now-clean mipmap texture into a second target.
549         auto sdc2 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType,
550                                                        mipmapView, MipmapMode::kLinear);
551         auto sdc2Task = sk_ref_sp(sdc2->testingOnly_PeekLastOpsTask());
552 
553         // Make sure the mipmap texture still has the same regen task.
554         REPORTER_ASSERT(reporter,
555                     drawingManager->getLastRenderTask(mipmapProxy.get()) == initialMipmapRegenTask);
556         SkASSERT(!mipmapProxy->mipmapsAreDirty());
557 
558         // Reset everything so we can go again, this time with the first draw not mipmapped.
559         dContext->flushAndSubmit();
560 
561         // Mip regen tasks don't get added as dependencies until makeClosed().
562         REPORTER_ASSERT(reporter, sdc1Task->dependsOn(initialMipmapRegenTask));
563         REPORTER_ASSERT(reporter, sdc2Task->dependsOn(initialMipmapRegenTask));
564 
565         // Render something to dirty the mips.
566         mipmapSDC->clear(SkPMColor4f{.1f, .2f, .3f, .4f});
567         auto mipmapRTCTask = sk_ref_sp(mipmapSDC->testingOnly_PeekLastOpsTask());
568         REPORTER_ASSERT(reporter, mipmapRTCTask);
569 
570         // mipmapProxy's last render task should now just be the opsTask containing the clear.
571         REPORTER_ASSERT(reporter,
572                     mipmapRTCTask.get() == drawingManager->getLastRenderTask(mipmapProxy.get()));
573 
574         // Mipmaps don't get marked dirty until makeClosed().
575         REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty());
576 
577         // Draw the dirty mipmap texture into a render target, but don't do mipmap filtering.
578         sdc1 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType,
579                                                   mipmapView, MipmapMode::kNone);
580 
581         // Mipmaps should have gotten marked dirty during makeClosed() when adding the dependency.
582         // Since the last draw did not use mips, they will not have been regenerated and should
583         // therefore still be dirty.
584         REPORTER_ASSERT(reporter, mipmapProxy->mipmapsAreDirty());
585 
586         // Since mips weren't regenerated, the last render task shouldn't have changed.
587         REPORTER_ASSERT(reporter,
588                     mipmapRTCTask.get() == drawingManager->getLastRenderTask(mipmapProxy.get()));
589 
590         // Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
591         sdc2 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType,
592                                                   std::move(mipmapView), MipmapMode::kLinear);
593         sdc2Task = sk_ref_sp(sdc2->testingOnly_PeekLastOpsTask());
594 
595         // Make sure the mipmap texture now has a new last render task that regenerates the mips,
596         // and that the mipmaps are now clean.
597         auto mipRegenTask2 = drawingManager->getLastRenderTask(mipmapProxy.get());
598         REPORTER_ASSERT(reporter, mipRegenTask2);
599         REPORTER_ASSERT(reporter, mipmapRTCTask.get() != mipRegenTask2);
600         SkASSERT(!mipmapProxy->mipmapsAreDirty());
601 
602         // Mip regen tasks don't get added as dependencies until makeClosed().
603         dContext->flushAndSubmit();
604         REPORTER_ASSERT(reporter, sdc2Task->dependsOn(mipRegenTask2));
605     }
606 }
607