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