Home | History | Annotate | Download | only in atlastext
      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