1/* 2 * Copyright 2020 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/gpu/GrDirectContext.h" 9#include "include/gpu/GrRecordingContext.h" 10#include "src/gpu/GrColorSpaceXform.h" 11#include "src/gpu/GrDirectContextPriv.h" 12#include "src/gpu/GrProxyProvider.h" 13#include "src/gpu/GrRecordingContextPriv.h" 14#include "src/gpu/geometry/GrQuad.h" 15#include "src/gpu/ops/OpsTask.h" 16#include "src/gpu/ops/TextureOp.h" 17#include "tests/Test.h" 18 19class OpsTaskTestingAccess { 20public: 21 typedef skgpu::v1::OpsTask::OpChain OpChain; 22}; 23 24static void check_chain(OpsTaskTestingAccess::OpChain* chain, SkRect firstRect, SkRect lastRect, 25 int expectedNumOps) { 26 int actualNumOps = 0; 27 for (const auto& op : GrOp::ChainRange<>(chain->head())) { 28 ++actualNumOps; 29 30 if (actualNumOps == 1) { 31 SkAssertResult(op.bounds() == firstRect.makeOutset(0.5f, 0.5f)); 32 } else if (actualNumOps == expectedNumOps) { 33 SkAssertResult(op.bounds() == lastRect.makeOutset(0.5f, 0.5f)); 34 } 35 } 36 37 SkAssertResult(actualNumOps == expectedNumOps); 38} 39 40static sk_sp<GrSurfaceProxy> create_proxy(GrRecordingContext* rContext) { 41 const GrCaps* caps = rContext->priv().caps(); 42 43 static constexpr SkISize kDimensions = {16, 16}; 44 45 const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888, 46 GrRenderable::kYes); 47 return rContext->priv().proxyProvider()->createProxy( 48 format, kDimensions, GrRenderable::kYes, 1, GrMipmapped::kNo, SkBackingFit::kExact, 49 SkBudgeted::kNo, GrProtected::kNo, GrInternalSurfaceFlags::kNone); 50} 51 52static GrOp::Owner create_op(GrDirectContext* dContext, SkRect rect, 53 const GrSurfaceProxyView& proxyView, bool isAA) { 54 DrawQuad quad; 55 56 quad.fDevice = GrQuad::MakeFromRect(rect.makeOutset(0.5f, 0.5f), SkMatrix::I()); 57 quad.fLocal = GrQuad(rect); 58 quad.fEdgeFlags = isAA ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone; 59 60 return skgpu::v1::TextureOp::Make(dContext, 61 proxyView, 62 kPremul_SkAlphaType, 63 nullptr, 64 GrSamplerState::Filter::kNearest, 65 GrSamplerState::MipmapMode::kNone, 66 {1.f, 1.f, 1.f, 1.f}, 67 skgpu::v1::TextureOp::Saturate::kYes, 68 SkBlendMode::kSrcOver, 69 isAA ? GrAAType::kCoverage 70 : GrAAType::kNone, 71 &quad, 72 nullptr); 73} 74 75// This unit test exercises the crbug.com/1112259 case. 76DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TextureOpTest, reporter, ctxInfo) { 77 78 GrDirectContext* dContext = ctxInfo.directContext(); 79 const GrCaps* caps = dContext->priv().caps(); 80 SkArenaAlloc arena{nullptr, 0, 1024}; 81 auto auditTrail = dContext->priv().auditTrail(); 82 83 if (!caps->dynamicStateArrayGeometryProcessorTextureSupport()) { 84 // This test requires chaining 85 return; 86 } 87 88 GrSurfaceProxyView proxyViewA(create_proxy(dContext), 89 kTopLeft_GrSurfaceOrigin, 90 GrSwizzle::RGBA()); 91 GrSurfaceProxyView proxyViewB(create_proxy(dContext), 92 kTopLeft_GrSurfaceOrigin, 93 GrSwizzle::RGBA()); 94 GrSurfaceProxyView proxyViewC(create_proxy(dContext), 95 kTopLeft_GrSurfaceOrigin, 96 GrSwizzle::RGBA()); 97 98 static const SkRect kOpARect{ 0, 0, 16, 16 }; 99 static const SkRect kOpBRect{ 32, 0, 48, 16 }; 100 static const SkRect kOpCRect{ 0, 32, 16, 48 }; 101 static const SkRect kOpDRect{ 32, 32, 48, 48 }; 102 103 // opA & opB can chain together but can't merge bc they have different proxies 104 GrOp::Owner opA = create_op(dContext, kOpARect, proxyViewA, false); 105 GrOp::Owner opB = create_op(dContext, kOpBRect, proxyViewB, false); 106 107 GrAppliedClip noClip = GrAppliedClip::Disabled(); 108 OpsTaskTestingAccess::OpChain chain1(std::move(opA), GrProcessorSet::EmptySetAnalysis(), 109 &noClip, nullptr); 110 chain1.appendOp(std::move(opB), GrProcessorSet::EmptySetAnalysis(), nullptr, &noClip, *caps, 111 &arena, dContext->priv().auditTrail()); 112 check_chain(&chain1, kOpARect, kOpBRect, 2); 113 114 // opC & opD can also chain together but can't merge (bc, again, they have different 115 // proxies). Note, however, that opA and opD do share a proxy so can be merged if opA's 116 // anti-aliasing is upgraded to coverage. 117 GrOp::Owner opC = create_op(dContext, kOpCRect, proxyViewC, true); 118 GrOp::Owner opD = create_op(dContext, kOpDRect, proxyViewA, true); 119 120 OpsTaskTestingAccess::OpChain chain2(std::move(opC), GrProcessorSet::EmptySetAnalysis(), 121 &noClip, nullptr); 122 chain2.appendOp(std::move(opD), GrProcessorSet::EmptySetAnalysis(), nullptr, &noClip, *caps, 123 &arena, auditTrail); 124 check_chain(&chain2, kOpCRect, kOpDRect, 2); 125 126 // opA and opD, now in separate chains, can merge when the two chains are combined while 127 // opB and opC can still only chain. 128 chain1.prependChain(&chain2, *caps, &arena, auditTrail); 129 130 // We should end up with the chain 131 // opC - opD/opA - opB 132 check_chain(&chain1, kOpCRect, kOpBRect, 3); 133 134 chain1.deleteOps(); 135} 136