Optimize FBO drawing with regions.

This optimization is currently disabled until Launcher is
modified to take advantage of it. The optimization can be
enabled by turning on RENDER_LAYERS_AS_REGIONS in the
OpenGLRenderer.h file.

Change-Id: I2fdf59d0f4dc690a3d7f712173ab8db3848b27b1
This commit is contained in:
Romain Guy
2010-10-27 18:57:51 -07:00
parent 2444ddb3d9
commit 5b3b35296e
43 changed files with 671 additions and 236 deletions

View File

@@ -129,6 +129,7 @@ public class LockPatternView extends View {
private long[] mVibePattern;
private int mAspect;
private final Matrix mArrowMatrix = new Matrix();
/**
* Represents a cell in the 3 X 3 matrix of the unlock pattern view.
@@ -923,7 +924,6 @@ public class LockPatternView extends View {
// This assumes that the arrow image is drawn at 12:00 with it's top edge
// coincident with the circle bitmap's top edge.
Bitmap arrow = green ? mBitmapArrowGreenUp : mBitmapArrowRedUp;
Matrix matrix = new Matrix();
final int cellWidth = mBitmapCircleDefault.getWidth();
final int cellHeight = mBitmapCircleDefault.getHeight();
@@ -933,10 +933,10 @@ public class LockPatternView extends View {
final float angle = (float) Math.toDegrees(theta) + 90.0f;
// compose matrix
matrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position
matrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f); // rotate about cell center
matrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos
canvas.drawBitmap(arrow, matrix, mPaint);
mArrowMatrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position
mArrowMatrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f); // rotate about cell center
mArrowMatrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos
canvas.drawBitmap(arrow, mArrowMatrix, mPaint);
}
/**

View File

@@ -38,7 +38,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia
LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
LOCAL_MODULE := libhwui
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false

View File

@@ -46,18 +46,21 @@ Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
mCurrentBuffer = meshBuffer;
mRegionMesh = NULL;
}
/**
* Binds the VBO used to render simple textured quads.
*/
Caches::~Caches() {
delete[] mRegionMesh;
}
///////////////////////////////////////////////////////////////////////////////
// VBO
///////////////////////////////////////////////////////////////////////////////
void Caches::bindMeshBuffer() {
bindMeshBuffer(meshBuffer);
}
/**
* Binds the specified VBO.
*/
void Caches::bindMeshBuffer(const GLuint buffer) {
if (mCurrentBuffer != buffer) {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
@@ -65,9 +68,6 @@ void Caches::bindMeshBuffer(const GLuint buffer) {
}
}
/**
* Unbinds the VBO used to render simple textured quads.
*/
void Caches::unbindMeshBuffer() {
if (mCurrentBuffer) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -75,5 +75,35 @@ void Caches::unbindMeshBuffer() {
}
}
TextureVertex* Caches::getRegionMesh() {
// Create the mesh, 2 triangles and 4 vertices per rectangle in the region
if (!mRegionMesh) {
mRegionMesh = new TextureVertex[REGION_MESH_QUAD_COUNT * 4];
uint16_t* regionIndices = new uint16_t[REGION_MESH_QUAD_COUNT * 6];
for (int i = 0; i < REGION_MESH_QUAD_COUNT; i++) {
uint16_t quad = i * 4;
int index = i * 6;
regionIndices[index ] = quad; // top-left
regionIndices[index + 1] = quad + 1; // top-right
regionIndices[index + 2] = quad + 2; // bottom-left
regionIndices[index + 3] = quad + 2; // bottom-left
regionIndices[index + 4] = quad + 1; // top-right
regionIndices[index + 5] = quad + 3; // bottom-right
}
glGenBuffers(1, &mRegionMeshIndices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mRegionMeshIndices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t),
regionIndices, GL_STATIC_DRAW);
delete[] regionIndices;
} else {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mRegionMeshIndices);
}
return mRegionMesh;
}
}; // namespace uirenderer
}; // namespace android

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_CACHES_H
#define ANDROID_UI_CACHES_H
#ifndef ANDROID_HWUI_CACHES_H
#define ANDROID_HWUI_CACHES_H
#ifndef LOG_TAG
#define LOG_TAG "OpenGLRenderer"
@@ -46,6 +46,8 @@ namespace uirenderer {
#define REQUIRED_TEXTURE_UNITS_COUNT 3
#define REGION_MESH_QUAD_COUNT 512
// Generates simple and textured vertices
#define FV(x, y, u, v) { { x, y }, { u, v } }
@@ -77,6 +79,7 @@ struct CacheLogger {
class Caches: public Singleton<Caches> {
Caches();
~Caches();
friend class Singleton<Caches>;
@@ -84,11 +87,33 @@ class Caches: public Singleton<Caches> {
GLuint mCurrentBuffer;
// Used to render layers
TextureVertex* mRegionMesh;
GLuint mRegionMeshIndices;
public:
/**
* Binds the VBO used to render simple textured quads.
*/
void bindMeshBuffer();
/**
* Binds the specified VBO if needed.
*/
void bindMeshBuffer(const GLuint buffer);
/**
* Unbinds the VBO used to render simple textured quads.
*/
void unbindMeshBuffer();
/**
* Returns the mesh used to draw regions. Calling this method will
* bind a VBO of type GL_ELEMENT_ARRAY_BUFFER that contains the
* indices for the region mesh.
*/
TextureVertex* getRegionMesh();
bool blend;
GLenum lastSrcMode;
GLenum lastDstMode;
@@ -118,7 +143,6 @@ public:
}; // class Caches
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_CACHES_H
#endif // ANDROID_HWUI_CACHES_H

View File

@@ -169,7 +169,8 @@ void DisplayList::replay(OpenGLRenderer& renderer) {
int saveCount = renderer.getSaveCount() - 1;
while (!mReader.eof()) {
switch (mReader.readInt()) {
int op = mReader.readInt();
switch (op) {
case AcquireContext: {
renderer.acquireContext();
}
@@ -195,6 +196,11 @@ void DisplayList::replay(OpenGLRenderer& renderer) {
getPaint(), getInt());
}
break;
case SaveLayerAlpha: {
renderer.saveLayerAlpha(getFloat(), getFloat(), getFloat(), getFloat(),
getInt(), getInt());
}
break;
case Translate: {
renderer.translate(getFloat(), getFloat());
}
@@ -400,6 +406,15 @@ int DisplayListRenderer::saveLayer(float left, float top, float right, float bot
return OpenGLRenderer::save(flags);
}
int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags) {
addOp(DisplayList::SaveLayerAlpha);
addBounds(left, top, right, bottom);
addInt(alpha);
addInt(flags);
return OpenGLRenderer::save(flags);
}
void DisplayListRenderer::translate(float dx, float dy) {
addOp(DisplayList::Translate);
addPoint(dx, dy);

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_DISPLAY_LIST_RENDERER_H
#define ANDROID_UI_DISPLAY_LIST_RENDERER_H
#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
#include <SkChunkAlloc.h>
#include <SkFlattenable.h>
@@ -85,6 +85,7 @@ public:
Restore,
RestoreToCount,
SaveLayer,
SaveLayerAlpha,
Translate,
Rotate,
Scale,
@@ -222,6 +223,8 @@ public:
int saveLayer(float left, float top, float right, float bottom,
SkPaint* p, int flags);
int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags);
void translate(float dx, float dy);
void rotate(float degrees);
@@ -411,4 +414,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_DISPLAY_LIST_RENDERER_H
#endif // ANDROID_HWUI_DISPLAY_LIST_RENDERER_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_EXTENSIONS_H
#define ANDROID_UI_EXTENSIONS_H
#ifndef ANDROID_HWUI_EXTENSIONS_H
#define ANDROID_HWUI_EXTENSIONS_H
#include <utils/SortedVector.h>
#include <utils/String8.h>
@@ -93,4 +93,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_EXTENSIONS_H
#endif // ANDROID_HWUI_EXTENSIONS_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_FBO_CACHE_H
#define ANDROID_UI_FBO_CACHE_H
#ifndef ANDROID_HWUI_FBO_CACHE_H
#define ANDROID_HWUI_FBO_CACHE_H
#include <GLES2/gl2.h>
@@ -76,4 +76,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_FBO_CACHE_H
#endif // ANDROID_HWUI_FBO_CACHE_H

View File

@@ -556,6 +556,8 @@ void FontRenderer::issueDrawCommand() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
mDrawn = true;
}
void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
@@ -595,6 +597,13 @@ void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float
mCurrentQuadIndex++;
if (mBounds) {
mBounds->left = fmin(mBounds->left, x1);
mBounds->top = fmin(mBounds->top, y3);
mBounds->right = fmax(mBounds->right, x3);
mBounds->bottom = fmax(mBounds->bottom, y1);
}
if (mCurrentQuadIndex == mMaxNumberOfQuads) {
issueDrawCommand();
mCurrentQuadIndex = 0;
@@ -674,22 +683,27 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
return image;
}
void FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y) {
bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
checkInit();
if (!mCurrentFont) {
LOGE("No font set");
return;
return false;
}
mDrawn = false;
mBounds = bounds;
mClip = clip;
mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y);
mBounds = NULL;
if (mCurrentQuadIndex != 0) {
issueDrawCommand();
mCurrentQuadIndex = 0;
}
return mDrawn;
}
void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_FONT_RENDERER_H
#define ANDROID_UI_FONT_RENDERER_H
#ifndef ANDROID_HWUI_FONT_RENDERER_H
#define ANDROID_HWUI_FONT_RENDERER_H
#include <utils/String8.h>
#include <utils/String16.h>
@@ -132,8 +132,8 @@ public:
}
void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
void renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
uint32_t len, int numGlyphs, int x, int y);
bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
uint32_t len, int numGlyphs, int x, int y, Rect* bounds);
struct DropShadow {
DropShadow() { };
@@ -257,6 +257,8 @@ protected:
uint32_t mIndexBufferID;
const Rect* mClip;
Rect* mBounds;
bool mDrawn;
bool mInitialized;
@@ -273,4 +275,4 @@ protected:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_FONT_RENDERER_H
#endif // ANDROID_HWUI_FONT_RENDERER_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_GAMMA_FONT_RENDERER_H
#define ANDROID_UI_GAMMA_FONT_RENDERER_H
#ifndef ANDROID_HWUI_GAMMA_FONT_RENDERER_H
#define ANDROID_HWUI_GAMMA_FONT_RENDERER_H
#include <SkPaint.h>
@@ -45,4 +45,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_GAMMA_FONT_RENDERER_H
#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_GRADIENT_CACHE_H
#define ANDROID_UI_GRADIENT_CACHE_H
#ifndef ANDROID_HWUI_GRADIENT_CACHE_H
#define ANDROID_HWUI_GRADIENT_CACHE_H
#include <SkShader.h>
@@ -93,4 +93,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_GRADIENT_CACHE_H
#endif // ANDROID_HWUI_GRADIENT_CACHE_H

View File

@@ -14,13 +14,15 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_LAYER_H
#define ANDROID_UI_LAYER_H
#ifndef ANDROID_HWUI_LAYER_H
#define ANDROID_HWUI_LAYER_H
#include <sys/types.h>
#include <GLES2/gl2.h>
#include <ui/Region.h>
#include <SkXfermode.h>
#include "Rect.h"
@@ -85,9 +87,15 @@ struct Layer {
* Height of the layer texture.
*/
uint32_t height;
/**
* Dirty region indicating what parts of the layer
* have been drawn.
*/
Region region;
}; // struct Layer
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_LAYER_H
#endif // ANDROID_HWUI_LAYER_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_LAYER_CACHE_H
#define ANDROID_UI_LAYER_CACHE_H
#ifndef ANDROID_HWUI_LAYER_CACHE_H
#define ANDROID_HWUI_LAYER_CACHE_H
#include "Layer.h"
#include "utils/SortedList.h"
@@ -138,4 +138,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_LAYER_CACHE_H
#endif // ANDROID_HWUI_LAYER_CACHE_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_LINE_H
#define ANDROID_UI_LINE_H
#ifndef ANDROID_HWUI_LINE_H
#define ANDROID_HWUI_LINE_H
#include <GLES2/gl2.h>
@@ -123,4 +123,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_LINE_H
#endif // ANDROID_HWUI_LINE_H

View File

@@ -271,6 +271,19 @@ void Matrix4::mapRect(Rect& r) const {
MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]);
MUL_ADD_STORE(r.top, data[kScaleY], data[kTranslateY]);
MUL_ADD_STORE(r.bottom, data[kScaleY], data[kTranslateY]);
if (r.left > r.right) {
float x = r.left;
r.left = r.right;
r.right = x;
}
if (r.top > r.bottom) {
float y = r.top;
r.top = r.bottom;
r.bottom = y;
}
return;
}

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_MATRIX_H
#define ANDROID_UI_MATRIX_H
#ifndef ANDROID_HWUI_MATRIX_H
#define ANDROID_HWUI_MATRIX_H
#include <SkMatrix.h>
@@ -137,4 +137,4 @@ typedef Matrix4 mat4;
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_MATRIX_H
#endif // ANDROID_HWUI_MATRIX_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_OPENGL_DEBUG_RENDERER_H
#define ANDROID_UI_OPENGL_DEBUG_RENDERER_H
#ifndef ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
#define ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
#include "OpenGLRenderer.h"
@@ -66,4 +66,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_OPENGL_DEBUG_RENDERER_H
#endif // ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H

