1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 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/AtlasTextOp.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkPoint3.h" 11cb93a386Sopenharmony_ci#include "include/core/SkSpan.h" 12cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h" 13cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h" 14cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h" 15cb93a386Sopenharmony_ci#include "src/core/SkMatrixProvider.h" 16cb93a386Sopenharmony_ci#include "src/core/SkStrikeCache.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 22cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 23cb93a386Sopenharmony_ci#include "src/gpu/effects/GrBitmapTextGeoProc.h" 24cb93a386Sopenharmony_ci#include "src/gpu/effects/GrDistanceFieldGeoProc.h" 25cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h" 26cb93a386Sopenharmony_ci#include "src/gpu/text/GrAtlasManager.h" 27cb93a386Sopenharmony_ci#include "src/gpu/text/GrDistanceFieldAdjustTable.h" 28cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#include <new> 31cb93a386Sopenharmony_ci#include <utility> 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_cinamespace skgpu::v1 { 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci// If we have thread local, then cache memory for a single AtlasTextOp. 36cb93a386Sopenharmony_cistatic thread_local void* gCache = nullptr; 37cb93a386Sopenharmony_civoid* AtlasTextOp::operator new(size_t s) { 38cb93a386Sopenharmony_ci if (gCache != nullptr) { 39cb93a386Sopenharmony_ci return std::exchange(gCache, nullptr); 40cb93a386Sopenharmony_ci } 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci return ::operator new(s); 43cb93a386Sopenharmony_ci} 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_civoid AtlasTextOp::operator delete(void* bytes) noexcept { 46cb93a386Sopenharmony_ci if (gCache == nullptr) { 47cb93a386Sopenharmony_ci gCache = bytes; 48cb93a386Sopenharmony_ci return; 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci ::operator delete(bytes); 51cb93a386Sopenharmony_ci} 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_civoid AtlasTextOp::ClearCache() { 54cb93a386Sopenharmony_ci ::operator delete(gCache); 55cb93a386Sopenharmony_ci gCache = nullptr; 56cb93a386Sopenharmony_ci} 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ciAtlasTextOp::AtlasTextOp(MaskType maskType, 59cb93a386Sopenharmony_ci bool needsTransform, 60cb93a386Sopenharmony_ci int glyphCount, 61cb93a386Sopenharmony_ci SkRect deviceRect, 62cb93a386Sopenharmony_ci Geometry* geo, 63cb93a386Sopenharmony_ci GrPaint&& paint) 64cb93a386Sopenharmony_ci : INHERITED{ClassID()} 65cb93a386Sopenharmony_ci , fProcessors(std::move(paint)) 66cb93a386Sopenharmony_ci , fNumGlyphs(glyphCount) 67cb93a386Sopenharmony_ci , fDFGPFlags(0) 68cb93a386Sopenharmony_ci , fMaskType(static_cast<uint32_t>(maskType)) 69cb93a386Sopenharmony_ci , fUsesLocalCoords(false) 70cb93a386Sopenharmony_ci , fNeedsGlyphTransform(needsTransform) 71cb93a386Sopenharmony_ci , fHasPerspective(needsTransform && geo->fDrawMatrix.hasPerspective()) 72cb93a386Sopenharmony_ci , fUseGammaCorrectDistanceTable(false) 73cb93a386Sopenharmony_ci , fHead{geo} 74cb93a386Sopenharmony_ci , fTail{&fHead->fNext} { 75cb93a386Sopenharmony_ci // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds 76cb93a386Sopenharmony_ci // we treat this as a set of non-AA rects rendered with a texture. 77cb93a386Sopenharmony_ci this->setBounds(deviceRect, HasAABloat::kNo, IsHairline::kNo); 78cb93a386Sopenharmony_ci} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ciAtlasTextOp::AtlasTextOp(MaskType maskType, 81cb93a386Sopenharmony_ci bool needsTransform, 82cb93a386Sopenharmony_ci int glyphCount, 83cb93a386Sopenharmony_ci SkRect deviceRect, 84cb93a386Sopenharmony_ci SkColor luminanceColor, 85cb93a386Sopenharmony_ci bool useGammaCorrectDistanceTable, 86cb93a386Sopenharmony_ci uint32_t DFGPFlags, 87cb93a386Sopenharmony_ci Geometry* geo, 88cb93a386Sopenharmony_ci GrPaint&& paint) 89cb93a386Sopenharmony_ci : INHERITED{ClassID()} 90cb93a386Sopenharmony_ci , fProcessors(std::move(paint)) 91cb93a386Sopenharmony_ci , fNumGlyphs(glyphCount) 92cb93a386Sopenharmony_ci , fDFGPFlags(DFGPFlags) 93cb93a386Sopenharmony_ci , fMaskType(static_cast<uint32_t>(maskType)) 94cb93a386Sopenharmony_ci , fUsesLocalCoords(false) 95cb93a386Sopenharmony_ci , fNeedsGlyphTransform(needsTransform) 96cb93a386Sopenharmony_ci , fHasPerspective(needsTransform && geo->fDrawMatrix.hasPerspective()) 97cb93a386Sopenharmony_ci , fUseGammaCorrectDistanceTable(useGammaCorrectDistanceTable) 98cb93a386Sopenharmony_ci , fLuminanceColor(luminanceColor) 99cb93a386Sopenharmony_ci , fHead{geo} 100cb93a386Sopenharmony_ci , fTail{&fHead->fNext} { 101cb93a386Sopenharmony_ci // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds 102cb93a386Sopenharmony_ci // we treat this as a set of non-AA rects rendered with a texture. 103cb93a386Sopenharmony_ci this->setBounds(deviceRect, HasAABloat::kNo, IsHairline::kNo); 104cb93a386Sopenharmony_ci} 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ciauto AtlasTextOp::Geometry::MakeForBlob(const GrAtlasSubRun& subRun, 107cb93a386Sopenharmony_ci const SkMatrix& drawMatrix, 108cb93a386Sopenharmony_ci SkPoint drawOrigin, 109cb93a386Sopenharmony_ci SkIRect clipRect, 110cb93a386Sopenharmony_ci sk_sp<GrTextBlob> blob, 111cb93a386Sopenharmony_ci const SkPMColor4f& color, 112cb93a386Sopenharmony_ci SkArenaAlloc* alloc) -> Geometry* { 113cb93a386Sopenharmony_ci // Bypass the automatic dtor behavior in SkArenaAlloc. I'm leaving this up to the Op to run 114cb93a386Sopenharmony_ci // all geometry dtors for now. 115cb93a386Sopenharmony_ci void* geo = alloc->makeBytesAlignedTo(sizeof(Geometry), alignof(Geometry)); 116cb93a386Sopenharmony_ci return new(geo) Geometry{subRun, 117cb93a386Sopenharmony_ci drawMatrix, 118cb93a386Sopenharmony_ci drawOrigin, 119cb93a386Sopenharmony_ci clipRect, 120cb93a386Sopenharmony_ci std::move(blob), 121cb93a386Sopenharmony_ci nullptr, 122cb93a386Sopenharmony_ci color}; 123cb93a386Sopenharmony_ci} 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_civoid AtlasTextOp::Geometry::fillVertexData(void *dst, int offset, int count) const { 126cb93a386Sopenharmony_ci SkMatrix positionMatrix = fDrawMatrix; 127cb93a386Sopenharmony_ci positionMatrix.preTranslate(fDrawOrigin.x(), fDrawOrigin.y()); 128cb93a386Sopenharmony_ci fSubRun.fillVertexData( 129cb93a386Sopenharmony_ci dst, offset, count, fColor.toBytes_RGBA(), positionMatrix, fClipRect); 130cb93a386Sopenharmony_ci} 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_civoid AtlasTextOp::visitProxies(const GrVisitProxyFunc& func) const { 133cb93a386Sopenharmony_ci fProcessors.visitProxies(func); 134cb93a386Sopenharmony_ci} 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci#if GR_TEST_UTILS 137cb93a386Sopenharmony_ciSkString AtlasTextOp::onDumpInfo() const { 138cb93a386Sopenharmony_ci SkString str; 139cb93a386Sopenharmony_ci int i = 0; 140cb93a386Sopenharmony_ci for(Geometry* geom = fHead; geom != nullptr; geom = geom->fNext) { 141cb93a386Sopenharmony_ci str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f\n", 142cb93a386Sopenharmony_ci i++, 143cb93a386Sopenharmony_ci geom->fColor.toBytes_RGBA(), 144cb93a386Sopenharmony_ci geom->fDrawOrigin.x(), 145cb93a386Sopenharmony_ci geom->fDrawOrigin.y()); 146cb93a386Sopenharmony_ci } 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_ci str += fProcessors.dumpProcessors(); 149cb93a386Sopenharmony_ci return str; 150cb93a386Sopenharmony_ci} 151cb93a386Sopenharmony_ci#endif 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ciGrDrawOp::FixedFunctionFlags AtlasTextOp::fixedFunctionFlags() const { 154cb93a386Sopenharmony_ci return FixedFunctionFlags::kNone; 155cb93a386Sopenharmony_ci} 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ciGrProcessorSet::Analysis AtlasTextOp::finalize(const GrCaps& caps, 158cb93a386Sopenharmony_ci const GrAppliedClip* clip, 159cb93a386Sopenharmony_ci GrClampType clampType) { 160cb93a386Sopenharmony_ci GrProcessorAnalysisCoverage coverage; 161cb93a386Sopenharmony_ci GrProcessorAnalysisColor color; 162cb93a386Sopenharmony_ci if (this->maskType() == MaskType::kColorBitmap) { 163cb93a386Sopenharmony_ci color.setToUnknown(); 164cb93a386Sopenharmony_ci } else { 165cb93a386Sopenharmony_ci // finalize() is called before any merging is done, so at this point there's at most one 166cb93a386Sopenharmony_ci // Geometry with a color. Later, for non-bitmap ops, we may have mixed colors. 167cb93a386Sopenharmony_ci color.setToConstant(fHead->fColor); 168cb93a386Sopenharmony_ci } 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci switch (this->maskType()) { 171cb93a386Sopenharmony_ci case MaskType::kGrayscaleCoverage: 172cb93a386Sopenharmony_ci case MaskType::kAliasedDistanceField: 173cb93a386Sopenharmony_ci case MaskType::kGrayscaleDistanceField: 174cb93a386Sopenharmony_ci coverage = GrProcessorAnalysisCoverage::kSingleChannel; 175cb93a386Sopenharmony_ci break; 176cb93a386Sopenharmony_ci case MaskType::kLCDCoverage: 177cb93a386Sopenharmony_ci case MaskType::kLCDDistanceField: 178cb93a386Sopenharmony_ci case MaskType::kLCDBGRDistanceField: 179cb93a386Sopenharmony_ci coverage = GrProcessorAnalysisCoverage::kLCD; 180cb93a386Sopenharmony_ci break; 181cb93a386Sopenharmony_ci case MaskType::kColorBitmap: 182cb93a386Sopenharmony_ci coverage = GrProcessorAnalysisCoverage::kNone; 183cb93a386Sopenharmony_ci break; 184cb93a386Sopenharmony_ci } 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci auto analysis = fProcessors.finalize(color, coverage, clip, &GrUserStencilSettings::kUnused, 187cb93a386Sopenharmony_ci caps, clampType, &fHead->fColor); 188cb93a386Sopenharmony_ci // TODO(michaelludwig): Once processor analysis can be done external to op creation/finalization 189cb93a386Sopenharmony_ci // the atlas op metadata can be fully const. This is okay for now since finalize() happens 190cb93a386Sopenharmony_ci // before the op is merged, so during combineIfPossible, metadata is effectively const. 191cb93a386Sopenharmony_ci fUsesLocalCoords = analysis.usesLocalCoords(); 192cb93a386Sopenharmony_ci return analysis; 193cb93a386Sopenharmony_ci} 194cb93a386Sopenharmony_ci 195cb93a386Sopenharmony_civoid AtlasTextOp::onPrepareDraws(GrMeshDrawTarget* target) { 196cb93a386Sopenharmony_ci auto resourceProvider = target->resourceProvider(); 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci // If we need local coordinates, compute an inverse view matrix. If this is solid color, the 199cb93a386Sopenharmony_ci // processor analysis will not require local coords and the GPs will skip local coords when 200cb93a386Sopenharmony_ci // the matrix is identity. When the shaders require local coords, combineIfPossible requires all 201cb93a386Sopenharmony_ci // all geometries to have same draw matrix. 202cb93a386Sopenharmony_ci SkMatrix localMatrix = SkMatrix::I(); 203cb93a386Sopenharmony_ci if (fUsesLocalCoords && !fHead->fDrawMatrix.invert(&localMatrix)) { 204cb93a386Sopenharmony_ci return; 205cb93a386Sopenharmony_ci } 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci GrAtlasManager* atlasManager = target->atlasManager(); 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci GrMaskFormat maskFormat = this->maskFormat(); 210cb93a386Sopenharmony_ci 211cb93a386Sopenharmony_ci unsigned int numActiveViews; 212cb93a386Sopenharmony_ci const GrSurfaceProxyView* views = atlasManager->getViews(maskFormat, &numActiveViews); 213cb93a386Sopenharmony_ci if (!views) { 214cb93a386Sopenharmony_ci SkDebugf("Could not allocate backing texture for atlas\n"); 215cb93a386Sopenharmony_ci return; 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci SkASSERT(views[0].proxy()); 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci static constexpr int kMaxTextures = GrBitmapTextGeoProc::kMaxTextures; 220cb93a386Sopenharmony_ci static_assert(GrDistanceFieldA8TextGeoProc::kMaxTextures == kMaxTextures); 221cb93a386Sopenharmony_ci static_assert(GrDistanceFieldLCDTextGeoProc::kMaxTextures == kMaxTextures); 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci auto primProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures); 224cb93a386Sopenharmony_ci for (unsigned i = 0; i < numActiveViews; ++i) { 225cb93a386Sopenharmony_ci primProcProxies[i] = views[i].proxy(); 226cb93a386Sopenharmony_ci // This op does not know its atlas proxies when it is added to a OpsTasks, so the proxies 227cb93a386Sopenharmony_ci // don't get added during the visitProxies call. Thus we add them here. 228cb93a386Sopenharmony_ci target->sampledProxyArray()->push_back(views[i].proxy()); 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci FlushInfo flushInfo; 232cb93a386Sopenharmony_ci flushInfo.fPrimProcProxies = primProcProxies; 233cb93a386Sopenharmony_ci flushInfo.fIndexBuffer = resourceProvider->refNonAAQuadIndexBuffer(); 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_ci if (this->usesDistanceFields()) { 236cb93a386Sopenharmony_ci flushInfo.fGeometryProcessor = this->setupDfProcessor(target->allocator(), 237cb93a386Sopenharmony_ci *target->caps().shaderCaps(), 238cb93a386Sopenharmony_ci localMatrix, views, numActiveViews); 239cb93a386Sopenharmony_ci } else { 240cb93a386Sopenharmony_ci auto filter = fNeedsGlyphTransform ? GrSamplerState::Filter::kLinear 241cb93a386Sopenharmony_ci : GrSamplerState::Filter::kNearest; 242cb93a386Sopenharmony_ci // Bitmap text uses a single color, combineIfPossible ensures all geometries have the same 243cb93a386Sopenharmony_ci // color, so we can use the first's without worry. 244cb93a386Sopenharmony_ci flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( 245cb93a386Sopenharmony_ci target->allocator(), *target->caps().shaderCaps(), fHead->fColor, 246cb93a386Sopenharmony_ci false, views, numActiveViews, filter, maskFormat, localMatrix, fHasPerspective); 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci const int vertexStride = (int)flushInfo.fGeometryProcessor->vertexStride(); 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci // Ensure we don't request an insanely large contiguous vertex allocation. 252cb93a386Sopenharmony_ci static const int kMaxVertexBytes = GrBufferAllocPool::kDefaultBufferSize; 253cb93a386Sopenharmony_ci const int quadSize = vertexStride * kVerticesPerGlyph; 254cb93a386Sopenharmony_ci const int maxQuadsPerBuffer = kMaxVertexBytes / quadSize; 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci int allGlyphsCursor = 0; 257cb93a386Sopenharmony_ci const int allGlyphsEnd = fNumGlyphs; 258cb93a386Sopenharmony_ci int quadCursor; 259cb93a386Sopenharmony_ci int quadEnd; 260cb93a386Sopenharmony_ci char* vertices; 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ci auto resetVertexBuffer = [&] { 263cb93a386Sopenharmony_ci quadCursor = 0; 264cb93a386Sopenharmony_ci quadEnd = std::min(maxQuadsPerBuffer, allGlyphsEnd - allGlyphsCursor); 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci vertices = (char*)target->makeVertexSpace( 267cb93a386Sopenharmony_ci vertexStride, 268cb93a386Sopenharmony_ci kVerticesPerGlyph * quadEnd, 269cb93a386Sopenharmony_ci &flushInfo.fVertexBuffer, 270cb93a386Sopenharmony_ci &flushInfo.fVertexOffset); 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ci if (!vertices || !flushInfo.fVertexBuffer) { 273cb93a386Sopenharmony_ci SkDebugf("Could not allocate vertices\n"); 274cb93a386Sopenharmony_ci return false; 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci return true; 277cb93a386Sopenharmony_ci }; 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci resetVertexBuffer(); 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci for (const Geometry* geo = fHead; geo != nullptr; geo = geo->fNext) { 282cb93a386Sopenharmony_ci const GrAtlasSubRun& subRun = geo->fSubRun; 283cb93a386Sopenharmony_ci SkASSERTF((int) subRun.vertexStride(geo->fDrawMatrix) == vertexStride, 284cb93a386Sopenharmony_ci "subRun stride: %d vertex buffer stride: %d\n", 285cb93a386Sopenharmony_ci (int)subRun.vertexStride(geo->fDrawMatrix), vertexStride); 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci const int subRunEnd = subRun.glyphCount(); 288cb93a386Sopenharmony_ci for (int subRunCursor = 0; subRunCursor < subRunEnd;) { 289cb93a386Sopenharmony_ci // Regenerate the atlas for the remainder of the glyphs in the run, or the remainder 290cb93a386Sopenharmony_ci // of the glyphs to fill the vertex buffer. 291cb93a386Sopenharmony_ci int regenEnd = subRunCursor + std::min(subRunEnd - subRunCursor, quadEnd - quadCursor); 292cb93a386Sopenharmony_ci auto[ok, glyphsRegenerated] = subRun.regenerateAtlas(subRunCursor, regenEnd, target); 293cb93a386Sopenharmony_ci // There was a problem allocating the glyph in the atlas. Bail. 294cb93a386Sopenharmony_ci if (!ok) { 295cb93a386Sopenharmony_ci return; 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci geo->fillVertexData(vertices + quadCursor * quadSize, subRunCursor, glyphsRegenerated); 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci subRunCursor += glyphsRegenerated; 301cb93a386Sopenharmony_ci quadCursor += glyphsRegenerated; 302cb93a386Sopenharmony_ci allGlyphsCursor += glyphsRegenerated; 303cb93a386Sopenharmony_ci flushInfo.fGlyphsToFlush += glyphsRegenerated; 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci if (quadCursor == quadEnd || subRunCursor < subRunEnd) { 306cb93a386Sopenharmony_ci // Flush if not all the glyphs are drawn because either the quad buffer is full or 307cb93a386Sopenharmony_ci // the atlas is out of space. 308cb93a386Sopenharmony_ci if (subRunCursor < subRunEnd) { 309cb93a386Sopenharmony_ci ATRACE_ANDROID_FRAMEWORK_ALWAYS("Atlas full"); 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci this->createDrawForGeneratedGlyphs(target, &flushInfo); 312cb93a386Sopenharmony_ci if (quadCursor == quadEnd && allGlyphsCursor < allGlyphsEnd) { 313cb93a386Sopenharmony_ci // If the vertex buffer is full and there are still glyphs to draw then 314cb93a386Sopenharmony_ci // get a new buffer. 315cb93a386Sopenharmony_ci if(!resetVertexBuffer()) { 316cb93a386Sopenharmony_ci return; 317cb93a386Sopenharmony_ci } 318cb93a386Sopenharmony_ci } 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci } 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci} 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_civoid AtlasTextOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) { 325cb93a386Sopenharmony_ci auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, 326cb93a386Sopenharmony_ci std::move(fProcessors), 327cb93a386Sopenharmony_ci GrPipeline::InputFlags::kNone); 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline, 330cb93a386Sopenharmony_ci &GrUserStencilSettings::kUnused); 331cb93a386Sopenharmony_ci} 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_civoid AtlasTextOp::createDrawForGeneratedGlyphs(GrMeshDrawTarget* target, 334cb93a386Sopenharmony_ci FlushInfo* flushInfo) const { 335cb93a386Sopenharmony_ci if (!flushInfo->fGlyphsToFlush) { 336cb93a386Sopenharmony_ci return; 337cb93a386Sopenharmony_ci } 338cb93a386Sopenharmony_ci 339cb93a386Sopenharmony_ci auto atlasManager = target->atlasManager(); 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci GrGeometryProcessor* gp = flushInfo->fGeometryProcessor; 342cb93a386Sopenharmony_ci GrMaskFormat maskFormat = this->maskFormat(); 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci unsigned int numActiveViews; 345cb93a386Sopenharmony_ci const GrSurfaceProxyView* views = atlasManager->getViews(maskFormat, &numActiveViews); 346cb93a386Sopenharmony_ci SkASSERT(views); 347cb93a386Sopenharmony_ci // Something has gone terribly wrong, bail 348cb93a386Sopenharmony_ci if (!views || 0 == numActiveViews) { 349cb93a386Sopenharmony_ci return; 350cb93a386Sopenharmony_ci } 351cb93a386Sopenharmony_ci if (gp->numTextureSamplers() != (int) numActiveViews) { 352cb93a386Sopenharmony_ci // During preparation the number of atlas pages has increased. 353cb93a386Sopenharmony_ci // Update the proxies used in the GP to match. 354cb93a386Sopenharmony_ci for (unsigned i = gp->numTextureSamplers(); i < numActiveViews; ++i) { 355cb93a386Sopenharmony_ci flushInfo->fPrimProcProxies[i] = views[i].proxy(); 356cb93a386Sopenharmony_ci // This op does not know its atlas proxies when it is added to a OpsTasks, so the 357cb93a386Sopenharmony_ci // proxies don't get added during the visitProxies call. Thus we add them here. 358cb93a386Sopenharmony_ci target->sampledProxyArray()->push_back(views[i].proxy()); 359cb93a386Sopenharmony_ci // These will get unreffed when the previously recorded draws destruct. 360cb93a386Sopenharmony_ci for (int d = 0; d < flushInfo->fNumDraws; ++d) { 361cb93a386Sopenharmony_ci flushInfo->fPrimProcProxies[i]->ref(); 362cb93a386Sopenharmony_ci } 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci if (this->usesDistanceFields()) { 365cb93a386Sopenharmony_ci if (this->isLCD()) { 366cb93a386Sopenharmony_ci reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewViews( 367cb93a386Sopenharmony_ci views, numActiveViews, GrSamplerState::Filter::kLinear); 368cb93a386Sopenharmony_ci } else { 369cb93a386Sopenharmony_ci reinterpret_cast<GrDistanceFieldA8TextGeoProc*>(gp)->addNewViews( 370cb93a386Sopenharmony_ci views, numActiveViews, GrSamplerState::Filter::kLinear); 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci } else { 373cb93a386Sopenharmony_ci auto filter = fNeedsGlyphTransform ? GrSamplerState::Filter::kLinear 374cb93a386Sopenharmony_ci : GrSamplerState::Filter::kNearest; 375cb93a386Sopenharmony_ci reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewViews(views, numActiveViews, filter); 376cb93a386Sopenharmony_ci } 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci int maxGlyphsPerDraw = static_cast<int>(flushInfo->fIndexBuffer->size() / sizeof(uint16_t) / 6); 379cb93a386Sopenharmony_ci GrSimpleMesh* mesh = target->allocMesh(); 380cb93a386Sopenharmony_ci mesh->setIndexedPatterned(flushInfo->fIndexBuffer, kIndicesPerGlyph, flushInfo->fGlyphsToFlush, 381cb93a386Sopenharmony_ci maxGlyphsPerDraw, flushInfo->fVertexBuffer, kVerticesPerGlyph, 382cb93a386Sopenharmony_ci flushInfo->fVertexOffset); 383cb93a386Sopenharmony_ci target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fPrimProcProxies, 384cb93a386Sopenharmony_ci GrPrimitiveType::kTriangles); 385cb93a386Sopenharmony_ci flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush; 386cb93a386Sopenharmony_ci flushInfo->fGlyphsToFlush = 0; 387cb93a386Sopenharmony_ci ++flushInfo->fNumDraws; 388cb93a386Sopenharmony_ci} 389cb93a386Sopenharmony_ci 390cb93a386Sopenharmony_ciGrOp::CombineResult AtlasTextOp::onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) { 391cb93a386Sopenharmony_ci auto that = t->cast<AtlasTextOp>(); 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_ci if (fDFGPFlags != that->fDFGPFlags || 394cb93a386Sopenharmony_ci fMaskType != that->fMaskType || 395cb93a386Sopenharmony_ci fUsesLocalCoords != that->fUsesLocalCoords || 396cb93a386Sopenharmony_ci fNeedsGlyphTransform != that->fNeedsGlyphTransform || 397cb93a386Sopenharmony_ci fHasPerspective != that->fHasPerspective || 398cb93a386Sopenharmony_ci fUseGammaCorrectDistanceTable != that->fUseGammaCorrectDistanceTable) { 399cb93a386Sopenharmony_ci // All flags must match for an op to be combined 400cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 401cb93a386Sopenharmony_ci } 402cb93a386Sopenharmony_ci 403cb93a386Sopenharmony_ci if (fProcessors != that->fProcessors) { 404cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 405cb93a386Sopenharmony_ci } 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_ci if (fUsesLocalCoords) { 408cb93a386Sopenharmony_ci // If the fragment processors use local coordinates, the GPs compute them using the inverse 409cb93a386Sopenharmony_ci // of the view matrix stored in a uniform, so all geometries must have the same matrix. 410cb93a386Sopenharmony_ci const SkMatrix& thisFirstMatrix = fHead->fDrawMatrix; 411cb93a386Sopenharmony_ci const SkMatrix& thatFirstMatrix = that->fHead->fDrawMatrix; 412cb93a386Sopenharmony_ci if (!SkMatrixPriv::CheapEqual(thisFirstMatrix, thatFirstMatrix)) { 413cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 414cb93a386Sopenharmony_ci } 415cb93a386Sopenharmony_ci } 416cb93a386Sopenharmony_ci 417cb93a386Sopenharmony_ci if (this->usesDistanceFields()) { 418cb93a386Sopenharmony_ci SkASSERT(that->usesDistanceFields()); 419cb93a386Sopenharmony_ci if (fLuminanceColor != that->fLuminanceColor) { 420cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci } else { 423cb93a386Sopenharmony_ci if (this->maskType() == MaskType::kColorBitmap && 424cb93a386Sopenharmony_ci fHead->fColor != that->fHead->fColor) { 425cb93a386Sopenharmony_ci // This ensures all merged bitmap color text ops have a constant color 426cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 427cb93a386Sopenharmony_ci } 428cb93a386Sopenharmony_ci } 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_ci fNumGlyphs += that->fNumGlyphs; 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci // After concat, that's geometry list is emptied so it will not unref the blobs when destructed 433cb93a386Sopenharmony_ci this->addGeometry(that->fHead); 434cb93a386Sopenharmony_ci that->fHead = nullptr; 435cb93a386Sopenharmony_ci return CombineResult::kMerged; 436cb93a386Sopenharmony_ci} 437cb93a386Sopenharmony_ci 438cb93a386Sopenharmony_ci// TODO trying to figure out why lcd is so whack 439cb93a386Sopenharmony_ciGrGeometryProcessor* AtlasTextOp::setupDfProcessor(SkArenaAlloc* arena, 440cb93a386Sopenharmony_ci const GrShaderCaps& caps, 441cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 442cb93a386Sopenharmony_ci const GrSurfaceProxyView* views, 443cb93a386Sopenharmony_ci unsigned int numActiveViews) const { 444cb93a386Sopenharmony_ci static constexpr int kDistanceAdjustLumShift = 5; 445cb93a386Sopenharmony_ci auto dfAdjustTable = GrDistanceFieldAdjustTable::Get(); 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ci // see if we need to create a new effect 448cb93a386Sopenharmony_ci if (this->isLCD()) { 449cb93a386Sopenharmony_ci float redCorrection = dfAdjustTable->getAdjustment( 450cb93a386Sopenharmony_ci SkColorGetR(fLuminanceColor) >> kDistanceAdjustLumShift, 451cb93a386Sopenharmony_ci fUseGammaCorrectDistanceTable); 452cb93a386Sopenharmony_ci float greenCorrection = dfAdjustTable->getAdjustment( 453cb93a386Sopenharmony_ci SkColorGetG(fLuminanceColor) >> kDistanceAdjustLumShift, 454cb93a386Sopenharmony_ci fUseGammaCorrectDistanceTable); 455cb93a386Sopenharmony_ci float blueCorrection = dfAdjustTable->getAdjustment( 456cb93a386Sopenharmony_ci SkColorGetB(fLuminanceColor) >> kDistanceAdjustLumShift, 457cb93a386Sopenharmony_ci fUseGammaCorrectDistanceTable); 458cb93a386Sopenharmony_ci GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust = 459cb93a386Sopenharmony_ci GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make( 460cb93a386Sopenharmony_ci redCorrection, greenCorrection, blueCorrection); 461cb93a386Sopenharmony_ci return GrDistanceFieldLCDTextGeoProc::Make(arena, caps, views, numActiveViews, 462cb93a386Sopenharmony_ci GrSamplerState::Filter::kLinear, widthAdjust, 463cb93a386Sopenharmony_ci fDFGPFlags, localMatrix); 464cb93a386Sopenharmony_ci } else { 465cb93a386Sopenharmony_ci#ifdef SK_GAMMA_APPLY_TO_A8 466cb93a386Sopenharmony_ci float correction = 0; 467cb93a386Sopenharmony_ci if (this->maskType() != MaskType::kAliasedDistanceField) { 468cb93a386Sopenharmony_ci U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, 469cb93a386Sopenharmony_ci fLuminanceColor); 470cb93a386Sopenharmony_ci correction = dfAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift, 471cb93a386Sopenharmony_ci fUseGammaCorrectDistanceTable); 472cb93a386Sopenharmony_ci } 473cb93a386Sopenharmony_ci return GrDistanceFieldA8TextGeoProc::Make(arena, caps, views, numActiveViews, 474cb93a386Sopenharmony_ci GrSamplerState::Filter::kLinear, correction, 475cb93a386Sopenharmony_ci fDFGPFlags, localMatrix); 476cb93a386Sopenharmony_ci#else 477cb93a386Sopenharmony_ci return GrDistanceFieldA8TextGeoProc::Make(arena, caps, views, numActiveViews, 478cb93a386Sopenharmony_ci GrSamplerState::Filter::kLinear, fDFGPFlags, 479cb93a386Sopenharmony_ci localMatrix); 480cb93a386Sopenharmony_ci#endif 481cb93a386Sopenharmony_ci } 482cb93a386Sopenharmony_ci} 483cb93a386Sopenharmony_ci 484cb93a386Sopenharmony_ci#if GR_TEST_UTILS 485cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h" 486cb93a386Sopenharmony_ci 487cb93a386Sopenharmony_ciGrOp::Owner AtlasTextOp::CreateOpTestingOnly(SurfaceDrawContext* sdc, 488cb93a386Sopenharmony_ci const SkPaint& skPaint, 489cb93a386Sopenharmony_ci const SkFont& font, 490cb93a386Sopenharmony_ci const SkMatrixProvider& mtxProvider, 491cb93a386Sopenharmony_ci const char* text, 492cb93a386Sopenharmony_ci int x, 493cb93a386Sopenharmony_ci int y) { 494cb93a386Sopenharmony_ci size_t textLen = (int)strlen(text); 495cb93a386Sopenharmony_ci 496cb93a386Sopenharmony_ci SkMatrix drawMatrix(mtxProvider.localToDevice()); 497cb93a386Sopenharmony_ci drawMatrix.preTranslate(x, y); 498cb93a386Sopenharmony_ci auto drawOrigin = SkPoint::Make(x, y); 499cb93a386Sopenharmony_ci SkGlyphRunBuilder builder; 500cb93a386Sopenharmony_ci auto glyphRunList = builder.textToGlyphRunList(font, skPaint, text, textLen, drawOrigin); 501cb93a386Sopenharmony_ci if (glyphRunList.empty()) { 502cb93a386Sopenharmony_ci return nullptr; 503cb93a386Sopenharmony_ci } 504cb93a386Sopenharmony_ci 505cb93a386Sopenharmony_ci auto rContext = sdc->recordingContext(); 506cb93a386Sopenharmony_ci GrSDFTControl control = 507cb93a386Sopenharmony_ci rContext->priv().getSDFTControl(sdc->surfaceProps().isUseDeviceIndependentFonts()); 508cb93a386Sopenharmony_ci 509cb93a386Sopenharmony_ci SkGlyphRunListPainter* painter = sdc->glyphRunPainter(); 510cb93a386Sopenharmony_ci sk_sp<GrTextBlob> blob = GrTextBlob::Make(glyphRunList, skPaint, drawMatrix, control, painter); 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_ci if (blob->subRunList().isEmpty()) { 513cb93a386Sopenharmony_ci return nullptr; 514cb93a386Sopenharmony_ci } 515cb93a386Sopenharmony_ci 516cb93a386Sopenharmony_ci GrAtlasSubRun* subRun = blob->subRunList().front().testingOnly_atlasSubRun(); 517cb93a386Sopenharmony_ci SkASSERT(subRun); 518cb93a386Sopenharmony_ci GrOp::Owner op; 519cb93a386Sopenharmony_ci std::tie(std::ignore, op) = subRun->makeAtlasTextOp( 520cb93a386Sopenharmony_ci nullptr, mtxProvider, glyphRunList.origin(), skPaint, sdc, nullptr); 521cb93a386Sopenharmony_ci return op; 522cb93a386Sopenharmony_ci} 523cb93a386Sopenharmony_ci 524cb93a386Sopenharmony_ci#endif 525cb93a386Sopenharmony_ci 526cb93a386Sopenharmony_ci} // namespace skgpu::v1 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci#if GR_TEST_UTILS 529cb93a386Sopenharmony_ci 530cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(AtlasTextOp) { 531cb93a386Sopenharmony_ci SkSimpleMatrixProvider matrixProvider(GrTest::TestMatrixInvertible(random)); 532cb93a386Sopenharmony_ci 533cb93a386Sopenharmony_ci SkPaint skPaint; 534cb93a386Sopenharmony_ci skPaint.setColor(random->nextU()); 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_ci SkFont font; 537cb93a386Sopenharmony_ci if (random->nextBool()) { 538cb93a386Sopenharmony_ci font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 539cb93a386Sopenharmony_ci } else { 540cb93a386Sopenharmony_ci font.setEdging(random->nextBool() ? SkFont::Edging::kAntiAlias : SkFont::Edging::kAlias); 541cb93a386Sopenharmony_ci } 542cb93a386Sopenharmony_ci font.setSubpixel(random->nextBool()); 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ci const char* text = "The quick brown fox jumps over the lazy dog."; 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_ci // create some random x/y offsets, including negative offsets 547cb93a386Sopenharmony_ci static const int kMaxTrans = 1024; 548cb93a386Sopenharmony_ci int xPos = (random->nextU() % 2) * 2 - 1; 549cb93a386Sopenharmony_ci int yPos = (random->nextU() % 2) * 2 - 1; 550cb93a386Sopenharmony_ci int xInt = (random->nextU() % kMaxTrans) * xPos; 551cb93a386Sopenharmony_ci int yInt = (random->nextU() % kMaxTrans) * yPos; 552cb93a386Sopenharmony_ci 553cb93a386Sopenharmony_ci return skgpu::v1::AtlasTextOp::CreateOpTestingOnly(sdc, skPaint, font, matrixProvider, 554cb93a386Sopenharmony_ci text, xInt, yInt); 555cb93a386Sopenharmony_ci} 556cb93a386Sopenharmony_ci 557cb93a386Sopenharmony_ci#endif 558