Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020 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 | |
| 8 | #include "src/gpu/tessellate/GrDrawAtlasPathOp.h" |
| 9 | |
| 10 | #include "src/gpu/GrOpFlushState.h" |
| 11 | #include "src/gpu/GrOpsRenderPass.h" |
| 12 | #include "src/gpu/GrProgramInfo.h" |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 13 | #include "src/gpu/GrVertexWriter.h" |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 14 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
| 15 | #include "src/gpu/glsl/GrGLSLGeometryProcessor.h" |
| 16 | #include "src/gpu/glsl/GrGLSLVarying.h" |
| 17 | #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" |
| 18 | |
| 19 | namespace { |
| 20 | |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 21 | class DrawAtlasPathShader : public GrGeometryProcessor { |
| 22 | public: |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 23 | DrawAtlasPathShader(const GrTextureProxy* atlasProxy, GrSwizzle swizzle, bool isInverseFill, |
| 24 | bool usesLocalCoords) |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 25 | : GrGeometryProcessor(kDrawAtlasPathShader_ClassID) |
| 26 | , fAtlasAccess(GrSamplerState::Filter::kNearest, atlasProxy->backendFormat(), swizzle) |
| 27 | , fAtlasDimensions(atlasProxy->backingStoreDimensions()) |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 28 | , fIsInverseFill(isInverseFill) |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 29 | , fUsesLocalCoords(usesLocalCoords) { |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 30 | fAttribs.emplace_back("dev_xywh", kInt4_GrVertexAttribType, kInt4_GrSLType); |
| 31 | fAttribs.emplace_back("atlas_xy", kInt2_GrVertexAttribType, kInt2_GrSLType); |
| 32 | fAttribs.emplace_back("color", kFloat4_GrVertexAttribType, kHalf4_GrSLType); |
| 33 | if (fIsInverseFill) { |
| 34 | fAttribs.emplace_back("drawbounds", kFloat4_GrVertexAttribType, kFloat4_GrSLType); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 35 | } |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 36 | if (fUsesLocalCoords) { |
| 37 | fAttribs.emplace_back("viewmatrix_scaleskew", kFloat4_GrVertexAttribType, |
| 38 | kFloat4_GrSLType); |
| 39 | fAttribs.emplace_back("viewmatrix_trans", kFloat2_GrVertexAttribType, kFloat2_GrSLType); |
| 40 | } |
| 41 | this->setInstanceAttributes(fAttribs.data(), fAttribs.count()); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 42 | this->setTextureSamplerCnt(1); |
| 43 | } |
| 44 | |
| 45 | private: |
| 46 | const char* name() const override { return "DrawAtlasPathShader"; } |
| 47 | void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { |
| 48 | b->add32(fUsesLocalCoords); |
| 49 | } |
| 50 | const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; } |
Robert Phillips | f10535f | 2021-03-23 09:30:45 -0400 | [diff] [blame] | 51 | GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 52 | |
| 53 | const TextureSampler fAtlasAccess; |
| 54 | const SkISize fAtlasDimensions; |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 55 | const bool fIsInverseFill; |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 56 | const bool fUsesLocalCoords; |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 57 | SkSTArray<6, GrGeometryProcessor::Attribute> fAttribs; |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 58 | |
| 59 | class Impl; |
| 60 | }; |
| 61 | |
| 62 | class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor { |
| 63 | void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { |
Robert Phillips | 787fd9d | 2021-03-22 14:48:09 -0400 | [diff] [blame] | 64 | const auto& shader = args.fGeomProc.cast<DrawAtlasPathShader>(); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 65 | args.fVaryingHandler->emitAttributes(shader); |
| 66 | |
| 67 | GrGLSLVarying atlasCoord(kFloat2_GrSLType); |
| 68 | args.fVaryingHandler->addVarying("atlascoord", &atlasCoord); |
| 69 | |
| 70 | GrGLSLVarying color(kHalf4_GrSLType); |
John Stiles | 4d7ac49 | 2021-03-09 20:16:43 -0500 | [diff] [blame] | 71 | args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 72 | args.fVaryingHandler->addPassThroughAttribute( |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 73 | shader.fAttribs[2], args.fOutputColor, |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 74 | GrGLSLVaryingHandler::Interpolation::kCanBeFlat); |
| 75 | |
| 76 | const char* atlasAdjust; |
| 77 | fAtlasAdjustUniform = args.fUniformHandler->addUniform( |
Ethan Nicholas | 16464c3 | 2020-04-06 13:53:05 -0400 | [diff] [blame] | 78 | nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "atlas_adjust", &atlasAdjust); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 79 | |
| 80 | args.fVertBuilder->codeAppendf(R"( |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 81 | float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1); |
| 82 | float2 devtopleft = float2(dev_xywh.xy);)"); |
| 83 | |
| 84 | if (shader.fIsInverseFill) { |
| 85 | args.fVertBuilder->codeAppendf(R"( |
| 86 | float2 devcoord = mix(drawbounds.xy, drawbounds.zw, T);)"); |
| 87 | } else { |
| 88 | args.fVertBuilder->codeAppendf(R"( |
| 89 | float2 devcoord = abs(float2(dev_xywh.zw)) * T + devtopleft;)"); |
| 90 | } |
| 91 | |
| 92 | args.fVertBuilder->codeAppendf(R"( |
| 93 | float2 atlascoord = devcoord - devtopleft; |
| 94 | bool transposed = dev_xywh.w < 0; // Negative height means the path is transposed. |
| 95 | if (transposed) { |
| 96 | atlascoord = atlascoord.yx; |
| 97 | } |
| 98 | atlascoord += float2(atlas_xy); |
| 99 | %s = atlascoord * %s;)", |
| 100 | atlasCoord.vsOut(), atlasAdjust); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 101 | |
| 102 | gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord"); |
| 103 | |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 104 | if (shader.fUsesLocalCoords) { |
| 105 | args.fVertBuilder->codeAppendf(R"( |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 106 | float2x2 M = float2x2(viewmatrix_scaleskew); |
| 107 | float2 localcoord = inverse(M) * (devcoord - viewmatrix_trans);)"); |
Michael Ludwig | 553db62 | 2020-06-19 10:47:30 -0400 | [diff] [blame] | 108 | gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord"); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 109 | } |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 110 | |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 111 | if (shader.fIsInverseFill) { |
| 112 | GrGLSLVarying atlasBounds(kFloat4_GrSLType); |
| 113 | args.fVaryingHandler->addVarying("atlasbounds", &atlasBounds, |
| 114 | GrGLSLVaryingHandler::Interpolation::kCanBeFlat); |
| 115 | args.fVertBuilder->codeAppendf(R"( |
| 116 | int2 atlas_wh = (transposed) ? abs(dev_xywh.wz) : dev_xywh.zw; |
| 117 | %s = float4(atlas_xy, atlas_xy + atlas_wh) * %s.xyxy;)", atlasBounds.vsOut(), |
| 118 | atlasAdjust); |
| 119 | |
| 120 | args.fFragBuilder->codeAppendf(R"( |
| 121 | half coverage = 0; |
| 122 | float2 atlascoord = %s; |
| 123 | float4 atlasbounds = %s; |
| 124 | if (all(greaterThan(atlascoord, atlasbounds.xy)) && |
| 125 | all(lessThan(atlascoord, atlasbounds.zw))) { |
| 126 | coverage = )", atlasCoord.fsIn(), atlasBounds.fsIn()); |
| 127 | args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], "atlascoord"); |
| 128 | args.fFragBuilder->codeAppendf(R"(.a; |
| 129 | } |
| 130 | half4 %s = half4(1 - coverage);)", args.fOutputCoverage); |
| 131 | } else { |
| 132 | args.fFragBuilder->codeAppendf("half4 %s = ", args.fOutputCoverage); |
| 133 | args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn()); |
| 134 | args.fFragBuilder->codeAppendf(".aaaa;"); |
| 135 | } |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 136 | } |
| 137 | |
Brian Osman | 609f159 | 2020-07-01 15:14:39 -0400 | [diff] [blame] | 138 | void setData(const GrGLSLProgramDataManager& pdman, |
Brian Salomon | 5a32828 | 2021-04-14 10:32:25 -0400 | [diff] [blame] | 139 | const GrShaderCaps&, |
Robert Phillips | 787fd9d | 2021-03-22 14:48:09 -0400 | [diff] [blame] | 140 | const GrGeometryProcessor& geomProc) override { |
| 141 | const SkISize& dimensions = geomProc.cast<DrawAtlasPathShader>().fAtlasDimensions; |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 142 | pdman.set2f(fAtlasAdjustUniform, 1.f / dimensions.width(), 1.f / dimensions.height()); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | GrGLSLUniformHandler::UniformHandle fAtlasAdjustUniform; |
| 146 | }; |
| 147 | |
Robert Phillips | f10535f | 2021-03-23 09:30:45 -0400 | [diff] [blame] | 148 | GrGLSLGeometryProcessor* DrawAtlasPathShader::createGLSLInstance(const GrShaderCaps&) const { |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 149 | return new Impl(); |
| 150 | } |
| 151 | |
| 152 | } // namespace |
| 153 | |
| 154 | GrProcessorSet::Analysis GrDrawAtlasPathOp::finalize(const GrCaps& caps, const GrAppliedClip* clip, |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 155 | GrClampType clampType) { |
| 156 | const GrProcessorSet::Analysis& analysis = fProcessors.finalize( |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 157 | fHeadInstance.fColor, GrProcessorAnalysisCoverage::kSingleChannel, clip, |
| 158 | &GrUserStencilSettings::kUnused, caps, clampType, &fHeadInstance.fColor); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 159 | fUsesLocalCoords = analysis.usesLocalCoords(); |
| 160 | return analysis; |
| 161 | } |
| 162 | |
| 163 | GrOp::CombineResult GrDrawAtlasPathOp::onCombineIfPossible( |
Herb Derby | e25c300 | 2020-10-27 15:57:27 -0400 | [diff] [blame] | 164 | GrOp* op, SkArenaAlloc* alloc, const GrCaps&) { |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 165 | auto* that = op->cast<GrDrawAtlasPathOp>(); |
| 166 | SkASSERT(fAtlasProxy == that->fAtlasProxy); |
| 167 | SkASSERT(fEnableHWAA == that->fEnableHWAA); |
| 168 | |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 169 | if (fIsInverseFill != that->fIsInverseFill || fProcessors != that->fProcessors) { |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 170 | return CombineResult::kCannotCombine; |
| 171 | } |
| 172 | |
| 173 | SkASSERT(fUsesLocalCoords == that->fUsesLocalCoords); |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 174 | auto* copy = alloc->make<Instance>(that->fHeadInstance); |
| 175 | *fTailInstance = copy; |
| 176 | fTailInstance = (!copy->fNext) ? ©->fNext : that->fTailInstance; |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 177 | fInstanceCount += that->fInstanceCount; |
| 178 | return CombineResult::kMerged; |
| 179 | } |
| 180 | |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 181 | void GrDrawAtlasPathOp::onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView& writeView, |
| 182 | GrAppliedClip*, const GrDstProxyView&, |
Greg Daniel | 42dbca5 | 2020-11-20 10:22:43 -0500 | [diff] [blame] | 183 | GrXferBarrierFlags renderPassXferBarriers, |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 184 | GrLoadOp colorLoadOp) { |
| 185 | SK_ABORT("DDL support not implemented for GrDrawAtlasPathOp."); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 186 | } |
| 187 | |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 188 | void GrDrawAtlasPathOp::onPrepare(GrOpFlushState* state) { |
| 189 | SkArenaAlloc* arena = state->allocator(); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 190 | |
| 191 | GrPipeline::InitArgs initArgs; |
| 192 | if (fEnableHWAA) { |
| 193 | initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias; |
| 194 | } |
| 195 | initArgs.fCaps = &state->caps(); |
| 196 | initArgs.fDstProxyView = state->drawOpArgs().dstProxyView(); |
Adlai Holler | e2296f7 | 2020-11-19 13:41:26 -0500 | [diff] [blame] | 197 | initArgs.fWriteSwizzle = state->drawOpArgs().writeView().swizzle(); |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 198 | auto pipeline = arena->make<GrPipeline>(initArgs, std::move(fProcessors), |
| 199 | state->detachAppliedClip()); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 200 | GrSwizzle swizzle = state->caps().getReadSwizzle(fAtlasProxy->backendFormat(), |
| 201 | GrColorType::kAlpha_8); |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 202 | auto shader = arena->make<DrawAtlasPathShader>(fAtlasProxy.get(), swizzle, fIsInverseFill, |
| 203 | fUsesLocalCoords); |
| 204 | fProgram = arena->make<GrProgramInfo>(state->writeView(), pipeline, |
| 205 | &GrUserStencilSettings::kUnused, shader, |
| 206 | GrPrimitiveType::kTriangleStrip, 0, |
| 207 | state->renderPassBarriers(), state->colorLoadOp()); |
Chris Dalton | 012f849 | 2020-03-05 11:49:15 -0700 | [diff] [blame] | 208 | |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 209 | if (GrVertexWriter instanceWriter = state->makeVertexSpace( |
| 210 | shader->instanceStride(), fInstanceCount, &fInstanceBuffer, &fBaseInstance)) { |
| 211 | for (const Instance* instance = &fHeadInstance; instance; instance = instance->fNext) { |
| 212 | instanceWriter.write( |
| 213 | instance->fDevXYWH, |
| 214 | instance->fAtlasXY, |
| 215 | instance->fColor, |
| 216 | GrVertexWriter::If(fIsInverseFill, instance->fDrawBoundsIfInverseFilled), |
| 217 | GrVertexWriter::If(fUsesLocalCoords, instance->fViewMatrixIfUsingLocalCoords)); |
| 218 | } |
| 219 | } |
| 220 | } |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 221 | |
Chris Dalton | baae2dd | 2021-06-25 14:52:49 -0600 | [diff] [blame^] | 222 | void GrDrawAtlasPathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) { |
| 223 | SkASSERT(fAtlasProxy->isInstantiated()); |
| 224 | state->bindPipelineAndScissorClip(*fProgram, this->bounds()); |
| 225 | state->bindTextures(fProgram->geomProc(), *fAtlasProxy, fProgram->pipeline()); |
Greg Daniel | 426274b | 2020-07-20 11:37:38 -0400 | [diff] [blame] | 226 | state->bindBuffers(nullptr, std::move(fInstanceBuffer), nullptr); |
Chris Dalton | aa0e45c | 2020-03-16 10:05:11 -0600 | [diff] [blame] | 227 | state->drawInstanced(fInstanceCount, fBaseInstance, 4, 0); |
Chris Dalton | 4e99853 | 2020-02-10 11:06:42 -0700 | [diff] [blame] | 228 | } |