Flutter Engine
The Flutter Engine
GrSurfaceResolveTest.cpp
Go to the documentation of this file.
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
16#include "include/core/SkRect.h"
25#include "include/gpu/GrTypes.h"
30#include "src/gpu/Swizzle.h"
46#include "tests/Test.h"
47#include "tests/TestUtils.h"
48#include "tools/gpu/FenceSync.h"
50
51#include <functional>
52#include <initializer_list>
53#include <memory>
54#include <utility>
55
56struct GrContextOptions;
57
58using namespace sk_gpu_test;
59
61 GrDirectContext* dContext,
62 const GrBackendTexture& tex,
63 const SkImageInfo& info,
64 SkColor expectedColor) {
65 // We have to do the readback of the backend texture wrapped in a different Skia surface than
66 // the one used in the main body of the test or else the readPixels call will trigger resolves
67 // itself.
69 tex,
71 /*sampleCnt=*/4,
73 nullptr,
74 nullptr);
75 SkBitmap actual;
76 actual.allocPixels(info);
77 if (!surface->readPixels(actual, 0, 0)) {
78 return false;
79 }
80
81 SkBitmap expected;
82 expected.allocPixels(info);
83 SkCanvas tmp(expected);
84 tmp.clear(expectedColor);
85 expected.setImmutable();
86
87 const float tols[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
88
89 auto error = std::function<ComparePixmapsErrorReporter>(
90 [reporter](int x, int y, const float diffs[4]) {
91 SkASSERT(x >= 0 && y >= 0);
92 ERRORF(reporter, "mismatch at %d, %d (%f, %f, %f %f)",
93 x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
94 });
95
96 return ComparePixels(expected.pixmap(), actual.pixmap(), tols, error);
97}
98
100 reporter,
101 ctxInfo,
103 auto dContext = ctxInfo.directContext();
104
106
107 auto managedTex = ManagedBackendTexture::MakeFromInfo(
109 if (!managedTex) {
110 return;
111 }
112 auto tex = managedTex->texture();
113 // Wrap the backend surface but tell it rendering with MSAA so that the wrapped texture is the
114 // resolve.
116 tex,
118 /*sampleCnt=*/4,
120 nullptr,
121 nullptr);
122
123 if (!surface) {
124 return;
125 }
126
127 const GrCaps* caps = dContext->priv().caps();
128 // In metal and vulkan if we prefer discardable msaa attachments we will also auto resolve. The
129 // GrBackendTexture and SkSurface are set up in a way that is compatible with discardable msaa
130 // for both backends.
131 bool autoResolves = caps->msaaResolvesAutomatically() ||
133
134 // First do a simple test where we clear the surface than flush with SkSurface::flush. This
135 // should trigger the resolve and the texture should have the correct data.
136 surface->getCanvas()->clear(SK_ColorRED);
137 dContext->flush(surface.get());
138 dContext->submit();
140
141 // Next try doing a GrDirectContext::flush without the surface which will not trigger a resolve
142 // on gpus without automatic msaa resolves.
143 surface->getCanvas()->clear(SK_ColorBLUE);
144 dContext->flush();
145 dContext->submit();
146 if (autoResolves) {
148 } else {
150 }
151
152 // Now doing a surface flush (even without any queued up normal work) should still resolve the
153 // surface.
154 dContext->flush(surface.get());
155 dContext->submit();
157
158 // Test using SkSurface::resolve with a GrDirectContext::flush
159 surface->getCanvas()->clear(SK_ColorRED);
161 dContext->flush();
162 dContext->submit();
164
165 // Calling resolve again should cause no issues as it is a no-op (there is an assert in the
166 // resolve op that the surface's msaa is dirty, we shouldn't hit that assert).
168 dContext->flush();
169 dContext->submit();
171
172 // Try resolving in the middle of draw calls. Non automatic resolve gpus should only see the
173 // results of the first draw.
174 surface->getCanvas()->clear(SK_ColorGREEN);
176 surface->getCanvas()->clear(SK_ColorBLUE);
177 dContext->flush();
178 dContext->submit();
179 if (autoResolves) {
181 } else {
183 }
184
185 // Test that a resolve between draws to a different surface doesn't cause the OpsTasks for that
186 // surface to be split. Fails if we hit validation asserts in GrDrawingManager.
187 // First clear out dirty msaa from previous test
188 dContext->flush(surface.get());
189
190 auto otherSurface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kYes, info);
191 REPORTER_ASSERT(reporter, otherSurface);
192 otherSurface->getCanvas()->clear(SK_ColorRED);
194 otherSurface->getCanvas()->clear(SK_ColorBLUE);
195 dContext->flush();
196 dContext->submit();
197
198 // Make sure resolving a non-msaa surface doesn't trigger a resolve call. We'll hit an assert
199 // that the msaa is not dirty if it does.
200 REPORTER_ASSERT(reporter, otherSurface);
201 otherSurface->getCanvas()->clear(SK_ColorRED);
202 SkSurfaces::ResolveMSAA(otherSurface);
203 dContext->flush();
204 dContext->submit();
205}
206
207// This test comes from crbug.com/1355807 and crbug.com/1365578. The underlying issue was:
208// * We would do a non-mipmapped draw of a proxy. This proxy would add a dependency from the ops
209// task to the proxy's last render task, which was a copy task targetting the proxy.
210// * We would do a mipmapped draw of the same proxy to the same ops task.
211// GrRenderTask::addDependency would detect the pre-existing dependency and early out before
212// adding the proxy to a resolve task.
213// We also test the case where the first draw should add a MSAA resolve and the second draw should
214// add a mipmap resolve.
215DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(NonmippedDrawBeforeMippedDraw,
216 reporter,
217 ctxInfo,
219 using ResolveFlags = GrSurfaceProxy::ResolveFlags;
220 auto dc = ctxInfo.directContext();
221
222 if (!dc->priv().caps()->mipmapSupport()) {
223 return;
224 }
225
226 for (int sampleCount : {1, 4}) {
227 GrRenderable renderable = sampleCount > 1 ? GrRenderable::kYes : GrRenderable::kNo;
228
229 auto bef = dc->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888, renderable);
230 if (sampleCount > 1) {
231 if (dc->priv().caps()->msaaResolvesAutomatically()) {
232 // MSAA won't add a resolve task.
233 continue;
234 }
235 sampleCount = dc->priv().caps()->getRenderTargetSampleCount(sampleCount, bef);
236 if (!sampleCount) {
237 continue;
238 }
239 }
240
241 // Create a mipmapped proxy
242 auto mmProxy = dc->priv().proxyProvider()->createProxy(bef,
243 {64, 64},
244 renderable,
245 sampleCount,
250 "test MM Proxy");
251 GrSurfaceProxyView mmProxyView{mmProxy,
254
255 if (sampleCount > 1) {
256 // Make sure MSAA surface needs a resolve by drawing to it. This also adds a last
257 // render task to the proxy.
258 auto drawContext = skgpu::ganesh::SurfaceDrawContext::Make(dc,
260 mmProxy,
261 nullptr,
264 drawContext->fillWithFP(GrFragmentProcessor::MakeColor(SK_PMColor4fWHITE));
265 } else {
266 // Use a copy, as in the original bug, to dirty the mipmap status and also install
267 // a last render task on the proxy.
268 auto src = dc->priv().proxyProvider()->createProxy(bef,
269 {64, 64},
271 1,
276 "testSrc");
278 dc, mmProxyView, {GrColorType::kRGBA_8888, kPremul_SkAlphaType, nullptr});
279 mmSC.testCopy(src);
280 }
281
284 nullptr,
286 {8, 8},
288 "testDrawDst");
289
290 // Do a non-mipmapped draw from the mipmapped texture. This should add a dependency on the
291 // copy task recorded above. If the src texture is also multisampled this should record a
292 // msaa-only resolve.
293 {
294 auto te = GrTextureEffect::Make(
295 mmProxyView,
297 SkMatrix::I(),
299 *dc->priv().caps());
300
302 paint.setColorFragmentProcessor(std::move(te));
303
304 drawDst->drawRect(nullptr,
305 std::move(paint),
306 GrAA::kNo,
307 SkMatrix::Scale(1/8.f, 1/8.f),
308 SkRect::Make(mmProxy->dimensions()));
309 if (sampleCount > 1) {
310 const GrTextureResolveRenderTask* resolveTask =
311 drawDst->getOpsTask()->resolveTask();
312 if (!resolveTask) {
313 ERRORF(reporter, "No resolve task after drawing MSAA proxy");
314 return;
315 }
316 if (resolveTask->flagsForProxy(mmProxy) != ResolveFlags::kMSAA) {
317 ERRORF(reporter, "Expected resolve flags to be kMSAA");
318 return;
319 }
320 }
321 }
322
323 // Now do a mipmapped draw from the same texture. Ensure that even though we have a
324 // dependency on the copy task we still ensure that a resolve is recorded.
325 {
326 auto te = GrTextureEffect::Make(
327 mmProxyView,
329 SkMatrix::I(),
331 *dc->priv().caps());
332
334 paint.setColorFragmentProcessor(std::move(te));
335
336 drawDst->drawRect(nullptr,
337 std::move(paint),
338 GrAA::kNo,
339 SkMatrix::Scale(1/8.f, 1/8.f),
340 SkRect::Make(mmProxy->dimensions()));
341 }
342 const GrTextureResolveRenderTask* resolveTask = drawDst->getOpsTask()->resolveTask();
343 if (!resolveTask) {
344 ERRORF(reporter, "No resolve task after drawing mip mapped proxy");
345 return;
346 }
347
348 ResolveFlags expectedFlags = GrSurfaceProxy::ResolveFlags::kMipMaps;
349 const char* expectedStr = "kMipMaps";
350 if (sampleCount > 1) {
352 expectedStr = "kMipMaps|kMSAA";
353 }
354 if (resolveTask->flagsForProxy(mmProxy) != expectedFlags) {
355 ERRORF(reporter, "Expected resolve flags to be %s", expectedStr);
356 return;
357 }
358 }
359}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
reporter
Definition: FontMgrTest.cpp:39
bool check_pixels(skiatest::Reporter *reporter, GrDirectContext *dContext, const GrBackendTexture &tex, const SkImageInfo &info, SkColor expectedColor)
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceResolveTest, reporter, ctxInfo, CtsEnforcement::kApiLevel_T)
@ kBottomLeft_GrSurfaceOrigin
Definition: GrTypes.h:149
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr SkPMColor4f SK_PMColor4fWHITE
Definition: SkColorData.h:380
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
bool ComparePixels(const GrCPixmap &a, const GrCPixmap &b, const float tolRGBA[4], std::function< ComparePixmapsErrorReporter > &error)
Definition: TestUtils.cpp:142
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
#define ERRORF(r,...)
Definition: Test.h:293
Definition: GrCaps.h:57
bool preferDiscardableMSAAAttachment() const
Definition: GrCaps.h:107
bool msaaResolvesAutomatically() const
Definition: GrCaps.h:100
static std::unique_ptr< GrFragmentProcessor > MakeColor(SkPMColor4f color)
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
void setImmutable()
Definition: SkBitmap.cpp:400
const SkPixmap & pixmap() const
Definition: SkBitmap.h:133
void clear(SkColor color)
Definition: SkCanvas.h:1199
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
static constexpr Swizzle RGBA()
Definition: Swizzle.h:66
static std::unique_ptr< SurfaceDrawContext > Make(GrRecordingContext *, GrColorType, sk_sp< GrSurfaceProxy >, sk_sp< SkColorSpace >, GrSurfaceOrigin, const SkSurfaceProps &)
const Paint & paint
Definition: color_source.cc:38
VkSurfaceKHR surface
Definition: main.cc:49
const uint8_t uint32_t uint32_t GError ** error
double y
double x
SK_API void ResolveMSAA(SkSurface *surface)
SK_API sk_sp< SkSurface > WrapBackendTexture(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, int sampleCnt, SkColorType colorType, sk_sp< SkColorSpace > colorSpace, const SkSurfaceProps *surfaceProps, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
Renderable
Definition: GpuTypes.h:69
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669