From e2bb380bc26749782c873e5488cfdf4e42b27346 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Fri, 13 Mar 2015 15:07:52 -0700 Subject: [PATCH] Use glops for text rendering Change-Id: I5e155c8baf3149f0ff231ec3c89dbff6bb8eae92 --- libs/hwui/FontRenderer.cpp | 42 +++++++++++++++++++----- libs/hwui/FontRenderer.h | 4 ++- libs/hwui/OpenGLRenderer.cpp | 12 +++---- libs/hwui/PathCache.cpp | 49 +++++++++++----------------- libs/hwui/PathCache.h | 20 +++++++++--- libs/hwui/Texture.h | 2 +- libs/hwui/font/CacheTexture.cpp | 71 ++++++++++++++++++++--------------------- libs/hwui/font/CacheTexture.h | 47 ++++++++++++++------------- libs/hwui/utils/Macros.h | 8 ++--- 9 files changed, 142 insertions(+), 113 deletions(-) diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index d1d2fccb55aa..fd2bdc60aa7b 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -19,6 +19,8 @@ #include "Caches.h" #include "Debug.h" #include "Extensions.h" +#include "Glop.h" +#include "GlopBuilder.h" #include "OpenGLRenderer.h" #include "PixelBuffer.h" #include "Rect.h" @@ -44,10 +46,12 @@ namespace uirenderer { // blur inputs smaller than this constant will bypass renderscript #define RS_MIN_INPUT_CUTOFF 10000 +#define USE_GLOPS true + /////////////////////////////////////////////////////////////////////////////// // TextSetupFunctor /////////////////////////////////////////////////////////////////////////////// -status_t TextSetupFunctor::setup(GLenum glyphFormat) { +void TextSetupFunctor::setup(GLenum glyphFormat) { renderer->setupDraw(); renderer->setupDrawTextGamma(paint); renderer->setupDrawDirtyRegionsDisabled(); @@ -84,8 +88,24 @@ status_t TextSetupFunctor::setup(GLenum glyphFormat) { renderer->setupDrawColorFilterUniforms(paint->getColorFilter()); renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate); renderer->setupDrawTextGammaUniforms(); +} - return NO_ERROR; +void TextSetupFunctor::draw(CacheTexture& texture, bool linearFiltering) { + int textureFillFlags = static_cast(texture.getFormat() == GL_ALPHA + ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone); + if (linearFiltering) { + textureFillFlags |= TextureFillFlags::kForceFilter; + } + const Matrix4& transform = pureTranslate ? Matrix4::identity() : *(renderer->currentTransform()); + Glop glop; + GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop) + .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount()) + .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha) + .setTransform(renderer->currentSnapshot()->getOrthoMatrix(), transform, false) + .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0)) + .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState) + .build(); + renderer->renderGlop(glop); } /////////////////////////////////////////////////////////////////////////////// @@ -196,7 +216,7 @@ void FontRenderer::flushLargeCaches(Vector& cacheTextures) { while (it.next()) { it.value()->invalidateTextureCache(cacheTexture); } - cacheTexture->releaseTexture(); + cacheTexture->releasePixelBuffer(); } } } @@ -290,7 +310,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp if (!cacheTexture->getPixelBuffer()) { Caches::getInstance().textureState().activateTexture(0); // Large-glyph texture memory is allocated only as needed - cacheTexture->allocateTexture(); + cacheTexture->allocatePixelBuffer(); } if (!cacheTexture->mesh()) { cacheTexture->allocateMesh(); @@ -402,7 +422,7 @@ CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum for if (allocate) { Caches::getInstance().textureState().activateTexture(0); - cacheTexture->allocateTexture(); + cacheTexture->allocatePixelBuffer(); cacheTexture->allocateMesh(); } @@ -497,9 +517,10 @@ void FontRenderer::issueDrawCommand(Vector& cacheTextures) { CacheTexture* texture = cacheTextures[i]; if (texture->canDraw()) { if (first) { + checkTextureUpdate(); +#if !USE_GLOPS mFunctor->setup(texture->getFormat()); - checkTextureUpdate(); renderState.meshState().bindQuadIndicesBuffer(); // If returns true, a VBO was bound and we must @@ -508,12 +529,17 @@ void FontRenderer::issueDrawCommand(Vector& cacheTextures) { forceRebind = renderState.meshState().unbindMeshBuffer(); caches.textureState().activateTexture(0); +#endif first = false; mDrawn = true; } +#if USE_GLOPS + mFunctor->draw(*texture, mLinearFiltering); +#endif +#if !USE_GLOPS caches.textureState().bindTexture(texture->getTextureId()); - texture->setLinearFiltering(mLinearFiltering, false); + texture->setLinearFiltering(mLinearFiltering); TextureVertex* mesh = texture->mesh(); MeshState& meshState = renderState.meshState(); @@ -522,7 +548,7 @@ void FontRenderer::issueDrawCommand(Vector& cacheTextures) { glDrawElements(GL_TRIANGLES, texture->meshElementCount(), GL_UNSIGNED_SHORT, texture->indices()); - +#endif texture->resetMesh(); forceRebind = false; } diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index cb63684c2879..0603389d1b70 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -59,7 +59,9 @@ public: , paint(paint) { } - status_t setup(GLenum glyphFormat); + void setup(GLenum glyphFormat); + + void draw(CacheTexture& texture, bool linearFiltering); OpenGLRenderer* renderer; float x; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 622b5708c065..378196934bc3 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2935,27 +2935,27 @@ int OpenGLRenderer::save(int flags) { } void OpenGLRenderer::restore() { - return mState.restore(); + mState.restore(); } void OpenGLRenderer::restoreToCount(int saveCount) { - return mState.restoreToCount(saveCount); + mState.restoreToCount(saveCount); } void OpenGLRenderer::translate(float dx, float dy, float dz) { - return mState.translate(dx, dy, dz); + mState.translate(dx, dy, dz); } void OpenGLRenderer::rotate(float degrees) { - return mState.rotate(degrees); + mState.rotate(degrees); } void OpenGLRenderer::scale(float sx, float sy) { - return mState.scale(sx, sy); + mState.scale(sx, sy); } void OpenGLRenderer::skew(float sx, float sy) { - return mState.skew(sx, sy); + mState.skew(sx, sy); } void OpenGLRenderer::setMatrix(const Matrix4& matrix) { diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 5b2e5e2b8e1e..27030728df7f 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -40,25 +40,25 @@ namespace uirenderer { // Cache entries /////////////////////////////////////////////////////////////////////////////// -PathDescription::PathDescription(): - type(kShapeNone), - join(SkPaint::kDefault_Join), - cap(SkPaint::kDefault_Cap), - style(SkPaint::kFill_Style), - miter(4.0f), - strokeWidth(1.0f), - pathEffect(nullptr) { +PathDescription::PathDescription() + : type(kShapeNone) + , join(SkPaint::kDefault_Join) + , cap(SkPaint::kDefault_Cap) + , style(SkPaint::kFill_Style) + , miter(4.0f) + , strokeWidth(1.0f) + , pathEffect(nullptr) { memset(&shape, 0, sizeof(Shape)); } -PathDescription::PathDescription(ShapeType type, const SkPaint* paint): - type(type), - join(paint->getStrokeJoin()), - cap(paint->getStrokeCap()), - style(paint->getStyle()), - miter(paint->getStrokeMiter()), - strokeWidth(paint->getStrokeWidth()), - pathEffect(paint->getPathEffect()) { +PathDescription::PathDescription(ShapeType type, const SkPaint* paint) + : type(type) + , join(paint->getStrokeJoin()) + , cap(paint->getStrokeCap()) + , style(paint->getStyle()) + , miter(paint->getStrokeMiter()) + , strokeWidth(paint->getStrokeWidth()) + , pathEffect(paint->getPathEffect()) { memset(&shape, 0, sizeof(Shape)); } @@ -132,18 +132,6 @@ static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap, canvas.drawPath(*path, pathPaint); } -static PathTexture* createTexture(float left, float top, float offset, - uint32_t width, uint32_t height, uint32_t id) { - PathTexture* texture = new PathTexture(Caches::getInstance()); - texture->left = left; - texture->top = top; - texture->offset = offset; - texture->width = width; - texture->height = height; - texture->generation = id; - return texture; -} - /////////////////////////////////////////////////////////////////////////////// // Cache constructor/destructor /////////////////////////////////////////////////////////////////////////////// @@ -267,7 +255,8 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p SkBitmap bitmap; drawPath(path, paint, bitmap, left, top, offset, width, height); - PathTexture* texture = createTexture(left, top, offset, width, height, + PathTexture* texture = new PathTexture(Caches::getInstance(), + left, top, offset, width, height, path->getGenerationID()); generateTexture(entry, &bitmap, texture); @@ -441,7 +430,7 @@ void PathCache::precache(const SkPath* path, const SkPaint* paint) { if (generate) { // It is important to specify the generation ID so we do not // attempt to precache the same path several times - texture = createTexture(0.0f, 0.0f, 0.0f, 0, 0, path->getGenerationID()); + texture = new PathTexture(Caches::getInstance(), path->getGenerationID()); sp task = new PathTask(path, paint, texture); texture->setTask(task); diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 23e35cb6b717..42976932b07c 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -59,7 +59,19 @@ class Caches; * Alpha texture used to represent a path. */ struct PathTexture: public Texture { - PathTexture(Caches& caches): Texture(caches) { + PathTexture(Caches& caches, float left, float top, + float offset, int width, int height, int generation) + : Texture(caches) + , left(left) + , top(top) + , offset(offset) { + this->width = width; + this->height = height; + this->generation = generation; + } + PathTexture(Caches& caches, int generation) + : Texture(caches) { + this->generation = generation; } ~PathTexture() { @@ -69,15 +81,15 @@ struct PathTexture: public Texture { /** * Left coordinate of the path bounds. */ - float left; + float left = 0; /** * Top coordinate of the path bounds. */ - float top; + float top = 0; /** * Offset to draw the path at the correct origin. */ - float offset; + float offset = 0; sp > task() const { return mTask; diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h index dfec46286579..7227ce0dd24c 100644 --- a/libs/hwui/Texture.h +++ b/libs/hwui/Texture.h @@ -78,7 +78,7 @@ public: /** * Indicates whether this texture should be cleaned up after use. */ - bool cleanup= false; + bool cleanup = false; /** * Optional, size of the original bitmap. */ diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index 9314126a5be0..845cf30313b7 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -109,13 +109,17 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) // CacheTexture /////////////////////////////////////////////////////////////////////////////// -CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) : - mTexture(nullptr), mTextureId(0), mWidth(width), mHeight(height), mFormat(format), - mLinearFiltering(false), mDirty(false), mNumGlyphs(0), - mMesh(nullptr), mCurrentQuad(0), mMaxQuadCount(maxQuadCount), - mCaches(Caches::getInstance()) { +CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) + : mTexture(Caches::getInstance()) + , mFormat(format) + , mMaxQuadCount(maxQuadCount) + , mCaches(Caches::getInstance()) { + mTexture.width = width; + mTexture.height = height; + mTexture.blend = true; + mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, - mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE); + getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE); // OpenGL ES 3.0+ lets us specify the row length for unpack operations such // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture. @@ -125,7 +129,7 @@ CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint3 CacheTexture::~CacheTexture() { releaseMesh(); - releaseTexture(); + releasePixelBuffer(); reset(); } @@ -144,35 +148,28 @@ void CacheTexture::init() { // reset, then create a new remainder space to start again reset(); mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, - mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE); + getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE); } void CacheTexture::releaseMesh() { delete[] mMesh; } -void CacheTexture::releaseTexture() { - if (mTexture) { - delete mTexture; - mTexture = nullptr; +void CacheTexture::releasePixelBuffer() { + if (mPixelBuffer) { + delete mPixelBuffer; + mPixelBuffer = nullptr; } - if (mTextureId) { - mCaches.textureState().deleteTexture(mTextureId); - mTextureId = 0; + if (mTexture.id) { + mCaches.textureState().deleteTexture(mTexture.id); + mTexture.id = 0; } mDirty = false; mCurrentQuad = 0; } -void CacheTexture::setLinearFiltering(bool linearFiltering, bool bind) { - if (linearFiltering != mLinearFiltering) { - mLinearFiltering = linearFiltering; - - const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST; - if (bind) mCaches.textureState().bindTexture(getTextureId()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); - } +void CacheTexture::setLinearFiltering(bool linearFiltering) { + mTexture.setFilter(linearFiltering ? GL_LINEAR : GL_NEAREST); } void CacheTexture::allocateMesh() { @@ -181,18 +178,18 @@ void CacheTexture::allocateMesh() { } } -void CacheTexture::allocateTexture() { - if (!mTexture) { - mTexture = PixelBuffer::create(mFormat, mWidth, mHeight); +void CacheTexture::allocatePixelBuffer() { + if (!mPixelBuffer) { + mPixelBuffer = PixelBuffer::create(mFormat, getWidth(), getHeight()); } - if (!mTextureId) { - glGenTextures(1, &mTextureId); + if (!mTexture.id) { + glGenTextures(1, &mTexture.id); - mCaches.textureState().bindTexture(mTextureId); + mCaches.textureState().bindTexture(mTexture.id); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Initialize texture dimensions - glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, + glTexImage2D(GL_TEXTURE_2D, 0, mFormat, getWidth(), getHeight(), 0, mFormat, GL_UNSIGNED_BYTE, nullptr); const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST; @@ -209,16 +206,16 @@ bool CacheTexture::upload() { uint32_t x = mHasUnpackRowLength ? dirtyRect.left : 0; uint32_t y = dirtyRect.top; - uint32_t width = mHasUnpackRowLength ? dirtyRect.getWidth() : mWidth; + uint32_t width = mHasUnpackRowLength ? dirtyRect.getWidth() : getWidth(); uint32_t height = dirtyRect.getHeight(); // The unpack row length only needs to be specified when a new // texture is bound if (mHasUnpackRowLength) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth); + glPixelStorei(GL_UNPACK_ROW_LENGTH, getWidth()); } - mTexture->upload(x, y, width, height); + mPixelBuffer->upload(x, y, width, height); setDirty(false); return mHasUnpackRowLength; @@ -258,7 +255,7 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_ return false; } - if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) { + if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > getHeight()) { return false; } @@ -295,10 +292,10 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_ cacheBlock->mWidth -= roundedUpW; cacheBlock->mX += roundedUpW; - if (mHeight - glyphH >= glyphH) { + if (getHeight() - glyphH >= glyphH) { // There's enough height left over to create a new CacheBlock CacheBlock* newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE, - roundedUpW, mHeight - glyphH - TEXTURE_BORDER_SIZE); + roundedUpW, getHeight() - glyphH - TEXTURE_BORDER_SIZE); #if DEBUG_FONT_RENDERER ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d", newBlock, newBlock->mX, newBlock->mY, diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h index 5d3f959c2b98..6dabc768ce6b 100644 --- a/libs/hwui/font/CacheTexture.h +++ b/libs/hwui/font/CacheTexture.h @@ -17,15 +17,15 @@ #ifndef ANDROID_HWUI_CACHE_TEXTURE_H #define ANDROID_HWUI_CACHE_TEXTURE_H -#include +#include "PixelBuffer.h" +#include "Rect.h" +#include "Texture.h" +#include "Vertex.h" +#include #include - #include -#include "../PixelBuffer.h" -#include "../Rect.h" -#include "../Vertex.h" namespace android { namespace uirenderer { @@ -80,9 +80,9 @@ public: void init(); void releaseMesh(); - void releaseTexture(); + void releasePixelBuffer(); - void allocateTexture(); + void allocatePixelBuffer(); void allocateMesh(); // Returns true if glPixelStorei(GL_UNPACK_ROW_LENGTH) must be reset @@ -92,11 +92,11 @@ public: bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY); inline uint16_t getWidth() const { - return mWidth; + return mTexture.width; } inline uint16_t getHeight() const { - return mHeight; + return mTexture.height; } inline GLenum getFormat() const { @@ -104,7 +104,7 @@ public: } inline uint32_t getOffset(uint16_t x, uint16_t y) const { - return (y * mWidth + x) * PixelBuffer::formatSize(mFormat); + return (y * getWidth() + x) * PixelBuffer::formatSize(mFormat); } inline const Rect* getDirtyRect() const { @@ -112,12 +112,17 @@ public: } inline PixelBuffer* getPixelBuffer() const { + return mPixelBuffer; + } + + Texture& getTexture() { + allocatePixelBuffer(); return mTexture; } GLuint getTextureId() { - allocateTexture(); - return mTextureId; + allocatePixelBuffer(); + return mTexture.id; } inline bool isDirty() const { @@ -131,7 +136,7 @@ public: /** * This method assumes that the proper texture unit is active. */ - void setLinearFiltering(bool linearFiltering, bool bind = true); + void setLinearFiltering(bool linearFiltering); inline uint16_t getGlyphCount() const { return mNumGlyphs; @@ -176,16 +181,14 @@ public: private: void setDirty(bool dirty); - PixelBuffer* mTexture; - GLuint mTextureId; - uint16_t mWidth; - uint16_t mHeight; + PixelBuffer* mPixelBuffer = nullptr; + Texture mTexture; GLenum mFormat; - bool mLinearFiltering; - bool mDirty; - uint16_t mNumGlyphs; - TextureVertex* mMesh; - uint32_t mCurrentQuad; + bool mLinearFiltering = false; + bool mDirty = false; + uint16_t mNumGlyphs = 0; + TextureVertex* mMesh = nullptr; + uint32_t mCurrentQuad = 0; uint32_t mMaxQuadCount; Caches& mCaches; CacheBlock* mCacheBlocks; diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h index 9f7ac1c4a5cf..1b31059021ef 100644 --- a/libs/hwui/utils/Macros.h +++ b/libs/hwui/utils/Macros.h @@ -36,8 +36,8 @@ #Type " must have standard layout") #define MAKE_FLAGS_ENUM(enumType) \ - inline int operator|=(int lhs, enumType rhs) { \ - return lhs | static_cast(rhs); \ + inline void operator|=(int& lhs, enumType rhs) { \ + lhs |= static_cast(rhs); \ } \ inline int operator|(int lhs, enumType rhs) { \ return lhs | static_cast(rhs); \ @@ -48,8 +48,8 @@ inline int operator|(enumType lhs, enumType rhs) { \ return static_cast(lhs) | static_cast(rhs); \ } \ - inline int operator&=(int lhs, enumType rhs) { \ - return lhs & static_cast(rhs); \ + inline void operator&=(int& lhs, enumType rhs) { \ + lhs &= static_cast(rhs); \ } \ inline int operator&(int lhs, enumType rhs) { \ return lhs & static_cast(rhs); \ -- 2.11.0