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