1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/ops/FillRectOp.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 11cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrOpsTypes.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrPaint.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h" 17cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 18cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrQuad.h" 19cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrQuadBuffer.h" 20cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrQuadUtils.h" 21cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h" 22cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h" 23cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h" 24cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" 25cb93a386Sopenharmony_ci#include "src/gpu/ops/QuadPerEdgeAA.h" 26cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_cinamespace { 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ciusing VertexSpec = skgpu::v1::QuadPerEdgeAA::VertexSpec; 31cb93a386Sopenharmony_ciusing ColorType = skgpu::v1::QuadPerEdgeAA::ColorType; 32cb93a386Sopenharmony_ciusing Subset = skgpu::v1::QuadPerEdgeAA::Subset; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci#if GR_TEST_UTILS 35cb93a386Sopenharmony_ciSkString dump_quad_info(int index, const GrQuad* deviceQuad, 36cb93a386Sopenharmony_ci const GrQuad* localQuad, const SkPMColor4f& color, 37cb93a386Sopenharmony_ci GrQuadAAFlags aaFlags) { 38cb93a386Sopenharmony_ci GrQuad safeLocal = localQuad ? *localQuad : GrQuad(); 39cb93a386Sopenharmony_ci SkString str; 40cb93a386Sopenharmony_ci str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n" 41cb93a386Sopenharmony_ci " device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), " 42cb93a386Sopenharmony_ci "(%.2f, %.2f, %.2f)],\n" 43cb93a386Sopenharmony_ci " local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), " 44cb93a386Sopenharmony_ci "(%.2f, %.2f, %.2f)]\n", 45cb93a386Sopenharmony_ci index, color.fR, color.fG, color.fB, color.fA, 46cb93a386Sopenharmony_ci (uint32_t) (aaFlags & GrQuadAAFlags::kLeft), 47cb93a386Sopenharmony_ci (uint32_t) (aaFlags & GrQuadAAFlags::kTop), 48cb93a386Sopenharmony_ci (uint32_t) (aaFlags & GrQuadAAFlags::kRight), 49cb93a386Sopenharmony_ci (uint32_t) (aaFlags & GrQuadAAFlags::kBottom), 50cb93a386Sopenharmony_ci deviceQuad->x(0), deviceQuad->y(0), deviceQuad->w(0), 51cb93a386Sopenharmony_ci deviceQuad->x(1), deviceQuad->y(1), deviceQuad->w(1), 52cb93a386Sopenharmony_ci deviceQuad->x(2), deviceQuad->y(2), deviceQuad->w(2), 53cb93a386Sopenharmony_ci deviceQuad->x(3), deviceQuad->y(3), deviceQuad->w(3), 54cb93a386Sopenharmony_ci safeLocal.x(0), safeLocal.y(0), safeLocal.w(0), 55cb93a386Sopenharmony_ci safeLocal.x(1), safeLocal.y(1), safeLocal.w(1), 56cb93a386Sopenharmony_ci safeLocal.x(2), safeLocal.y(2), safeLocal.w(2), 57cb93a386Sopenharmony_ci safeLocal.x(3), safeLocal.y(3), safeLocal.w(3)); 58cb93a386Sopenharmony_ci return str; 59cb93a386Sopenharmony_ci} 60cb93a386Sopenharmony_ci#endif 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ciclass FillRectOpImpl final : public GrMeshDrawOp { 63cb93a386Sopenharmony_ciprivate: 64cb93a386Sopenharmony_ci using Helper = GrSimpleMeshDrawOpHelperWithStencil; 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_cipublic: 67cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* context, 68cb93a386Sopenharmony_ci GrPaint&& paint, 69cb93a386Sopenharmony_ci GrAAType aaType, 70cb93a386Sopenharmony_ci DrawQuad* quad, 71cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings, 72cb93a386Sopenharmony_ci Helper::InputFlags inputFlags) { 73cb93a386Sopenharmony_ci // Clean up deviations between aaType and edgeAA 74cb93a386Sopenharmony_ci GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice, 75cb93a386Sopenharmony_ci &aaType, &quad->fEdgeFlags); 76cb93a386Sopenharmony_ci return Helper::FactoryHelper<FillRectOpImpl>(context, std::move(paint), aaType, quad, 77cb93a386Sopenharmony_ci stencilSettings, inputFlags); 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci // aaType is passed to Helper in the initializer list, so incongruities between aaType and 81cb93a386Sopenharmony_ci // edgeFlags must be resolved prior to calling this constructor. 82cb93a386Sopenharmony_ci FillRectOpImpl(GrProcessorSet* processorSet, SkPMColor4f paintColor, GrAAType aaType, 83cb93a386Sopenharmony_ci DrawQuad* quad, const GrUserStencilSettings* stencil, 84cb93a386Sopenharmony_ci Helper::InputFlags inputFlags) 85cb93a386Sopenharmony_ci : INHERITED(ClassID()) 86cb93a386Sopenharmony_ci , fHelper(processorSet, aaType, stencil, inputFlags) 87cb93a386Sopenharmony_ci , fQuads(1, !fHelper.isTrivial()) { 88cb93a386Sopenharmony_ci // Set bounds before clipping so we don't have to worry about unioning the bounds of 89cb93a386Sopenharmony_ci // the two potential quads (GrQuad::bounds() is perspective-safe). 90cb93a386Sopenharmony_ci bool hairline = GrQuadUtils::WillUseHairline(quad->fDevice, aaType, quad->fEdgeFlags); 91cb93a386Sopenharmony_ci this->setBounds(quad->fDevice.bounds(), HasAABloat(aaType == GrAAType::kCoverage), 92cb93a386Sopenharmony_ci hairline ? IsHairline::kYes : IsHairline::kNo); 93cb93a386Sopenharmony_ci DrawQuad extra; 94cb93a386Sopenharmony_ci // Always crop to W>0 to remain consistent with GrQuad::bounds() 95cb93a386Sopenharmony_ci int count = GrQuadUtils::ClipToW0(quad, &extra); 96cb93a386Sopenharmony_ci if (count == 0) { 97cb93a386Sopenharmony_ci // We can't discard the op at this point, but disable AA flags so it won't go through 98cb93a386Sopenharmony_ci // inset/outset processing 99cb93a386Sopenharmony_ci quad->fEdgeFlags = GrQuadAAFlags::kNone; 100cb93a386Sopenharmony_ci count = 1; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci // Conservatively keep track of the local coordinates; it may be that the paint doesn't 104cb93a386Sopenharmony_ci // need them after analysis is finished. If the paint is known to be solid up front they 105cb93a386Sopenharmony_ci // can be skipped entirely. 106cb93a386Sopenharmony_ci fQuads.append(quad->fDevice, {paintColor, quad->fEdgeFlags}, 107cb93a386Sopenharmony_ci fHelper.isTrivial() ? nullptr : &quad->fLocal); 108cb93a386Sopenharmony_ci if (count > 1) { 109cb93a386Sopenharmony_ci fQuads.append(extra.fDevice, { paintColor, extra.fEdgeFlags }, 110cb93a386Sopenharmony_ci fHelper.isTrivial() ? nullptr : &extra.fLocal); 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci const char* name() const override { return "FillRectOp"; } 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci void visitProxies(const GrVisitProxyFunc& func) const override { 117cb93a386Sopenharmony_ci if (fProgramInfo) { 118cb93a386Sopenharmony_ci fProgramInfo->visitFPProxies(func); 119cb93a386Sopenharmony_ci } else { 120cb93a386Sopenharmony_ci return fHelper.visitProxies(func); 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 125cb93a386Sopenharmony_ci GrClampType clampType) override { 126cb93a386Sopenharmony_ci // Initialize aggregate color analysis with the first quad's color (which always exists) 127cb93a386Sopenharmony_ci auto iter = fQuads.metadata(); 128cb93a386Sopenharmony_ci SkAssertResult(iter.next()); 129cb93a386Sopenharmony_ci GrProcessorAnalysisColor quadColors(iter->fColor); 130cb93a386Sopenharmony_ci // Then combine the colors of any additional quads (e.g. from MakeSet) 131cb93a386Sopenharmony_ci while(iter.next()) { 132cb93a386Sopenharmony_ci quadColors = GrProcessorAnalysisColor::Combine(quadColors, iter->fColor); 133cb93a386Sopenharmony_ci if (quadColors.isUnknown()) { 134cb93a386Sopenharmony_ci // No point in accumulating additional starting colors, combining cannot make it 135cb93a386Sopenharmony_ci // less unknown. 136cb93a386Sopenharmony_ci break; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA 141cb93a386Sopenharmony_ci // then the coverage is always 1.0, so specify kNone for more optimal blending. 142cb93a386Sopenharmony_ci auto coverage = fHelper.aaType() == GrAAType::kCoverage 143cb93a386Sopenharmony_ci ? GrProcessorAnalysisCoverage::kSingleChannel 144cb93a386Sopenharmony_ci : GrProcessorAnalysisCoverage::kNone; 145cb93a386Sopenharmony_ci auto result = fHelper.finalizeProcessors(caps, clip, clampType, coverage, &quadColors); 146cb93a386Sopenharmony_ci // If there is a constant color after analysis, that means all of the quads should be set 147cb93a386Sopenharmony_ci // to the same color (even if they started out with different colors). 148cb93a386Sopenharmony_ci iter = fQuads.metadata(); 149cb93a386Sopenharmony_ci SkPMColor4f colorOverride; 150cb93a386Sopenharmony_ci if (quadColors.isConstant(&colorOverride)) { 151cb93a386Sopenharmony_ci fColorType = skgpu::v1::QuadPerEdgeAA::MinColorType(colorOverride); 152cb93a386Sopenharmony_ci while(iter.next()) { 153cb93a386Sopenharmony_ci iter->fColor = colorOverride; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci } else { 156cb93a386Sopenharmony_ci // Otherwise compute the color type needed as the max over all quads. 157cb93a386Sopenharmony_ci fColorType = ColorType::kNone; 158cb93a386Sopenharmony_ci while(iter.next()) { 159cb93a386Sopenharmony_ci fColorType = std::max(fColorType, 160cb93a386Sopenharmony_ci skgpu::v1::QuadPerEdgeAA::MinColorType(iter->fColor)); 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci // Most SkShaders' FPs multiply their calculated color by the paint color or alpha. We want 164cb93a386Sopenharmony_ci // to use ColorType::kNone to optimize out that multiply. However, if there are no color 165cb93a386Sopenharmony_ci // FPs then were really writing a special shader for white rectangles and not saving any 166cb93a386Sopenharmony_ci // multiples. So in that case use bytes to avoid the extra shader (and possibly work around 167cb93a386Sopenharmony_ci // an ANGLE issue: crbug.com/942565). 168cb93a386Sopenharmony_ci if (fColorType == ColorType::kNone && !result.hasColorFragmentProcessor()) { 169cb93a386Sopenharmony_ci fColorType = ColorType::kByte; 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci return result; 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { 176cb93a386Sopenharmony_ci // Since the AA type of the whole primitive is kept consistent with the per edge AA flags 177cb93a386Sopenharmony_ci // the helper's fixed function flags are appropriate. 178cb93a386Sopenharmony_ci return fHelper.fixedFunctionFlags(); 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ciprivate: 184cb93a386Sopenharmony_ci friend class skgpu::v1::FillRectOp; // for access to addQuad 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci#if GR_TEST_UTILS 187cb93a386Sopenharmony_ci int numQuads() const final { return fQuads.count(); } 188cb93a386Sopenharmony_ci#endif 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci VertexSpec vertexSpec() const { 191cb93a386Sopenharmony_ci auto indexBufferOption = skgpu::v1::QuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(), 192cb93a386Sopenharmony_ci fQuads.count()); 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ci return VertexSpec(fQuads.deviceQuadType(), fColorType, fQuads.localQuadType(), 195cb93a386Sopenharmony_ci fHelper.usesLocalCoords(), Subset::kNo, fHelper.aaType(), 196cb93a386Sopenharmony_ci fHelper.compatibleWithCoverageAsAlpha(), indexBufferOption); 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci GrProgramInfo* programInfo() override { 200cb93a386Sopenharmony_ci return fProgramInfo; 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci void onCreateProgramInfo(const GrCaps* caps, 204cb93a386Sopenharmony_ci SkArenaAlloc* arena, 205cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 206cb93a386Sopenharmony_ci bool usesMSAASurface, 207cb93a386Sopenharmony_ci GrAppliedClip&& appliedClip, 208cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 209cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 210cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 211cb93a386Sopenharmony_ci const VertexSpec vertexSpec = this->vertexSpec(); 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci GrGeometryProcessor* gp = skgpu::v1::QuadPerEdgeAA::MakeProcessor(arena, vertexSpec); 214cb93a386Sopenharmony_ci SkASSERT(gp->vertexStride() == vertexSpec.vertexSize()); 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, usesMSAASurface, 217cb93a386Sopenharmony_ci std::move(appliedClip), 218cb93a386Sopenharmony_ci dstProxyView, gp, 219cb93a386Sopenharmony_ci vertexSpec.primitiveType(), 220cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 221cb93a386Sopenharmony_ci } 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci void onPrePrepareDraws(GrRecordingContext* rContext, 224cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 225cb93a386Sopenharmony_ci GrAppliedClip* clip, 226cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 227cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 228cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 229cb93a386Sopenharmony_ci TRACE_EVENT0("skia.gpu", TRACE_FUNC); 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci SkASSERT(!fPrePreparedVertices); 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ci INHERITED::onPrePrepareDraws(rContext, writeView, clip, dstProxyView, 234cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci SkArenaAlloc* arena = rContext->priv().recordTimeAllocator(); 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci const VertexSpec vertexSpec = this->vertexSpec(); 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad(); 241cb93a386Sopenharmony_ci const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices; 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci fPrePreparedVertices = arena->makeArrayDefault<char>(totalVertexSizeInBytes); 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci this->tessellate(vertexSpec, fPrePreparedVertices); 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_ci void tessellate(const VertexSpec& vertexSpec, char* dst) const { 249cb93a386Sopenharmony_ci static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty(); 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci skgpu::v1::QuadPerEdgeAA::Tessellator tessellator(vertexSpec, dst); 252cb93a386Sopenharmony_ci auto iter = fQuads.iterator(); 253cb93a386Sopenharmony_ci while (iter.next()) { 254cb93a386Sopenharmony_ci // All entries should have local coords, or no entries should have local coords, 255cb93a386Sopenharmony_ci // matching !helper.isTrivial() (which is more conservative than helper.usesLocalCoords) 256cb93a386Sopenharmony_ci SkASSERT(iter.isLocalValid() != fHelper.isTrivial()); 257cb93a386Sopenharmony_ci auto info = iter.metadata(); 258cb93a386Sopenharmony_ci tessellator.append(iter.deviceQuad(), iter.localQuad(), 259cb93a386Sopenharmony_ci info.fColor, kEmptyDomain, info.fAAFlags); 260cb93a386Sopenharmony_ci } 261cb93a386Sopenharmony_ci } 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_ci void onPrepareDraws(GrMeshDrawTarget* target) override { 264cb93a386Sopenharmony_ci TRACE_EVENT0("skia.gpu", TRACE_FUNC); 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci const VertexSpec vertexSpec = this->vertexSpec(); 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci // Make sure that if the op thought it was a solid color, the vertex spec does not use 269cb93a386Sopenharmony_ci // local coords. 270cb93a386Sopenharmony_ci SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords()); 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ci const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad(); 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ci // Fill the allocated vertex data 275cb93a386Sopenharmony_ci void* vdata = target->makeVertexSpace(vertexSpec.vertexSize(), totalNumVertices, 276cb93a386Sopenharmony_ci &fVertexBuffer, &fBaseVertex); 277cb93a386Sopenharmony_ci if (!vdata) { 278cb93a386Sopenharmony_ci SkDebugf("Could not allocate vertices\n"); 279cb93a386Sopenharmony_ci return; 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci if (fPrePreparedVertices) { 283cb93a386Sopenharmony_ci const size_t totalVertexSizeInBytes = vertexSpec.vertexSize() * totalNumVertices; 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci memcpy(vdata, fPrePreparedVertices, totalVertexSizeInBytes); 286cb93a386Sopenharmony_ci } else { 287cb93a386Sopenharmony_ci this->tessellate(vertexSpec, (char*) vdata); 288cb93a386Sopenharmony_ci } 289cb93a386Sopenharmony_ci 290cb93a386Sopenharmony_ci if (vertexSpec.needsIndexBuffer()) { 291cb93a386Sopenharmony_ci fIndexBuffer = skgpu::v1::QuadPerEdgeAA::GetIndexBuffer(target, 292cb93a386Sopenharmony_ci vertexSpec.indexBufferOption()); 293cb93a386Sopenharmony_ci if (!fIndexBuffer) { 294cb93a386Sopenharmony_ci SkDebugf("Could not allocate indices\n"); 295cb93a386Sopenharmony_ci return; 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci } 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 301cb93a386Sopenharmony_ci if (!fVertexBuffer) { 302cb93a386Sopenharmony_ci return; 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci const VertexSpec vertexSpec = this->vertexSpec(); 306cb93a386Sopenharmony_ci 307cb93a386Sopenharmony_ci if (vertexSpec.needsIndexBuffer() && !fIndexBuffer) { 308cb93a386Sopenharmony_ci return; 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci if (!fProgramInfo) { 312cb93a386Sopenharmony_ci this->createProgramInfo(flushState); 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci const int totalNumVertices = fQuads.count() * vertexSpec.verticesPerQuad(); 316cb93a386Sopenharmony_ci 317cb93a386Sopenharmony_ci flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds); 318cb93a386Sopenharmony_ci flushState->bindBuffers(std::move(fIndexBuffer), nullptr, std::move(fVertexBuffer)); 319cb93a386Sopenharmony_ci flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline()); 320cb93a386Sopenharmony_ci skgpu::v1::QuadPerEdgeAA::IssueDraw(flushState->caps(), flushState->opsRenderPass(), 321cb93a386Sopenharmony_ci vertexSpec, 0, fQuads.count(), totalNumVertices, 322cb93a386Sopenharmony_ci fBaseVertex); 323cb93a386Sopenharmony_ci } 324cb93a386Sopenharmony_ci 325cb93a386Sopenharmony_ci CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override { 326cb93a386Sopenharmony_ci TRACE_EVENT0("skia.gpu", TRACE_FUNC); 327cb93a386Sopenharmony_ci auto that = t->cast<FillRectOpImpl>(); 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci bool upgradeToCoverageAAOnMerge = false; 330cb93a386Sopenharmony_ci if (fHelper.aaType() != that->fHelper.aaType()) { 331cb93a386Sopenharmony_ci if (!CanUpgradeAAOnMerge(fHelper.aaType(), that->fHelper.aaType())) { 332cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci upgradeToCoverageAAOnMerge = true; 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci if (CombinedQuadCountWillOverflow(fHelper.aaType(), upgradeToCoverageAAOnMerge, 338cb93a386Sopenharmony_ci fQuads.count() + that->fQuads.count())) { 339cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw 343cb93a386Sopenharmony_ci // ops together, so pass true as the last argument. 344cb93a386Sopenharmony_ci if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) { 345cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 346cb93a386Sopenharmony_ci } 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_ci // If the paints were compatible, the trivial/solid-color state should be the same 349cb93a386Sopenharmony_ci SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial()); 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci // If the processor sets are compatible, the two ops are always compatible; it just needs to 352cb93a386Sopenharmony_ci // adjust the state of the op to be the more general quad and aa types of the two ops and 353cb93a386Sopenharmony_ci // then concatenate the per-quad data. 354cb93a386Sopenharmony_ci fColorType = std::max(fColorType, that->fColorType); 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa 357cb93a386Sopenharmony_ci // types to be none and coverage, in which case this op's aa type must be lifted to coverage 358cb93a386Sopenharmony_ci // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed. 359cb93a386Sopenharmony_ci if (upgradeToCoverageAAOnMerge) { 360cb93a386Sopenharmony_ci fHelper.setAAType(GrAAType::kCoverage); 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_ci fQuads.concat(that->fQuads); 364cb93a386Sopenharmony_ci return CombineResult::kMerged; 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci#if GR_TEST_UTILS 368cb93a386Sopenharmony_ci SkString onDumpInfo() const override { 369cb93a386Sopenharmony_ci SkString str = SkStringPrintf("# draws: %u\n", fQuads.count()); 370cb93a386Sopenharmony_ci str.appendf("Device quad type: %u, local quad type: %u\n", 371cb93a386Sopenharmony_ci (uint32_t) fQuads.deviceQuadType(), (uint32_t) fQuads.localQuadType()); 372cb93a386Sopenharmony_ci str += fHelper.dumpInfo(); 373cb93a386Sopenharmony_ci int i = 0; 374cb93a386Sopenharmony_ci auto iter = fQuads.iterator(); 375cb93a386Sopenharmony_ci while(iter.next()) { 376cb93a386Sopenharmony_ci const ColorAndAA& info = iter.metadata(); 377cb93a386Sopenharmony_ci str += dump_quad_info(i, iter.deviceQuad(), iter.localQuad(), 378cb93a386Sopenharmony_ci info.fColor, info.fAAFlags); 379cb93a386Sopenharmony_ci i++; 380cb93a386Sopenharmony_ci } 381cb93a386Sopenharmony_ci return str; 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci#endif 384cb93a386Sopenharmony_ci 385cb93a386Sopenharmony_ci bool canAddQuads(int numQuads, GrAAType aaType) { 386cb93a386Sopenharmony_ci // The new quad's aa type should be the same as the first quad's or none, except when the 387cb93a386Sopenharmony_ci // first quad's aa type was already downgraded to none, in which case the stored type must 388cb93a386Sopenharmony_ci // be lifted to back to the requested type. 389cb93a386Sopenharmony_ci int quadCount = fQuads.count() + numQuads; 390cb93a386Sopenharmony_ci if (aaType != fHelper.aaType() && aaType != GrAAType::kNone) { 391cb93a386Sopenharmony_ci auto indexBufferOption = skgpu::v1::QuadPerEdgeAA::CalcIndexBufferOption(aaType, 392cb93a386Sopenharmony_ci quadCount); 393cb93a386Sopenharmony_ci if (quadCount > skgpu::v1::QuadPerEdgeAA::QuadLimit(indexBufferOption)) { 394cb93a386Sopenharmony_ci // Promoting to the new aaType would've caused an overflow of the indexBuffer 395cb93a386Sopenharmony_ci // limit 396cb93a386Sopenharmony_ci return false; 397cb93a386Sopenharmony_ci } 398cb93a386Sopenharmony_ci 399cb93a386Sopenharmony_ci // Original quad was downgraded to non-aa, lift back up to this quad's required type 400cb93a386Sopenharmony_ci SkASSERT(fHelper.aaType() == GrAAType::kNone); 401cb93a386Sopenharmony_ci fHelper.setAAType(aaType); 402cb93a386Sopenharmony_ci } else { 403cb93a386Sopenharmony_ci auto indexBufferOption = skgpu::v1::QuadPerEdgeAA::CalcIndexBufferOption( 404cb93a386Sopenharmony_ci fHelper.aaType(), quadCount); 405cb93a386Sopenharmony_ci if (quadCount > skgpu::v1::QuadPerEdgeAA::QuadLimit(indexBufferOption)) { 406cb93a386Sopenharmony_ci return false; // This op can't grow any more 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci } 409cb93a386Sopenharmony_ci 410cb93a386Sopenharmony_ci return true; 411cb93a386Sopenharmony_ci } 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible. 414cb93a386Sopenharmony_ci // But since it's avoiding the op list management, it must update the op's bounds. 415cb93a386Sopenharmony_ci bool addQuad(DrawQuad* quad, const SkPMColor4f& color, GrAAType aaType) { 416cb93a386Sopenharmony_ci SkRect newBounds = this->bounds(); 417cb93a386Sopenharmony_ci newBounds.joinPossiblyEmptyRect(quad->fDevice.bounds()); 418cb93a386Sopenharmony_ci 419cb93a386Sopenharmony_ci DrawQuad extra; 420cb93a386Sopenharmony_ci int count = quad->fEdgeFlags != GrQuadAAFlags::kNone ? GrQuadUtils::ClipToW0(quad, &extra) 421cb93a386Sopenharmony_ci : 1; 422cb93a386Sopenharmony_ci if (count == 0 ) { 423cb93a386Sopenharmony_ci // Just skip the append (trivial success) 424cb93a386Sopenharmony_ci return true; 425cb93a386Sopenharmony_ci } else if (!this->canAddQuads(count, aaType)) { 426cb93a386Sopenharmony_ci // Not enough room in the index buffer for the AA type 427cb93a386Sopenharmony_ci return false; 428cb93a386Sopenharmony_ci } else { 429cb93a386Sopenharmony_ci // Can actually add the 1 or 2 quads representing the draw 430cb93a386Sopenharmony_ci fQuads.append(quad->fDevice, { color, quad->fEdgeFlags }, 431cb93a386Sopenharmony_ci fHelper.isTrivial() ? nullptr : &quad->fLocal); 432cb93a386Sopenharmony_ci if (count > 1) { 433cb93a386Sopenharmony_ci fQuads.append(extra.fDevice, { color, extra.fEdgeFlags }, 434cb93a386Sopenharmony_ci fHelper.isTrivial() ? nullptr : &extra.fLocal); 435cb93a386Sopenharmony_ci } 436cb93a386Sopenharmony_ci // Update the bounds 437cb93a386Sopenharmony_ci this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage), 438cb93a386Sopenharmony_ci IsHairline::kNo); 439cb93a386Sopenharmony_ci return true; 440cb93a386Sopenharmony_ci } 441cb93a386Sopenharmony_ci } 442cb93a386Sopenharmony_ci 443cb93a386Sopenharmony_ci struct ColorAndAA { 444cb93a386Sopenharmony_ci SkPMColor4f fColor; 445cb93a386Sopenharmony_ci GrQuadAAFlags fAAFlags; 446cb93a386Sopenharmony_ci }; 447cb93a386Sopenharmony_ci 448cb93a386Sopenharmony_ci Helper fHelper; 449cb93a386Sopenharmony_ci GrQuadBuffer<ColorAndAA> fQuads; 450cb93a386Sopenharmony_ci char* fPrePreparedVertices = nullptr; 451cb93a386Sopenharmony_ci 452cb93a386Sopenharmony_ci GrProgramInfo* fProgramInfo = nullptr; 453cb93a386Sopenharmony_ci ColorType fColorType; 454cb93a386Sopenharmony_ci 455cb93a386Sopenharmony_ci sk_sp<const GrBuffer> fVertexBuffer; 456cb93a386Sopenharmony_ci sk_sp<const GrBuffer> fIndexBuffer; 457cb93a386Sopenharmony_ci int fBaseVertex; 458cb93a386Sopenharmony_ci 459cb93a386Sopenharmony_ci using INHERITED = GrMeshDrawOp; 460cb93a386Sopenharmony_ci}; 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ci} // anonymous namespace 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_cinamespace skgpu::v1 { 465cb93a386Sopenharmony_ci 466cb93a386Sopenharmony_ciGrOp::Owner FillRectOp::Make(GrRecordingContext* context, 467cb93a386Sopenharmony_ci GrPaint&& paint, 468cb93a386Sopenharmony_ci GrAAType aaType, 469cb93a386Sopenharmony_ci DrawQuad* quad, 470cb93a386Sopenharmony_ci const GrUserStencilSettings* stencil, 471cb93a386Sopenharmony_ci InputFlags inputFlags) { 472cb93a386Sopenharmony_ci return FillRectOpImpl::Make(context, std::move(paint), aaType, std::move(quad), stencil, 473cb93a386Sopenharmony_ci inputFlags); 474cb93a386Sopenharmony_ci} 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_ciGrOp::Owner FillRectOp::MakeNonAARect(GrRecordingContext* context, 477cb93a386Sopenharmony_ci GrPaint&& paint, 478cb93a386Sopenharmony_ci const SkMatrix& view, 479cb93a386Sopenharmony_ci const SkRect& rect, 480cb93a386Sopenharmony_ci const GrUserStencilSettings* stencil) { 481cb93a386Sopenharmony_ci DrawQuad quad{GrQuad::MakeFromRect(rect, view), GrQuad(rect), GrQuadAAFlags::kNone}; 482cb93a386Sopenharmony_ci return FillRectOpImpl::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil, 483cb93a386Sopenharmony_ci InputFlags::kNone); 484cb93a386Sopenharmony_ci} 485cb93a386Sopenharmony_ci 486cb93a386Sopenharmony_ciGrOp::Owner FillRectOp::MakeOp(GrRecordingContext* context, 487cb93a386Sopenharmony_ci GrPaint&& paint, 488cb93a386Sopenharmony_ci GrAAType aaType, 489cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 490cb93a386Sopenharmony_ci const GrQuadSetEntry quads[], 491cb93a386Sopenharmony_ci int cnt, 492cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings, 493cb93a386Sopenharmony_ci int* numConsumed) { 494cb93a386Sopenharmony_ci // First make a draw op for the first quad in the set 495cb93a386Sopenharmony_ci SkASSERT(cnt > 0); 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci DrawQuad quad{GrQuad::MakeFromRect(quads[0].fRect, viewMatrix), 498cb93a386Sopenharmony_ci GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix), 499cb93a386Sopenharmony_ci quads[0].fAAFlags}; 500cb93a386Sopenharmony_ci paint.setColor4f(quads[0].fColor); 501cb93a386Sopenharmony_ci GrOp::Owner op = FillRectOp::Make(context, std::move(paint), aaType, 502cb93a386Sopenharmony_ci &quad, stencilSettings, InputFlags::kNone); 503cb93a386Sopenharmony_ci auto fillRects = op->cast<FillRectOpImpl>(); 504cb93a386Sopenharmony_ci 505cb93a386Sopenharmony_ci *numConsumed = 1; 506cb93a386Sopenharmony_ci // Accumulate remaining quads similar to onCombineIfPossible() without creating an op 507cb93a386Sopenharmony_ci for (int i = 1; i < cnt; ++i) { 508cb93a386Sopenharmony_ci quad = {GrQuad::MakeFromRect(quads[i].fRect, viewMatrix), 509cb93a386Sopenharmony_ci GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix), 510cb93a386Sopenharmony_ci quads[i].fAAFlags}; 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_ci GrAAType resolvedAA; 513cb93a386Sopenharmony_ci GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, quad.fDevice, 514cb93a386Sopenharmony_ci &resolvedAA, &quad.fEdgeFlags); 515cb93a386Sopenharmony_ci 516cb93a386Sopenharmony_ci if (!fillRects->addQuad(&quad, quads[i].fColor, resolvedAA)) { 517cb93a386Sopenharmony_ci break; 518cb93a386Sopenharmony_ci } 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ci (*numConsumed)++; 521cb93a386Sopenharmony_ci } 522cb93a386Sopenharmony_ci 523cb93a386Sopenharmony_ci return op; 524cb93a386Sopenharmony_ci} 525cb93a386Sopenharmony_ci 526cb93a386Sopenharmony_civoid FillRectOp::AddFillRectOps(skgpu::v1::SurfaceDrawContext* sdc, 527cb93a386Sopenharmony_ci const GrClip* clip, 528cb93a386Sopenharmony_ci GrRecordingContext* context, 529cb93a386Sopenharmony_ci GrPaint&& paint, 530cb93a386Sopenharmony_ci GrAAType aaType, 531cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 532cb93a386Sopenharmony_ci const GrQuadSetEntry quads[], 533cb93a386Sopenharmony_ci int cnt, 534cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) { 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_ci int offset = 0; 537cb93a386Sopenharmony_ci int numLeft = cnt; 538cb93a386Sopenharmony_ci while (numLeft) { 539cb93a386Sopenharmony_ci int numConsumed = 0; 540cb93a386Sopenharmony_ci 541cb93a386Sopenharmony_ci GrOp::Owner op = MakeOp(context, GrPaint::Clone(paint), aaType, viewMatrix, 542cb93a386Sopenharmony_ci &quads[offset], numLeft, stencilSettings, 543cb93a386Sopenharmony_ci &numConsumed); 544cb93a386Sopenharmony_ci 545cb93a386Sopenharmony_ci offset += numConsumed; 546cb93a386Sopenharmony_ci numLeft -= numConsumed; 547cb93a386Sopenharmony_ci 548cb93a386Sopenharmony_ci sdc->addDrawOp(clip, std::move(op)); 549cb93a386Sopenharmony_ci } 550cb93a386Sopenharmony_ci 551cb93a386Sopenharmony_ci SkASSERT(offset == cnt); 552cb93a386Sopenharmony_ci} 553cb93a386Sopenharmony_ci 554cb93a386Sopenharmony_ci} // namespace skgpu::v1 555cb93a386Sopenharmony_ci 556cb93a386Sopenharmony_ci#if GR_TEST_UTILS 557cb93a386Sopenharmony_ci 558cb93a386Sopenharmony_ciuint32_t skgpu::v1::FillRectOp::ClassID() { 559cb93a386Sopenharmony_ci return FillRectOpImpl::ClassID(); 560cb93a386Sopenharmony_ci} 561cb93a386Sopenharmony_ci 562cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h" 563cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 564cb93a386Sopenharmony_ci 565cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(FillRectOp) { 566cb93a386Sopenharmony_ci SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); 567cb93a386Sopenharmony_ci SkRect rect = GrTest::TestRect(random); 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci GrAAType aaType = GrAAType::kNone; 570cb93a386Sopenharmony_ci if (random->nextBool()) { 571cb93a386Sopenharmony_ci aaType = (numSamples > 1) ? GrAAType::kMSAA : GrAAType::kCoverage; 572cb93a386Sopenharmony_ci } 573cb93a386Sopenharmony_ci const GrUserStencilSettings* stencil = random->nextBool() ? nullptr 574cb93a386Sopenharmony_ci : GrGetRandomStencil(random, context); 575cb93a386Sopenharmony_ci 576cb93a386Sopenharmony_ci GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone; 577cb93a386Sopenharmony_ci aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone; 578cb93a386Sopenharmony_ci aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone; 579cb93a386Sopenharmony_ci aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone; 580cb93a386Sopenharmony_ci aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone; 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci if (random->nextBool()) { 583cb93a386Sopenharmony_ci if (random->nextBool()) { 584cb93a386Sopenharmony_ci // Single local matrix 585cb93a386Sopenharmony_ci SkMatrix localMatrix = GrTest::TestMatrixInvertible(random); 586cb93a386Sopenharmony_ci DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), 587cb93a386Sopenharmony_ci GrQuad::MakeFromRect(rect, localMatrix), aaFlags}; 588cb93a386Sopenharmony_ci return skgpu::v1::FillRectOp::Make(context, std::move(paint), aaType, &quad, stencil); 589cb93a386Sopenharmony_ci } else { 590cb93a386Sopenharmony_ci // Pass local rect directly 591cb93a386Sopenharmony_ci SkRect localRect = GrTest::TestRect(random); 592cb93a386Sopenharmony_ci DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), 593cb93a386Sopenharmony_ci GrQuad(localRect), aaFlags}; 594cb93a386Sopenharmony_ci return skgpu::v1::FillRectOp::Make(context, std::move(paint), aaType, &quad, stencil); 595cb93a386Sopenharmony_ci } 596cb93a386Sopenharmony_ci } else { 597cb93a386Sopenharmony_ci // The simplest constructor 598cb93a386Sopenharmony_ci DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(rect), aaFlags}; 599cb93a386Sopenharmony_ci return skgpu::v1::FillRectOp::Make(context, std::move(paint), aaType, &quad, stencil); 600cb93a386Sopenharmony_ci } 601cb93a386Sopenharmony_ci} 602cb93a386Sopenharmony_ci 603cb93a386Sopenharmony_ci#endif 604