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