Use glops for text rendering

Change-Id: I5e155c8baf3149f0ff231ec3c89dbff6bb8eae92
This commit is contained in:
Chris Craik
2015-03-13 15:07:52 -07:00
parent 8c6e4b3980
commit e2bb380bc2
9 changed files with 142 additions and 113 deletions

View File

@@ -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<int>(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<CacheTexture*>& 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<CacheTexture*>& 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<CacheTexture*>& 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<CacheTexture*>& cacheTextures) {
glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
GL_UNSIGNED_SHORT, texture->indices());
#endif
texture->resetMesh();
forceRebind = false;
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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<PathTask> task = new PathTask(path, paint, texture);
texture->setTask(task);

View File

@@ -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<SkBitmap*> > task() const {
return mTask;

View File

@@ -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.
*/

View File

@@ -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,

View File

@@ -17,15 +17,15 @@
#ifndef ANDROID_HWUI_CACHE_TEXTURE_H
#define ANDROID_HWUI_CACHE_TEXTURE_H
#include "PixelBuffer.h"
#include "Rect.h"
#include "Texture.h"
#include "Vertex.h"
#include <GLES3/gl3.h>
#include <SkScalerContext.h>
#include <utils/Log.h>
#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;

View File

@@ -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<int>(rhs); \
inline void operator|=(int& lhs, enumType rhs) { \
lhs |= static_cast<int>(rhs); \
} \
inline int operator|(int lhs, enumType rhs) { \
return lhs | static_cast<int>(rhs); \
@@ -48,8 +48,8 @@
inline int operator|(enumType lhs, enumType rhs) { \
return static_cast<int>(lhs) | static_cast<int>(rhs); \
} \
inline int operator&=(int lhs, enumType rhs) { \
return lhs & static_cast<int>(rhs); \
inline void operator&=(int& lhs, enumType rhs) { \
lhs &= static_cast<int>(rhs); \
} \
inline int operator&(int lhs, enumType rhs) { \
return lhs & static_cast<int>(rhs); \