View File

@@ -26,6 +26,8 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
#include <ui/Rect.h>
#include "OpenGLRenderer.h"
namespace android {
@@ -285,7 +287,7 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags) {
if (alpha == 0xff) {
if (alpha >= 255 - ALPHA_THRESHOLD) {
return saveLayer(left, top, right, bottom, NULL, flags);
} else {
SkPaint paint;
@@ -377,7 +379,6 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
bounds.getHeight() > mCaches.maxTextureSize) {
snapshot->invisible = true;
} else {
// TODO: Should take the mode into account
snapshot->invisible = snapshot->previous->invisible ||
(alpha <= ALPHA_THRESHOLD && fboLayer);
}
@@ -387,8 +388,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
return false;
}
glActiveTexture(GL_TEXTURE0);
glActiveTexture(gTextureUnits[0]);
Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
if (!layer) {
return false;
@@ -405,56 +405,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
snapshot->layer = layer;
if (fboLayer) {
layer->fbo = mCaches.fboCache.get();
snapshot->flags |= Snapshot::kFlagIsFboLayer;
snapshot->fbo = layer->fbo;
snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
snapshot->height = bounds.getHeight();
snapshot->flags |= Snapshot::kFlagDirtyOrtho;
snapshot->orthoMatrix.load(mOrthoMatrix);
// Bind texture to FBO
glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
glBindTexture(GL_TEXTURE_2D, layer->texture);
// Initialize the texture if needed
if (layer->empty) {
layer->empty = false;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
layer->texture, 0);
#if DEBUG_LAYERS
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
glDeleteTextures(1, &layer->texture);
mCaches.fboCache.put(layer->fbo);
delete layer;
return false;
}
#endif
// Clear the FBO
glScissor(0.0f, 0.0f, bounds.getWidth() + 1.0f, bounds.getHeight() + 1.0f);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
dirtyClip();
// Change the ortho projection
glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
return createFboLayer(layer, bounds, snapshot, previousFbo);
} else {
// Copy the framebuffer into the layer
glBindTexture(GL_TEXTURE_2D, layer->texture);
@@ -475,6 +426,82 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
return true;
}
bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
GLuint previousFbo) {
layer->fbo = mCaches.fboCache.get();
#if RENDER_LAYERS_AS_REGIONS
snapshot->region = &snapshot->layer->region;
snapshot->flags |= Snapshot::kFlagFboTarget;
#endif
Rect clip(bounds);
snapshot->transform->mapRect(clip);
clip.intersect(*snapshot->clipRect);
clip.snapToPixelBoundaries();
clip.intersect(snapshot->previous->viewport);
mat4 inverse;
inverse.loadInverse(*mSnapshot->transform);
inverse.mapRect(clip);
clip.snapToPixelBoundaries();
clip.intersect(bounds);
snapshot->flags |= Snapshot::kFlagIsFboLayer;
snapshot->fbo = layer->fbo;
snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
//snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
snapshot->height = bounds.getHeight();
snapshot->flags |= Snapshot::kFlagDirtyOrtho;
snapshot->orthoMatrix.load(mOrthoMatrix);
// Bind texture to FBO
glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
glBindTexture(GL_TEXTURE_2D, layer->texture);
// Initialize the texture if needed
if (layer->empty) {
layer->empty = false;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
layer->texture, 0);
#if DEBUG_LAYERS_AS_REGIONS
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
glDeleteTextures(1, &layer->texture);
mCaches.fboCache.put(layer->fbo);
delete layer;
return false;
}
#endif
// Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
glScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
dirtyClip();
// Change the ortho projection
glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
return true;
}
/**
* Read the documentation of createLayer() before doing anything in this method.
*/
@@ -484,42 +511,36 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
return;
}
const bool fboLayer = current->flags & SkCanvas::kClipToLayer_SaveFlag;
const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
if (fboLayer) {
// Unbind current FBO and restore previous one
glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
}
// Restore the clip from the previous snapshot
Rect& clip(*previous->clipRect);
clip.snapToPixelBoundaries();
glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight());
Layer* layer = current->layer;
const Rect& rect = layer->layer;
if (!fboLayer && layer->alpha < 255) {
drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
layer->alpha << 24, SkXfermode::kDstIn_Mode, true);
// Required below, composeLayerRect() will divide by 255
layer->alpha = 255;
}
const Rect& texCoords = layer->texCoords;
mCaches.unbindMeshBuffer();
resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
glActiveTexture(gTextureUnits[0]);
if (fboLayer) {
drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
&mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount);
} else {
drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
1.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
&mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, true, true);
}
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
// When the layer is stored in an FBO, we can save a bit of fillrate by
// drawing only the dirty region
if (fboLayer) {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
composeLayerRegion(layer, rect);
} else {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
composeLayerRect(layer, rect, true);
}
if (fboLayer) {
// Detach the texture from the FBO
@@ -541,6 +562,159 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
}
}
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
const Rect& texCoords = layer->texCoords;
resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
&mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
}
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
#if RENDER_LAYERS_AS_REGIONS
if (layer->region.isRect()) {
composeLayerRect(layer, rect);
layer->region.clear();
return;
}
if (!layer->region.isEmpty()) {
size_t count;
const android::Rect* rects = layer->region.getArray(&count);
setupDraw();
ProgramDescription description;
description.hasTexture = true;
const float alpha = layer->alpha / 255.0f;
const bool setColor = description.setColor(alpha, alpha, alpha, alpha);
chooseBlending(layer->blend || layer->alpha < 255, layer->mode, description, false);
useProgram(mCaches.programCache.get(description));
// Texture
bindTexture(layer->texture);
glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
// Always premultiplied
if (setColor) {
mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha);
}
// Mesh
int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
glEnableVertexAttribArray(texCoordsSlot);
mModelView.loadIdentity();
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
const float texX = 1.0f / float(layer->width);
const float texY = 1.0f / float(layer->height);
TextureVertex* mesh = mCaches.getRegionMesh();
GLsizei numQuads = 0;
glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
gMeshStride, &mesh[0].position[0]);
glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
gMeshStride, &mesh[0].texture[0]);
for (size_t i = 0; i < count; i++) {
const android::Rect* r = &rects[i];
const float u1 = r->left * texX;
const float v1 = (rect.getHeight() - r->top) * texY;
const float u2 = r->right * texX;
const float v2 = (rect.getHeight() - r->bottom) * texY;
// TODO: Reject quads outside of the clip
TextureVertex::set(mesh++, r->left, r->top, u1, v1);
TextureVertex::set(mesh++, r->right, r->top, u2, v1);
TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
numQuads++;
if (numQuads >= REGION_MESH_QUAD_COUNT) {
glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
numQuads = 0;
mesh = mCaches.getRegionMesh();
}
}
if (numQuads > 0) {
glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(texCoordsSlot);
#if DEBUG_LAYERS_AS_REGIONS
uint32_t colors[] = {
0x7fff0000, 0x7f00ff00,
0x7f0000ff, 0x7fff00ff,
};
int offset = 0;
int32_t top = rects[0].top;
int i = 0;
for (size_t i = 0; i < count; i++) {
if (top != rects[i].top) {
offset ^= 0x2;
top = rects[i].top;
}
Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
SkXfermode::kSrcOver_Mode);
}
#endif
layer->region.clear();
}
#else
composeLayerRect(layer, rect);
#endif
}
void OpenGLRenderer::dirtyLayer(const float left, const float top,
const float right, const float bottom, const mat4 transform) {
#if RENDER_LAYERS_AS_REGIONS
if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) {
Rect bounds(left, top, right, bottom);
transform.mapRect(bounds);
bounds.intersect(*mSnapshot->clipRect);
bounds.snapToPixelBoundaries();
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
if (!dirty.isEmpty()) {
mSnapshot->region->orSelf(dirty);
}
}
#endif
}
void OpenGLRenderer::dirtyLayer(const float left, const float top,
const float right, const float bottom) {
#if RENDER_LAYERS_AS_REGIONS
if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) {
Rect bounds(left, top, right, bottom);
bounds.intersect(*mSnapshot->clipRect);
bounds.snapToPixelBoundaries();
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
if (!dirty.isEmpty()) {
mSnapshot->region->orSelf(dirty);
}
}
#endif
}
void OpenGLRenderer::setupDraw() {
clearLayerRegions();
if (mDirtyClip) {
@@ -551,21 +725,26 @@ void OpenGLRenderer::setupDraw() {
void OpenGLRenderer::clearLayerRegions() {
if (mLayers.size() == 0 || mSnapshot->invisible) return;
Rect clipRect(*mSnapshot->clipRect);
clipRect.snapToPixelBoundaries();
for (uint32_t i = 0; i < mLayers.size(); i++) {
Rect* bounds = mLayers.itemAt(i);
if (clipRect.intersects(*bounds)) {
// Clear the framebuffer where the layer will draw
glScissor(bounds->left, mSnapshot->height - bounds->bottom,
bounds->getWidth(), bounds->getHeight());
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Clear the framebuffer where the layer will draw
glScissor(bounds->left, mSnapshot->height - bounds->bottom,
bounds->getWidth(), bounds->getHeight());
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Restore the clip
dirtyClip();
}
delete bounds;
}
mLayers.clear();
// Restore the clip
dirtyClip();
mLayers.clear();
}
///////////////////////////////////////////////////////////////////////////////
@@ -678,7 +857,12 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* pai
if (!texture) return;
const AutoTexture autoCleanup(texture);
drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
// This could be done in a cheaper way, all we need is pass the matrix
// to the vertex shader. The save/restore is a bit overkill.
save(SkCanvas::kMatrix_SaveFlag);
concatMatrix(matrix);
drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
restore();
}
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
@@ -738,11 +922,21 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int
right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
if (mesh) {
// Specify right and bottom as +1.0f from left/top to prevent scaling since the
// patch mesh already defines the final size
drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
// Mark the current layer dirty where we are going to draw the patch
if ((mSnapshot->flags & Snapshot::kFlagFboTarget) &&
mSnapshot->region && mesh->hasEmptyQuads) {
const size_t count = mesh->quads.size();
for (size_t i = 0; i < count; i++) {
Rect bounds = mesh->quads.itemAt(i);
dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
*mSnapshot->transform);
}
}
drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer);
GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
true, !mesh->hasEmptyQuads);
}
}
@@ -801,6 +995,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
mModelView.scale(length, strokeWidth, 1.0f);
}
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
// TODO: Add bounds to the layer's region
if (mShader) {
mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot);
@@ -904,13 +1099,34 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
// Assume that the modelView matrix does not force scales, rotates, etc.
const bool linearFilter = mSnapshot->transform->changesBounds();
// Dimensions are set to (0,0), the layer (if any) won't be dirtied
setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit,
x, y, r, g, b, a, mode, false, true, NULL, NULL);
const Rect& clip = mSnapshot->getLocalClip();
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
#if RENDER_LAYERS_AS_REGIONS
bool hasLayer = (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
#else
bool hasLayer = false;
#endif
mCaches.unbindMeshBuffer();
fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
if (fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y,
hasLayer ? &bounds : NULL)) {
#if RENDER_LAYERS_AS_REGIONS
if (hasLayer) {
mSnapshot->transform->mapRect(bounds);
bounds.intersect(*mSnapshot->clipRect);
bounds.snapToPixelBoundaries();
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
mSnapshot->region->orSelf(dirty);
}
#endif
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
@@ -1081,7 +1297,12 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t
} else {
mModelView.loadIdentity();
}
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
if (width > 0 && height > 0) {
dirtyLayer(x, y, x + width, y + height, *mSnapshot->transform);
}
if (setColor) {
mCaches.currentProgram->setColor(r, g, b, a);
}
@@ -1214,9 +1435,11 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo
mModelView.scale(right - left, bottom - top, 1.0f);
if (!ignoreTransform) {
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
} else {
mat4 identity;
mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
dirtyLayer(left, top, right, bottom);
}
mCaches.currentProgram->setColor(r, g, b, a);
@@ -1251,7 +1474,7 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool swapSrcDst, bool ignoreTransform, GLuint vbo) {
bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
setupDraw();
ProgramDescription description;
@@ -1262,16 +1485,20 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
}
mModelView.loadTranslate(left, top, 0.0f);
mModelView.scale(right - left, bottom - top, 1.0f);
if (!ignoreScale) {
mModelView.scale(right - left, bottom - top, 1.0f);
}
chooseBlending(blend || alpha < 1.0f, mode, description, swapSrcDst);
useProgram(mCaches.programCache.get(description));
if (!ignoreTransform) {
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
if (dirty) dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
} else {
mat4 m;
mCaches.currentProgram->set(mOrthoMatrix, mModelView, m);
mat4 identity;
mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
if (dirty) dirtyLayer(left, top, right, bottom);
}
// Texture

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_OPENGL_RENDERER_H
#define ANDROID_UI_OPENGL_RENDERER_H
#ifndef ANDROID_HWUI_OPENGL_RENDERER_H
#define ANDROID_HWUI_OPENGL_RENDERER_H
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -50,6 +50,10 @@ namespace uirenderer {
// Debug
#define DEBUG_OPENGL 1
// If turned on, layers drawn inside FBOs are optimized with regions
#define RENDER_LAYERS_AS_REGIONS 0
#define DEBUG_LAYERS_AS_REGIONS 0
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
@@ -175,6 +179,34 @@ private:
bool createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo);
/**
* Creates a new layer stored in the specified snapshot as an FBO.
*
* @param layer The layer to store as an FBO
* @param snapshot The snapshot associated with the new layer
* @param bounds The bounds of the layer
* @param previousFbo The name of the current framebuffer
*/
bool createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
GLuint previousFbo);
/**
* Compose the specified layer as a region.
*
* @param layer The layer to compose
* @param rect The layer's bounds
*/
void composeLayerRegion(Layer* layer, const Rect& rect);
/**
* Compose the specified layer as a simple rectangle.
*
* @param layer The layer to compose
* @param rect The layer's bounds
* @param swap If true, the source and destination are swapped
*/
void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
/**
* Clears all the regions corresponding to the current list of layers.
* This method MUST be invoked before any drawing operation.
@@ -192,7 +224,7 @@ private:
* @param color The rectangle's ARGB color, defined as a packed 32 bits word
* @param mode The Skia xfermode to use
* @param ignoreTransform True if the current transform should be ignored
* @paran ignoreBlending True if the blending is set by the caller
* @param ignoreBlending True if the blending is set by the caller
*/
void drawColorRect(float left, float top, float right, float bottom,
int color, SkXfermode::Mode mode, bool ignoreTransform = false);
@@ -252,11 +284,14 @@ private:
* @param swapSrcDst Whether or not the src and dst blending operations should be swapped
* @param ignoreTransform True if the current transform should be ignored
* @param vbo The VBO used to draw the mesh
* @param ignoreScale True if the model view matrix should not be scaled
* @param dirty True if calling this method should dirty the current layer
*/
void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
float alpha, SkXfermode::Mode mode, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0);
bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
bool ignoreScale = false, bool dirty = true);
/**
* Prepares the renderer to draw the specified shadow. The active texture
@@ -411,6 +446,18 @@ private:
mDirtyClip = true;
}
/**
* Mark the layer as dirty at the specified coordinates. The coordinates
* are transformed with the supplied matrix.
*/
void dirtyLayer(const float left, const float top, const float right, const float bottom,
const mat4 transform);
/**
* Mark the layer as dirty at the specified coordinates.
*/
void dirtyLayer(const float left, const float top, const float right, const float bottom);
// Dimensions of the drawing surface
int mWidth, mHeight;
@@ -462,4 +509,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_OPENGL_RENDERER_H
#endif // ANDROID_HWUI_OPENGL_RENDERER_H

