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/SkImageInfo.h"
17 #include "include/core/SkMatrix.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkSamplingOptions.h"
21 #include "include/core/SkSurface.h"
22 #include "include/core/SkSurfaceProps.h"
23 #include "include/core/SkTypes.h"
24 #include "include/gpu/GpuTypes.h"
25 #include "include/gpu/ganesh/GrBackendSurface.h"
26 #include "include/gpu/ganesh/GrContextOptions.h"
27 #include "include/gpu/ganesh/GrDirectContext.h"
28 #include "include/gpu/ganesh/GrRecordingContext.h"
29 #include "include/gpu/ganesh/GrTypes.h"
30 #include "include/gpu/ganesh/SkImageGanesh.h"
31 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
32 #include "include/gpu/ganesh/mock/GrMockTypes.h"
33 #include "include/private/SkColorData.h"
34 #include "include/private/gpu/ganesh/GrTextureGenerator.h"
35 #include "include/private/gpu/ganesh/GrTypesPriv.h"
36 #include "src/gpu/SkBackingFit.h"
37 #include "src/gpu/Swizzle.h"
38 #include "src/gpu/ganesh/Device.h"
39 #include "src/gpu/ganesh/GrBackendTextureImageGenerator.h"
40 #include "src/gpu/ganesh/GrCaps.h"
41 #include "src/gpu/ganesh/GrColorSpaceXform.h"
42 #include "src/gpu/ganesh/GrDirectContextPriv.h"
43 #include "src/gpu/ganesh/GrDrawingManager.h"
44 #include "src/gpu/ganesh/GrProxyProvider.h"
45 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
46 #include "src/gpu/ganesh/GrSamplerState.h"
47 #include "src/gpu/ganesh/GrSemaphore.h"
48 #include "src/gpu/ganesh/GrSurfaceProxy.h"
49 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
50 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
51 #include "src/gpu/ganesh/GrTexture.h"
52 #include "src/gpu/ganesh/GrTextureProxy.h"
53 #include "src/gpu/ganesh/SkGr.h"
54 #include "src/gpu/ganesh/SurfaceDrawContext.h"
55 #include "src/gpu/ganesh/ops/OpsTask.h"
56 #include "src/gpu/ganesh/surface/SkSurface_Ganesh.h"
57 #include "tests/CtsEnforcement.h"
58 #include "tests/Test.h"
59 #include "tools/gpu/BackendSurfaceFactory.h"
60 #include "tools/gpu/BackendTextureImageFactory.h"
61 #include "tools/gpu/ManagedBackendTexture.h"
62 #include "tools/gpu/ProxyUtils.h"
63
64 #include <initializer_list>
65 #include <memory>
66 #include <utility>
67
68 class GrRenderTask;
69
70 #if defined(SK_DIRECT3D)
71 #include "include/gpu/ganesh/d3d/GrD3DTypes.h"
72 #endif
73
74 #if defined(SK_METAL)
75 #include "include/gpu/ganesh/mtl/GrMtlBackendSurface.h"
76 #endif
77
78 #if defined(SK_GL)
79 #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
80 #include "include/gpu/ganesh/gl/GrGLTypes.h"
81 #endif
82
83 #if defined(SK_VULKAN)
84 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
85 #include "include/gpu/ganesh/vk/GrVkTypes.h"
86 #endif
87
88 static constexpr int kSize = 8;
89
90 // Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in
91 // SkImages and SkSurfaces
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)92 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest,
93 reporter,
94 ctxInfo,
95 CtsEnforcement::kApiLevel_T) {
96 using namespace skgpu;
97
98 auto dContext = ctxInfo.directContext();
99 if (!dContext->priv().caps()->mipmapSupport()) {
100 return;
101 }
102
103 Protected isProtected = Protected(dContext->priv().caps()->supportsProtectedContent());
104
105 for (auto mipmapped : { Mipmapped::kNo, Mipmapped::kYes }) {
106 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
107 // createBackendTexture currently doesn't support uploading data to mip maps
108 // so we don't send any. However, we pretend there is data for the checks below which is
109 // fine since we are never actually using these textures for any work on the gpu.
110 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithData(dContext,
111 kSize,
112 kSize,
113 kRGBA_8888_SkColorType,
114 SkColors::kTransparent,
115 mipmapped,
116 renderable,
117 isProtected);
118 if (!mbet) {
119 ERRORF(reporter, "Could not make texture.");
120 return;
121 }
122
123 sk_sp<GrTextureProxy> proxy;
124 sk_sp<SkImage> image;
125 if (renderable == GrRenderable::kYes) {
126 sk_sp<SkSurface> surface = SkSurfaces::WrapBackendTexture(
127 dContext,
128 mbet->texture(),
129 kTopLeft_GrSurfaceOrigin,
130 0,
131 kRGBA_8888_SkColorType,
132 /*color space*/ nullptr,
133 /*surface props*/ nullptr,
134 sk_gpu_test::ManagedBackendTexture::ReleaseProc,
135 mbet->releaseContext());
136
137 auto device = ((SkSurface_Ganesh*)surface.get())->getDevice();
138 proxy = device->readSurfaceView().asTextureProxyRef();
139 } else {
140 image = SkImages::BorrowTextureFrom(dContext,
141 mbet->texture(),
142 kTopLeft_GrSurfaceOrigin,
143 kRGBA_8888_SkColorType,
144 kPremul_SkAlphaType,
145 /* color space */ nullptr,
146 sk_gpu_test::ManagedBackendTexture::ReleaseProc,
147 mbet->releaseContext());
148 REPORTER_ASSERT(reporter, (mipmapped == Mipmapped::kYes) == image->hasMipmaps());
149 proxy = sk_ref_sp(sk_gpu_test::GetTextureImageProxy(image.get(), dContext));
150 }
151 REPORTER_ASSERT(reporter, proxy);
152 if (!proxy) {
153 continue;
154 }
155
156 REPORTER_ASSERT(reporter, proxy->isInstantiated());
157
158 GrTexture* texture = proxy->peekTexture();
159 REPORTER_ASSERT(reporter, texture);
160 if (!texture) {
161 continue;
162 }
163
164 if (mipmapped == Mipmapped::kYes) {
165 REPORTER_ASSERT(reporter, Mipmapped::kYes == texture->mipmapped());
166 if (GrRenderable::kYes == renderable) {
167 REPORTER_ASSERT(reporter, texture->mipmapsAreDirty());
168 } else {
169 REPORTER_ASSERT(reporter, !texture->mipmapsAreDirty());
170 }
171 } else {
172 REPORTER_ASSERT(reporter, Mipmapped::kNo == texture->mipmapped());
173 }
174 }
175 }
176 }
177
178 // Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator
179 // 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)180 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest,
181 reporter,
182 ctxInfo,
183 CtsEnforcement::kApiLevel_T) {
184 using namespace skgpu;
185
186 auto dContext = ctxInfo.directContext();
187 if (!dContext->priv().caps()->mipmapSupport()) {
188 return;
189 }
190
191 Protected isProtected = Protected(dContext->priv().caps()->supportsProtectedContent());
192
193 for (auto betMipmapped : { Mipmapped::kNo, Mipmapped::kYes }) {
194 for (auto requestMipmapped : { Mipmapped::kNo, Mipmapped::kYes }) {
195 auto ii =
196 SkImageInfo::Make({kSize, kSize}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
197 sk_sp<SkImage> image = sk_gpu_test::MakeBackendTextureImage(
198 dContext, ii, SkColors::kTransparent, betMipmapped,
199 Renderable::kNo,
200 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
201 isProtected);
202 REPORTER_ASSERT(reporter, (betMipmapped == Mipmapped::kYes) == image->hasMipmaps());
203
204 GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(), dContext);
205 REPORTER_ASSERT(reporter, proxy);
206 if (!proxy) {
207 return;
208 }
209
210 REPORTER_ASSERT(reporter, proxy->isInstantiated());
211
212 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
213 REPORTER_ASSERT(reporter, texture);
214 if (!texture) {
215 return;
216 }
217
218 std::unique_ptr<GrTextureGenerator> textureGen = GrBackendTextureImageGenerator::Make(
219 texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType,
220 kPremul_SkAlphaType, nullptr);
221 REPORTER_ASSERT(reporter, textureGen);
222 if (!textureGen) {
223 return;
224 }
225
226 SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
227 kPremul_SkAlphaType);
228 GrSurfaceProxyView genView = textureGen->generateTexture(
229 dContext, imageInfo, requestMipmapped, GrImageTexGenPolicy::kDraw);
230 GrSurfaceProxy* genProxy = genView.proxy();
231
232 REPORTER_ASSERT(reporter, genProxy);
233 if (!genProxy) {
234 return;
235 }
236
237 if (genProxy->isLazy()) {
238 genProxy->priv().doLazyInstantiation(dContext->priv().resourceProvider());
239 } else if (!genProxy->isInstantiated()) {
240 genProxy->instantiate(dContext->priv().resourceProvider());
241 }
242
243 REPORTER_ASSERT(reporter, genProxy->isInstantiated());
244 if (!genProxy->isInstantiated()) {
245 return;
246 }
247
248 GrTexture* genTexture = genProxy->peekTexture();
249 REPORTER_ASSERT(reporter, genTexture);
250 if (!genTexture) {
251 return;
252 }
253
254 GrBackendTexture backendTex = texture->getBackendTexture();
255 GrBackendTexture genBackendTex = genTexture->getBackendTexture();
256
257 if (GrBackendApi::kOpenGL == genBackendTex.backend()) {
258 #ifdef SK_GL
259 GrGLTextureInfo genTexInfo;
260 GrGLTextureInfo origTexInfo;
261 if (GrBackendTextures::GetGLTextureInfo(genBackendTex, &genTexInfo) &&
262 GrBackendTextures::GetGLTextureInfo(backendTex, &origTexInfo)) {
263 if (requestMipmapped == Mipmapped::kYes && betMipmapped == Mipmapped::kNo) {
264 // We did a copy so the texture IDs should be different
265 REPORTER_ASSERT(reporter, origTexInfo.fID != genTexInfo.fID);
266 } else {
267 REPORTER_ASSERT(reporter, origTexInfo.fID == genTexInfo.fID);
268 }
269 } else {
270 ERRORF(reporter, "Failed to get GrGLTextureInfo");
271 }
272 #endif
273 #ifdef SK_VULKAN
274 } else if (GrBackendApi::kVulkan == genBackendTex.backend()) {
275 GrVkImageInfo genImageInfo;
276 GrVkImageInfo origImageInfo;
277 if (GrBackendTextures::GetVkImageInfo(genBackendTex, &genImageInfo) &&
278 GrBackendTextures::GetVkImageInfo(backendTex, &origImageInfo)) {
279 if (requestMipmapped == Mipmapped::kYes && betMipmapped == Mipmapped::kNo) {
280 // We did a copy so the texture IDs should be different
281 REPORTER_ASSERT(reporter, origImageInfo.fImage != genImageInfo.fImage);
282 } else {
283 REPORTER_ASSERT(reporter, origImageInfo.fImage == genImageInfo.fImage);
284 }
285 } else {
286 ERRORF(reporter, "Failed to get GrVkImageInfo");
287 }
288 #endif
289 #ifdef SK_METAL
290 } else if (GrBackendApi::kMetal == genBackendTex.backend()) {
291 GrMtlTextureInfo genImageInfo;
292 GrMtlTextureInfo origImageInfo;
293 if (GrBackendTextures::GetMtlTextureInfo(genBackendTex, &genImageInfo) &&
294 GrBackendTextures::GetMtlTextureInfo(backendTex, &origImageInfo)) {
295 if (requestMipmapped == Mipmapped::kYes && betMipmapped == Mipmapped::kNo) {
296 // We did a copy so the texture IDs should be different
297 REPORTER_ASSERT(reporter, origImageInfo.fTexture != genImageInfo.fTexture);
298 } else {
299 REPORTER_ASSERT(reporter, origImageInfo.fTexture == genImageInfo.fTexture);
300 }
301 } else {
302 ERRORF(reporter, "Failed to get GrMtlTextureInfo");
303 }
304 #endif
305 #ifdef SK_DIRECT3D
306 } else if (GrBackendApi::kDirect3D == genBackendTex.backend()) {
307 GrD3DTextureResourceInfo genImageInfo;
308 GrD3DTextureResourceInfo origImageInfo;
309 if (genBackendTex.getD3DTextureResourceInfo(&genImageInfo) &&
310 backendTex.getD3DTextureResourceInfo(&origImageInfo)) {
311 if (requestMipmapped == Mipmapped::kYes && betMipmapped == Mipmapped::kNo) {
312 // We did a copy so the texture resources should be different
313 REPORTER_ASSERT(reporter,
314 origImageInfo.fResource != genImageInfo.fResource);
315 } else {
316 REPORTER_ASSERT(reporter,
317 origImageInfo.fResource == genImageInfo.fResource);
318 }
319 } else {
320 ERRORF(reporter, "Failed to get GrMtlTextureInfo");
321 }
322 #endif
323 } else {
324 REPORTER_ASSERT(reporter, false);
325 }
326 }
327 }
328 }
329
330 // Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the
331 // resource we took the snapshot of.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)332 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest,
333 reporter,
334 ctxInfo,
335 CtsEnforcement::kApiLevel_T) {
336 auto dContext = ctxInfo.directContext();
337 if (!dContext->priv().caps()->mipmapSupport()) {
338 return;
339 }
340
341 GrProtected isProtected = GrProtected(dContext->priv().caps()->supportsProtectedContent());
342
343 auto resourceProvider = dContext->priv().resourceProvider();
344
345 for (auto willUseMips : {false, true}) {
346 for (auto isWrapped : {false, true}) {
347 skgpu::Mipmapped mipmapped =
348 willUseMips ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
349 sk_sp<SkSurface> surface;
350 SkImageInfo info =
351 SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
352 if (isWrapped) {
353 surface = sk_gpu_test::MakeBackendTextureSurface(dContext,
354 info,
355 kTopLeft_GrSurfaceOrigin,
356 /* sample count */ 1,
357 mipmapped,
358 isProtected);
359 } else {
360 surface = SkSurfaces::RenderTarget(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_Ganesh*)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 = SkSurfaces::RenderTarget(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 dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
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 dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
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::ganesh::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 skgpu::Mipmapped::kNo,
441 SkBackingFit::kApprox,
442 skgpu::Budgeted::kYes,
443 GrProtected::kNo,
444 /*label=*/"DrawMipMapViewTest");
445
446 auto sdc = skgpu::ganesh::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 skgpu::Mipmapped::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::ganesh::SurfaceDrawContext::Make(dContext.get(),
517 colorType,
518 mipmapProxy,
519 nullptr,
520 kTopLeft_GrSurfaceOrigin,
521 SkSurfaceProps());
522
523 mipmapSDC->clear(SkPMColor4f{.1f, .2f, .3f, .4f});
524 REPORTER_ASSERT(reporter, drawingManager->getLastRenderTask(mipmapProxy.get()));
525 // mipmapProxy's last render task should now just be the opsTask containing the clear.
526 REPORTER_ASSERT(reporter,
527 mipmapSDC->testingOnly_PeekLastOpsTask() ==
528 drawingManager->getLastRenderTask(mipmapProxy.get()));
529
530 // Mipmaps don't get marked dirty until makeClosed().
531 REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty());
532
533 skgpu::Swizzle swizzle = dContext->priv().caps()->getReadSwizzle(format, colorType);
534 GrSurfaceProxyView mipmapView(mipmapProxy, kTopLeft_GrSurfaceOrigin, swizzle);
535
536 // Draw the dirty mipmap texture into a render target.
537 auto sdc1 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType,
538 mipmapView, MipmapMode::kLinear);
539 auto sdc1Task = sk_ref_sp(sdc1->testingOnly_PeekLastOpsTask());
540
541 // Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as
542 // soon as a GrTextureResolveRenderTask was inserted. The way we know they were resolved is
543 // if mipmapProxy->getLastRenderTask() has switched from the opsTask that drew to it, to the
544 // task that resolved its mips.
545 GrRenderTask* initialMipmapRegenTask = drawingManager->getLastRenderTask(mipmapProxy.get());
546 REPORTER_ASSERT(reporter, initialMipmapRegenTask);
547 REPORTER_ASSERT(reporter,
548 initialMipmapRegenTask != mipmapSDC->testingOnly_PeekLastOpsTask());
549 REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty());
550
551 // Draw the now-clean mipmap texture into a second target.
552 auto sdc2 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType,
553 mipmapView, MipmapMode::kLinear);
554 auto sdc2Task = sk_ref_sp(sdc2->testingOnly_PeekLastOpsTask());
555
556 // Make sure the mipmap texture still has the same regen task.
557 REPORTER_ASSERT(reporter,
558 drawingManager->getLastRenderTask(mipmapProxy.get()) == initialMipmapRegenTask);
559 SkASSERT(!mipmapProxy->mipmapsAreDirty());
560
561 // Reset everything so we can go again, this time with the first draw not mipmapped.
562 dContext->flushAndSubmit();
563
564 // Mip regen tasks don't get added as dependencies until makeClosed().
565 REPORTER_ASSERT(reporter, sdc1Task->dependsOn(initialMipmapRegenTask));
566 REPORTER_ASSERT(reporter, sdc2Task->dependsOn(initialMipmapRegenTask));
567
568 // Render something to dirty the mips.
569 mipmapSDC->clear(SkPMColor4f{.1f, .2f, .3f, .4f});
570 auto mipmapRTCTask = sk_ref_sp(mipmapSDC->testingOnly_PeekLastOpsTask());
571 REPORTER_ASSERT(reporter, mipmapRTCTask);
572
573 // mipmapProxy's last render task should now just be the opsTask containing the clear.
574 REPORTER_ASSERT(reporter,
575 mipmapRTCTask.get() == drawingManager->getLastRenderTask(mipmapProxy.get()));
576
577 // Mipmaps don't get marked dirty until makeClosed().
578 REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty());
579
580 // Draw the dirty mipmap texture into a render target, but don't do mipmap filtering.
581 sdc1 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType,
582 mipmapView, MipmapMode::kNone);
583
584 // Mipmaps should have gotten marked dirty during makeClosed() when adding the dependency.
585 // Since the last draw did not use mips, they will not have been regenerated and should
586 // therefore still be dirty.
587 REPORTER_ASSERT(reporter, mipmapProxy->mipmapsAreDirty());
588
589 // Since mips weren't regenerated, the last render task shouldn't have changed.
590 REPORTER_ASSERT(reporter,
591 mipmapRTCTask.get() == drawingManager->getLastRenderTask(mipmapProxy.get()));
592
593 // Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
594 sdc2 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType,
595 std::move(mipmapView), MipmapMode::kLinear);
596 sdc2Task = sk_ref_sp(sdc2->testingOnly_PeekLastOpsTask());
597
598 // Make sure the mipmap texture now has a new last render task that regenerates the mips,
599 // and that the mipmaps are now clean.
600 auto mipRegenTask2 = drawingManager->getLastRenderTask(mipmapProxy.get());
601 REPORTER_ASSERT(reporter, mipRegenTask2);
602 REPORTER_ASSERT(reporter, mipmapRTCTask.get() != mipRegenTask2);
603 SkASSERT(!mipmapProxy->mipmapsAreDirty());
604
605 // Mip regen tasks don't get added as dependencies until makeClosed().
606 dContext->flushAndSubmit();
607 REPORTER_ASSERT(reporter, sdc2Task->dependsOn(mipRegenTask2));
608 }
609 }
610