• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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