View File

@@ -34,6 +34,7 @@ Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQua
// 2 triangles per patch, 3 vertices per triangle
verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
mVertices = new TextureVertex[verticesCount];
hasEmptyQuads = emptyQuads > 0;
glGenBuffers(1, &meshBuffer);
}
@@ -51,6 +52,8 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
float left, float top, float right, float bottom,
const int32_t* xDivs, const int32_t* yDivs,
const uint32_t width, const uint32_t height, const uint32_t colorKey) {
if (hasEmptyQuads) quads.clear();
const uint32_t xStretchCount = (width + 1) >> 1;
const uint32_t yStretchCount = (height + 1) >> 1;
@@ -118,7 +121,7 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
mVertices, GL_STATIC_DRAW);
}
inline void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
const int32_t xDivs[], uint32_t xCount, float stretchX, float width, float bitmapWidth,
uint32_t& quadCount, const uint32_t colorKey) {
float previousStepX = 0.0f;
@@ -150,12 +153,17 @@ inline void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float
generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount, colorKey);
}
inline void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
float u1, float v1, float u2, float v2, uint32_t& quadCount, const uint32_t colorKey) {
if (((colorKey >> quadCount++) & 0x1) == 1) {
return;
}
if (hasEmptyQuads) {
Rect bounds(x1, y1, x2, y2);
quads.add(bounds);
}
// Left triangle
TextureVertex::set(vertex++, x1, y1, u1, v1);
TextureVertex::set(vertex++, x2, y1, u2, v1);

View File

@@ -14,13 +14,16 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_PATCH_H
#define ANDROID_UI_PATCH_H
#ifndef ANDROID_HWUI_PATCH_H
#define ANDROID_HWUI_PATCH_H
#include <sys/types.h>
#include <GLES2/gl2.h>
#include <utils/Vector.h>
#include "Rect.h"
#include "Vertex.h"
#include "utils/Compare.h"
@@ -96,15 +99,17 @@ struct Patch {
GLuint meshBuffer;
uint32_t verticesCount;
Vector<Rect> quads;
bool hasEmptyQuads;
private:
TextureVertex* mVertices;
static inline void generateRow(TextureVertex*& vertex, float y1, float y2,
void generateRow(TextureVertex*& vertex, float y1, float y2,
float v1, float v2, const int32_t xDivs[], uint32_t xCount,
float stretchX, float width, float bitmapWidth,
uint32_t& quadCount, const uint32_t colorKey);
static inline void generateQuad(TextureVertex*& vertex,
void generateQuad(TextureVertex*& vertex,
float x1, float y1, float x2, float y2,
float u1, float v1, float u2, float v2,
uint32_t& quadCount, const uint32_t colorKey);
@@ -113,4 +118,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_PATCH_H
#endif // ANDROID_HWUI_PATCH_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_PATCH_CACHE_H
#define ANDROID_UI_PATCH_CACHE_H
#ifndef ANDROID_HWUI_PATCH_CACHE_H
#define ANDROID_HWUI_PATCH_CACHE_H
#include <utils/KeyedVector.h>
@@ -62,4 +62,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_PATCH_CACHE_H
#endif // ANDROID_HWUI_PATCH_CACHE_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_PATH_CACHE_H
#define ANDROID_UI_PATH_CACHE_H
#ifndef ANDROID_HWUI_PATH_CACHE_H
#define ANDROID_HWUI_PATH_CACHE_H
#include <SkBitmap.h>
#include <SkPaint.h>
@@ -170,4 +170,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_PATH_CACHE_H
#endif // ANDROID_HWUI_PATH_CACHE_H

View File

@@ -21,12 +21,6 @@
namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
// Shaders
///////////////////////////////////////////////////////////////////////////////
#define SHADER_SOURCE(name, source) const char* name = #source
///////////////////////////////////////////////////////////////////////////////
// Base program
///////////////////////////////////////////////////////////////////////////////

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_PROGRAM_H
#define ANDROID_UI_PROGRAM_H
#ifndef ANDROID_HWUI_PROGRAM_H
#define ANDROID_HWUI_PROGRAM_H
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -131,4 +131,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_PROGRAM_H
#endif // ANDROID_HWUI_PROGRAM_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_PROGRAM_CACHE_H
#define ANDROID_UI_PROGRAM_CACHE_H
#ifndef ANDROID_HWUI_PROGRAM_CACHE_H
#define ANDROID_HWUI_PROGRAM_CACHE_H
#include <utils/KeyedVector.h>
#include <utils/Log.h>
@@ -258,4 +258,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_PROGRAM_CACHE_H
#endif // ANDROID_HWUI_PROGRAM_CACHE_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_PROPERTIES_H
#define ANDROID_UI_PROPERTIES_H
#ifndef ANDROID_HWUI_PROPERTIES_H
#define ANDROID_HWUI_PROPERTIES_H
#include <cutils/properties.h>
@@ -45,15 +45,15 @@
#define MB(s) s * 1024 * 1024
#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f
#define DEFAULT_LAYER_CACHE_SIZE 6.0f
#define DEFAULT_LAYER_CACHE_SIZE 8.0f
#define DEFAULT_PATH_CACHE_SIZE 4.0f
#define DEFAULT_PATCH_CACHE_SIZE 512
#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
#define DEFAULT_FBO_CACHE_SIZE 25
#define DEFAULT_FBO_CACHE_SIZE 12
#define DEFAULT_TEXT_GAMMA 1.4f
#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
#endif // ANDROID_UI_PROPERTIES_H
#endif // ANDROID_HWUI_PROPERTIES_H

View File

@@ -14,8 +14,10 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_RECT_H
#define ANDROID_UI_RECT_H
#ifndef ANDROID_HWUI_RECT_H
#define ANDROID_HWUI_RECT_H
#include <cmath>
#include <utils/Log.h>
@@ -32,25 +34,35 @@ struct Rect {
float right;
float bottom;
Rect():
// Used by Region
typedef float value_type;
inline Rect():
left(0),
top(0),
right(0),
bottom(0) {
}
Rect(float left, float top, float right, float bottom):
inline Rect(float left, float top, float right, float bottom):
left(left),
top(top),
right(right),
bottom(bottom) {
}
Rect(const Rect& r) {
inline Rect(float width, float height):
left(0.0f),
top(0.0f),
right(width),
bottom(height) {
}
inline Rect(const Rect& r) {
set(r);
}
Rect(Rect& r) {
inline Rect(Rect& r) {
set(r);
}
@@ -72,22 +84,26 @@ struct Rect {
return memcmp(&a, &b, sizeof(a));
}
bool isEmpty() const {
inline void clear() {
left = top = right = bottom = 0.0f;
}
inline bool isEmpty() const {
return left >= right || top >= bottom;
}
void setEmpty() {
memset(this, 0, sizeof(*this));
inline void setEmpty() {
left = top = right = bottom = 0.0f;
}
void set(float left, float top, float right, float bottom) {
inline void set(float left, float top, float right, float bottom) {
this->left = left;
this->right = right;
this->top = top;
this->bottom = bottom;
}
void set(const Rect& r) {
inline void set(const Rect& r) {
set(r.left, r.top, r.right, r.bottom);
}
@@ -148,6 +164,13 @@ struct Rect {
return false;
}
void translate(float dx, float dy) {
left += dx;
right += dx;
top += dy;
bottom += dy;
}
void snapToPixelBoundaries() {
left = floorf(left + 0.5f);
top = floorf(top + 0.5f);
@@ -164,4 +187,4 @@ struct Rect {
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_RECT_H
#endif // ANDROID_HWUI_RECT_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_RESOURCE_CACHE_H
#define ANDROID_UI_RESOURCE_CACHE_H
#ifndef ANDROID_HWUI_RESOURCE_CACHE_H
#define ANDROID_HWUI_RESOURCE_CACHE_H
#include <SkBitmap.h>
#include <SkiaColorFilter.h>
@@ -75,4 +75,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_RESOURCE_CACHE_H
#endif // ANDROID_HWUI_RESOURCE_CACHE_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_SKIA_COLOR_FILTER_H
#define ANDROID_UI_SKIA_COLOR_FILTER_H
#ifndef ANDROID_HWUI_SKIA_COLOR_FILTER_H
#define ANDROID_HWUI_SKIA_COLOR_FILTER_H
#include <GLES2/gl2.h>
#include <SkColorFilter.h>
@@ -123,4 +123,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_SKIA_COLOR_FILTER_H
#endif // ANDROID_HWUI_SKIA_COLOR_FILTER_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_SKIA_SHADER_H
#define ANDROID_UI_SKIA_SHADER_H
#ifndef ANDROID_HWUI_SKIA_SHADER_H
#define ANDROID_HWUI_SKIA_SHADER_H
#include <SkShader.h>
#include <SkXfermode.h>
@@ -216,4 +216,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_SKIA_SHADER_H
#endif // ANDROID_HWUI_SKIA_SHADER_H

View File

@@ -14,16 +14,16 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_SNAPSHOT_H
#define ANDROID_UI_SNAPSHOT_H
#ifndef ANDROID_HWUI_SNAPSHOT_H
#define ANDROID_HWUI_SNAPSHOT_H
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <utils/RefBase.h>
#include <ui/Region.h>
#include <SkCanvas.h>
#include <SkRegion.h>
#include "Layer.h"
#include "Matrix.h"
@@ -46,6 +46,7 @@ public:
Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false) {
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
region = NULL;
}
/**
@@ -75,6 +76,13 @@ public:
} else {
flags |= Snapshot::kFlagDirtyLocalClip;
}
if (s->flags & Snapshot::kFlagFboTarget) {
flags |= Snapshot::kFlagFboTarget;
region = s->region;
} else {
region = NULL;
}
}
/**
@@ -105,6 +113,11 @@ public:
* Indicates that this snapshot has changed the ortho matrix.
*/
kFlagDirtyOrtho = 0x10,
/**
* Indicates that this snapshot or an ancestor snapshot is
* an FBO layer.
*/
kFlagFboTarget = 0x20
};
/**
@@ -243,6 +256,11 @@ public:
*/
Rect* clipRect;
/**
* The ancestor layer's dirty region..
*/
Region* region;
private:
mat4 mTransformRoot;
Rect mClipRectRoot;
@@ -253,4 +271,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_SNAPSHOT_H
#endif // ANDROID_HWUI_SNAPSHOT_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
#define ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
#ifndef ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
#define ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
#include <GLES2/gl2.h>
@@ -148,4 +148,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
#endif // ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_TEXTURE_H
#define ANDROID_UI_TEXTURE_H
#ifndef ANDROID_HWUI_TEXTURE_H
#define ANDROID_HWUI_TEXTURE_H
#include <GLES2/gl2.h>
@@ -86,4 +86,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_TEXTURE_H
#endif // ANDROID_HWUI_TEXTURE_H

View File

@@ -200,9 +200,13 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege
texture->blend = !bitmap->isOpaque();
break;
case SkBitmap::kIndex8_Config:
uploadPalettedTexture(resize, bitmap, texture->width, texture->height);
uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
texture->blend = false;
break;
case SkBitmap::kARGB_4444_Config:
uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
texture->blend = true;
break;
default:
LOGW("Unsupported bitmap config: %d", bitmap->getConfig());
break;
@@ -215,7 +219,7 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
void TextureCache::uploadPalettedTexture(bool resize, SkBitmap* bitmap,
void TextureCache::uploadLoFiTexture(bool resize, SkBitmap* bitmap,
uint32_t width, uint32_t height) {
SkBitmap rgbaBitmap;
rgbaBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_TEXTURE_CACHE_H
#define ANDROID_UI_TEXTURE_CACHE_H
#ifndef ANDROID_HWUI_TEXTURE_CACHE_H
#define ANDROID_HWUI_TEXTURE_CACHE_H
#include <SkBitmap.h>
@@ -93,7 +93,7 @@ private:
*/
void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
void uploadPalettedTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
void uploadLoFiTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
void uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
GLenum type, const GLvoid * data);
@@ -115,4 +115,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_TEXTURE_CACHE_H
#endif // ANDROID_HWUI_TEXTURE_CACHE_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_VERTEX_H
#define ANDROID_UI_VERTEX_H
#ifndef ANDROID_HWUI_VERTEX_H
#define ANDROID_HWUI_VERTEX_H
namespace android {
namespace uirenderer {
@@ -43,4 +43,4 @@ struct TextureVertex {
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_VERTEX_H
#endif // ANDROID_HWUI_VERTEX_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_COMPARE_H
#define ANDROID_UI_COMPARE_H
#ifndef ANDROID_HWUI_COMPARE_H
#define ANDROID_HWUI_COMPARE_H
#include <cmath>
@@ -37,4 +37,4 @@
if (a < rhs.a) return true; \
if (a == rhs.a)
#endif // ANDROID_UI_COMPARE_H
#endif // ANDROID_HWUI_COMPARE_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_GENERATION_CACHE_H
#define ANDROID_UI_GENERATION_CACHE_H
#ifndef ANDROID_HWUI_GENERATION_CACHE_H
#define ANDROID_HWUI_GENERATION_CACHE_H
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -242,4 +242,4 @@ void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) {
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_GENERATION_CACHE_H
#endif // ANDROID_HWUI_GENERATION_CACHE_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_SORTED_LIST_H
#define ANDROID_UI_SORTED_LIST_H
#ifndef ANDROID_HWUI_SORTED_LIST_H
#define ANDROID_HWUI_SORTED_LIST_H
#include <stdint.h>
#include <sys/types.h>
@@ -239,4 +239,4 @@ int SortedList<TYPE>::do_compare(const void* lhs, const void* rhs) const {
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_SORTED_LIST_H
#endif // ANDROID_HWUI_SORTED_LIST_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef ANDROID_UI_SORTED_LIST_IMPL_H
#define ANDROID_UI_SORTED_LIST_IMPL_H
#ifndef ANDROID_HWUI_SORTED_LIST_IMPL_H
#define ANDROID_HWUI_SORTED_LIST_IMPL_H
#include <utils/VectorImpl.h>
@@ -62,4 +62,4 @@ private:
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_UI_SORTED_LIST_IMPL_H
#endif // ANDROID_HWUI_SORTED_LIST_IMPL_H

View File

@@ -289,7 +289,7 @@ private:
void flushSpan() {
bool merge = false;
if (tail-head == ssize_t(span.size())) {
Rect const* p = cur;
Rect const* p = span.editArray();
Rect const* q = head;
if (p->top == q->bottom) {
merge = true;