Loading core/java/android/view/GLES20Layer.java +4 −3 Original line number Diff line number Diff line Loading @@ -66,10 +66,11 @@ class GLES20Layer extends HardwareLayer { @Override void resize(int width, int height) { if (!isValid() || width <= 0 || height <= 0) return; if (width > mLayerWidth || height > mLayerHeight) { mWidth = width; mHeight = height; if (width != mLayerWidth || height != mLayerHeight) { int[] layerInfo = new int[2]; GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo); Loading libs/hwui/Caches.cpp +2 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "Caches.h" #include "Properties.h" #include "LayerRenderer.h" namespace android { Loading Loading @@ -116,12 +117,7 @@ void Caches::clearGarbage() { size_t count = mLayerGarbage.size(); for (size_t i = 0; i < count; i++) { Layer* layer = mLayerGarbage.itemAt(i); if (layer) { if (layer->fbo) glDeleteFramebuffers(1, &layer->fbo); if (layer->texture) glDeleteTextures(1, &layer->texture); delete layer; } LayerRenderer::destroyLayer(layer); } mLayerGarbage.clear(); } Loading libs/hwui/LayerCache.cpp +25 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,31 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) { return layer; } bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t height) { // TODO: We should be smarter and see if we have a texture of the appropriate // 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) { return true; } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, layer->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if (glGetError() != GL_NO_ERROR) { return false; } layer->width = entry.mWidth; layer->height = entry.mHeight; return true; } bool LayerCache::put(Layer* layer) { const uint32_t size = layer->width * layer->height * 4; // Don't even try to cache a layer that's bigger than the cache Loading libs/hwui/LayerCache.h +11 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,17 @@ public: * Clears the cache. This causes all layers to be deleted. */ void clear(); /** * Resize the specified layer if needed. * * @param layer The layer to resize * @param width The new width of the layer * @param height The new height of the layer * * @return True if the layer was resized or nothing happened, false if * a failure occurred during the resizing operation */ bool resize(Layer* layer, const uint32_t width, const uint32_t height); /** * Sets the maximum size of the cache in bytes. Loading libs/hwui/LayerRenderer.cpp +60 −68 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <ui/Rect.h> #include "LayerCache.h" #include "LayerRenderer.h" #include "Properties.h" #include "Rect.h" Loading @@ -34,21 +35,24 @@ void LayerRenderer::prepareDirty(float left, float top, float right, float botto glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo); const float width = mLayer->layer.getWidth(); const float height = mLayer->layer.getHeight(); #if RENDER_LAYERS_AS_REGIONS Rect dirty(left, top, right, bottom); if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 && dirty.right >= mLayer->width && dirty.bottom >= mLayer->height)) { dirty.right >= width && dirty.bottom >= height)) { mLayer->region.clear(); dirty.set(0.0f, 0.0f, mLayer->width, mLayer->height); dirty.set(0.0f, 0.0f, width, height); } else { dirty.intersect(0.0f, 0.0f, mLayer->width, mLayer->height); dirty.intersect(0.0f, 0.0f, width, height); android::Rect r(dirty.left, dirty.top, dirty.right, dirty.bottom); mLayer->region.subtractSelf(r); } OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque); #else OpenGLRenderer::prepareDirty(0.0f, 0.0f, mLayer->width, mLayer->height, opaque); OpenGLRenderer::prepareDirty(0.0f, 0.0f, width, height, opaque); #endif } Loading Loading @@ -162,64 +166,56 @@ void LayerRenderer::generateMesh() { Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) { LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height); Layer* layer = new Layer(width, height); GLuint previousFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); glGenFramebuffers(1, &layer->fbo); glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); if (glGetError() != GL_NO_ERROR) { glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); glDeleteBuffers(1, &layer->fbo); return 0; GLuint fbo = Caches::getInstance().fboCache.get(); if (!fbo) { LOGW("Could not obtain an FBO"); return NULL; } glActiveTexture(GL_TEXTURE0); glGenTextures(1, &layer->texture); glBindTexture(GL_TEXTURE_2D, layer->texture); Layer* layer = Caches::getInstance().layerCache.get(width, height); if (!layer) { LOGW("Could not obtain a layer"); return NULL; } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); layer->fbo = 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->region.clear(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLuint previousFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); glBindTexture(GL_TEXTURE_2D, layer->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, // 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 (glGetError() != GL_NO_ERROR) { LOGD("Could not allocate texture"); glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); glDeleteBuffers(1, &layer->fbo); glDeleteTextures(1, &layer->texture); Caches::getInstance().fboCache.put(fbo); delete layer; return 0; return NULL; } } glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layer->texture, 0); if (glGetError() != GL_NO_ERROR) { glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); glDeleteBuffers(1, &layer->fbo); glDeleteTextures(1, &layer->texture); delete layer; return 0; } glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); layer->layer.set(0.0f, 0.0f, width, height); layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f); layer->alpha = 255; layer->mode = SkXfermode::kSrcOver_Mode; layer->blend = !isOpaque; layer->empty = false; layer->colorFilter = NULL; return layer; } Loading @@ -227,27 +223,17 @@ 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); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, layer->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if (glGetError() != GL_NO_ERROR) { glDeleteBuffers(1, &layer->fbo); glDeleteTextures(1, &layer->texture); layer->width = 0; layer->height = 0; layer->fbo = 0; layer->texture = 0; 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); } else { if (layer->texture) glDeleteTextures(1, &layer->texture); delete layer; return false; } layer->width = width; layer->height = height; } return true; } Loading @@ -255,10 +241,16 @@ void LayerRenderer::destroyLayer(Layer* layer) { if (layer) { LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo); if (layer->fbo) glDeleteFramebuffers(1, &layer->fbo); if (layer->texture) glDeleteTextures(1, &layer->texture); if (layer->fbo) { Caches::getInstance().fboCache.put(layer->fbo); } if (!Caches::getInstance().layerCache.put(layer)) { if (layer->texture) glDeleteTextures(1, &layer->texture); delete layer; } else { layer->region.clear(); } } } Loading Loading
core/java/android/view/GLES20Layer.java +4 −3 Original line number Diff line number Diff line Loading @@ -66,10 +66,11 @@ class GLES20Layer extends HardwareLayer { @Override void resize(int width, int height) { if (!isValid() || width <= 0 || height <= 0) return; if (width > mLayerWidth || height > mLayerHeight) { mWidth = width; mHeight = height; if (width != mLayerWidth || height != mLayerHeight) { int[] layerInfo = new int[2]; GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo); Loading
libs/hwui/Caches.cpp +2 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "Caches.h" #include "Properties.h" #include "LayerRenderer.h" namespace android { Loading Loading @@ -116,12 +117,7 @@ void Caches::clearGarbage() { size_t count = mLayerGarbage.size(); for (size_t i = 0; i < count; i++) { Layer* layer = mLayerGarbage.itemAt(i); if (layer) { if (layer->fbo) glDeleteFramebuffers(1, &layer->fbo); if (layer->texture) glDeleteTextures(1, &layer->texture); delete layer; } LayerRenderer::destroyLayer(layer); } mLayerGarbage.clear(); } Loading
libs/hwui/LayerCache.cpp +25 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,31 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) { return layer; } bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t height) { // TODO: We should be smarter and see if we have a texture of the appropriate // 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) { return true; } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, layer->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if (glGetError() != GL_NO_ERROR) { return false; } layer->width = entry.mWidth; layer->height = entry.mHeight; return true; } bool LayerCache::put(Layer* layer) { const uint32_t size = layer->width * layer->height * 4; // Don't even try to cache a layer that's bigger than the cache Loading
libs/hwui/LayerCache.h +11 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,17 @@ public: * Clears the cache. This causes all layers to be deleted. */ void clear(); /** * Resize the specified layer if needed. * * @param layer The layer to resize * @param width The new width of the layer * @param height The new height of the layer * * @return True if the layer was resized or nothing happened, false if * a failure occurred during the resizing operation */ bool resize(Layer* layer, const uint32_t width, const uint32_t height); /** * Sets the maximum size of the cache in bytes. Loading
libs/hwui/LayerRenderer.cpp +60 −68 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <ui/Rect.h> #include "LayerCache.h" #include "LayerRenderer.h" #include "Properties.h" #include "Rect.h" Loading @@ -34,21 +35,24 @@ void LayerRenderer::prepareDirty(float left, float top, float right, float botto glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo); const float width = mLayer->layer.getWidth(); const float height = mLayer->layer.getHeight(); #if RENDER_LAYERS_AS_REGIONS Rect dirty(left, top, right, bottom); if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 && dirty.right >= mLayer->width && dirty.bottom >= mLayer->height)) { dirty.right >= width && dirty.bottom >= height)) { mLayer->region.clear(); dirty.set(0.0f, 0.0f, mLayer->width, mLayer->height); dirty.set(0.0f, 0.0f, width, height); } else { dirty.intersect(0.0f, 0.0f, mLayer->width, mLayer->height); dirty.intersect(0.0f, 0.0f, width, height); android::Rect r(dirty.left, dirty.top, dirty.right, dirty.bottom); mLayer->region.subtractSelf(r); } OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque); #else OpenGLRenderer::prepareDirty(0.0f, 0.0f, mLayer->width, mLayer->height, opaque); OpenGLRenderer::prepareDirty(0.0f, 0.0f, width, height, opaque); #endif } Loading Loading @@ -162,64 +166,56 @@ void LayerRenderer::generateMesh() { Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) { LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height); Layer* layer = new Layer(width, height); GLuint previousFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); glGenFramebuffers(1, &layer->fbo); glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); if (glGetError() != GL_NO_ERROR) { glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); glDeleteBuffers(1, &layer->fbo); return 0; GLuint fbo = Caches::getInstance().fboCache.get(); if (!fbo) { LOGW("Could not obtain an FBO"); return NULL; } glActiveTexture(GL_TEXTURE0); glGenTextures(1, &layer->texture); glBindTexture(GL_TEXTURE_2D, layer->texture); Layer* layer = Caches::getInstance().layerCache.get(width, height); if (!layer) { LOGW("Could not obtain a layer"); return NULL; } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); layer->fbo = 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->region.clear(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLuint previousFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); glBindTexture(GL_TEXTURE_2D, layer->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, // 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 (glGetError() != GL_NO_ERROR) { LOGD("Could not allocate texture"); glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); glDeleteBuffers(1, &layer->fbo); glDeleteTextures(1, &layer->texture); Caches::getInstance().fboCache.put(fbo); delete layer; return 0; return NULL; } } glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layer->texture, 0); if (glGetError() != GL_NO_ERROR) { glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); glDeleteBuffers(1, &layer->fbo); glDeleteTextures(1, &layer->texture); delete layer; return 0; } glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); layer->layer.set(0.0f, 0.0f, width, height); layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f); layer->alpha = 255; layer->mode = SkXfermode::kSrcOver_Mode; layer->blend = !isOpaque; layer->empty = false; layer->colorFilter = NULL; return layer; } Loading @@ -227,27 +223,17 @@ 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); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, layer->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if (glGetError() != GL_NO_ERROR) { glDeleteBuffers(1, &layer->fbo); glDeleteTextures(1, &layer->texture); layer->width = 0; layer->height = 0; layer->fbo = 0; layer->texture = 0; 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); } else { if (layer->texture) glDeleteTextures(1, &layer->texture); delete layer; return false; } layer->width = width; layer->height = height; } return true; } Loading @@ -255,10 +241,16 @@ void LayerRenderer::destroyLayer(Layer* layer) { if (layer) { LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo); if (layer->fbo) glDeleteFramebuffers(1, &layer->fbo); if (layer->texture) glDeleteTextures(1, &layer->texture); if (layer->fbo) { Caches::getInstance().fboCache.put(layer->fbo); } if (!Caches::getInstance().layerCache.put(layer)) { if (layer->texture) glDeleteTextures(1, &layer->texture); delete layer; } else { layer->region.clear(); } } } Loading