am 8d4c23b9
: Merge "Introduce PixelBuffer API to enable PBOs" into jb-mr2-dev
* commit '8d4c23b9c32f8c0328ebca538bb801716fe4478a': Introduce PixelBuffer API to enable PBOs
This commit is contained in:
@ -30,6 +30,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
|||||||
PatchCache.cpp \
|
PatchCache.cpp \
|
||||||
PathCache.cpp \
|
PathCache.cpp \
|
||||||
PathTessellator.cpp \
|
PathTessellator.cpp \
|
||||||
|
PixelBuffer.cpp \
|
||||||
Program.cpp \
|
Program.cpp \
|
||||||
ProgramCache.cpp \
|
ProgramCache.cpp \
|
||||||
RenderBufferCache.cpp \
|
RenderBufferCache.cpp \
|
||||||
|
@ -70,6 +70,7 @@ void Caches::init() {
|
|||||||
mCurrentPositionPointer = this;
|
mCurrentPositionPointer = this;
|
||||||
mCurrentPositionStride = 0;
|
mCurrentPositionStride = 0;
|
||||||
mCurrentTexCoordsPointer = this;
|
mCurrentTexCoordsPointer = this;
|
||||||
|
mCurrentPixelBuffer = 0;
|
||||||
|
|
||||||
mTexCoordsArrayEnabled = false;
|
mTexCoordsArrayEnabled = false;
|
||||||
|
|
||||||
@ -365,6 +366,28 @@ bool Caches::unbindIndicesBuffer() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PBO
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool Caches::bindPixelBuffer(const GLuint buffer) {
|
||||||
|
if (mCurrentPixelBuffer != buffer) {
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
|
||||||
|
mCurrentPixelBuffer = buffer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Caches::unbindPixelBuffer() {
|
||||||
|
if (mCurrentPixelBuffer) {
|
||||||
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
mCurrentPixelBuffer = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Meshes and textures
|
// Meshes and textures
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -175,6 +175,16 @@ public:
|
|||||||
bool bindIndicesBuffer(const GLuint buffer);
|
bool bindIndicesBuffer(const GLuint buffer);
|
||||||
bool unbindIndicesBuffer();
|
bool unbindIndicesBuffer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the specified buffer as the current GL unpack pixel buffer.
|
||||||
|
*/
|
||||||
|
bool bindPixelBuffer(const GLuint buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the current unpack pixel buffer to 0 (default value.)
|
||||||
|
*/
|
||||||
|
bool unbindPixelBuffer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds an attrib to the specified float vertex pointer.
|
* Binds an attrib to the specified float vertex pointer.
|
||||||
* Assumes a stride of gMeshStride and a size of 2.
|
* Assumes a stride of gMeshStride and a size of 2.
|
||||||
@ -307,6 +317,7 @@ private:
|
|||||||
|
|
||||||
GLuint mCurrentBuffer;
|
GLuint mCurrentBuffer;
|
||||||
GLuint mCurrentIndicesBuffer;
|
GLuint mCurrentIndicesBuffer;
|
||||||
|
GLuint mCurrentPixelBuffer;
|
||||||
void* mCurrentPositionPointer;
|
void* mCurrentPositionPointer;
|
||||||
GLsizei mCurrentPositionStride;
|
GLsizei mCurrentPositionStride;
|
||||||
void* mCurrentTexCoordsPointer;
|
void* mCurrentTexCoordsPointer;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <utils/Trace.h>
|
#include <utils/Trace.h>
|
||||||
|
|
||||||
|
#include "Caches.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "DisplayListOp.h"
|
#include "DisplayListOp.h"
|
||||||
#include "OpenGLRenderer.h"
|
#include "OpenGLRenderer.h"
|
||||||
@ -377,6 +378,8 @@ static status_t replayBatchList(Vector<DrawOpBatch*>& batchList,
|
|||||||
|
|
||||||
status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
|
status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
|
||||||
ATRACE_NAME("flush drawing commands");
|
ATRACE_NAME("flush drawing commands");
|
||||||
|
Caches::getInstance().fontRenderer->endPrecaching();
|
||||||
|
|
||||||
status_t status = DrawGlInfo::kStatusDone;
|
status_t status = DrawGlInfo::kStatusDone;
|
||||||
|
|
||||||
if (isEmpty()) return status; // nothing to flush
|
if (isEmpty()) return status; // nothing to flush
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "Extensions.h"
|
#include "Extensions.h"
|
||||||
#include "FontRenderer.h"
|
#include "FontRenderer.h"
|
||||||
|
#include "PixelBuffer.h"
|
||||||
#include "Rect.h"
|
#include "Rect.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
@ -133,26 +134,13 @@ void FontRenderer::flushAllAndInvalidate() {
|
|||||||
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
||||||
mCacheTextures[i]->init();
|
mCacheTextures[i]->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_FONT_RENDERER
|
|
||||||
uint16_t totalGlyphs = 0;
|
|
||||||
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
|
||||||
totalGlyphs += mCacheTextures[i]->getGlyphCount();
|
|
||||||
// Erase caches, just as a debugging facility
|
|
||||||
if (mCacheTextures[i]->getTexture()) {
|
|
||||||
memset(mCacheTextures[i]->getTexture(), 0,
|
|
||||||
mCacheTextures[i]->getWidth() * mCacheTextures[i]->getHeight());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontRenderer::flushLargeCaches() {
|
void FontRenderer::flushLargeCaches() {
|
||||||
// Start from 1; don't deallocate smallest/default texture
|
// Start from 1; don't deallocate smallest/default texture
|
||||||
for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
|
for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
|
||||||
CacheTexture* cacheTexture = mCacheTextures[i];
|
CacheTexture* cacheTexture = mCacheTextures[i];
|
||||||
if (cacheTexture->getTexture()) {
|
if (cacheTexture->getPixelBuffer()) {
|
||||||
cacheTexture->init();
|
cacheTexture->init();
|
||||||
LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
|
LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
|
||||||
while (it.next()) {
|
while (it.next()) {
|
||||||
@ -226,7 +214,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
|
|||||||
|
|
||||||
uint32_t cacheWidth = cacheTexture->getWidth();
|
uint32_t cacheWidth = cacheTexture->getWidth();
|
||||||
|
|
||||||
if (!cacheTexture->getTexture()) {
|
if (!cacheTexture->getPixelBuffer()) {
|
||||||
Caches::getInstance().activeTexture(0);
|
Caches::getInstance().activeTexture(0);
|
||||||
// Large-glyph texture memory is allocated only as needed
|
// Large-glyph texture memory is allocated only as needed
|
||||||
cacheTexture->allocateTexture();
|
cacheTexture->allocateTexture();
|
||||||
@ -239,7 +227,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
|
|||||||
// or anti-aliased (8 bits per pixel)
|
// or anti-aliased (8 bits per pixel)
|
||||||
SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
|
SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
|
||||||
|
|
||||||
uint8_t* cacheBuffer = cacheTexture->getTexture();
|
uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
|
||||||
uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
|
uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
|
||||||
|
|
||||||
// Copy the glyph image, taking the mask format into account
|
// Copy the glyph image, taking the mask format into account
|
||||||
@ -377,56 +365,36 @@ void FontRenderer::checkTextureUpdate() {
|
|||||||
Caches& caches = Caches::getInstance();
|
Caches& caches = Caches::getInstance();
|
||||||
GLuint lastTextureId = 0;
|
GLuint lastTextureId = 0;
|
||||||
|
|
||||||
// OpenGL ES 3.0+ lets us specify the row length for unpack operations such
|
bool resetPixelStore = false;
|
||||||
// as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
|
|
||||||
// With OpenGL ES 2.0 we have to upload entire stripes instead.
|
|
||||||
const bool hasUnpackRowLength = Extensions::getInstance().getMajorGlVersion() >= 3;
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
// Iterate over all the cache textures and see which ones need to be updated
|
// Iterate over all the cache textures and see which ones need to be updated
|
||||||
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
||||||
CacheTexture* cacheTexture = mCacheTextures[i];
|
CacheTexture* cacheTexture = mCacheTextures[i];
|
||||||
if (cacheTexture->isDirty() && cacheTexture->getTexture()) {
|
if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
|
||||||
const Rect* dirtyRect = cacheTexture->getDirtyRect();
|
|
||||||
uint32_t x = hasUnpackRowLength ? dirtyRect->left : 0;
|
|
||||||
uint32_t y = dirtyRect->top;
|
|
||||||
uint32_t width = cacheTexture->getWidth();
|
|
||||||
uint32_t height = dirtyRect->getHeight();
|
|
||||||
void* textureData = cacheTexture->getTexture() + y * width + x;
|
|
||||||
|
|
||||||
if (cacheTexture->getTextureId() != lastTextureId) {
|
if (cacheTexture->getTextureId() != lastTextureId) {
|
||||||
lastTextureId = cacheTexture->getTextureId();
|
lastTextureId = cacheTexture->getTextureId();
|
||||||
caches.activeTexture(0);
|
caches.activeTexture(0);
|
||||||
glBindTexture(GL_TEXTURE_2D, lastTextureId);
|
glBindTexture(GL_TEXTURE_2D, lastTextureId);
|
||||||
|
|
||||||
// The unpack row length only needs to be specified when a new
|
|
||||||
// texture is bound
|
|
||||||
if (hasUnpackRowLength) {
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can upload a sub-rectangle, use the dirty rect width
|
if (cacheTexture->upload()) {
|
||||||
// instead of the width of the entire texture
|
resetPixelStore = true;
|
||||||
if (hasUnpackRowLength) {
|
|
||||||
width = dirtyRect->getWidth();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_FONT_RENDERER
|
#if DEBUG_FONT_RENDERER
|
||||||
ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d",
|
ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d",
|
||||||
i, x, y, width, height);
|
i, x, y, width, height);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
|
|
||||||
GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
|
|
||||||
|
|
||||||
cacheTexture->setDirty(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unbind any PBO we might have used to update textures
|
||||||
|
caches.unbindPixelBuffer();
|
||||||
|
|
||||||
// Reset to default unpack row length to avoid affecting texture
|
// Reset to default unpack row length to avoid affecting texture
|
||||||
// uploads in other parts of the renderer
|
// uploads in other parts of the renderer
|
||||||
if (hasUnpackRowLength) {
|
if (resetPixelStore) {
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,13 +507,14 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
|
|||||||
uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
|
uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
|
||||||
checkInit();
|
checkInit();
|
||||||
|
|
||||||
|
DropShadow image;
|
||||||
|
image.width = 0;
|
||||||
|
image.height = 0;
|
||||||
|
image.image = NULL;
|
||||||
|
image.penX = 0;
|
||||||
|
image.penY = 0;
|
||||||
|
|
||||||
if (!mCurrentFont) {
|
if (!mCurrentFont) {
|
||||||
DropShadow image;
|
|
||||||
image.width = 0;
|
|
||||||
image.height = 0;
|
|
||||||
image.image = NULL;
|
|
||||||
image.penX = 0;
|
|
||||||
image.penY = 0;
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,6 +528,11 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
|
|||||||
uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
|
uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
|
||||||
uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
|
uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
|
||||||
|
|
||||||
|
uint32_t maxSize = Caches::getInstance().maxTextureSize;
|
||||||
|
if (paddedWidth > maxSize || paddedHeight > maxSize) {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
// Align buffers for renderscript usage
|
// Align buffers for renderscript usage
|
||||||
if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
|
if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
|
||||||
paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
|
paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
|
||||||
@ -578,10 +552,12 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
|
|||||||
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
|
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
|
||||||
Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
|
Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
|
||||||
|
|
||||||
|
// Unbind any PBO we might have used
|
||||||
|
Caches::getInstance().unbindPixelBuffer();
|
||||||
|
|
||||||
blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
|
blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
DropShadow image;
|
|
||||||
image.width = paddedWidth;
|
image.width = paddedWidth;
|
||||||
image.height = paddedHeight;
|
image.height = paddedHeight;
|
||||||
image.image = dataBuffer;
|
image.image = dataBuffer;
|
||||||
@ -612,6 +588,10 @@ void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, con
|
|||||||
font->precache(paint, text, numGlyphs);
|
font->precache(paint, text, numGlyphs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FontRenderer::endPrecaching() {
|
||||||
|
checkTextureUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
|
bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
|
||||||
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
|
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
|
||||||
const float* positions, Rect* bounds, Functor* functor) {
|
const float* positions, Rect* bounds, Functor* functor) {
|
||||||
@ -690,5 +670,16 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int
|
|||||||
*image = outImage;
|
*image = outImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t FontRenderer::getCacheSize() const {
|
||||||
|
uint32_t size = 0;
|
||||||
|
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
||||||
|
CacheTexture* cacheTexture = mCacheTextures[i];
|
||||||
|
if (cacheTexture && cacheTexture->getPixelBuffer()) {
|
||||||
|
size += cacheTexture->getPixelBuffer()->getSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
}; // namespace uirenderer
|
}; // namespace uirenderer
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
@ -61,6 +61,7 @@ public:
|
|||||||
void setFont(SkPaint* paint, const mat4& matrix);
|
void setFont(SkPaint* paint, const mat4& matrix);
|
||||||
|
|
||||||
void precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix);
|
void precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix);
|
||||||
|
void endPrecaching();
|
||||||
|
|
||||||
// bounds is an out parameter
|
// bounds is an out parameter
|
||||||
bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
|
bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
|
||||||
@ -95,16 +96,7 @@ public:
|
|||||||
mLinearFiltering = linearFiltering;
|
mLinearFiltering = linearFiltering;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getCacheSize() const {
|
uint32_t getCacheSize() const;
|
||||||
uint32_t size = 0;
|
|
||||||
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
|
||||||
CacheTexture* cacheTexture = mCacheTextures[i];
|
|
||||||
if (cacheTexture && cacheTexture->getTexture()) {
|
|
||||||
size += cacheTexture->getWidth() * cacheTexture->getHeight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Font;
|
friend class Font;
|
||||||
|
@ -129,6 +129,12 @@ void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderGammaFontRenderer::endPrecaching() {
|
||||||
|
if (mRenderer) {
|
||||||
|
mRenderer->endPrecaching();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Lookup-based renderer
|
// Lookup-based renderer
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -146,6 +152,12 @@ LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() {
|
|||||||
mRenderer = NULL;
|
mRenderer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LookupGammaFontRenderer::endPrecaching() {
|
||||||
|
if (mRenderer) {
|
||||||
|
mRenderer->endPrecaching();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Lookup-based renderer, using 3 different correction tables
|
// Lookup-based renderer, using 3 different correction tables
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -177,6 +189,14 @@ Lookup3GammaFontRenderer::~Lookup3GammaFontRenderer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Lookup3GammaFontRenderer::endPrecaching() {
|
||||||
|
for (int i = 0; i < kGammaCount; i++) {
|
||||||
|
if (mRenderers[i]) {
|
||||||
|
mRenderers[i]->endPrecaching();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Lookup3GammaFontRenderer::clear() {
|
void Lookup3GammaFontRenderer::clear() {
|
||||||
for (int i = 0; i < kGammaCount; i++) {
|
for (int i = 0; i < kGammaCount; i++) {
|
||||||
delete mRenderers[i];
|
delete mRenderers[i];
|
||||||
|
@ -40,6 +40,8 @@ public:
|
|||||||
virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
|
virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
|
||||||
virtual void setupProgram(ProgramDescription& description, Program* program) const = 0;
|
virtual void setupProgram(ProgramDescription& description, Program* program) const = 0;
|
||||||
|
|
||||||
|
virtual void endPrecaching() = 0;
|
||||||
|
|
||||||
static GammaFontRenderer* createRenderer();
|
static GammaFontRenderer* createRenderer();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -86,6 +88,8 @@ public:
|
|||||||
void describe(ProgramDescription& description, const SkPaint* paint) const;
|
void describe(ProgramDescription& description, const SkPaint* paint) const;
|
||||||
void setupProgram(ProgramDescription& description, Program* program) const;
|
void setupProgram(ProgramDescription& description, Program* program) const;
|
||||||
|
|
||||||
|
void endPrecaching();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShaderGammaFontRenderer(bool multiGamma);
|
ShaderGammaFontRenderer(bool multiGamma);
|
||||||
|
|
||||||
@ -134,6 +138,8 @@ public:
|
|||||||
void setupProgram(ProgramDescription& description, Program* program) const {
|
void setupProgram(ProgramDescription& description, Program* program) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void endPrecaching();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LookupGammaFontRenderer();
|
LookupGammaFontRenderer();
|
||||||
|
|
||||||
@ -171,6 +177,8 @@ public:
|
|||||||
void setupProgram(ProgramDescription& description, Program* program) const {
|
void setupProgram(ProgramDescription& description, Program* program) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void endPrecaching();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Lookup3GammaFontRenderer();
|
Lookup3GammaFontRenderer();
|
||||||
|
|
||||||
|
@ -2644,6 +2644,9 @@ void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesC
|
|||||||
mCaches.dropShadowCache.setFontRenderer(fontRenderer);
|
mCaches.dropShadowCache.setFontRenderer(fontRenderer);
|
||||||
const ShadowTexture* shadow = mCaches.dropShadowCache.get(
|
const ShadowTexture* shadow = mCaches.dropShadowCache.get(
|
||||||
paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
|
paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
|
||||||
|
// If the drop shadow exceeds the max texture size or couldn't be
|
||||||
|
// allocated, skip drawing
|
||||||
|
if (!shadow) return;
|
||||||
const AutoTexture autoCleanup(shadow);
|
const AutoTexture autoCleanup(shadow);
|
||||||
|
|
||||||
const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
|
const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
|
||||||
|
163
libs/hwui/PixelBuffer.cpp
Normal file
163
libs/hwui/PixelBuffer.cpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_TAG "OpenGLRenderer"
|
||||||
|
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include "Caches.h"
|
||||||
|
#include "Extensions.h"
|
||||||
|
#include "PixelBuffer.h"
|
||||||
|
#include "Properties.h"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
namespace uirenderer {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CPU pixel buffer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class CpuPixelBuffer: public PixelBuffer {
|
||||||
|
public:
|
||||||
|
CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
|
||||||
|
~CpuPixelBuffer();
|
||||||
|
|
||||||
|
uint8_t* map(AccessMode mode = kAccessMode_ReadWrite);
|
||||||
|
void unmap();
|
||||||
|
|
||||||
|
uint8_t* getMappedPointer() const;
|
||||||
|
|
||||||
|
void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t* mBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height):
|
||||||
|
PixelBuffer(format, width, height) {
|
||||||
|
mBuffer = new uint8_t[width * height * formatSize(format)];
|
||||||
|
}
|
||||||
|
|
||||||
|
CpuPixelBuffer::~CpuPixelBuffer() {
|
||||||
|
delete[] mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* CpuPixelBuffer::map(AccessMode mode) {
|
||||||
|
if (mAccessMode == kAccessMode_None) {
|
||||||
|
mAccessMode = mode;
|
||||||
|
}
|
||||||
|
return mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CpuPixelBuffer::unmap() {
|
||||||
|
mAccessMode = kAccessMode_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* CpuPixelBuffer::getMappedPointer() const {
|
||||||
|
return mAccessMode == kAccessMode_None ? NULL : mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
|
||||||
|
mFormat, GL_UNSIGNED_BYTE, mBuffer + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GPU pixel buffer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class GpuPixelBuffer: public PixelBuffer {
|
||||||
|
public:
|
||||||
|
GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
|
||||||
|
~GpuPixelBuffer();
|
||||||
|
|
||||||
|
uint8_t* map(AccessMode mode = kAccessMode_ReadWrite);
|
||||||
|
void unmap();
|
||||||
|
|
||||||
|
uint8_t* getMappedPointer() const;
|
||||||
|
|
||||||
|
void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLuint mBuffer;
|
||||||
|
uint8_t* mMappedPointer;
|
||||||
|
Caches& mCaches;
|
||||||
|
};
|
||||||
|
|
||||||
|
GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height):
|
||||||
|
PixelBuffer(format, width, height), mMappedPointer(0), mCaches(Caches::getInstance()) {
|
||||||
|
glGenBuffers(1, &mBuffer);
|
||||||
|
mCaches.bindPixelBuffer(mBuffer);
|
||||||
|
glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), NULL, GL_DYNAMIC_DRAW);
|
||||||
|
mCaches.unbindPixelBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
GpuPixelBuffer::~GpuPixelBuffer() {
|
||||||
|
glDeleteBuffers(1, &mBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* GpuPixelBuffer::map(AccessMode mode) {
|
||||||
|
if (mAccessMode == kAccessMode_None) {
|
||||||
|
mCaches.bindPixelBuffer(mBuffer);
|
||||||
|
mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
|
||||||
|
mAccessMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mMappedPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuPixelBuffer::unmap() {
|
||||||
|
if (mAccessMode != kAccessMode_None) {
|
||||||
|
if (mMappedPointer) {
|
||||||
|
mCaches.bindPixelBuffer(mBuffer);
|
||||||
|
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||||
|
}
|
||||||
|
mAccessMode = kAccessMode_None;
|
||||||
|
mMappedPointer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* GpuPixelBuffer::getMappedPointer() const {
|
||||||
|
return mMappedPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
|
||||||
|
// If the buffer is not mapped, unmap() will not bind it
|
||||||
|
mCaches.bindPixelBuffer(mBuffer);
|
||||||
|
unmap();
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
|
||||||
|
GL_UNSIGNED_BYTE, (void*) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Factory
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
|
||||||
|
bool gpuBuffer = type == kBufferType_Auto && Extensions::getInstance().getMajorGlVersion() >= 3;
|
||||||
|
if (gpuBuffer) {
|
||||||
|
char property[PROPERTY_VALUE_MAX];
|
||||||
|
if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "false") > 0) {
|
||||||
|
if (!strcmp(property, "true")) {
|
||||||
|
return new GpuPixelBuffer(format, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new CpuPixelBuffer(format, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace uirenderer
|
||||||
|
}; // namespace android
|
180
libs/hwui/PixelBuffer.h
Normal file
180
libs/hwui/PixelBuffer.h
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANDROID_HWUI_PIXEL_BUFFER_H
|
||||||
|
#define ANDROID_HWUI_PIXEL_BUFFER_H
|
||||||
|
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
namespace uirenderer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a pixel buffer. A pixel buffer will be backed either by a
|
||||||
|
* PBO on OpenGL ES 3.0 and higher or by an array of uint8_t on other
|
||||||
|
* versions. If the buffer is backed by a PBO it will of type
|
||||||
|
* GL_PIXEL_UNPACK_BUFFER.
|
||||||
|
*
|
||||||
|
* To read from or write into a PixelBuffer you must first map the
|
||||||
|
* buffer using the map(AccessMode) method. This method returns a
|
||||||
|
* pointer to the beginning of the buffer.
|
||||||
|
*
|
||||||
|
* Before the buffer can be used by the GPU, for instance to upload
|
||||||
|
* a texture, you must first unmap the buffer. To do so, call the
|
||||||
|
* unmap() method.
|
||||||
|
*
|
||||||
|
* Mapping and unmapping a PixelBuffer can have the side effect of
|
||||||
|
* changing the currently active GL_PIXEL_UNPACK_BUFFER. It is
|
||||||
|
* therefore recommended to call Caches::unbindPixelbuffer() after
|
||||||
|
* using a PixelBuffer to upload to a texture.
|
||||||
|
*/
|
||||||
|
class PixelBuffer {
|
||||||
|
public:
|
||||||
|
enum BufferType {
|
||||||
|
kBufferType_Auto,
|
||||||
|
kBufferType_CPU
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AccessMode {
|
||||||
|
kAccessMode_None = 0,
|
||||||
|
kAccessMode_Read = GL_MAP_READ_BIT,
|
||||||
|
kAccessMode_Write = GL_MAP_WRITE_BIT,
|
||||||
|
kAccessMode_ReadWrite = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new PixelBuffer object with the specified format and
|
||||||
|
* dimensions. The buffer is immediately allocated.
|
||||||
|
*
|
||||||
|
* The buffer type specifies how the buffer should be allocated.
|
||||||
|
* By default this method will automatically choose whether to allocate
|
||||||
|
* a CPU or GPU buffer.
|
||||||
|
*/
|
||||||
|
static PixelBuffer* create(GLenum format, uint32_t width, uint32_t height,
|
||||||
|
BufferType type = kBufferType_Auto);
|
||||||
|
|
||||||
|
virtual ~PixelBuffer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the format of this render buffer.
|
||||||
|
*/
|
||||||
|
GLenum getFormat() const {
|
||||||
|
return mFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps this before with the specified access mode. This method
|
||||||
|
* returns a pointer to the region of memory where the buffer was
|
||||||
|
* mapped.
|
||||||
|
*
|
||||||
|
* If the buffer is already mapped when this method is invoked,
|
||||||
|
* this method will return the previously mapped pointer. The
|
||||||
|
* access mode can only be changed by calling unmap() first.
|
||||||
|
*
|
||||||
|
* The specified access mode cannot be kAccessMode_None.
|
||||||
|
*/
|
||||||
|
virtual uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmaps this buffer, if needed. After the buffer is unmapped,
|
||||||
|
* the pointer previously returned by map() becomes invalid and
|
||||||
|
* should not be used. After calling this method, getMappedPointer()
|
||||||
|
* will always return NULL.
|
||||||
|
*/
|
||||||
|
virtual void unmap() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current access mode for this buffer. If the buffer
|
||||||
|
* is not mapped, this method returns kAccessMode_None.
|
||||||
|
*/
|
||||||
|
AccessMode getAccessMode() const {
|
||||||
|
return mAccessMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently mapped pointer. Returns NULL if the buffer
|
||||||
|
* is not mapped.
|
||||||
|
*/
|
||||||
|
virtual uint8_t* getMappedPointer() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload the specified rectangle of this pixe buffer as a
|
||||||
|
* GL_TEXTURE_2D texture. Calling this method will trigger
|
||||||
|
* an unmap() if necessary.
|
||||||
|
*/
|
||||||
|
virtual void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the width of the render buffer in pixels.
|
||||||
|
*/
|
||||||
|
uint32_t getWidth() const {
|
||||||
|
return mWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the height of the render buffer in pixels.
|
||||||
|
*/
|
||||||
|
uint32_t getHeight() const {
|
||||||
|
return mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of this pixel buffer in bytes.
|
||||||
|
*/
|
||||||
|
uint32_t getSize() const {
|
||||||
|
return mWidth * mHeight * formatSize(mFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes per pixel in the specified format.
|
||||||
|
*
|
||||||
|
* Supported formats:
|
||||||
|
* GL_ALPHA
|
||||||
|
* GL_RGBA
|
||||||
|
*/
|
||||||
|
static uint32_t formatSize(GLenum format) {
|
||||||
|
switch (format) {
|
||||||
|
case GL_ALPHA:
|
||||||
|
return 1;
|
||||||
|
case GL_RGBA:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Creates a new render buffer in the specified format and dimensions.
|
||||||
|
* The format must be GL_ALPHA or GL_RGBA.
|
||||||
|
*/
|
||||||
|
PixelBuffer(GLenum format, uint32_t width, uint32_t height):
|
||||||
|
mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum mFormat;
|
||||||
|
|
||||||
|
uint32_t mWidth;
|
||||||
|
uint32_t mHeight;
|
||||||
|
|
||||||
|
AccessMode mAccessMode;
|
||||||
|
|
||||||
|
}; // class PixelBuffer
|
||||||
|
|
||||||
|
}; // namespace uirenderer
|
||||||
|
}; // namespace android
|
||||||
|
|
||||||
|
#endif // ANDROID_HWUI_PIXEL_BUFFER_H
|
@ -25,6 +25,10 @@
|
|||||||
* the OpenGLRenderer.
|
* the OpenGLRenderer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compile-time properties
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// If turned on, text is interpreted as glyphs instead of UTF-16
|
// If turned on, text is interpreted as glyphs instead of UTF-16
|
||||||
#define RENDER_TEXT_AS_GLYPHS 1
|
#define RENDER_TEXT_AS_GLYPHS 1
|
||||||
|
|
||||||
@ -39,6 +43,10 @@
|
|||||||
// to properly implement overdraw debugging
|
// to properly implement overdraw debugging
|
||||||
#define STENCIL_BUFFER_SIZE 8
|
#define STENCIL_BUFFER_SIZE 8
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Debug properties
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug level for app developers. The value is a numeric value defined
|
* Debug level for app developers. The value is a numeric value defined
|
||||||
* by the DebugLevel enum below.
|
* by the DebugLevel enum below.
|
||||||
@ -81,6 +89,23 @@ enum DebugLevel {
|
|||||||
*/
|
*/
|
||||||
#define PROPERTY_DEBUG_STENCIL_CLIP "debug.hwui.show_non_rect_clip"
|
#define PROPERTY_DEBUG_STENCIL_CLIP "debug.hwui.show_non_rect_clip"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables draw operation deferral if set to "true", forcing draw
|
||||||
|
* commands to be issued to OpenGL in order, and processed in sequence
|
||||||
|
* with state-manipulation canvas commands.
|
||||||
|
*/
|
||||||
|
#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to disable draw operation reordering when deferring draw operations
|
||||||
|
* Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
|
||||||
|
*/
|
||||||
|
#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Runtime configuration properties
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to enable/disable scissor optimization. The accepted values are
|
* Used to enable/disable scissor optimization. The accepted values are
|
||||||
* "true" and "false". The default value is "false".
|
* "true" and "false". The default value is "false".
|
||||||
@ -97,17 +122,10 @@ enum DebugLevel {
|
|||||||
#define PROPERTY_DISABLE_SCISSOR_OPTIMIZATION "ro.hwui.disable_scissor_opt"
|
#define PROPERTY_DISABLE_SCISSOR_OPTIMIZATION "ro.hwui.disable_scissor_opt"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables draw operation deferral if set to "true", forcing draw
|
* Indicates whether PBOs can be used to back pixel buffers.
|
||||||
* commands to be issued to OpenGL in order, and processed in sequence
|
* Accepted values are "true" and "false".
|
||||||
* with state-manipulation canvas commands.
|
|
||||||
*/
|
*/
|
||||||
#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
|
#define PROPERTY_ENABLE_GPU_PIXEL_BUFFERS "hwui.use_gpu_pixel_buffers"
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to disable draw operation reordering when deferring draw operations
|
|
||||||
* Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
|
|
||||||
*/
|
|
||||||
#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
|
|
||||||
|
|
||||||
// These properties are defined in mega-bytes
|
// These properties are defined in mega-bytes
|
||||||
#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
|
#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
|
||||||
@ -152,8 +170,9 @@ enum DebugLevel {
|
|||||||
// Lumincance threshold above which white gamma correction is applied. Range: [0..255]
|
// Lumincance threshold above which white gamma correction is applied. Range: [0..255]
|
||||||
#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "hwui.text_gamma.white_threshold"
|
#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "hwui.text_gamma.white_threshold"
|
||||||
|
|
||||||
// Converts a number of mega-bytes into bytes
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define MB(s) s * 1024 * 1024
|
// Default property values
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
|
#define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
|
||||||
#define DEFAULT_LAYER_CACHE_SIZE 16.0f
|
#define DEFAULT_LAYER_CACHE_SIZE 16.0f
|
||||||
@ -170,6 +189,13 @@ enum DebugLevel {
|
|||||||
#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
|
#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
|
||||||
#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
|
#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Misc
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Converts a number of mega-bytes into bytes
|
||||||
|
#define MB(s) s * 1024 * 1024
|
||||||
|
|
||||||
static DebugLevel readDebugLevel() {
|
static DebugLevel readDebugLevel() {
|
||||||
char property[PROPERTY_VALUE_MAX];
|
char property[PROPERTY_VALUE_MAX];
|
||||||
if (property_get(PROPERTY_DEBUG, property, NULL) > 0) {
|
if (property_get(PROPERTY_DEBUG, property, NULL) > 0) {
|
||||||
|
@ -178,6 +178,10 @@ ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32
|
|||||||
FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, text, 0,
|
FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, text, 0,
|
||||||
len, numGlyphs, radius, positions);
|
len, numGlyphs, radius, positions);
|
||||||
|
|
||||||
|
if (!shadow.image) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
texture = new ShadowTexture;
|
texture = new ShadowTexture;
|
||||||
texture->left = shadow.penX;
|
texture->left = shadow.penX;
|
||||||
texture->top = shadow.penY;
|
texture->top = shadow.penY;
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "CacheTexture.h"
|
#include "CacheTexture.h"
|
||||||
#include "../Debug.h"
|
#include "../Debug.h"
|
||||||
|
#include "../Extensions.h"
|
||||||
|
#include "../PixelBuffer.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace uirenderer {
|
namespace uirenderer {
|
||||||
@ -111,6 +113,11 @@ CacheTexture::CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCoun
|
|||||||
mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount) {
|
mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount) {
|
||||||
mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
|
mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
|
||||||
mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
|
mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// With OpenGL ES 2.0 we have to upload entire stripes instead.
|
||||||
|
mHasES3 = Extensions::getInstance().getMajorGlVersion() >= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
CacheTexture::~CacheTexture() {
|
CacheTexture::~CacheTexture() {
|
||||||
@ -143,7 +150,7 @@ void CacheTexture::releaseMesh() {
|
|||||||
|
|
||||||
void CacheTexture::releaseTexture() {
|
void CacheTexture::releaseTexture() {
|
||||||
if (mTexture) {
|
if (mTexture) {
|
||||||
delete[] mTexture;
|
delete mTexture;
|
||||||
mTexture = NULL;
|
mTexture = NULL;
|
||||||
}
|
}
|
||||||
if (mTextureId) {
|
if (mTextureId) {
|
||||||
@ -154,6 +161,17 @@ void CacheTexture::releaseTexture() {
|
|||||||
mCurrentQuad = 0;
|
mCurrentQuad = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CacheTexture::setLinearFiltering(bool linearFiltering, bool bind) {
|
||||||
|
if (linearFiltering != mLinearFiltering) {
|
||||||
|
mLinearFiltering = linearFiltering;
|
||||||
|
|
||||||
|
const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
|
||||||
|
if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CacheTexture::allocateMesh() {
|
void CacheTexture::allocateMesh() {
|
||||||
if (!mMesh) {
|
if (!mMesh) {
|
||||||
mMesh = new TextureVertex[mMaxQuadCount * 4];
|
mMesh = new TextureVertex[mMaxQuadCount * 4];
|
||||||
@ -162,7 +180,7 @@ void CacheTexture::allocateMesh() {
|
|||||||
|
|
||||||
void CacheTexture::allocateTexture() {
|
void CacheTexture::allocateTexture() {
|
||||||
if (!mTexture) {
|
if (!mTexture) {
|
||||||
mTexture = new uint8_t[mWidth * mHeight];
|
mTexture = PixelBuffer::create(GL_ALPHA, mWidth, mHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mTextureId) {
|
if (!mTextureId) {
|
||||||
@ -183,6 +201,34 @@ void CacheTexture::allocateTexture() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CacheTexture::upload() {
|
||||||
|
const Rect& dirtyRect = mDirtyRect;
|
||||||
|
|
||||||
|
uint32_t x = mHasES3 ? dirtyRect.left : 0;
|
||||||
|
uint32_t y = dirtyRect.top;
|
||||||
|
uint32_t width = mHasES3 ? dirtyRect.getWidth() : mWidth;
|
||||||
|
uint32_t height = dirtyRect.getHeight();
|
||||||
|
|
||||||
|
// The unpack row length only needs to be specified when a new
|
||||||
|
// texture is bound
|
||||||
|
if (mHasES3) {
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTexture->upload(x, y, width, height, y * mWidth + x);
|
||||||
|
|
||||||
|
setDirty(false);
|
||||||
|
|
||||||
|
return mHasES3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CacheTexture::setDirty(bool dirty) {
|
||||||
|
mDirty = dirty;
|
||||||
|
if (!dirty) {
|
||||||
|
mDirtyRect.setEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
|
bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
|
||||||
if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) {
|
if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
namespace android {
|
namespace android {
|
||||||
namespace uirenderer {
|
namespace uirenderer {
|
||||||
|
|
||||||
|
class PixelBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
|
* CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
|
||||||
* Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
|
* Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
|
||||||
@ -83,6 +85,10 @@ public:
|
|||||||
void allocateTexture();
|
void allocateTexture();
|
||||||
void allocateMesh();
|
void allocateMesh();
|
||||||
|
|
||||||
|
// Returns true if glPixelStorei(GL_UNPACK_ROW_LENGTH) must be reset
|
||||||
|
// This method will also call setDirty(false)
|
||||||
|
bool upload();
|
||||||
|
|
||||||
bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
|
bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
|
||||||
|
|
||||||
inline uint16_t getWidth() const {
|
inline uint16_t getWidth() const {
|
||||||
@ -97,7 +103,7 @@ public:
|
|||||||
return &mDirtyRect;
|
return &mDirtyRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t* getTexture() const {
|
inline PixelBuffer* getPixelBuffer() const {
|
||||||
return mTexture;
|
return mTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,13 +116,6 @@ public:
|
|||||||
return mDirty;
|
return mDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setDirty(bool dirty) {
|
|
||||||
mDirty = dirty;
|
|
||||||
if (!dirty) {
|
|
||||||
mDirtyRect.setEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool getLinearFiltering() const {
|
inline bool getLinearFiltering() const {
|
||||||
return mLinearFiltering;
|
return mLinearFiltering;
|
||||||
}
|
}
|
||||||
@ -124,16 +123,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* This method assumes that the proper texture unit is active.
|
* This method assumes that the proper texture unit is active.
|
||||||
*/
|
*/
|
||||||
void setLinearFiltering(bool linearFiltering, bool bind = true) {
|
void setLinearFiltering(bool linearFiltering, bool bind = true);
|
||||||
if (linearFiltering != mLinearFiltering) {
|
|
||||||
mLinearFiltering = linearFiltering;
|
|
||||||
|
|
||||||
const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
|
|
||||||
if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16_t getGlyphCount() const {
|
inline uint16_t getGlyphCount() const {
|
||||||
return mNumGlyphs;
|
return mNumGlyphs;
|
||||||
@ -176,7 +166,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t* mTexture;
|
void setDirty(bool dirty);
|
||||||
|
|
||||||
|
PixelBuffer* mTexture;
|
||||||
GLuint mTextureId;
|
GLuint mTextureId;
|
||||||
uint16_t mWidth;
|
uint16_t mWidth;
|
||||||
uint16_t mHeight;
|
uint16_t mHeight;
|
||||||
@ -188,6 +180,7 @@ private:
|
|||||||
uint32_t mMaxQuadCount;
|
uint32_t mMaxQuadCount;
|
||||||
CacheBlock* mCacheBlocks;
|
CacheBlock* mCacheBlocks;
|
||||||
Rect mDirtyRect;
|
Rect mDirtyRect;
|
||||||
|
bool mHasES3;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace uirenderer
|
}; // namespace uirenderer
|
||||||
|
@ -25,11 +25,12 @@
|
|||||||
#include <SkGlyph.h>
|
#include <SkGlyph.h>
|
||||||
#include <SkUtils.h>
|
#include <SkUtils.h>
|
||||||
|
|
||||||
#include "Debug.h"
|
|
||||||
#include "FontUtil.h"
|
#include "FontUtil.h"
|
||||||
#include "Font.h"
|
#include "Font.h"
|
||||||
#include "FontRenderer.h"
|
#include "../Debug.h"
|
||||||
#include "Properties.h"
|
#include "../FontRenderer.h"
|
||||||
|
#include "../PixelBuffer.h"
|
||||||
|
#include "../Properties.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace uirenderer {
|
namespace uirenderer {
|
||||||
@ -200,25 +201,23 @@ void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
|
|||||||
p[3].x(), p[3].y(), u1, v1, glyph->mCacheTexture);
|
p[3].x(), p[3].y(), u1, v1, glyph->mCacheTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
|
void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
|
||||||
uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
|
uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds, const float* pos) {
|
||||||
int nPenX = x + glyph->mBitmapLeft;
|
int dstX = x + glyph->mBitmapLeft;
|
||||||
int nPenY = y + glyph->mBitmapTop;
|
int dstY = y + glyph->mBitmapTop;
|
||||||
|
|
||||||
uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
|
|
||||||
uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
|
|
||||||
|
|
||||||
CacheTexture* cacheTexture = glyph->mCacheTexture;
|
CacheTexture* cacheTexture = glyph->mCacheTexture;
|
||||||
uint32_t cacheWidth = cacheTexture->getWidth();
|
|
||||||
const uint8_t* cacheBuffer = cacheTexture->getTexture();
|
|
||||||
|
|
||||||
uint32_t cacheX = 0, cacheY = 0;
|
uint32_t cacheWidth = cacheTexture->getWidth();
|
||||||
int32_t bX = 0, bY = 0;
|
uint32_t startY = glyph->mStartY * cacheWidth;
|
||||||
for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
|
uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth);
|
||||||
for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
|
|
||||||
uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
|
PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer();
|
||||||
bitmap[bY * bitmapW + bX] = tempCol;
|
const uint8_t* cacheBuffer = pixelBuffer->map();
|
||||||
}
|
|
||||||
|
for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY;
|
||||||
|
cacheY += cacheWidth, bitmapY += bitmapWidth) {
|
||||||
|
memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user