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/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