diff options
Diffstat (limited to 'src/atlastext')
-rw-r--r-- | src/atlastext/SkAtlasTextContext.cpp | 17 | ||||
-rw-r--r-- | src/atlastext/SkAtlasTextTarget.cpp | 143 | ||||
-rw-r--r-- | src/atlastext/SkInternalAtlasTextContext.cpp | 117 | ||||
-rw-r--r-- | src/atlastext/SkInternalAtlasTextContext.h | 80 |
4 files changed, 357 insertions, 0 deletions
diff --git a/src/atlastext/SkAtlasTextContext.cpp b/src/atlastext/SkAtlasTextContext.cpp new file mode 100644 index 0000000000..85e79118ee --- /dev/null +++ b/src/atlastext/SkAtlasTextContext.cpp @@ -0,0 +1,17 @@ +/* + * 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 "SkAtlasTextContext.h" +#include "SkAtlasTextRenderer.h" +#include "SkInternalAtlasTextContext.h" + +sk_sp<SkAtlasTextContext> SkAtlasTextContext::Make(sk_sp<SkAtlasTextRenderer> renderer) { + return sk_sp<SkAtlasTextContext>(new SkAtlasTextContext(std::move(renderer))); +} + +SkAtlasTextContext::SkAtlasTextContext(sk_sp<SkAtlasTextRenderer> renderer) + : fInternalContext(SkInternalAtlasTextContext::Make(std::move(renderer))) {} diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp new file mode 100644 index 0000000000..57ece37b4f --- /dev/null +++ b/src/atlastext/SkAtlasTextTarget.cpp @@ -0,0 +1,143 @@ +/* + * 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 "SkAtlasTextTarget.h" +#include "GrClip.h" +#include "SkAtlasTextContext.h" +#include "SkAtlasTextFont.h" +#include "SkAtlasTextRenderer.h" +#include "SkGr.h" +#include "SkInternalAtlasTextContext.h" +#include "ops/GrAtlasTextOp.h" +#include "text/GrAtlasTextContext.h" + +SkAtlasTextTarget::SkAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height, + void* handle) + : fHandle(handle), fContext(std::move(context)), fWidth(width), fHeight(height) {} + +SkAtlasTextTarget::~SkAtlasTextTarget() { fContext->renderer()->targetDeleted(fHandle); } + +////////////////////////////////////////////////////////////////////////////// + +static const GrColorSpaceInfo kColorSpaceInfo(nullptr, kRGBA_8888_GrPixelConfig); + +////////////////////////////////////////////////////////////////////////////// + +class SkInternalAtlasTextTarget : public GrTextUtils::Target, public SkAtlasTextTarget { +public: + SkInternalAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height, + void* handle) + : GrTextUtils::Target(width, height, kColorSpaceInfo) + , SkAtlasTextTarget(std::move(context), width, height, handle) {} + + /** GrTextUtils::Target overrides */ + + void addDrawOp(const GrClip&, std::unique_ptr<GrAtlasTextOp> op) override; + + void drawPath(const GrClip&, const SkPath&, const SkPaint&, const SkMatrix& viewMatrix, + const SkMatrix* pathMatrix, const SkIRect& clipBounds) override { + SkDebugf("Path glyph??"); + } + + void makeGrPaint(GrMaskFormat, const SkPaint& skPaint, const SkMatrix&, + GrPaint* grPaint) override { + grPaint->setColor4f(SkColorToPremulGrColor4fLegacy(skPaint.getColor())); + } + + /** SkAtlasTextTarget overrides */ + + void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, uint32_t color, + const SkAtlasTextFont&) override; + void flush() override; + +private: + uint32_t fColor; + using SkAtlasTextTarget::fWidth; + using SkAtlasTextTarget::fHeight; + struct RecordedOp { + std::unique_ptr<GrAtlasTextOp> fOp; + uint32_t fColor; + }; + SkTArray<RecordedOp, true> fOps; +}; + +////////////////////////////////////////////////////////////////////////////// + +std::unique_ptr<SkAtlasTextTarget> SkAtlasTextTarget::Make(sk_sp<SkAtlasTextContext> context, + int width, int height, void* handle) { + return std::unique_ptr<SkAtlasTextTarget>( + new SkInternalAtlasTextTarget(std::move(context), width, height, handle)); +} + +////////////////////////////////////////////////////////////////////////////// + +#include "GrContextPriv.h" +#include "GrDrawingManager.h" + +void SkInternalAtlasTextTarget::drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, uint32_t color, const SkAtlasTextFont& font) { + SkPaint paint; + paint.setAntiAlias(true); + paint.setTypeface(font.refTypeface()); + paint.setTextSize(font.size()); + paint.setStyle(SkPaint::kFill_Style); + + // TODO: Figure out what if anything to do with these: + // Paint setTextEncoding? Font isEnableByteCodeHints()? Font isUseNonLinearMetrics()? + + // The atlas text context does munging of the paint color. We store the client's color here + // and the context will write it into the final vertices given to the client's renderer. + fColor = color; + + // The pixel geometry here is arbitrary. We don't draw LCD text. + SkSurfaceProps props(SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry); + auto* grContext = this->context()->internal().grContext(); + auto bounds = SkIRect::MakeWH(fWidth, fHeight); + auto atlasTextContext = grContext->contextPriv().drawingManager()->getAtlasTextContext(); + atlasTextContext->drawText(grContext, this, GrNoClip(), paint, SkMatrix::I(), props, + (const char*)text, byteLength, x, y, bounds); +} + +void SkInternalAtlasTextTarget::addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) { + SkASSERT(clip.quickContains(SkRect::MakeIWH(fWidth, fHeight))); + // The SkAtlasTextRenderer currently only handles grayscale SDF glyphs. + if (op->maskType() != GrAtlasTextOp::kGrayscaleDistanceField_MaskType) { + return; + } + // TODO: batch ops here. + op->visitProxies([](GrSurfaceProxy*) {}); + fOps.emplace_back(RecordedOp{std::move(op), fColor}); +} + +void SkInternalAtlasTextTarget::flush() { + for (int i = 0; i < fOps.count(); ++i) { + fOps[i].fOp->executeForTextTarget(this, fOps[i].fColor); + } + this->context()->internal().flush(); + fOps.reset(); +} + +void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target, uint32_t color) { + FlushInfo flushInfo; + SkAutoGlyphCache glyphCache; + auto& context = target->context()->internal(); + auto* atlasGlyphCache = context.grContext()->getAtlasGlyphCache(); + for (int i = 0; i < fGeoCount; ++i) { + GrAtlasTextBlob::VertexRegenerator regenerator( + fGeoData[i].fBlob, fGeoData[i].fRun, fGeoData[i].fSubRun, fGeoData[i].fViewMatrix, + fGeoData[i].fX, fGeoData[i].fY, color, &context, atlasGlyphCache, &glyphCache); + GrAtlasTextBlob::VertexRegenerator::Result result; + do { + result = regenerator.regenerate(); + context.recordDraw(result.fFirstVertex, result.fGlyphsRegenerated, target->handle()); + if (!result.fFinished) { + // Make space in the atlas so we can continue generating vertices. + context.flush(); + } + } while (!result.fFinished); + } +} diff --git a/src/atlastext/SkInternalAtlasTextContext.cpp b/src/atlastext/SkInternalAtlasTextContext.cpp new file mode 100644 index 0000000000..8be7e1fb67 --- /dev/null +++ b/src/atlastext/SkInternalAtlasTextContext.cpp @@ -0,0 +1,117 @@ +/* + * 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 "SkAtlasTextContext.h" +#include "SkAtlasTextRenderer.h" +#include "text/GrAtlasGlyphCache.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; + fGrContext = GrContext::MakeMock(nullptr, options); +} + +SkInternalAtlasTextContext::~SkInternalAtlasTextContext() { + if (fDistanceFieldAtlas.fProxy) { + SkASSERT(1 == fGrContext->getAtlasGlyphCache()->getAtlasPageCount(kA8_GrMaskFormat)); + fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle); + } +} + +GrAtlasGlyphCache* SkInternalAtlasTextContext::atlasGlyphCache() { + return fGrContext->getAtlasGlyphCache(); +} + +GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() { + return fGrContext->getTextBlobCache(); +} + +GrDeferredUploadToken SkInternalAtlasTextContext::addInlineUpload( + GrDeferredTextureUploadFn&& upload) { + auto token = this->nextDrawToken(); + fInlineUploads.append(&fArena, InlineUpload{std::move(upload), token}); + return token; +} + +GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload( + GrDeferredTextureUploadFn&& upload) { + fASAPUploads.append(&fArena, std::move(upload)); + return this->nextTokenToFlush(); +} + +void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyphCnt, + 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; + // GrAtlasTextContext encodes a texture index into the lower bit of each texture coord. + // This isn't expected by SkAtlasTextRenderer subclasses. + vertex->fTextureCoord.fX /= 2; + vertex->fTextureCoord.fY /= 2; + } + fDraws.append(&fArena, Draw{glyphCnt, this->issueDrawToken(), targetHandle, vertexData}); +} + +void SkInternalAtlasTextContext::flush() { + auto* atlasGlyphCache = fGrContext->getAtlasGlyphCache(); + if (!fDistanceFieldAtlas.fProxy) { + SkASSERT(1 == atlasGlyphCache->getAtlasPageCount(kA8_GrMaskFormat)); + fDistanceFieldAtlas.fProxy = atlasGlyphCache->getProxies(kA8_GrMaskFormat)->get(); + 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, + GrPixelConfig config, const void* data, size_t rowBytes) -> bool { + SkASSERT(kAlpha_8_GrPixelConfig == config); + 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 draw = fDraws.begin(); + auto inlineUpload = fInlineUploads.begin(); + while (draw != fDraws.end()) { + 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); + ++draw; + } + fASAPUploads.reset(); + fInlineUploads.reset(); + fDraws.reset(); + fArena.reset(); +} diff --git a/src/atlastext/SkInternalAtlasTextContext.h b/src/atlastext/SkInternalAtlasTextContext.h new file mode 100644 index 0000000000..1bb12cee5a --- /dev/null +++ b/src/atlastext/SkInternalAtlasTextContext.h @@ -0,0 +1,80 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkInternalAtlasTextContext_DEFINED +#define SkInternalAtlasTextContext_DEFINED + +#include "GrDeferredUpload.h" +#include "SkArenaAlloc.h" +#include "SkArenaAllocList.h" +#include "SkRefCnt.h" + +class SkAtlasTextRenderer; +class GrContext; +class GrAtlasGlyphCache; +class GrTextBlobCache; + +/** + * The implementation of SkAtlasTextContext. This exists to hide the details from the public class. + * and to be able to use other private types. + */ +class SkInternalAtlasTextContext : public GrDeferredUploadTarget { +public: + static std::unique_ptr<SkInternalAtlasTextContext> Make(sk_sp<SkAtlasTextRenderer>); + + ~SkInternalAtlasTextContext() override; + + SkAtlasTextRenderer* renderer() const { return fRenderer.get(); } + + GrContext* grContext() const { return fGrContext.get(); } + GrAtlasGlyphCache* atlasGlyphCache(); + GrTextBlobCache* textBlobCache(); + + GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) override; + + GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&&) override; + + void recordDraw(const void* vertexData, int glyphCnt, void* targetHandle); + + void flush(); + +private: + class DeferredUploader; + SkInternalAtlasTextContext() = delete; + SkInternalAtlasTextContext(const SkInternalAtlasTextContext&) = delete; + SkInternalAtlasTextContext& operator=(const SkInternalAtlasTextContext&) = delete; + + SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer>); + + sk_sp<SkAtlasTextRenderer> fRenderer; + + struct AtlasTexture { + void* fTextureHandle = nullptr; + GrTextureProxy* fProxy = nullptr; + }; + + struct Draw { + int fGlyphCnt; + GrDeferredUploadToken fToken; + void* fTargetHandle; + const void* fVertexData; + }; + + struct InlineUpload { + GrDeferredTextureUploadFn fUpload; + GrDeferredUploadToken fToken; + }; + + SkArenaAllocList<InlineUpload> fInlineUploads; + SkArenaAllocList<Draw> fDraws; + SkArenaAllocList<GrDeferredTextureUploadFn> fASAPUploads; + SkArenaAlloc fArena{1024 * 40}; + sk_sp<GrContext> fGrContext; + AtlasTexture fDistanceFieldAtlas; +}; + +#endif |