1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 9cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 10cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h" 13cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h" 14cb93a386Sopenharmony_ci#include "src/image/SkImage_GpuBase.h" 15cb93a386Sopenharmony_ci#include "tests/Test.h" 16cb93a386Sopenharmony_ci#include "tools/gpu/ProxyUtils.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci// Tests that MIP maps are created and invalidated as expected when drawing to and from GrTextures. 19cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrTextureMipMapInvalidationTest, reporter, ctxInfo) { 20cb93a386Sopenharmony_ci auto context = ctxInfo.directContext(); 21cb93a386Sopenharmony_ci if (!context->priv().caps()->mipmapSupport()) { 22cb93a386Sopenharmony_ci return; 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci auto isMipped = [reporter](SkSurface* surf) { 26cb93a386Sopenharmony_ci sk_sp<SkImage> image = surf->makeImageSnapshot(); 27cb93a386Sopenharmony_ci GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(), 28cb93a386Sopenharmony_ci surf->recordingContext()); 29cb93a386Sopenharmony_ci bool proxyIsMipmapped = proxy->mipmapped() == GrMipmapped::kYes; 30cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, proxyIsMipmapped == image->hasMipmaps()); 31cb93a386Sopenharmony_ci return image->hasMipmaps(); 32cb93a386Sopenharmony_ci }; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci auto mipsAreDirty = [](SkSurface* surf) { 35cb93a386Sopenharmony_ci sk_sp<SkImage> image = surf->makeImageSnapshot(); 36cb93a386Sopenharmony_ci GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(image.get(), 37cb93a386Sopenharmony_ci surf->recordingContext()); 38cb93a386Sopenharmony_ci return proxy->peekTexture()->mipmapsAreDirty(); 39cb93a386Sopenharmony_ci }; 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci auto info = SkImageInfo::MakeN32Premul(256, 256); 42cb93a386Sopenharmony_ci for (auto allocateMips : {false, true}) { 43cb93a386Sopenharmony_ci auto surf1 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0, 44cb93a386Sopenharmony_ci kBottomLeft_GrSurfaceOrigin, nullptr, 45cb93a386Sopenharmony_ci allocateMips); 46cb93a386Sopenharmony_ci auto surf2 = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info); 47cb93a386Sopenharmony_ci // Draw something just in case we ever had a solid color optimization 48cb93a386Sopenharmony_ci surf1->getCanvas()->drawCircle(128, 128, 50, SkPaint()); 49cb93a386Sopenharmony_ci surf1->flushAndSubmit(); 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci // No mipmaps initially 52cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci // Painting with downscale and medium filter quality should result in mipmap creation 55cb93a386Sopenharmony_ci // Flush the context rather than the canvas as flushing the canvas triggers MIP level 56cb93a386Sopenharmony_ci // generation. 57cb93a386Sopenharmony_ci SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kLinear); 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci surf2->getCanvas()->scale(0.2f, 0.2f); 60cb93a386Sopenharmony_ci surf2->getCanvas()->drawImage(surf1->makeImageSnapshot(), 0, 0, sampling); 61cb93a386Sopenharmony_ci context->flushAndSubmit(); 62cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips); 63cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !allocateMips || !mipsAreDirty(surf1.get())); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci // Changing the contents of the surface should invalidate the mipmap, but not de-allocate 66cb93a386Sopenharmony_ci surf1->getCanvas()->drawCircle(128, 128, 100, SkPaint()); 67cb93a386Sopenharmony_ci context->flushAndSubmit(); 68cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isMipped(surf1.get()) == allocateMips); 69cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, mipsAreDirty(surf1.get())); 70cb93a386Sopenharmony_ci } 71cb93a386Sopenharmony_ci} 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReimportImageTextureWithMipLevels, reporter, ctxInfo) { 74cb93a386Sopenharmony_ci auto dContext = ctxInfo.directContext(); 75cb93a386Sopenharmony_ci if (!dContext->priv().caps()->mipmapSupport()) { 76cb93a386Sopenharmony_ci return; 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci static constexpr auto kCreateWithMipMaps = true; 79cb93a386Sopenharmony_ci auto surf = SkSurface::MakeRenderTarget( 80cb93a386Sopenharmony_ci dContext, SkBudgeted::kYes, 81cb93a386Sopenharmony_ci SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType), 1, 82cb93a386Sopenharmony_ci kTopLeft_GrSurfaceOrigin, nullptr, kCreateWithMipMaps); 83cb93a386Sopenharmony_ci if (!surf) { 84cb93a386Sopenharmony_ci return; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci surf->getCanvas()->drawColor(SK_ColorDKGRAY); 87cb93a386Sopenharmony_ci auto img = surf->makeImageSnapshot(); 88cb93a386Sopenharmony_ci if (!img) { 89cb93a386Sopenharmony_ci return; 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci surf.reset(); 92cb93a386Sopenharmony_ci GrBackendTexture btex; 93cb93a386Sopenharmony_ci SkImage::BackendTextureReleaseProc texRelease; 94cb93a386Sopenharmony_ci if (!SkImage::MakeBackendTextureFromSkImage(dContext, std::move(img), &btex, &texRelease)) { 95cb93a386Sopenharmony_ci // Not all backends support stealing textures yet. 96cb93a386Sopenharmony_ci // ERRORF(reporter, "Could not turn image into texture"); 97cb93a386Sopenharmony_ci return; 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, btex.hasMipmaps()); 100cb93a386Sopenharmony_ci // Reimport the texture as an image and perform a downsampling draw with medium quality which 101cb93a386Sopenharmony_ci // should use the upper MIP levels. 102cb93a386Sopenharmony_ci img = SkImage::MakeFromTexture(dContext, btex, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, 103cb93a386Sopenharmony_ci kPremul_SkAlphaType, nullptr); 104cb93a386Sopenharmony_ci const auto singlePixelInfo = 105cb93a386Sopenharmony_ci SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); 106cb93a386Sopenharmony_ci surf = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kYes, singlePixelInfo, 1, 107cb93a386Sopenharmony_ci kTopLeft_GrSurfaceOrigin, nullptr); 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci surf->getCanvas()->drawImageRect(img, SkRect::MakeWH(1, 1), 110cb93a386Sopenharmony_ci SkSamplingOptions(SkFilterMode::kLinear, 111cb93a386Sopenharmony_ci SkMipmapMode::kLinear)); 112cb93a386Sopenharmony_ci uint32_t pixel; 113cb93a386Sopenharmony_ci surf->readPixels(singlePixelInfo, &pixel, sizeof(uint32_t), 0, 0); 114cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pixel == SkPreMultiplyColor(SK_ColorDKGRAY)); 115cb93a386Sopenharmony_ci img.reset(); 116cb93a386Sopenharmony_ci texRelease(btex); 117cb93a386Sopenharmony_ci} 118