summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2011-07-07 20:55:08 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-07-07 20:55:08 -0700
commit69abbd8791f57f39a861c6f569da2f712bb6b5db (patch)
treed8d4ce3c11d5fe99468a77126ce473ba310016e7 /libs
parent4a6d113ba0f33ce5dc14e59463e928ba309e1c2e (diff)
parent9ace8f5e79e76893fe4ca9e4d10f6c4056330485 (diff)
downloadframeworks_base-69abbd8791f57f39a861c6f569da2f712bb6b5db.zip
frameworks_base-69abbd8791f57f39a861c6f569da2f712bb6b5db.tar.gz
frameworks_base-69abbd8791f57f39a861c6f569da2f712bb6b5db.tar.bz2
Merge "Use NEAREST filtering for layers whenever possible."
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Layer.h231
-rw-r--r--libs/hwui/LayerCache.cpp50
-rw-r--r--libs/hwui/LayerCache.h2
-rw-r--r--libs/hwui/LayerRenderer.cpp124
-rw-r--r--libs/hwui/OpenGLRenderer.cpp156
-rw-r--r--libs/hwui/Texture.h20
6 files changed, 381 insertions, 202 deletions
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 0310bc3..3c2d80d 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -27,6 +27,7 @@
#include "Rect.h"
#include "SkiaColorFilter.h"
+#include "Texture.h"
#include "Vertex.h"
namespace android {
@@ -40,14 +41,18 @@ namespace uirenderer {
* A layer has dimensions and is backed by an OpenGL texture or FBO.
*/
struct Layer {
- Layer(const uint32_t layerWidth, const uint32_t layerHeight):
- width(layerWidth), height(layerHeight) {
+ Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
mesh = NULL;
meshIndices = NULL;
meshElementCount = 0;
- isCacheable = true;
- isTextureLayer = false;
+ cacheable = true;
+ textureLayer = false;
renderTarget = GL_TEXTURE_2D;
+ texture.width = layerWidth;
+ texture.height = layerHeight;
+ colorFilter = NULL;
+ firstFilter = true;
+ firstWrap = true;
}
~Layer() {
@@ -64,12 +69,152 @@ struct Layer {
regionRect.set(bounds.leftTop().x, bounds.leftTop().y,
bounds.rightBottom().x, bounds.rightBottom().y);
- const float texX = 1.0f / float(width);
- const float texY = 1.0f / float(height);
+ const float texX = 1.0f / float(texture.width);
+ const float texY = 1.0f / float(texture.height);
const float height = layer.getHeight();
texCoords.set(
regionRect.left * texX, (height - regionRect.top) * texY,
regionRect.right * texX, (height - regionRect.bottom) * texY);
+
+ regionRect.translate(layer.left, layer.top);
+ }
+
+ inline uint32_t getWidth() {
+ return texture.width;
+ }
+
+ inline uint32_t getHeight() {
+ return texture.height;
+ }
+
+ void setSize(uint32_t width, uint32_t height) {
+ texture.width = width;
+ texture.height = height;
+ }
+
+ inline void setBlend(bool blend) {
+ texture.blend = blend;
+ }
+
+ inline bool isBlend() {
+ return texture.blend;
+ }
+
+ inline void setAlpha(int alpha) {
+ this->alpha = alpha;
+ }
+
+ inline void setAlpha(int alpha, SkXfermode::Mode mode) {
+ this->alpha = alpha;
+ this->mode = mode;
+ }
+
+ inline int getAlpha() {
+ return alpha;
+ }
+
+ inline SkXfermode::Mode getMode() {
+ return mode;
+ }
+
+ inline void setEmpty(bool empty) {
+ this->empty = empty;
+ }
+
+ inline bool isEmpty() {
+ return empty;
+ }
+
+ inline void setFbo(GLuint fbo) {
+ this->fbo = fbo;
+ }
+
+ inline GLuint getFbo() {
+ return fbo;
+ }
+
+ inline GLuint* getTexturePointer() {
+ return &texture.id;
+ }
+
+ inline GLuint getTexture() {
+ return texture.id;
+ }
+
+ inline GLenum getRenderTarget() {
+ return renderTarget;
+ }
+
+ inline void setRenderTarget(GLenum renderTarget) {
+ this->renderTarget = renderTarget;
+ }
+
+ void setWrap(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false) {
+ if (firstWrap || force || wrapS != texture.wrapS || wrapT != texture.wrapT) {
+ firstWrap = true;
+ texture.setWrap(wrapS, wrapT);
+ if (bindTexture) {
+ glBindTexture(renderTarget, texture.id);
+ }
+ glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
+ glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT);
+ }
+ }
+
+ void setFilter(GLenum min, GLenum mag, bool bindTexture = false, bool force = false) {
+ if (firstFilter || force || min != texture.minFilter || mag != texture.magFilter) {
+ firstFilter = false;
+ texture.setFilter(min, mag);
+ if (bindTexture) {
+ glBindTexture(renderTarget, texture.id);
+ }
+ glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min);
+ glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag);
+ }
+ }
+
+ inline bool isCacheable() {
+ return cacheable;
+ }
+
+ inline void setCacheable(bool cacheable) {
+ this->cacheable = cacheable;
+ }
+
+ inline bool isTextureLayer() {
+ return textureLayer;
+ }
+
+ inline void setTextureLayer(bool textureLayer) {
+ this->textureLayer = textureLayer;
+ }
+
+ inline SkiaColorFilter* getColorFilter() {
+ return colorFilter;
+ }
+
+ inline void setColorFilter(SkiaColorFilter* filter) {
+ colorFilter = filter;
+ }
+
+ inline void bindTexture() {
+ glBindTexture(renderTarget, texture.id);
+ }
+
+ inline void generateTexture() {
+ glGenTextures(1, &texture.id);
+ }
+
+ inline void deleteTexture() {
+ if (texture.id) glDeleteTextures(1, &texture.id);
+ }
+
+ inline void allocateTexture(GLenum format, GLenum storage) {
+ glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL);
+ }
+
+ inline mat4& getTexTransform() {
+ return texTransform;
}
/**
@@ -82,23 +227,29 @@ struct Layer {
Rect texCoords;
/**
- * Name of the FBO used to render the layer. If the name is 0
- * this layer is not backed by an FBO, but a simple texture.
+ * Dirty region indicating what parts of the layer
+ * have been drawn.
*/
- GLuint fbo;
-
+ Region region;
/**
- * Opacity of the layer.
+ * If the region is a rectangle, coordinates of the
+ * region are stored here.
*/
- int alpha;
+ Rect regionRect;
+
/**
- * Blending mode of the layer.
+ * If the layer can be rendered as a mesh, this is non-null.
*/
- SkXfermode::Mode mode;
+ TextureVertex* mesh;
+ uint16_t* meshIndices;
+ GLsizei meshElementCount;
+
+private:
/**
- * Indicates whether this layer should be blended.
+ * Name of the FBO used to render the layer. If the name is 0
+ * this layer is not backed by an FBO, but a simple texture.
*/
- bool blend;
+ GLuint fbo;
/**
* Indicates whether this layer has been used already.
@@ -106,28 +257,25 @@ struct Layer {
bool empty;
/**
- * Name of the texture used to render the layer.
- */
- GLuint texture;
- /**
- * Width of the layer texture.
+ * The texture backing this layer.
*/
- uint32_t width;
+ Texture texture;
+
/**
- * Height of the layer texture.
+ * If set to true (by default), the layer can be reused.
*/
- uint32_t height;
+ bool cacheable;
/**
- * Dirty region indicating what parts of the layer
- * have been drawn.
+ * When set to true, this layer must be treated as a texture
+ * layer.
*/
- Region region;
+ bool textureLayer;
+
/**
- * If the region is a rectangle, coordinates of the
- * region are stored here.
+ * Indicates the render target.
*/
- Rect regionRect;
+ GLenum renderTarget;
/**
* Color filter used to draw this layer. Optional.
@@ -135,32 +283,21 @@ struct Layer {
SkiaColorFilter* colorFilter;
/**
- * If the layer can be rendered as a mesh, this is non-null.
- */
- TextureVertex* mesh;
- uint16_t* meshIndices;
- GLsizei meshElementCount;
-
- /**
- * If set to true (by default), the layer can be reused.
+ * Opacity of the layer.
*/
- bool isCacheable;
-
+ int alpha;
/**
- * When set to true, this layer must be treated as a texture
- * layer.
+ * Blending mode of the layer.
*/
- bool isTextureLayer;
+ SkXfermode::Mode mode;
/**
* Optional texture coordinates transform.
*/
mat4 texTransform;
- /**
- * Indicates the render target.
- */
- GLenum renderTarget;
+ bool firstFilter;
+ bool firstWrap;
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index b2d795f..1a15e87 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -68,8 +68,8 @@ void LayerCache::setMaxSize(uint32_t maxSize) {
void LayerCache::deleteLayer(Layer* layer) {
if (layer) {
- mSize -= layer->width * layer->height * 4;
- glDeleteTextures(1, &layer->texture);
+ mSize -= layer->getWidth() * layer->getHeight() * 4;
+ layer->deleteTexture();
delete layer;
}
}
@@ -93,29 +93,23 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) {
mCache.removeAt(index);
layer = entry.mLayer;
- mSize -= layer->width * layer->height * 4;
+ mSize -= layer->getWidth() * layer->getHeight() * 4;
- LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height);
+ LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
} else {
LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
layer = new Layer(entry.mWidth, entry.mHeight);
- layer->blend = true;
- layer->empty = true;
- layer->fbo = 0;
- layer->colorFilter = NULL;
-
- glGenTextures(1, &layer->texture);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
-
+ layer->setBlend(true);
+ layer->setEmpty(true);
+ layer->setFbo(0);
+
+ layer->generateTexture();
+ layer->bindTexture();
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
#if DEBUG_LAYERS
size_t size = mCache.size();
for (size_t i = 0; i < size; i++) {
@@ -133,30 +127,30 @@ bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t heigh
// size already in the cache, and reuse it instead of creating a new one
LayerEntry entry(width, height);
- if (entry.mWidth <= layer->width && entry.mHeight <= layer->height) {
+ if (entry.mWidth <= layer->getWidth() && entry.mHeight <= layer->getHeight()) {
return true;
}
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ uint32_t oldWidth = layer->getWidth();
+ uint32_t oldHeight = layer->getHeight();
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glActiveTexture(GL_TEXTURE0);
+ layer->bindTexture();
+ layer->setSize(entry.mWidth, entry.mHeight);
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
if (glGetError() != GL_NO_ERROR) {
+ layer->setSize(oldWidth, oldHeight);
return false;
}
- layer->width = entry.mWidth;
- layer->height = entry.mHeight;
-
return true;
}
bool LayerCache::put(Layer* layer) {
- if (!layer->isCacheable) return false;
+ if (!layer->isCacheable()) return false;
- const uint32_t size = layer->width * layer->height * 4;
+ const uint32_t size = layer->getWidth() * layer->getHeight() * 4;
// Don't even try to cache a layer that's bigger than the cache
if (size < mMaxSize) {
// TODO: Use an LRU
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index d2d5f39..81b8bf3 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -119,7 +119,7 @@ private:
}
LayerEntry(Layer* layer):
- mLayer(layer), mWidth(layer->width), mHeight(layer->height) {
+ mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) {
}
bool operator<(const LayerEntry& rhs) const {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e034a86..44f2a40 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -32,9 +32,9 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
- LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
+ LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
- glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo());
const float width = mLayer->layer.getWidth();
const float height = mLayer->layer.getHeight();
@@ -62,14 +62,14 @@ void LayerRenderer::finish() {
generateMesh();
- LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->fbo);
+ LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->getFbo());
// No need to unbind our FBO, this will be taken care of by the caller
// who will invoke OpenGLRenderer::resume()
}
GLint LayerRenderer::getTargetFbo() {
- return mLayer->fbo;
+ return mLayer->getFbo();
}
///////////////////////////////////////////////////////////////////////////////
@@ -128,8 +128,8 @@ void LayerRenderer::generateMesh() {
}
mLayer->meshElementCount = elementCount;
- const float texX = 1.0f / float(mLayer->width);
- const float texY = 1.0f / float(mLayer->height);
+ const float texX = 1.0f / float(mLayer->getWidth());
+ const float texY = 1.0f / float(mLayer->getHeight());
const float height = mLayer->layer.getHeight();
TextureVertex* mesh = mLayer->mesh;
@@ -182,40 +182,41 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque
return NULL;
}
- layer->fbo = fbo;
+ layer->setFbo(fbo);
layer->layer.set(0.0f, 0.0f, width, height);
- layer->texCoords.set(0.0f, height / float(layer->height),
- width / float(layer->width), 0.0f);
- layer->alpha = 255;
- layer->mode = SkXfermode::kSrcOver_Mode;
- layer->blend = !isOpaque;
- layer->colorFilter = NULL;
+ layer->texCoords.set(0.0f, height / float(layer->getHeight()),
+ width / float(layer->getWidth()), 0.0f);
+ layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
+ layer->setBlend(!isOpaque);
+ layer->setColorFilter(NULL);
layer->region.clear();
GLuint previousFbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
- glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
+ layer->bindTexture();
// 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);
+ if (layer->isEmpty()) {
+ layer->setEmpty(false);
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
if (glGetError() != GL_NO_ERROR) {
LOGD("Could not allocate texture");
+
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- glDeleteTextures(1, &layer->texture);
Caches::getInstance().fboCache.put(fbo);
+
+ layer->deleteTexture();
delete layer;
+
return NULL;
}
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- layer->texture, 0);
+ layer->getTexture(), 0);
glDisable(GL_SCISSOR_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -229,14 +230,14 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque
bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
if (layer) {
- LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->fbo, width, height);
+ LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height);
if (Caches::getInstance().layerCache.resize(layer, width, height)) {
layer->layer.set(0.0f, 0.0f, width, height);
- layer->texCoords.set(0.0f, height / float(layer->height),
- width / float(layer->width), 0.0f);
+ layer->texCoords.set(0.0f, height / float(layer->getHeight()),
+ width / float(layer->getWidth()), 0.0f);
} else {
- if (layer->texture) glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
return false;
}
@@ -245,37 +246,23 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
return true;
}
-static void setTextureParameters(Layer* layer) {
- glBindTexture(layer->renderTarget, layer->texture);
-
- glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-}
-
Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
LAYER_RENDERER_LOGD("Creating new texture layer");
Layer* layer = new Layer(0, 0);
- layer->isCacheable = false;
- layer->isTextureLayer = true;
- layer->blend = !isOpaque;
- layer->empty = true;
- layer->fbo = 0;
- layer->colorFilter = NULL;
- layer->fbo = 0;
+ layer->setCacheable(false);
+ layer->setTextureLayer(true);
+ layer->setBlend(!isOpaque);
+ layer->setEmpty(true);
+ layer->setFbo(0);
+ layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f);
- layer->alpha = 255;
- layer->mode = SkXfermode::kSrcOver_Mode;
- layer->colorFilter = NULL;
layer->region.clear();
- layer->renderTarget = GL_NONE; // see ::updateTextureLayer()
+ layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
glActiveTexture(GL_TEXTURE0);
- glGenTextures(1, &layer->texture);
+ layer->generateTexture();
return layer;
}
@@ -283,31 +270,32 @@ Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
bool isOpaque, GLenum renderTarget, float* transform) {
if (layer) {
- layer->blend = !isOpaque;
- layer->width = width;
- layer->height = height;
+ layer->setBlend(!isOpaque);
+ layer->setSize(width, height);
layer->layer.set(0.0f, 0.0f, width, height);
layer->region.set(width, height);
layer->regionRect.set(0.0f, 0.0f, width, height);
- layer->texTransform.load(transform);
+ layer->getTexTransform().load(transform);
- if (renderTarget != layer->renderTarget) {
- layer->renderTarget = renderTarget;
- setTextureParameters(layer);
+ if (renderTarget != layer->getRenderTarget()) {
+ layer->setRenderTarget(renderTarget);
+ layer->bindTexture();
+ layer->setFilter(GL_NEAREST, GL_NEAREST, false, true);
+ layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, false, true);
}
}
}
void LayerRenderer::destroyLayer(Layer* layer) {
if (layer) {
- LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo);
+ LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->getFbo());
- if (layer->fbo) {
- Caches::getInstance().fboCache.put(layer->fbo);
+ if (layer->getFbo()) {
+ Caches::getInstance().fboCache.put(layer->getFbo());
}
if (!Caches::getInstance().layerCache.put(layer)) {
- if (layer->texture) glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
} else {
layer->region.clear();
@@ -317,7 +305,7 @@ void LayerRenderer::destroyLayer(Layer* layer) {
void LayerRenderer::destroyLayerDeferred(Layer* layer) {
if (layer) {
- LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->fbo);
+ LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo());
Caches::getInstance().deleteLayerDeferred(layer);
}
@@ -325,7 +313,7 @@ void LayerRenderer::destroyLayerDeferred(Layer* layer) {
bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
Caches& caches = Caches::getInstance();
- if (layer && layer->isTextureLayer && bitmap->width() <= caches.maxTextureSize &&
+ if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
bitmap->height() <= caches.maxTextureSize) {
GLuint fbo = caches.fboCache.get();
@@ -365,12 +353,11 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
break;
}
- float alpha = layer->alpha;
- SkXfermode::Mode mode = layer->mode;
+ float alpha = layer->getAlpha();
+ SkXfermode::Mode mode = layer->getMode();
- layer->mode = SkXfermode::kSrc_Mode;
- layer->alpha = 255;
- layer->fbo = fbo;
+ layer->setAlpha(255, SkXfermode::kSrc_Mode);
+ layer->setFbo(fbo);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
@@ -399,7 +386,7 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
LayerRenderer renderer(layer);
renderer.setViewport(bitmap->width(), bitmap->height());
renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
- bitmap->width(), bitmap->height(), !layer->blend);
+ bitmap->width(), bitmap->height(), !layer->isBlend());
if ((error = glGetError()) != GL_NO_ERROR) goto error;
{
@@ -424,9 +411,8 @@ error:
#endif
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- layer->mode = mode;
- layer->alpha = alpha;
- layer->fbo = 0;
+ layer->setAlpha(alpha, mode);
+ layer->setFbo(0);
glDeleteTextures(1, &texture);
caches.fboCache.put(fbo);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1c06a0b..cb5a82b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -449,12 +449,11 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
return false;
}
- layer->mode = mode;
- layer->alpha = alpha;
+ layer->setAlpha(alpha, mode);
layer->layer.set(bounds);
- layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height),
- bounds.getWidth() / float(layer->width), 0.0f);
- layer->colorFilter = mColorFilter;
+ layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
+ bounds.getWidth() / float(layer->getWidth()), 0.0f);
+ layer->setColorFilter(mColorFilter);
// Save the layer in the snapshot
snapshot->flags |= Snapshot::kFlagIsLayer;
@@ -464,12 +463,13 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
return createFboLayer(layer, bounds, snapshot, previousFbo);
} else {
// Copy the framebuffer into the layer
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ layer->bindTexture();
if (!bounds.isEmpty()) {
- if (layer->empty) {
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left,
- snapshot->height - bounds.bottom, layer->width, layer->height, 0);
- layer->empty = false;
+ if (layer->isEmpty()) {
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ bounds.left, snapshot->height - bounds.bottom,
+ layer->getWidth(), layer->getHeight(), 0);
+ layer->setEmpty(false);
} else {
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
@@ -485,7 +485,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
GLuint previousFbo) {
- layer->fbo = mCaches.fboCache.get();
+ layer->setFbo(mCaches.fboCache.get());
#if RENDER_LAYERS_AS_REGIONS
snapshot->region = &snapshot->layer->region;
@@ -507,7 +507,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna
clip.translate(-bounds.left, -bounds.top);
snapshot->flags |= Snapshot::kFlagIsFboLayer;
- snapshot->fbo = layer->fbo;
+ snapshot->fbo = layer->getFbo();
snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
@@ -516,18 +516,17 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna
snapshot->orthoMatrix.load(mOrthoMatrix);
// Bind texture to FBO
- glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
+ glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
+ layer->bindTexture();
// 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);
+ if (layer->isEmpty()) {
+ layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
+ layer->setEmpty(false);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- layer->texture, 0);
+ layer->getTexture(), 0);
#if DEBUG_LAYERS_AS_REGIONS
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -535,8 +534,8 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna
LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- glDeleteTextures(1, &layer->texture);
- mCaches.fboCache.put(layer->fbo);
+ layer->deleteTexture();
+ mCaches.fboCache.put(layer->getFbo());
delete layer;
@@ -578,11 +577,11 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
Layer* layer = current->layer;
const Rect& rect = layer->layer;
- if (!fboLayer && layer->alpha < 255) {
+ if (!fboLayer && layer->getAlpha() < 255) {
drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
- layer->alpha << 24, SkXfermode::kDstIn_Mode, true);
+ layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
// Required below, composeLayerRect() will divide by 255
- layer->alpha = 255;
+ layer->setAlpha(255);
}
mCaches.unbindMeshBuffer();
@@ -593,18 +592,16 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
// drawing only the dirty region
if (fboLayer) {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
- if (layer->colorFilter) {
- setupColorFilter(layer->colorFilter);
+ if (layer->getColorFilter()) {
+ setupColorFilter(layer->getColorFilter());
}
composeLayerRegion(layer, rect);
- if (layer->colorFilter) {
+ if (layer->getColorFilter()) {
resetColorFilter();
}
- } else {
- if (!rect.isEmpty()) {
- dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
- composeLayerRect(layer, rect, true);
- }
+ } else if (!rect.isEmpty()) {
+ dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+ composeLayerRect(layer, rect, true);
}
if (fboLayer) {
@@ -622,16 +619,16 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
// Failing to add the layer to the cache should happen only if the layer is too large
if (!mCaches.layerCache.put(layer)) {
LAYER_LOGD("Deleting layer");
- glDeleteTextures(1, &layer->texture);
+ layer->deleteTexture();
delete layer;
}
}
void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
- float alpha = layer->alpha / 255.0f;
+ float alpha = layer->getAlpha() / 255.0f;
setupDraw();
- if (layer->renderTarget == GL_TEXTURE_2D) {
+ if (layer->getRenderTarget() == GL_TEXTURE_2D) {
setupDrawWithTexture();
} else {
setupDrawWithExternalTexture();
@@ -639,17 +636,26 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
setupDrawTextureTransform();
setupDrawColor(alpha, alpha, alpha, alpha);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode);
+ setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
setupDrawProgram();
- setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- if (layer->renderTarget == GL_TEXTURE_2D) {
- setupDrawTexture(layer->texture);
+ if (layer->getRenderTarget() == GL_TEXTURE_2D) {
+ setupDrawTexture(layer->getTexture());
} else {
- setupDrawExternalTexture(layer->texture);
+ setupDrawExternalTexture(layer->getTexture());
}
- setupDrawTextureTransformUniforms(layer->texTransform);
+ if (mSnapshot->transform->isPureTranslate()) {
+ const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
+ }
+ setupDrawTextureTransformUniforms(layer->getTexTransform());
setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -658,14 +664,32 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
}
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
- if (!layer->isTextureLayer) {
+ if (!layer->isTextureLayer()) {
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);
+ float x = rect.left;
+ float y = rect.top;
+ bool simpleTransform = mSnapshot->transform->isPureTranslate();
+
+ if (simpleTransform) {
+ // When we're swapping, the layer is already in screen coordinates
+ if (!swap) {
+ x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+ }
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST, true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR, true);
+ }
+
+ drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
+ layer->getTexture(), layer->getAlpha() / 255.0f,
+ layer->getMode(), layer->isBlend(),
+ &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
+ GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
} else {
@@ -690,9 +714,9 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
size_t count;
const android::Rect* rects = layer->region.getArray(&count);
- const float alpha = layer->alpha / 255.0f;
- const float texX = 1.0f / float(layer->width);
- const float texY = 1.0f / float(layer->height);
+ const float alpha = layer->getAlpha() / 255.0f;
+ const float texX = 1.0f / float(layer->getWidth());
+ const float texY = 1.0f / float(layer->getHeight());
const float height = rect.getHeight();
TextureVertex* mesh = mCaches.getRegionMesh();
@@ -702,13 +726,22 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
setupDrawWithTexture();
setupDrawColor(alpha, alpha, alpha, alpha);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
+ setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- setupDrawTexture(layer->texture);
- setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
+ setupDrawTexture(layer->getTexture());
+ if (mSnapshot->transform->isPureTranslate()) {
+ const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
+ }
setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]);
for (size_t i = 0; i < count; i++) {
@@ -2154,8 +2187,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- layer->alpha = alpha;
- layer->mode = mode;
+ layer->setAlpha(alpha, mode);
#if RENDER_LAYERS_AS_REGIONS
if (!layer->region.isEmpty()) {
@@ -2169,13 +2201,23 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
setupDrawWithTexture();
setupDrawColor(a, a, a, a);
setupDrawColorFilter();
- setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
+ setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
setupDrawProgram();
- setupDrawModelViewTranslate(x, y,
- x + layer->layer.getWidth(), y + layer->layer.getHeight());
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- setupDrawTexture(layer->texture);
+ setupDrawTexture(layer->getTexture());
+ if (mSnapshot->transform->isPureTranslate()) {
+ x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
+ y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
+
+ layer->setFilter(GL_NEAREST, GL_NEAREST);
+ setupDrawModelViewTranslate(x, y,
+ x + layer->layer.getWidth(), y + layer->layer.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR, GL_LINEAR);
+ setupDrawModelViewTranslate(x, y,
+ x + layer->layer.getWidth(), y + layer->layer.getHeight());
+ }
setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
glDrawElements(GL_TRIANGLES, layer->meshElementCount,
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 4922bb3..c6ae326 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -29,8 +29,22 @@ struct Texture {
Texture() {
cleanup = false;
bitmapSize = 0;
+
wrapS = GL_CLAMP_TO_EDGE;
wrapT = GL_CLAMP_TO_EDGE;
+
+ minFilter = GL_NEAREST;
+ magFilter = GL_NEAREST;
+ }
+
+ void setWrap(GLenum wrapS, GLenum wrapT) {
+ this->wrapS = wrapS;
+ this->wrapT = wrapT;
+ }
+
+ void setFilter(GLenum min, GLenum mag) {
+ minFilter = min;
+ magFilter = mag;
}
/**
@@ -67,6 +81,12 @@ struct Texture {
*/
GLenum wrapS;
GLenum wrapT;
+
+ /**
+ * Last filters set on this texture. Defaults to GL_NEAREST.
+ */
+ GLenum minFilter;
+ GLenum magFilter;
}; // struct Texture
class AutoTexture {