| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "SkInternalAtlasTextContext.h" |
| #include "GrContext.h" |
| #include "GrContextPriv.h" |
| #include "SkAtlasTextContext.h" |
| #include "SkAtlasTextRenderer.h" |
| #include "text/GrGlyphCache.h" |
| |
| SkAtlasTextRenderer* SkGetAtlasTextRendererFromInternalContext( |
| class SkInternalAtlasTextContext& internal) { |
| return internal.renderer(); |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| std::unique_ptr<SkInternalAtlasTextContext> SkInternalAtlasTextContext::Make( |
| sk_sp<SkAtlasTextRenderer> renderer) { |
| return std::unique_ptr<SkInternalAtlasTextContext>( |
| new SkInternalAtlasTextContext(std::move(renderer))); |
| } |
| |
| SkInternalAtlasTextContext::SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer> renderer) |
| : fRenderer(std::move(renderer)) { |
| GrContextOptions options; |
| options.fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo; |
| options.fMinDistanceFieldFontSize = 0.f; |
| options.fGlyphsAsPathsFontSize = SK_ScalarInfinity; |
| options.fDistanceFieldGlyphVerticesAlwaysHaveW = GrContextOptions::Enable::kYes; |
| fGrContext = GrContext::MakeMock(nullptr, options); |
| } |
| |
| SkInternalAtlasTextContext::~SkInternalAtlasTextContext() { |
| if (fDistanceFieldAtlas.fProxy) { |
| #ifdef SK_DEBUG |
| auto atlasManager = fGrContext->contextPriv().getAtlasManager(); |
| if (atlasManager) { |
| unsigned int numProxies; |
| atlasManager->getProxies(kA8_GrMaskFormat, &numProxies); |
| SkASSERT(1 == numProxies); |
| } |
| #endif |
| fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle); |
| } |
| } |
| |
| GrGlyphCache* SkInternalAtlasTextContext::glyphCache() { |
| return fGrContext->contextPriv().getGlyphCache(); |
| } |
| |
| GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() { |
| return fGrContext->contextPriv().getTextBlobCache(); |
| } |
| |
| GrDeferredUploadToken SkInternalAtlasTextContext::addInlineUpload( |
| GrDeferredTextureUploadFn&& upload) { |
| auto token = fTokenTracker.nextDrawToken(); |
| fInlineUploads.append(&fArena, InlineUpload{std::move(upload), token}); |
| return token; |
| } |
| |
| GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload( |
| GrDeferredTextureUploadFn&& upload) { |
| fASAPUploads.append(&fArena, std::move(upload)); |
| return fTokenTracker.nextTokenToFlush(); |
| } |
| |
| void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyphCnt, |
| const SkMatrix& matrix, void* targetHandle) { |
| auto vertexDataSize = sizeof(SkAtlasTextRenderer::SDFVertex) * 4 * glyphCnt; |
| auto vertexData = fArena.makeArrayDefault<char>(vertexDataSize); |
| memcpy(vertexData, srcVertexData, vertexDataSize); |
| for (int i = 0; i < 4 * glyphCnt; ++i) { |
| auto* vertex = reinterpret_cast<SkAtlasTextRenderer::SDFVertex*>(vertexData) + i; |
| // GrTextContext encodes a texture index into the lower bit of each texture coord. |
| // This isn't expected by SkAtlasTextRenderer subclasses. |
| vertex->fTextureCoordX /= 2; |
| vertex->fTextureCoordY /= 2; |
| matrix.mapHomogeneousPoints(&vertex->fPosition, &vertex->fPosition, 1); |
| } |
| fDraws.append(&fArena, |
| Draw{glyphCnt, fTokenTracker.issueDrawToken(), targetHandle, vertexData}); |
| } |
| |
| void SkInternalAtlasTextContext::flush() { |
| auto* atlasManager = fGrContext->contextPriv().getAtlasManager(); |
| if (!fDistanceFieldAtlas.fProxy) { |
| unsigned int numProxies; |
| fDistanceFieldAtlas.fProxy = atlasManager->getProxies(kA8_GrMaskFormat, &numProxies)->get(); |
| SkASSERT(1 == numProxies); |
| fDistanceFieldAtlas.fTextureHandle = |
| fRenderer->createTexture(SkAtlasTextRenderer::AtlasFormat::kA8, |
| fDistanceFieldAtlas.fProxy->width(), |
| fDistanceFieldAtlas.fProxy->height()); |
| } |
| GrDeferredTextureUploadWritePixelsFn writePixelsFn = |
| [this](GrTextureProxy* proxy, int left, int top, int width, int height, |
| GrColorType colorType, const void* data, size_t rowBytes) -> bool { |
| SkASSERT(GrColorType::kAlpha_8 == colorType); |
| SkASSERT(proxy == this->fDistanceFieldAtlas.fProxy); |
| void* handle = fDistanceFieldAtlas.fTextureHandle; |
| this->fRenderer->setTextureData(handle, data, left, top, width, height, rowBytes); |
| return true; |
| }; |
| for (const auto& upload : fASAPUploads) { |
| upload(writePixelsFn); |
| } |
| auto inlineUpload = fInlineUploads.begin(); |
| for (const auto& draw : fDraws) { |
| while (inlineUpload != fInlineUploads.end() && inlineUpload->fToken == draw.fToken) { |
| inlineUpload->fUpload(writePixelsFn); |
| ++inlineUpload; |
| } |
| auto vertices = reinterpret_cast<const SkAtlasTextRenderer::SDFVertex*>(draw.fVertexData); |
| fRenderer->drawSDFGlyphs(draw.fTargetHandle, fDistanceFieldAtlas.fTextureHandle, vertices, |
| draw.fGlyphCnt); |
| fTokenTracker.flushToken(); |
| } |
| fASAPUploads.reset(); |
| fInlineUploads.reset(); |
| fDraws.reset(); |
| fArena.reset(); |
| } |