1/*
2 * Copyright 2017 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 "include/atlastext/SkAtlasTextContext.h"
9#include "include/atlastext/SkAtlasTextRenderer.h"
10#include "include/gpu/GrContext.h"
11#include "src/atlastext/SkInternalAtlasTextContext.h"
12#include "src/gpu/GrContextPriv.h"
13#include "src/gpu/text/GrAtlasManager.h"
14#include "src/gpu/text/GrStrikeCache.h"
15
16SkAtlasTextRenderer* SkGetAtlasTextRendererFromInternalContext(
17 class SkInternalAtlasTextContext& internal) {
18 return internal.renderer();
19}
20
21//////////////////////////////////////////////////////////////////////////////
22
23std::unique_ptr<SkInternalAtlasTextContext> SkInternalAtlasTextContext::Make(
24 sk_sp<SkAtlasTextRenderer> renderer) {
25 return std::unique_ptr<SkInternalAtlasTextContext>(
26 new SkInternalAtlasTextContext(std::move(renderer)));
27}
28
29SkInternalAtlasTextContext::SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer> renderer)
30 : fRenderer(std::move(renderer)) {
31 GrContextOptions options;
32 options.fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo;
33 options.fMinDistanceFieldFontSize = 0.f;
34 options.fGlyphsAsPathsFontSize = SK_ScalarInfinity;
35 options.fDistanceFieldGlyphVerticesAlwaysHaveW = GrContextOptions::Enable::kYes;
36 fGrContext = GrContext::MakeMock(nullptr, options);
37}
38
39SkInternalAtlasTextContext::~SkInternalAtlasTextContext() {
40 if (fDistanceFieldAtlas.fProxy) {
41#ifdef SK_DEBUG
42 auto atlasManager = fGrContext->priv().getAtlasManager();
43 if (atlasManager) {
44 unsigned int numProxies;
45 atlasManager->getViews(kA8_GrMaskFormat, &numProxies);
46 SkASSERT(1 == numProxies);
47 }
48#endif
49 fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle);
50 }
51}
52
53GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() {
54 return fGrContext->priv().getTextBlobCache();
55}
56
57GrDeferredUploadToken SkInternalAtlasTextContext::addInlineUpload(
58 GrDeferredTextureUploadFn&& upload) {
59 auto token = fTokenTracker.nextDrawToken();
60 fInlineUploads.append(&fArena, InlineUpload{std::move(upload), token});
61 return token;
62}
63
64GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload(
65 GrDeferredTextureUploadFn&& upload) {
66 fASAPUploads.append(&fArena, std::move(upload));
67 return fTokenTracker.nextTokenToFlush();
68}
69
70void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyphCnt,
71 const SkMatrix& matrix, void* targetHandle) {
72 auto vertexDataSize = sizeof(SkAtlasTextRenderer::SDFVertex) * 4 * glyphCnt;
73 auto vertexData = fArena.makeArrayDefault<char>(vertexDataSize);
74 memcpy(vertexData, srcVertexData, vertexDataSize);
75 for (int i = 0; i < 4 * glyphCnt; ++i) {
76 auto* vertex = reinterpret_cast<SkAtlasTextRenderer::SDFVertex*>(vertexData) + i;
77 // GrTextContext encodes a texture index into the lower bit of each texture coord.
78 // This isn't expected by SkAtlasTextRenderer subclasses.
79 vertex->fTextureCoordX /= 2;
80 vertex->fTextureCoordY /= 2;
81 matrix.mapHomogeneousPoints(&vertex->fPosition, &vertex->fPosition, 1);
82 }
83 fDraws.append(&fArena,
84 Draw{glyphCnt, fTokenTracker.issueDrawToken(), targetHandle, vertexData});
85}
86
87void SkInternalAtlasTextContext::flush() {
88 auto* atlasManager = fGrContext->priv().getAtlasManager();
89 if (!fDistanceFieldAtlas.fProxy) {
90 unsigned int numProxies;
91 fDistanceFieldAtlas.fProxy =
92 atlasManager->getViews(kA8_GrMaskFormat, &numProxies)->asTextureProxy();
93 SkASSERT(1 == numProxies);
94 fDistanceFieldAtlas.fTextureHandle =
95 fRenderer->createTexture(SkAtlasTextRenderer::AtlasFormat::kA8,
96 fDistanceFieldAtlas.fProxy->width(),
97 fDistanceFieldAtlas.fProxy->height());
98 }
99 GrDeferredTextureUploadWritePixelsFn writePixelsFn =
100 [this](GrTextureProxy* proxy, int left, int top, int width, int height,
101 GrColorType colorType, const void* data, size_t rowBytes) -> bool {
102 SkASSERT(GrColorType::kAlpha_8 == colorType);
103 SkASSERT(proxy == this->fDistanceFieldAtlas.fProxy);
104 void* handle = fDistanceFieldAtlas.fTextureHandle;
105 this->fRenderer->setTextureData(handle, data, left, top, width, height, rowBytes);
106 return true;
107 };
108 for (const auto& upload : fASAPUploads) {
109 upload(writePixelsFn);
110 }
111 auto inlineUpload = fInlineUploads.begin();
112 for (const auto& draw : fDraws) {
113 while (inlineUpload != fInlineUploads.end() && inlineUpload->fToken == draw.fToken) {
114 inlineUpload->fUpload(writePixelsFn);
115 ++inlineUpload;
116 }
117 auto vertices = reinterpret_cast<const SkAtlasTextRenderer::SDFVertex*>(draw.fVertexData);
118 fRenderer->drawSDFGlyphs(draw.fTargetHandle, fDistanceFieldAtlas.fTextureHandle, vertices,
119 draw.fGlyphCnt);
120 fTokenTracker.flushToken();
121 }
122 fASAPUploads.reset();
123 fInlineUploads.reset();
124 fDraws.reset();
125 fArena.reset();
126}
127