diff options
-rw-r--r-- | libs/hwui/Layer.cpp | 45 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 31 | ||||
-rw-r--r-- | libs/hwui/LayerCache.cpp | 25 | ||||
-rw-r--r-- | libs/hwui/LayerCache.h | 15 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 9 | ||||
-rw-r--r-- | tests/HwAccelerationTest/res/layout/view_layers_5.xml | 25 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java | 65 |
8 files changed, 162 insertions, 55 deletions
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 1d85b70..79dbfb0 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -54,6 +54,51 @@ Layer::~Layer() { deleteTexture(); } +uint32_t Layer::computeIdealWidth(uint32_t layerWidth) { + return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE); +} + +uint32_t Layer::computeIdealHeight(uint32_t layerHeight) { + return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE); +} + +bool Layer::resize(const uint32_t width, const uint32_t height) { + uint32_t desiredWidth = computeIdealWidth(width); + uint32_t desiredHeight = computeIdealWidth(height); + + if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) { + return true; + } + + uint32_t oldWidth = getWidth(); + uint32_t oldHeight = getHeight(); + + setSize(desiredWidth, desiredHeight); + + if (fbo) { + Caches::getInstance().activeTexture(0); + bindTexture(); + allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); + + if (glGetError() != GL_NO_ERROR) { + setSize(oldWidth, oldHeight); + return false; + } + } + + if (stencil) { + bindStencilRenderBuffer(); + allocateStencilRenderBuffer(); + + if (glGetError() != GL_NO_ERROR) { + setSize(oldWidth, oldHeight); + return false; + } + } + + return true; +} + void Layer::removeFbo(bool flush) { if (stencil) { // TODO: recycle & cache instead of simply deleting diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 9ef4894..a551b3f 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -48,6 +48,9 @@ struct Layer { Layer(const uint32_t layerWidth, const uint32_t layerHeight); ~Layer(); + static uint32_t computeIdealWidth(uint32_t layerWidth); + static uint32_t computeIdealHeight(uint32_t layerHeight); + /** * Calling this method will remove (either by recycling or * destroying) the associated FBO, if present, and any render @@ -91,6 +94,17 @@ struct Layer { return texture.height; } + /** + * Resize the layer and its texture if needed. + * + * @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(const uint32_t width, const uint32_t height); + void setSize(uint32_t width, uint32_t height) { texture.width = width; texture.height = height; @@ -203,6 +217,12 @@ struct Layer { } } + inline void bindStencilRenderBuffer() { + if (stencil) { + glBindRenderbuffer(GL_RENDERBUFFER, stencil); + } + } + inline void generateTexture() { if (!texture.id) { glGenTextures(1, &texture.id); @@ -229,7 +249,16 @@ struct Layer { #if DEBUG_LAYERS ALOGD(" Allocate layer: %dx%d", getWidth(), getHeight()); #endif - glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL); + if (texture.id) { + glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, + format, storage, NULL); + } + } + + inline void allocateStencilRenderBuffer() { + if (stencil) { + glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWidth(), getHeight()); + } } inline mat4& getTexTransform() { diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index cfc5b04..4278464 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -136,31 +136,6 @@ void LayerCache::dump() { } } -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->getWidth() && entry.mHeight <= layer->getHeight()) { - return true; - } - - uint32_t oldWidth = layer->getWidth(); - uint32_t oldHeight = layer->getHeight(); - - Caches::getInstance().activeTexture(0); - 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; - } - - return true; -} - bool LayerCache::put(Layer* layer) { if (!layer->isCacheable()) return false; diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h index fc2cd91..7720b42 100644 --- a/libs/hwui/LayerCache.h +++ b/libs/hwui/LayerCache.h @@ -72,17 +72,6 @@ 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. @@ -108,8 +97,8 @@ public: } LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(NULL) { - mWidth = uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE); - mHeight = uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE); + mWidth = Layer::computeIdealWidth(layerWidth); + mHeight = Layer::computeIdealHeight(layerHeight); } LayerEntry(Layer* layer): diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index ba59bb3..61bedbb 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -264,7 +264,7 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { if (layer) { LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height); - if (Caches::getInstance().layerCache.resize(layer, width, height)) { + if (layer->resize(width, height)) { layer->layer.set(0.0f, 0.0f, width, height); layer->texCoords.set(0.0f, height / float(layer->getHeight()), width / float(layer->getWidth()), 0.0f); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index be34b40..f55bc9d 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1248,11 +1248,12 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) { // TODO: See Layer::removeFbo(). The stencil renderbuffer should be cached GLuint buffer; glGenRenderbuffers(1, &buffer); - glBindRenderbuffer(GL_RENDERBUFFER, buffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, - layer->getWidth(), layer->getHeight()); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer); + layer->setStencilRenderBuffer(buffer); + layer->bindStencilRenderBuffer(); + layer->allocateStencilRenderBuffer(); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer); } } diff --git a/tests/HwAccelerationTest/res/layout/view_layers_5.xml b/tests/HwAccelerationTest/res/layout/view_layers_5.xml index 36cf8c9..5baf583 100644 --- a/tests/HwAccelerationTest/res/layout/view_layers_5.xml +++ b/tests/HwAccelerationTest/res/layout/view_layers_5.xml @@ -48,13 +48,32 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Grow layer" /> + + <Button + android:onClick="enableClip" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Circle clip" /> + + <Button + android:onClick="disableClip" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="No clip" /> </LinearLayout> - <ListView - android:id="@+id/list1" + <view class="com.android.test.hwui.ViewLayersActivity5$ClipFrameLayout" + android:id="@+id/container" android:layout_width="0dip" android:layout_height="match_parent" - android:layout_weight="1" /> + android:layout_weight="1"> + + <ListView + android:id="@+id/list1" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </view> </LinearLayout> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java index 2664977..cbbb7ef 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity5.java @@ -19,14 +19,18 @@ package com.android.test.hwui; import android.app.Activity; import android.content.Context; import android.content.res.Resources; +import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.os.Bundle; +import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import android.widget.FrameLayout; import android.widget.ListView; import android.widget.TextView; @@ -37,30 +41,75 @@ public class ViewLayersActivity5 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + + init(); + setContentView(R.layout.view_layers_5); + setupList(R.id.list1); + } + + public static class ClipFrameLayout extends FrameLayout { + private final Path mClipPath = new Path(); + private boolean mClipEnabled; + + public ClipFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ClipFrameLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public boolean isClipEnabled() { + return mClipEnabled; + } + public void setClipEnabled(boolean clipEnabled) { + mClipEnabled = clipEnabled; + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (mClipEnabled) { + mClipPath.reset(); + mClipPath.addCircle(getWidth() / 2.0f, getHeight() / 2.0f, + Math.min(getWidth(), getHeight()) / 3.0f, Path.Direction.CW); + + canvas.clipPath(mClipPath); + } + super.dispatchDraw(canvas); + } + } + + private void init() { mPaint.setColorFilter(new PorterDuffColorFilter(0xff00ff00, PorterDuff.Mode.MULTIPLY)); + } - setupList(R.id.list1); + public void enableClip(View v) { + ((ClipFrameLayout) findViewById(R.id.container)).setClipEnabled(true); + } + + public void disableClip(View v) { + ((ClipFrameLayout) findViewById(R.id.container)).setClipEnabled(false); } public void enableLayer(View v) { - findViewById(R.id.list1).setLayerType(View.LAYER_TYPE_HARDWARE, mPaint); + findViewById(R.id.container).setLayerType(View.LAYER_TYPE_HARDWARE, mPaint); } public void disableLayer(View v) { - findViewById(R.id.list1).setLayerType(View.LAYER_TYPE_NONE, null); + findViewById(R.id.container).setLayerType(View.LAYER_TYPE_NONE, null); } public void growLayer(View v) { - findViewById(R.id.list1).getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; - findViewById(R.id.list1).requestLayout(); + findViewById(R.id.container).getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT; + findViewById(R.id.container).requestLayout(); } public void shrinkLayer(View v) { - findViewById(R.id.list1).getLayoutParams().height = 300; - findViewById(R.id.list1).requestLayout(); + findViewById(R.id.container).getLayoutParams().height = 300; + findViewById(R.id.container).requestLayout(); } private void setupList(int listId) { |