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 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 atlasGlyphCache = fGrContext->contextPriv().getAtlasGlyphCache(); 42 SkASSERT(1 == atlasGlyphCache->getAtlasPageCount(kA8_GrMaskFormat)); 43 #endif 44 fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle); 45 } 46 } 47 48 GrAtlasGlyphCache* SkInternalAtlasTextContext::atlasGlyphCache() { 49 return fGrContext->contextPriv().getAtlasGlyphCache(); 50 } 51 52 GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() { 53 return fGrContext->contextPriv().getTextBlobCache(); 54 } 55 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 63 GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload( 64 GrDeferredTextureUploadFn&& upload) { 65 fASAPUploads.append(&fArena, std::move(upload)); 66 return fTokenTracker.nextTokenToFlush(); 67 } 68 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 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