Flutter Engine
The Flutter Engine
DMSAATest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 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
20#include "include/core/SkRect.h"
24#include "include/core/SkSize.h"
33#include "include/gpu/GrTypes.h"
45#include "tests/Test.h"
47
48#include <cstdint>
49#include <cstring>
50#include <memory>
51#include <utility>
52
53namespace {
54
56static SkSurfaceProps kBasicProps(0, kUnknown_SkPixelGeometry);
57constexpr static SkPMColor4f kTransYellow = {.5f,.5f,.0f,.5f};
58constexpr static SkPMColor4f kTransCyan = {.0f,.5f,.5f,.5f};
59constexpr static int kWidth=10, kHeight=10;
60
61}
62
64 const SkPMColor4f& color,
65 SkBlendMode blendMode) {
67 paint.setColor4f(color);
68 paint.setXPFactory(GrXPFactory::FromBlendMode(blendMode));
69 sdc->drawRect(nullptr, std::move(paint), GrAA::kYes, SkMatrix::I(),
70 SkRect::MakeIWH(kWidth, kHeight), nullptr);
71}
72
74 const SkPMColor4f& color,
75 SkBlendMode blendMode) {
76 // drawVertices should always trigger dmsaa, but draw something non-rectangular just to be 100%
77 // certain.
78 static const SkPoint kVertices[3] = {{-.5f,-.5f}, {kWidth * 2.1f, 0}, {0, kHeight * 2.1f}};
80 memcpy(builder.positions(), kVertices, sizeof(kVertices));
81 auto vertices = builder.detach();
82
84 paint.setColor4f(color);
85 paint.setXPFactory(GrXPFactory::FromBlendMode(blendMode));
86 sdc->drawVertices(nullptr, std::move(paint), SkMatrix::I(), vertices);
87}
88
89static bool fuzzy_equals(const float a[4], const SkPMColor4f& b) {
90 constexpr static float kTolerance = 2.5f / 256;
91 for (int i = 0; i < 4; ++i) {
92 if (!SkScalarNearlyEqual(a[i], b.vec()[i], kTolerance)) {
93 return false;
94 }
95 }
96 return true;
97}
98
101 GrDirectContext* ctx,
102 const SkPMColor4f& color) {
105 sdc->readPixels(ctx, pixmap, {0, 0});
106 auto pix = static_cast<const float*>(pixmap.addr());
107 for (int y = 0; y < kHeight; ++y) {
108 for (int x = 0; x < kWidth; ++x) {
109 if (!fuzzy_equals(pix, color)) {
110 ERRORF(reporter, "SDC color mismatch.\n"
111 "Got [%0.3f, %0.3f, %0.3f, %0.3f]\n"
112 "Expected [%0.3f, %0.3f, %0.3f, %0.3f]",
113 pix[0], pix[1], pix[2], pix[3], color.fR, color.fG, color.fB, color.fA);
114 return;
115 }
116 pix += 4;
117 }
118 }
119}
120
121DEF_GANESH_TEST_FOR_CONTEXTS(DMSAA_preserve_contents,
123 reporter,
124 ctxInfo,
125 nullptr,
127 auto dContext = ctxInfo.directContext();
128 auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(dContext,
130 nullptr,
132 {kWidth, kHeight},
133 kDMSAAProps,
134 /*label=*/{});
135
136 // Initialize the texture and dmsaa attachment with transparent.
138 check_sdc_color(reporter, sdc.get(), dContext, SK_PMColor4fTRANSPARENT);
139
140 // Clear the main texture to yellow.
141 sdc->clear(kTransYellow);
142
143 // Close the opsTask by doing a readback.
144 check_sdc_color(reporter, sdc.get(), dContext, kTransYellow);
145
146 // Now the DMSAA attachment is clear and the texture is yellow. Blend cyan into the DMSAA
147 // attachment. This will fail if the yellow from the main texture doesn't get copied into the
148 // DMSAA attachment before the renderPass.
149 draw_paint_with_dmsaa(sdc.get(), kTransCyan, SkBlendMode::kSrcOver);
150 SkPMColor4f dstColor = SkBlendMode_Apply(SkBlendMode::kSrcOver, kTransCyan, kTransYellow);
151
152 check_sdc_color(reporter, sdc.get(), dContext, dstColor);
153}
154
156 options->fSuppressAdvancedBlendEquations = true;
157 options->fSuppressFramebufferFetch = true;
158}
159
162 reporter,
163 ctxInfo,
166 auto dContext = ctxInfo.directContext();
167 auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(dContext,
169 nullptr,
171 {kWidth, kHeight},
172 kDMSAAProps,
173 /*label=*/{});
174
175 // Initialize the texture and dmsaa attachment with transparent.
177 check_sdc_color(reporter, sdc.get(), dContext, SK_PMColor4fTRANSPARENT);
178
179 sdc->clear(SK_PMColor4fWHITE);
181
182 draw_paint_with_dmsaa(sdc.get(), kTransYellow, SkBlendMode::kDarken);
183 dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransYellow, dstColor);
184
185 draw_paint_with_dmsaa(sdc.get(), kTransCyan, SkBlendMode::kDarken);
186 dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransCyan, dstColor);
187
188 check_sdc_color(reporter, sdc.get(), dContext, dstColor);
189}
190
191DEF_GANESH_TEST_FOR_CONTEXTS(DMSAA_aa_dst_read_after_dmsaa,
193 reporter,
194 ctxInfo,
197 auto dContext = ctxInfo.directContext();
198 auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(dContext,
200 nullptr,
202 {kWidth, kHeight},
203 kDMSAAProps,
204 /*label=*/{});
205
206 // Initialize the texture and dmsaa attachment with transparent.
208 check_sdc_color(reporter, sdc.get(), dContext, SK_PMColor4fTRANSPARENT);
209
210 sdc->clear(SK_PMColor4fWHITE);
212
213 draw_paint_with_dmsaa(sdc.get(), kTransYellow, SkBlendMode::kDarken);
214 dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransYellow, dstColor);
215
216 // Draw with aa after dmsaa. This should break up the render pass and issue a texture barrier.
217 draw_paint_with_aa(sdc.get(), kTransCyan, SkBlendMode::kDarken);
218 dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransCyan, dstColor);
219
220 check_sdc_color(reporter, sdc.get(), dContext, dstColor);
221}
222
223DEF_GANESH_TEST_FOR_CONTEXTS(DMSAA_dst_read_with_existing_barrier,
225 reporter,
226 ctxInfo,
229 auto dContext = ctxInfo.directContext();
230 auto sdc = skgpu::ganesh::SurfaceDrawContext::Make(dContext,
232 nullptr,
234 {kWidth, kHeight},
235 kDMSAAProps,
236 /*label=*/{});
237
238 // Initialize the texture and dmsaa attachment with transparent.
240 check_sdc_color(reporter, sdc.get(), dContext, SK_PMColor4fTRANSPARENT);
241
242 sdc->clear(SK_PMColor4fWHITE);
244
245 // Blend to the texture (not the dmsaa attachment) with a dst read. This creates a texture
246 // barrier.
247 draw_paint_with_aa(sdc.get(), kTransYellow, SkBlendMode::kDarken);
248 dstColor = SkBlendMode_Apply(SkBlendMode::kDarken, kTransYellow, dstColor);
249
250 // Blend to the msaa attachment _without_ a dst read. This ensures we respect the prior texture
251 // barrier by splitting the opsTask.
252 draw_paint_with_dmsaa(sdc.get(), kTransCyan, SkBlendMode::kSrcOver);
253 dstColor = SkBlendMode_Apply(SkBlendMode::kSrcOver, kTransCyan, dstColor);
254
255 check_sdc_color(reporter, sdc.get(), dContext, dstColor);
256}
257
258// This test is used to test for crbug.com/1241134. The bug appears on Adreno5xx devices with OS
259// PQ3A. It does not repro on the earlier PPR1 version since the extend blend func extension was not
260// present on the older driver.
261DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(DMSAA_dual_source_blend_disable,
262 reporter,
263 ctxInfo,
265 SkISize surfaceDims = {100, 100};
266 SkISize texDims = {50, 50};
267 auto context = ctxInfo.directContext();
268
269 auto sourceTexture = context->createBackendTexture(texDims.width(),
270 texDims.height(),
276
277 auto sourceImage = SkImages::BorrowTextureFrom(context,
278 sourceTexture,
282 nullptr);
283
284 auto texture1 = context->createBackendTexture(surfaceDims.width(),
285 surfaceDims.height(),
291
292 auto texture2 = context->createBackendTexture(surfaceDims.width(),
293 surfaceDims.height(),
299
301 paint.setBlendMode(SkBlendMode::kSrc);
302
303 SkRect srcRect = SkRect::MakeIWH(texDims.width(), texDims.height());
304 SkRect dstRect = SkRect::MakeXYWH(texDims.width()/2, texDims.height()/2,
305 texDims.width(), texDims.height());
306
307 // First we do an image draw to a DMSAA surface with kSrc blend mode. This will trigger us to
308 // use dual source blending if supported.
309 // Note: The draw here doesn't actually use the dmsaa multisampled buffer. However, by using
310 // a dmsaa surface it forces us to use the FillRRectOp instead of the normal FillQuad path. It
311 // is unclear why, but using the FillRRectOp is required to repro the bug.
312 {
314 texture1,
316 1,
318 nullptr,
319 &kDMSAAProps);
320
321 surface->getCanvas()->drawImageRect(sourceImage,
322 srcRect,
323 dstRect,
325 &paint,
327 // Make sure there isn't any batching
328 context->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
329 }
330
331 // Next we do an image draw to a different surface that doesn't have the dmsaa flag. This will
332 // trigger use to disable blending. However, when the bug is present the driver still seems to
333 // try and use a "src2" blend value and ends up just writing the original dst color of yellow.
334 {
336 texture2,
338 1,
340 nullptr,
341 &kBasicProps);
342
343 surface->getCanvas()->drawImageRect(sourceImage,
344 srcRect,
345 dstRect,
347 &paint,
349 context->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
350 }
351
352 {
353 auto readImage = SkImages::BorrowTextureFrom(context,
354 texture2,
358 nullptr);
359 SkImageInfo dstIInfo = SkImageInfo::Make(texDims.width(),
360 texDims.height(),
363 nullptr);
364
366 bitmap.allocPixels(dstIInfo);
367
368 bool success = readImage->readPixels(context, bitmap.pixmap(), dstRect.fLeft, dstRect.fTop);
369 if (!success) {
370 ERRORF(reporter, "Failed to read pixels");
371 return;
372 }
373 auto pix = static_cast<const uint32_t*>(bitmap.getAddr(0, 0));
374 for (int x = 0; x < 50; ++x) {
375 for (int y = 0; y < 50; ++y) {
376 uint32_t pixColor = pix[x + y * 50];
377 if (pixColor != 0xFFFF0000) {
378 ERRORF(reporter, "Didn't get a blue pixel at %d, %d. Got 0x%8X",
379 x, y, pixColor);
380 continue;
381 }
382 }
383 }
384 }
385 sourceImage.reset();
386 // Need to make sure the gpu is fully finished before deleting the textures
387 context->flushAndSubmit(GrSyncCpu::kYes);
388 context->deleteBackendTexture(sourceTexture);
389 context->deleteBackendTexture(texture1);
390 context->deleteBackendTexture(texture2);
391}
const char * options
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(DMSAA_dual_source_blend_disable, reporter, ctxInfo, CtsEnforcement::kApiLevel_T)
Definition: DMSAATest.cpp:261
static void draw_paint_with_aa(skgpu::ganesh::SurfaceDrawContext *sdc, const SkPMColor4f &color, SkBlendMode blendMode)
Definition: DMSAATest.cpp:63
static void check_sdc_color(skiatest::Reporter *reporter, skgpu::ganesh::SurfaceDrawContext *sdc, GrDirectContext *ctx, const SkPMColor4f &color)
Definition: DMSAATest.cpp:99
static void require_dst_reads(GrContextOptions *options)
Definition: DMSAATest.cpp:155
DEF_GANESH_TEST_FOR_CONTEXTS(DMSAA_preserve_contents, &skgpu::IsRenderingContext, reporter, ctxInfo, nullptr, CtsEnforcement::kApiLevel_T)
Definition: DMSAATest.cpp:121
static bool fuzzy_equals(const float a[4], const SkPMColor4f &b)
Definition: DMSAATest.cpp:89
static void draw_paint_with_dmsaa(skgpu::ganesh::SurfaceDrawContext *sdc, const SkPMColor4f &color, SkBlendMode blendMode)
Definition: DMSAATest.cpp:73
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
reporter
Definition: FontMgrTest.cpp:39
static constexpr float kTolerance
Definition: GrQuadUtils.cpp:29
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
SkPMColor4f SkBlendMode_Apply(SkBlendMode mode, const SkPMColor4f &src, const SkPMColor4f &dst)
SkBlendMode
Definition: SkBlendMode.h:38
@ kSrcOver
r = s + (1-sa)*d
@ kDarken
rc = s + d - max(s*da, d*sa), ra = kSrcOver
constexpr SkPMColor4f SK_PMColor4fWHITE
Definition: SkColorData.h:380
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
Definition: SkColorData.h:378
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition: SkColorType.h:40
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:107
@ kUnknown_SkPixelGeometry
#define ERRORF(r,...)
Definition: Test.h:293
T * addr() const
Definition: GrPixmap.h:20
static GrPixmap Allocate(const GrImageInfo &info)
Definition: GrPixmap.h:101
static const GrXPFactory * FromBlendMode(SkBlendMode)
@ kStrict_SrcRectConstraint
sample only inside bounds; slower
Definition: SkCanvas.h:1542
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
@ kTriangles_VertexMode
Definition: SkVertices.h:31
bool readPixels(GrDirectContext *dContext, GrPixmap dst, SkIPoint srcPt)
static std::unique_ptr< SurfaceDrawContext > Make(GrRecordingContext *, GrColorType, sk_sp< GrSurfaceProxy >, sk_sp< SkColorSpace >, GrSurfaceOrigin, const SkSurfaceProps &)
void drawRect(const GrClip *, GrPaint &&paint, GrAA, const SkMatrix &viewMatrix, const SkRect &, const GrStyle *style=nullptr)
void drawVertices(const GrClip *, GrPaint &&paint, const SkMatrix &viewMatrix, sk_sp< SkVertices > vertices, GrPrimitiveType *overridePrimType=nullptr, bool skipColorXform=false)
const Paint & paint
Definition: color_source.cc:38
DlColor color
VkSurfaceKHR surface
Definition: main.cc:49
static bool b
struct MyStruct a[10]
double y
double x
constexpr SkColor4f kRed
Definition: SkColor.h:440
constexpr SkColor4f kBlue
Definition: SkColor.h:442
constexpr SkColor4f kYellow
Definition: SkColor.h:443
SK_API sk_sp< SkImage > BorrowTextureFrom(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
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)
Definition: bitmap.py:1
bool IsRenderingContext(skgpu::ContextType type)
Definition: ContextType.cpp:88
SkSamplingOptions(SkFilterMode::kLinear))
Definition: SkSize.h:16
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
static SkRect MakeIWH(int w, int h)
Definition: SkRect.h:623
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15
constexpr size_t kHeight
constexpr size_t kWidth