| /* | |
| * Copyright 2021 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "include/core/SkAlphaType.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkColorSpace.h" | |
| #include "include/core/SkColorType.h" | |
| #include "include/core/SkImageInfo.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkPath.h" | |
| #include "include/core/SkPathBuilder.h" | |
| #include "include/core/SkPathTypes.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkSurface.h" | |
| #include "include/core/SkTypes.h" | |
| #include "include/gpu/GpuTypes.h" | |
| #include "include/gpu/ganesh/GrDirectContext.h" | |
| #include "include/gpu/ganesh/GrTypes.h" | |
| #include "include/gpu/ganesh/SkSurfaceGanesh.h" | |
| #include "src/core/SkAutoPixmapStorage.h" | |
| #include "tests/CtsEnforcement.h" | |
| #include "tests/Test.h" | |
| #include <array> | |
| #include <initializer_list> | |
| struct GrContextOptions; | |
| DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(crbug_1271431, | |
| reporter, | |
| context_info, | |
| CtsEnforcement::kApiLevel_T) { | |
| GrDirectContext* dc = context_info.directContext(); | |
| // Make sure we don't get recycled render targets that already have stencil attachments. | |
| dc->freeGpuResources(); | |
| SkImageInfo ii = SkImageInfo::Make({100, 100}, | |
| kRGBA_8888_SkColorType, | |
| kPremul_SkAlphaType, | |
| nullptr); | |
| std::array<sk_sp<SkSurface>, 2> surfs = { | |
| SkSurfaces::RenderTarget(dc, skgpu::Budgeted::kYes, ii, 1, nullptr), | |
| SkSurfaces::RenderTarget(dc, skgpu::Budgeted::kYes, ii, 1, nullptr)}; | |
| // Make sure the surfaces' proxies are instantiated without stencil. Creating textures lazily | |
| // can invalidate the current tracked FBO since FBO state must be modified to during | |
| // GrGLRenderTarget creation. | |
| for (int i = 0; i < 2; ++i) { | |
| surfs[i]->getCanvas()->clear(SK_ColorWHITE); | |
| dc->flushAndSubmit(surfs[i].get(), GrSyncCpu::kNo); | |
| } | |
| auto drawWithStencilClip = [&](SkSurface& surf, SkColor color) { | |
| SkPath clip = SkPathBuilder() | |
| .addCircle(50, 50, 50) | |
| .addCircle(50, 50, 10, SkPathDirection::kCCW) | |
| .detach(); | |
| SkPaint paint; | |
| paint.setColor(color); | |
| surf.getCanvas()->clipPath(clip, false); | |
| surf.getCanvas()->drawRect(SkRect::MakeLTRB(0,0, 100, 100), paint); | |
| }; | |
| // Use surfs[0] create to create a cached stencil buffer that is also sized for surfs[1]. | |
| drawWithStencilClip(*surfs[0], SK_ColorRED); | |
| dc->flushAndSubmit(surfs[0].get(), GrSyncCpu::kNo); | |
| // Make sure surf[1]'s FBO is bound but without using draws that would attach stencil. | |
| surfs[1]->getCanvas()->clear(SK_ColorGREEN); | |
| dc->flushAndSubmit(surfs[1].get(), GrSyncCpu::kNo); | |
| // Now use stencil for clipping. We should now have the following properties: | |
| // 1) surf[1]'s FBO is already bound | |
| // 2) surf[1] doesn't have a stencil buffer | |
| // 3) There is an appropriately sized stencil buffer in the cache (used with surf[0]). This is | |
| // important because creating a new stencil buffer will invalidate the bound FBO tracking. | |
| // The bug was that because the correct FBO was already bound we would not rebind and would | |
| // skip the lazy stencil attachment in GrGLRenderTarget. This would cause the clip to fail. | |
| drawWithStencilClip(*surfs[1], SK_ColorBLUE); | |
| // Check that four pixels that should have been clipped out of the blue draw are green. | |
| SkAutoPixmapStorage rb; | |
| rb.alloc(surfs[1]->imageInfo().makeWH(1, 1)); | |
| for (int x : {5, 95}) { | |
| for (int y : {5, 95}) { | |
| if (!surfs[1]->readPixels(rb, x, y)) { | |
| ERRORF(reporter, "readback failed"); | |
| return; | |
| } | |
| if (*rb.addr32() != SK_ColorGREEN) { | |
| ERRORF(reporter, | |
| "Expected green at (%d, %d), instead got 0x%08x.", | |
| x, | |
| y, | |
| *rb.addr32()); | |
| return; | |
| } | |
| } | |
| } | |
| } |