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