1 /*
2 * Copyright 2021 Google LLC
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 "include/core/SkAlphaType.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkColorType.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPath.h"
16 #include "include/core/SkPathTypes.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkSurface.h"
20 #include "include/core/SkTypes.h"
21 #include "include/gpu/GpuTypes.h"
22 #include "include/gpu/ganesh/GrDirectContext.h"
23 #include "include/gpu/ganesh/GrTypes.h"
24 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
25 #include "src/core/SkAutoPixmapStorage.h"
26 #include "tests/CtsEnforcement.h"
27 #include "tests/Test.h"
28
29 #include <initializer_list>
30
31 struct GrContextOptions;
32
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(crbug_1271431,reporter,context_info,CtsEnforcement::kApiLevel_T)33 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(crbug_1271431,
34 reporter,
35 context_info,
36 CtsEnforcement::kApiLevel_T) {
37 GrDirectContext* dc = context_info.directContext();
38
39 // Make sure we don't get recycled render targets that already have stencil attachments.
40 dc->freeGpuResources();
41
42 SkImageInfo ii = SkImageInfo::Make({100, 100},
43 kRGBA_8888_SkColorType,
44 kPremul_SkAlphaType,
45 nullptr);
46 sk_sp<SkSurface> surfs[2]{SkSurfaces::RenderTarget(dc, skgpu::Budgeted::kYes, ii, 1, nullptr),
47 SkSurfaces::RenderTarget(dc, skgpu::Budgeted::kYes, ii, 1, nullptr)};
48
49 // Make sure the surfaces' proxies are instantiated without stencil. Creating textures lazily
50 // can invalidate the current tracked FBO since FBO state must be modified to during
51 // GrGLRenderTarget creation.
52 for (int i = 0; i < 2; ++i) {
53 surfs[i]->getCanvas()->clear(SK_ColorWHITE);
54 dc->flushAndSubmit(surfs[i].get(), GrSyncCpu::kNo);
55 }
56
57 auto drawWithStencilClip = [&](SkSurface& surf, SkColor color) {
58 SkPath clip;
59 clip.addCircle(50, 50, 50);
60 clip.addCircle(50, 50, 10, SkPathDirection::kCCW);
61 SkPaint paint;
62 paint.setColor(color);
63 surf.getCanvas()->clipPath(clip, false);
64 surf.getCanvas()->drawRect(SkRect::MakeLTRB(0,0, 100, 100), paint);
65 };
66
67 // Use surfs[0] create to create a cached stencil buffer that is also sized for surfs[1].
68 drawWithStencilClip(*surfs[0], SK_ColorRED);
69 dc->flushAndSubmit(surfs[0].get(), GrSyncCpu::kNo);
70
71 // Make sure surf[1]'s FBO is bound but without using draws that would attach stencil.
72 surfs[1]->getCanvas()->clear(SK_ColorGREEN);
73 dc->flushAndSubmit(surfs[1].get(), GrSyncCpu::kNo);
74
75 // Now use stencil for clipping. We should now have the following properties:
76 // 1) surf[1]'s FBO is already bound
77 // 2) surf[1] doesn't have a stencil buffer
78 // 3) There is an appropriately sized stencil buffer in the cache (used with surf[0]). This is
79 // important because creating a new stencil buffer will invalidate the bound FBO tracking.
80 // The bug was that because the correct FBO was already bound we would not rebind and would
81 // skip the lazy stencil attachment in GrGLRenderTarget. This would cause the clip to fail.
82 drawWithStencilClip(*surfs[1], SK_ColorBLUE);
83
84 // Check that four pixels that should have been clipped out of the blue draw are green.
85 SkAutoPixmapStorage rb;
86 rb.alloc(surfs[1]->imageInfo().makeWH(1, 1));
87 for (int x : {5, 95}) {
88 for (int y : {5, 95}) {
89 if (!surfs[1]->readPixels(rb, x, y)) {
90 ERRORF(reporter, "readback failed");
91 return;
92 }
93 if (*rb.addr32() != SK_ColorGREEN) {
94 ERRORF(reporter,
95 "Expected green at (%d, %d), instead got 0x%08x.",
96 x,
97 y,
98 *rb.addr32());
99 return;
100 }
101 }
102 }
103 }
104