| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/core/SkAlphaType.h" |
| #include "include/core/SkBitmap.h" |
| #include "include/core/SkBlendMode.h" |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkColor.h" |
| #include "include/core/SkColorSpace.h" |
| #include "include/core/SkColorType.h" |
| #include "include/core/SkImage.h" |
| #include "include/core/SkImageGenerator.h" |
| #include "include/core/SkImageInfo.h" |
| #include "include/core/SkMatrix.h" |
| #include "include/core/SkRect.h" |
| #include "include/core/SkRefCnt.h" |
| #include "include/core/SkSamplingOptions.h" |
| #include "include/core/SkSurface.h" |
| #include "include/core/SkSurfaceProps.h" |
| #include "include/core/SkTypes.h" |
| #include "include/gpu/GpuTypes.h" |
| #include "include/gpu/GrBackendSurface.h" |
| #include "include/gpu/GrContextOptions.h" |
| #include "include/gpu/GrDirectContext.h" |
| #include "include/gpu/GrRecordingContext.h" |
| #include "include/gpu/GrTypes.h" |
| #include "include/gpu/ganesh/SkImageGanesh.h" |
| #include "include/gpu/mock/GrMockTypes.h" |
| #include "include/private/SkColorData.h" |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" |
| #include "src/gpu/SkBackingFit.h" |
| #include "src/gpu/Swizzle.h" |
| #include "src/gpu/ganesh/Device_v1.h" |
| #include "src/gpu/ganesh/GrBackendTextureImageGenerator.h" |
| #include "src/gpu/ganesh/GrCaps.h" |
| #include "src/gpu/ganesh/GrColorSpaceXform.h" |
| #include "src/gpu/ganesh/GrDirectContextPriv.h" |
| #include "src/gpu/ganesh/GrDrawingManager.h" |
| #include "src/gpu/ganesh/GrProxyProvider.h" |
| #include "src/gpu/ganesh/GrRecordingContextPriv.h" |
| #include "src/gpu/ganesh/GrSamplerState.h" |
| #include "src/gpu/ganesh/GrSemaphore.h" |
| #include "src/gpu/ganesh/GrSurfaceProxy.h" |
| #include "src/gpu/ganesh/GrSurfaceProxyPriv.h" |
| #include "src/gpu/ganesh/GrSurfaceProxyView.h" |
| #include "src/gpu/ganesh/GrTexture.h" |
| #include "src/gpu/ganesh/GrTextureProxy.h" |
| #include "src/gpu/ganesh/SkGr.h" |
| #include "src/gpu/ganesh/SurfaceDrawContext.h" |
| #include "src/gpu/ganesh/ops/OpsTask.h" |
| #include "src/image/SkSurface_Gpu.h" |
| #include "tests/CtsEnforcement.h" |
| #include "tests/Test.h" |
| #include "tools/gpu/BackendSurfaceFactory.h" |
| #include "tools/gpu/BackendTextureImageFactory.h" |
| #include "tools/gpu/ManagedBackendTexture.h" |
| #include "tools/gpu/ProxyUtils.h" |
| |
| #include <initializer_list> |
| #include <memory> |
| #include <utility> |
| |
| class GrRenderTask; |
| |
| #if defined(SK_DIRECT3D) |
| #include "include/gpu/d3d/GrD3DTypes.h" |
| #endif |
| |
| #if defined(SK_GL) |
| #include "include/gpu/gl/GrGLTypes.h" |
| #endif |
| |
| #if defined(SK_VULKAN) |
| #include "include/gpu/vk/GrVkTypes.h" |
| #endif |
| |
| #if defined(SK_DAWN) |
| #include "include/gpu/dawn/GrDawnTypes.h" |
| #include "dawn/webgpu_cpp.h" |
| #endif |
| |
| static constexpr int kSize = 8; |
| |
| // Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in |
| // SkImages and SkSurfaces |
| DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest, |
| reporter, |
| ctxInfo, |
| CtsEnforcement::kApiLevel_T) { |
| auto dContext = ctxInfo.directContext(); |
| if (!dContext->priv().caps()->mipmapSupport()) { |
| return; |
| } |
| |
| for (auto mipmapped : {GrMipmapped::kNo, GrMipmapped::kYes}) { |
| for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) { |
| // createBackendTexture currently doesn't support uploading data to mip maps |
| // so we don't send any. However, we pretend there is data for the checks below which is |
| // fine since we are never actually using these textures for any work on the gpu. |
| auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithData(dContext, |
| kSize, |
| kSize, |
| kRGBA_8888_SkColorType, |
| SkColors::kTransparent, |
| mipmapped, |
| renderable, |
| GrProtected::kNo); |
| if (!mbet) { |
| ERRORF(reporter, "Could not make texture."); |
| return; |
| } |
| |
| sk_sp<GrTextureProxy> proxy; |
| sk_sp<SkImage> image; |
| if (renderable == GrRenderable::kYes) { |
| sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture( |
| dContext, |
| mbet->texture(), |
| kTopLeft_GrSurfaceOrigin, |
| 0, |
| kRGBA_8888_SkColorType, |
| /*color space*/ nullptr, |
| /*surface props*/ nullptr, |
| sk_gpu_test::ManagedBackendTexture::ReleaseProc, |
| mbet->releaseContext()); |
| |
| auto device = ((SkSurface_Gpu*)surface.get())->getDevice(); |
| proxy = device->readSurfaceView().asTextureProxyRef(); |
| } else { |
| image = SkImages::BorrowTextureFrom(dContext, |
| mbet->texture(), |
| kTopLeft_GrSurfaceOrigin, |
| kRGBA_8888_SkColorType, |
| kPremul_SkAlphaType, |
| /* color space */ nullptr, |
| sk_gpu_test::ManagedBackendTexture::ReleaseProc, |
| mbet->releaseContext()); |
| REPORTER_ASSERT(reporter, (mipmapped == GrMipmapped::kYes) == image->hasMipmaps()); |
| proxy = sk_ref_sp(sk_gpu_test::GetTextureImageProxy(image.get(), dContext)); |
| } |
| REPORTER_ASSERT(reporter, proxy); |
| if (!proxy) { |
| continue; |
| } |
| |
| REPORTER_ASSERT(reporter, proxy->isInstantiated()); |
| |
| GrTexture* texture = proxy->peekTexture(); |
| REPORTER_ASSERT(reporter, texture); |
| if (!texture) { |
| continue; |
| } |
| |
| if (mipmapped == GrMipmapped::kYes) { |
| REPORTER_ASSERT(reporter, GrMipmapped::kYes == texture->mipmapped()); |
| if (GrRenderable::kYes == renderable) { |
| REPORTER_ASSERT(reporter, texture->mipmapsAreDirty()); |
| } else { |
| REPORTER_ASSERT(reporter, !texture->mipmapsAreDirty()); |
| } |
| } else { |
| REPORTER_ASSERT(reporter, GrMipmapped::kNo == texture->mipmapped()); |
| } |
| } |
| } |
| } |
| |
| // Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator |
| // 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) { |
| auto dContext = ctxInfo.directContext(); |
| if (!dContext->priv().caps()->mipmapSupport()) { |
| return; |
| } |
| |
| for (auto betMipmapped : {GrMipmapped::kNo, GrMipmapped::kYes}) { |
| for (auto requestMipmapped : {GrMipmapped::kNo, GrMipmapped::kYes}) { |
| auto ii = |
| SkImageInfo::Make({kSize, kSize}, kRGBA_8888_SkColorType, kPremul_SkAlphaType); |
| sk_sp<SkImage> image = sk_gpu_test::MakeBackendTextureImage( |
| dContext, ii, SkColors::kTransparent, betMipmapped); |
| REPORTER_ASSERT(reporter, (betMipmapped == GrMipmapped::kYes) == image->hasMipmaps()); |
| |
| GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(), dContext); |
| REPORTER_ASSERT(reporter, proxy); |
| if (!proxy) { |
| return; |
| } |
| |
| REPORTER_ASSERT(reporter, proxy->isInstantiated()); |
| |
| sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture()); |
| REPORTER_ASSERT(reporter, texture); |
| if (!texture) { |
| return; |
| } |
| |
| std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make( |
| texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType, |
| kPremul_SkAlphaType, nullptr); |
| REPORTER_ASSERT(reporter, imageGen); |
| if (!imageGen) { |
| return; |
| } |
| |
| SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, |
| kPremul_SkAlphaType); |
| GrSurfaceProxyView genView = imageGen->generateTexture( |
| dContext, imageInfo, requestMipmapped, GrImageTexGenPolicy::kDraw); |
| GrSurfaceProxy* genProxy = genView.proxy(); |
| |
| REPORTER_ASSERT(reporter, genProxy); |
| if (!genProxy) { |
| return; |
| } |
| |
| if (genProxy->isLazy()) { |
| genProxy->priv().doLazyInstantiation(dContext->priv().resourceProvider()); |
| } else if (!genProxy->isInstantiated()) { |
| genProxy->instantiate(dContext->priv().resourceProvider()); |
| } |
| |
| REPORTER_ASSERT(reporter, genProxy->isInstantiated()); |
| if (!genProxy->isInstantiated()) { |
| return; |
| } |
| |
| GrTexture* genTexture = genProxy->peekTexture(); |
| REPORTER_ASSERT(reporter, genTexture); |
| if (!genTexture) { |
| return; |
| } |
| |
| GrBackendTexture backendTex = texture->getBackendTexture(); |
| GrBackendTexture genBackendTex = genTexture->getBackendTexture(); |
| |
| if (GrBackendApi::kOpenGL == genBackendTex.backend()) { |
| #ifdef SK_GL |
| GrGLTextureInfo genTexInfo; |
| GrGLTextureInfo origTexInfo; |
| if (genBackendTex.getGLTextureInfo(&genTexInfo) && |
| backendTex.getGLTextureInfo(&origTexInfo)) { |
| if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) { |
| // We did a copy so the texture IDs should be different |
| REPORTER_ASSERT(reporter, origTexInfo.fID != genTexInfo.fID); |
| } else { |
| REPORTER_ASSERT(reporter, origTexInfo.fID == genTexInfo.fID); |
| } |
| } else { |
| ERRORF(reporter, "Failed to get GrGLTextureInfo"); |
| } |
| #endif |
| #ifdef SK_VULKAN |
| } else if (GrBackendApi::kVulkan == genBackendTex.backend()) { |
| GrVkImageInfo genImageInfo; |
| GrVkImageInfo origImageInfo; |
| if (genBackendTex.getVkImageInfo(&genImageInfo) && |
| backendTex.getVkImageInfo(&origImageInfo)) { |
| if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) { |
| // We did a copy so the texture IDs should be different |
| REPORTER_ASSERT(reporter, origImageInfo.fImage != genImageInfo.fImage); |
| } else { |
| REPORTER_ASSERT(reporter, origImageInfo.fImage == genImageInfo.fImage); |
| } |
| } else { |
| ERRORF(reporter, "Failed to get GrVkImageInfo"); |
| } |
| #endif |
| #ifdef SK_METAL |
| } else if (GrBackendApi::kMetal == genBackendTex.backend()) { |
| GrMtlTextureInfo genImageInfo; |
| GrMtlTextureInfo origImageInfo; |
| if (genBackendTex.getMtlTextureInfo(&genImageInfo) && |
| backendTex.getMtlTextureInfo(&origImageInfo)) { |
| if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) { |
| // We did a copy so the texture IDs should be different |
| REPORTER_ASSERT(reporter, origImageInfo.fTexture != genImageInfo.fTexture); |
| } else { |
| REPORTER_ASSERT(reporter, origImageInfo.fTexture == genImageInfo.fTexture); |
| } |
| } else { |
| ERRORF(reporter, "Failed to get GrMtlTextureInfo"); |
| } |
| #endif |
| #ifdef SK_DIRECT3D |
| } else if (GrBackendApi::kDirect3D == genBackendTex.backend()) { |
| GrD3DTextureResourceInfo genImageInfo; |
| GrD3DTextureResourceInfo origImageInfo; |
| if (genBackendTex.getD3DTextureResourceInfo(&genImageInfo) && |
| backendTex.getD3DTextureResourceInfo(&origImageInfo)) { |
| if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) { |
| // We did a copy so the texture resources should be different |
| REPORTER_ASSERT(reporter, |
| origImageInfo.fResource != genImageInfo.fResource); |
| } else { |
| REPORTER_ASSERT(reporter, |
| origImageInfo.fResource == genImageInfo.fResource); |
| } |
| } else { |
| ERRORF(reporter, "Failed to get GrMtlTextureInfo"); |
| } |
| #endif |
| #ifdef SK_DAWN |
| } else if (GrBackendApi::kDawn == genBackendTex.backend()) { |
| GrDawnTextureInfo genImageInfo; |
| GrDawnTextureInfo origImageInfo; |
| if (genBackendTex.getDawnTextureInfo(&genImageInfo) && |
| backendTex.getDawnTextureInfo(&origImageInfo)) { |
| if (requestMipmapped == GrMipmapped::kYes && betMipmapped == GrMipmapped::kNo) { |
| // We did a copy so the texture IDs should be different |
| REPORTER_ASSERT(reporter, |
| origImageInfo.fTexture.Get() != genImageInfo.fTexture.Get()); |
| } else { |
| REPORTER_ASSERT(reporter, |
| origImageInfo.fTexture.Get() == genImageInfo.fTexture.Get()); |
| } |
| } else { |
| ERRORF(reporter, "Failed to get GrDawnTextureInfo"); |
| } |
| #endif |
| } else { |
| REPORTER_ASSERT(reporter, false); |
| } |
| } |
| } |
| } |
| |
| // Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the |
| // resource we took the snapshot of. |
| DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest, |
| reporter, |
| ctxInfo, |
| CtsEnforcement::kApiLevel_T) { |
| auto dContext = ctxInfo.directContext(); |
| if (!dContext->priv().caps()->mipmapSupport()) { |
| return; |
| } |
| |
| auto resourceProvider = dContext->priv().resourceProvider(); |
| |
| for (auto willUseMips : {false, true}) { |
| for (auto isWrapped : {false, true}) { |
| GrMipmapped mipmapped = willUseMips ? GrMipmapped::kYes : GrMipmapped::kNo; |
| sk_sp<SkSurface> surface; |
| SkImageInfo info = |
| SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType); |
| if (isWrapped) { |
| surface = sk_gpu_test::MakeBackendTextureSurface(dContext, |
| info, |
| kTopLeft_GrSurfaceOrigin, |
| /* sample count */ 1, |
| mipmapped); |
| } else { |
| surface = SkSurface::MakeRenderTarget(dContext, |
| skgpu::Budgeted::kYes, |
| info, |
| /* sample count */ 1, |
| kTopLeft_GrSurfaceOrigin, |
| nullptr, |
| willUseMips); |
| } |
| REPORTER_ASSERT(reporter, surface); |
| auto device = ((SkSurface_Gpu*)surface.get())->getDevice(); |
| GrTextureProxy* texProxy = device->readSurfaceView().asTextureProxy(); |
| REPORTER_ASSERT(reporter, mipmapped == texProxy->mipmapped()); |
| |
| texProxy->instantiate(resourceProvider); |
| GrTexture* texture = texProxy->peekTexture(); |
| REPORTER_ASSERT(reporter, mipmapped == texture->mipmapped()); |
| |
| sk_sp<SkImage> image = surface->makeImageSnapshot(); |
| REPORTER_ASSERT(reporter, willUseMips == image->hasMipmaps()); |
| REPORTER_ASSERT(reporter, image); |
| texProxy = sk_gpu_test::GetTextureImageProxy(image.get(), dContext); |
| REPORTER_ASSERT(reporter, mipmapped == texProxy->mipmapped()); |
| |
| texProxy->instantiate(resourceProvider); |
| texture = texProxy->peekTexture(); |
| REPORTER_ASSERT(reporter, mipmapped == texture->mipmapped()); |
| } |
| } |
| } |
| |
| // Test that we don't create a mip mapped texture if the size is 1x1 even if the filter mode is set |
| // 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) { |
| auto dContext = ctxInfo.directContext(); |
| if (!dContext->priv().caps()->mipmapSupport()) { |
| return; |
| } |
| |
| // Make surface to draw into |
| SkImageInfo info = SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType); |
| sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(dContext, skgpu::Budgeted::kNo, info); |
| |
| // Make 1x1 raster bitmap |
| SkBitmap bmp; |
| bmp.allocN32Pixels(1, 1); |
| SkPMColor* pixel = reinterpret_cast<SkPMColor*>(bmp.getPixels()); |
| *pixel = 0; |
| |
| sk_sp<SkImage> bmpImage = bmp.asImage(); |
| |
| // Make sure we scale so we don't optimize out the use of mips. |
| surface->getCanvas()->scale(0.5f, 0.5f); |
| |
| // This should upload the image to a non mipped GrTextureProxy. |
| surface->getCanvas()->drawImage(bmpImage, 0, 0); |
| surface->flushAndSubmit(); |
| |
| // Now set the filter quality to high so we use mip maps. We should find the non mipped texture |
| // in the cache for the SkImage. Since the texture is 1x1 we should just use that texture |
| // instead of trying to do a copy to a mipped texture. |
| surface->getCanvas()->drawImage(bmpImage, 0, 0, SkSamplingOptions({1.0f/3, 1.0f/3})); |
| surface->flushAndSubmit(); |
| } |
| |
| // Create a new render target and draw 'mipmapView' into it using the provided 'filter'. |
| static std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> draw_mipmap_into_new_render_target( |
| GrRecordingContext* rContext, |
| GrColorType colorType, |
| SkAlphaType alphaType, |
| GrSurfaceProxyView mipmapView, |
| GrSamplerState::MipmapMode mm) { |
| auto proxyProvider = rContext->priv().proxyProvider(); |
| sk_sp<GrSurfaceProxy> renderTarget = |
| proxyProvider->createProxy(mipmapView.proxy()->backendFormat(), |
| {1, 1}, |
| GrRenderable::kYes, |
| 1, |
| GrMipmapped::kNo, |
| SkBackingFit::kApprox, |
| skgpu::Budgeted::kYes, |
| GrProtected::kNo, |
| /*label=*/"DrawMipMapViewTest"); |
| |
| auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(rContext, |
| colorType, |
| std::move(renderTarget), |
| nullptr, |
| kTopLeft_GrSurfaceOrigin, |
| SkSurfaceProps()); |
| |
| sdc->drawTexture(nullptr, |
| std::move(mipmapView), |
| alphaType, |
| GrSamplerState::Filter::kLinear, |
| mm, |
| SkBlendMode::kSrcOver, |
| {1, 1, 1, 1}, |
| SkRect::MakeWH(4, 4), |
| SkRect::MakeWH(1, 1), |
| GrQuadAAFlags::kAll, |
| SkCanvas::kFast_SrcRectConstraint, |
| SkMatrix::I(), |
| nullptr); |
| return sdc; |
| } |
| |
| // Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask. |
| DEF_GANESH_TEST(GrManyDependentsMipMappedTest, |
| reporter, |
| /* options */, |
| CtsEnforcement::kApiLevel_T) { |
| using Enable = GrContextOptions::Enable; |
| using MipmapMode = GrSamplerState::MipmapMode; |
| |
| for (auto enableSortingAndReduction : {Enable::kYes, Enable::kNo}) { |
| GrMockOptions mockOptions; |
| mockOptions.fMipmapSupport = true; |
| GrContextOptions ctxOptions; |
| ctxOptions.fReduceOpsTaskSplitting = enableSortingAndReduction; |
| sk_sp<GrDirectContext> dContext = GrDirectContext::MakeMock(&mockOptions, ctxOptions); |
| GrDrawingManager* drawingManager = dContext->priv().drawingManager(); |
| if (!dContext) { |
| ERRORF(reporter, "could not create mock dContext with fReduceOpsTaskSplitting %s.", |
| (Enable::kYes == enableSortingAndReduction) ? "enabled" : "disabled"); |
| continue; |
| } |
| |
| SkASSERT(dContext->priv().caps()->mipmapSupport()); |
| |
| GrBackendFormat format = dContext->defaultBackendFormat( |
| kRGBA_8888_SkColorType, GrRenderable::kYes); |
| GrColorType colorType = GrColorType::kRGBA_8888; |
| SkAlphaType alphaType = kPremul_SkAlphaType; |
| |
| GrProxyProvider* proxyProvider = dContext->priv().proxyProvider(); |
| |
| // Create a mipmapped render target. |
| |
| sk_sp<GrTextureProxy> mipmapProxy = |
| proxyProvider->createProxy(format, |
| {4, 4}, |
| GrRenderable::kYes, |
| 1, |
| GrMipmapped::kYes, |
| SkBackingFit::kExact, |
| skgpu::Budgeted::kYes, |
| GrProtected::kNo, |
| /*label=*/"ManyDependentsMipMappedTest"); |
| |
| // Mark the mipmaps clean to ensure things still work properly when they won't be marked |
| // dirty again until GrRenderTask::makeClosed(). |
| mipmapProxy->markMipmapsClean(); |
| |
| auto mipmapSDC = skgpu::ganesh::SurfaceDrawContext::Make(dContext.get(), |
| colorType, |
| mipmapProxy, |
| nullptr, |
| kTopLeft_GrSurfaceOrigin, |
| SkSurfaceProps()); |
| |
| mipmapSDC->clear(SkPMColor4f{.1f, .2f, .3f, .4f}); |
| REPORTER_ASSERT(reporter, drawingManager->getLastRenderTask(mipmapProxy.get())); |
| // mipmapProxy's last render task should now just be the opsTask containing the clear. |
| REPORTER_ASSERT(reporter, |
| mipmapSDC->testingOnly_PeekLastOpsTask() == |
| drawingManager->getLastRenderTask(mipmapProxy.get())); |
| |
| // Mipmaps don't get marked dirty until makeClosed(). |
| REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty()); |
| |
| skgpu::Swizzle swizzle = dContext->priv().caps()->getReadSwizzle(format, colorType); |
| GrSurfaceProxyView mipmapView(mipmapProxy, kTopLeft_GrSurfaceOrigin, swizzle); |
| |
| // Draw the dirty mipmap texture into a render target. |
| auto sdc1 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType, |
| mipmapView, MipmapMode::kLinear); |
| auto sdc1Task = sk_ref_sp(sdc1->testingOnly_PeekLastOpsTask()); |
| |
| // Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as |
| // soon as a GrTextureResolveRenderTask was inserted. The way we know they were resolved is |
| // if mipmapProxy->getLastRenderTask() has switched from the opsTask that drew to it, to the |
| // task that resolved its mips. |
| GrRenderTask* initialMipmapRegenTask = drawingManager->getLastRenderTask(mipmapProxy.get()); |
| REPORTER_ASSERT(reporter, initialMipmapRegenTask); |
| REPORTER_ASSERT(reporter, |
| initialMipmapRegenTask != mipmapSDC->testingOnly_PeekLastOpsTask()); |
| REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty()); |
| |
| // Draw the now-clean mipmap texture into a second target. |
| auto sdc2 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType, |
| mipmapView, MipmapMode::kLinear); |
| auto sdc2Task = sk_ref_sp(sdc2->testingOnly_PeekLastOpsTask()); |
| |
| // Make sure the mipmap texture still has the same regen task. |
| REPORTER_ASSERT(reporter, |
| drawingManager->getLastRenderTask(mipmapProxy.get()) == initialMipmapRegenTask); |
| SkASSERT(!mipmapProxy->mipmapsAreDirty()); |
| |
| // Reset everything so we can go again, this time with the first draw not mipmapped. |
| dContext->flushAndSubmit(); |
| |
| // Mip regen tasks don't get added as dependencies until makeClosed(). |
| REPORTER_ASSERT(reporter, sdc1Task->dependsOn(initialMipmapRegenTask)); |
| REPORTER_ASSERT(reporter, sdc2Task->dependsOn(initialMipmapRegenTask)); |
| |
| // Render something to dirty the mips. |
| mipmapSDC->clear(SkPMColor4f{.1f, .2f, .3f, .4f}); |
| auto mipmapRTCTask = sk_ref_sp(mipmapSDC->testingOnly_PeekLastOpsTask()); |
| REPORTER_ASSERT(reporter, mipmapRTCTask); |
| |
| // mipmapProxy's last render task should now just be the opsTask containing the clear. |
| REPORTER_ASSERT(reporter, |
| mipmapRTCTask.get() == drawingManager->getLastRenderTask(mipmapProxy.get())); |
| |
| // Mipmaps don't get marked dirty until makeClosed(). |
| REPORTER_ASSERT(reporter, !mipmapProxy->mipmapsAreDirty()); |
| |
| // Draw the dirty mipmap texture into a render target, but don't do mipmap filtering. |
| sdc1 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType, |
| mipmapView, MipmapMode::kNone); |
| |
| // Mipmaps should have gotten marked dirty during makeClosed() when adding the dependency. |
| // Since the last draw did not use mips, they will not have been regenerated and should |
| // therefore still be dirty. |
| REPORTER_ASSERT(reporter, mipmapProxy->mipmapsAreDirty()); |
| |
| // Since mips weren't regenerated, the last render task shouldn't have changed. |
| REPORTER_ASSERT(reporter, |
| mipmapRTCTask.get() == drawingManager->getLastRenderTask(mipmapProxy.get())); |
| |
| // Draw the stil-dirty mipmap texture into a second target with mipmap filtering. |
| sdc2 = draw_mipmap_into_new_render_target(dContext.get(), colorType, alphaType, |
| std::move(mipmapView), MipmapMode::kLinear); |
| sdc2Task = sk_ref_sp(sdc2->testingOnly_PeekLastOpsTask()); |
| |
| // Make sure the mipmap texture now has a new last render task that regenerates the mips, |
| // and that the mipmaps are now clean. |
| auto mipRegenTask2 = drawingManager->getLastRenderTask(mipmapProxy.get()); |
| REPORTER_ASSERT(reporter, mipRegenTask2); |
| REPORTER_ASSERT(reporter, mipmapRTCTask.get() != mipRegenTask2); |
| SkASSERT(!mipmapProxy->mipmapsAreDirty()); |
| |
| // Mip regen tasks don't get added as dependencies until makeClosed(). |
| dContext->flushAndSubmit(); |
| REPORTER_ASSERT(reporter, sdc2Task->dependsOn(mipRegenTask2)); |
| } |
| } |