• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 "tests/Test.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkSurface.h"
13 #include "src/gpu/GrCaps.h"
14 #include "src/gpu/GrDirectContextPriv.h"
15 #include "src/gpu/GrPixmap.h"
16 #include "tests/TestUtils.h"
17 #include "tools/gpu/ManagedBackendTexture.h"
18 
19 using namespace sk_gpu_test;
20 
check_pixels(skiatest::Reporter * reporter,GrDirectContext * dContext,const GrBackendTexture & tex,const SkImageInfo & info,SkColor expectedColor)21 bool check_pixels(skiatest::Reporter* reporter,
22                   GrDirectContext* dContext,
23                   const GrBackendTexture& tex,
24                   const SkImageInfo& info,
25                   SkColor expectedColor) {
26     // We have to do the readback of the backend texture wrapped in a different Skia surface than
27     // the one used in the main body of the test or else the readPixels call will trigger resolves
28     // itself.
29     sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(dContext,
30                                                                  tex,
31                                                                  kTopLeft_GrSurfaceOrigin,
32                                                                  /*sampleCnt=*/4,
33                                                                  kRGBA_8888_SkColorType,
34                                                                  nullptr, nullptr);
35     SkBitmap actual;
36     actual.allocPixels(info);
37     if (!surface->readPixels(actual, 0, 0)) {
38         return false;
39     }
40 
41     SkBitmap expected;
42     expected.allocPixels(info);
43     SkCanvas tmp(expected);
44     tmp.clear(expectedColor);
45     expected.setImmutable();
46 
47     const float tols[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
48 
49     auto error = std::function<ComparePixmapsErrorReporter>(
50         [reporter](int x, int y, const float diffs[4]) {
51             SkASSERT(x >= 0 && y >= 0);
52             ERRORF(reporter, "mismatch at %d, %d (%f, %f, %f %f)",
53                    x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
54         });
55 
56     return ComparePixels(expected.pixmap(), actual.pixmap(), tols, error);
57 }
58 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceResolveTest,reporter,ctxInfo)59 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceResolveTest, reporter, ctxInfo) {
60     auto dContext = ctxInfo.directContext();
61 
62     SkImageInfo info = SkImageInfo::Make(8, 8, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
63 
64     auto managedTex = ManagedBackendTexture::MakeFromInfo(dContext,
65                                                           info,
66                                                           GrMipmapped::kNo,
67                                                           GrRenderable::kYes);
68     if (!managedTex) {
69         return;
70     }
71     auto tex = managedTex->texture();
72     // Wrap the backend surface but tell it rendering with MSAA so that the wrapped texture is the
73     // resolve.
74     sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(dContext,
75                                                                  tex,
76                                                                  kTopLeft_GrSurfaceOrigin,
77                                                                  /*sampleCnt=*/4,
78                                                                  kRGBA_8888_SkColorType,
79                                                                  nullptr, nullptr);
80 
81     if (!surface) {
82         return;
83     }
84 
85     const GrCaps* caps = dContext->priv().caps();
86     // In metal and vulkan if we prefer discardable msaa attachments we will also auto resolve. The
87     // GrBackendTexture and SkSurface are set up in a way that is compatible with discardable msaa
88     // for both backends.
89     bool autoResolves = caps->msaaResolvesAutomatically() ||
90                         caps->preferDiscardableMSAAAttachment();
91 
92     // First do a simple test where we clear the surface than flush with SkSurface::flush. This
93     // should trigger the resolve and the texture should have the correct data.
94     surface->getCanvas()->clear(SK_ColorRED);
95     surface->flush();
96     dContext->submit();
97     REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorRED));
98 
99     // Next try doing a GrDirectContext::flush which will not trigger a resolve on gpus without
100     // automatic msaa resolves.
101     surface->getCanvas()->clear(SK_ColorBLUE);
102     dContext->flush();
103     dContext->submit();
104     if (autoResolves) {
105         REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorBLUE));
106     } else {
107         REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorRED));
108     }
109 
110     // Now doing a surface flush (even without any queued up normal work) should still resolve the
111     // surface.
112     surface->flush();
113     dContext->submit();
114     REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorBLUE));
115 
116     // Test using SkSurface::resolve with a GrDirectContext::flush
117     surface->getCanvas()->clear(SK_ColorRED);
118     surface->resolveMSAA();
119     dContext->flush();
120     dContext->submit();
121     REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorRED));
122 
123     // Calling resolve again should cause no issues as it is a no-op (there is an assert in the
124     // resolve op that the surface's msaa is dirty, we shouldn't hit that assert).
125     surface->resolveMSAA();
126     dContext->flush();
127     dContext->submit();
128     REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorRED));
129 
130     // Try resolving in the middle of draw calls. Non automatic resolve gpus should only see the
131     // results of the first draw.
132     surface->getCanvas()->clear(SK_ColorGREEN);
133     surface->resolveMSAA();
134     surface->getCanvas()->clear(SK_ColorBLUE);
135     dContext->flush();
136     dContext->submit();
137     if (autoResolves) {
138         REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorBLUE));
139     } else {
140         REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorGREEN));
141     }
142 
143     // Test that a resolve between draws to a different surface doesn't cause the OpsTasks for that
144     // surface to be split. Fails if we hit validation asserts in GrDrawingManager.
145     // First clear out dirty msaa from previous test
146     surface->flush();
147 
148     auto otherSurface = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kYes, info);
149     REPORTER_ASSERT(reporter, otherSurface);
150     otherSurface->getCanvas()->clear(SK_ColorRED);
151     surface->resolveMSAA();
152     otherSurface->getCanvas()->clear(SK_ColorBLUE);
153     dContext->flush();
154     dContext->submit();
155 
156     // Make sure resolving a non-msaa surface doesn't trigger a resolve call. We'll hit an assert
157     // that the msaa is not dirty if it does.
158     REPORTER_ASSERT(reporter, otherSurface);
159     otherSurface->getCanvas()->clear(SK_ColorRED);
160     otherSurface->resolveMSAA();
161     dContext->flush();
162     dContext->submit();
163 }
164 
165