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 | |
16 | SkAtlasTextRenderer* SkGetAtlasTextRendererFromInternalContext( |
17 | class SkInternalAtlasTextContext& internal) { |
18 | return internal.renderer(); |
19 | } |
20 | |
21 | ////////////////////////////////////////////////////////////////////////////// |
22 | |
23 | std::unique_ptr<SkInternalAtlasTextContext> SkInternalAtlasTextContext::Make( |
24 | sk_sp<SkAtlasTextRenderer> renderer) { |
25 | return std::unique_ptr<SkInternalAtlasTextContext>( |
26 | new SkInternalAtlasTextContext(std::move(renderer))); |
27 | } |
28 | |
29 | SkInternalAtlasTextContext::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 | |
39 | SkInternalAtlasTextContext::~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 | |
53 | GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() { |
54 | return fGrContext->priv().getTextBlobCache(); |
55 | } |
56 | |
57 | GrDeferredUploadToken SkInternalAtlasTextContext::addInlineUpload( |
58 | GrDeferredTextureUploadFn&& upload) { |
59 | auto token = fTokenTracker.nextDrawToken(); |
60 | fInlineUploads.append(&fArena, InlineUpload{std::move(upload), token}); |
61 | return token; |
62 | } |
63 | |
64 | GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload( |
65 | GrDeferredTextureUploadFn&& upload) { |
66 | fASAPUploads.append(&fArena, std::move(upload)); |
67 | return fTokenTracker.nextTokenToFlush(); |
68 | } |
69 | |
70 | void 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 | |
87 | void 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 | |