diff options
-rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
-rw-r--r-- | libs/hwui/Caches.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/Caches.h | 6 | ||||
-rw-r--r-- | libs/hwui/Debug.h | 3 | ||||
-rw-r--r-- | libs/hwui/Extensions.cpp | 87 | ||||
-rw-r--r-- | libs/hwui/Extensions.h | 61 | ||||
-rw-r--r-- | libs/hwui/GradientCache.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 56 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 28 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 5 | ||||
-rw-r--r-- | libs/hwui/RenderBuffer.h | 171 | ||||
-rw-r--r-- | libs/hwui/Snapshot.cpp | 3 | ||||
-rw-r--r-- | libs/hwui/Stencil.cpp | 29 | ||||
-rw-r--r-- | libs/hwui/Stencil.h | 7 | ||||
-rw-r--r-- | libs/hwui/TextureCache.cpp | 2 |
17 files changed, 369 insertions, 114 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 549edd2bf7b3..7dce1ca2375a 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -14,6 +14,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) DisplayListLogBuffer.cpp \ DisplayListRenderer.cpp \ Dither.cpp \ + Extensions.cpp \ FboCache.cpp \ GradientCache.cpp \ Layer.cpp \ diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 1a86b3a4b32b..492bb7d171f5 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -47,7 +47,7 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -Caches::Caches(): Singleton<Caches>(), mInitialized(false) { +Caches::Caches(): Singleton<Caches>(), mExtensions(Extensions::getInstance()), mInitialized(false) { init(); initFont(); initExtensions(); @@ -100,7 +100,7 @@ void Caches::initFont() { } void Caches::initExtensions() { - if (extensions.hasDebugMarker()) { + if (mExtensions.hasDebugMarker()) { eventMark = glInsertEventMarkerEXT; startMark = glPushGroupMarkerEXT; endMark = glPopGroupMarkerEXT; @@ -110,7 +110,7 @@ void Caches::initExtensions() { endMark = endMarkNull; } - if (extensions.hasDebugLabel()) { + if (mExtensions.hasDebugLabel()) { setLabel = glLabelObjectEXT; getLabel = glGetObjectLabelEXT; } else { @@ -470,13 +470,13 @@ void Caches::resetScissor() { /////////////////////////////////////////////////////////////////////////////// void Caches::startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard) { - if (extensions.hasTiledRendering() && !debugOverdraw) { + if (mExtensions.hasTiledRendering() && !debugOverdraw) { glStartTilingQCOM(x, y, width, height, (discard ? GL_NONE : GL_COLOR_BUFFER_BIT0_QCOM)); } } void Caches::endTiling() { - if (extensions.hasTiledRendering() && !debugOverdraw) { + if (mExtensions.hasTiledRendering() && !debugOverdraw) { glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM); } } diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 1c4d05f2b51d..f1d028568ca6 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -25,7 +25,6 @@ #include <cutils/compiler.h> -#include "Extensions.h" #include "FontRenderer.h" #include "GammaFontRenderer.h" #include "TextureCache.h" @@ -244,9 +243,6 @@ public: // VBO to draw with GLuint meshBuffer; - // GL extensions - Extensions extensions; - // Misc GLint maxTextureSize; bool debugLayersUpdates; @@ -312,6 +308,8 @@ private: GLint mScissorWidth; GLint mScissorHeight; + Extensions& mExtensions; + // Used to render layers TextureVertex* mRegionMesh; GLuint mRegionMeshIndices; diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h index dfc4e25cc085..5f8baacb710c 100644 --- a/libs/hwui/Debug.h +++ b/libs/hwui/Debug.h @@ -44,6 +44,9 @@ // Turn on to display info about layers #define DEBUG_LAYERS 0 +// Turn on to make stencil operations easier to debug +#define DEBUG_STENCIL 0 + // Turn on to display debug info about 9patch objects #define DEBUG_PATCHES 0 // Turn on to "explode" 9patch objects diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp new file mode 100644 index 000000000000..edc90fbc80f0 --- /dev/null +++ b/libs/hwui/Extensions.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Debug.h" +#include "Extensions.h" + +namespace android { + +using namespace uirenderer; +ANDROID_SINGLETON_STATIC_INSTANCE(Extensions); + +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////////////// + +// Debug +#if DEBUG_EXTENSIONS + #define EXT_LOGD(...) ALOGD(__VA_ARGS__) +#else + #define EXT_LOGD(...) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Constructors +/////////////////////////////////////////////////////////////////////////////// + +Extensions::Extensions(): Singleton<Extensions>() { + const char* buffer = (const char*) glGetString(GL_EXTENSIONS); + const char* current = buffer; + const char* head = current; + EXT_LOGD("Available GL extensions:"); + do { + head = strchr(current, ' '); + String8 s(current, head ? head - current : strlen(current)); + if (s.length()) { + mExtensionList.add(s); + EXT_LOGD(" %s", s.string()); + } + current = head + 1; + } while (head); + + mHasNPot = hasExtension("GL_OES_texture_npot"); + mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch"); + mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer"); + mHasDebugMarker = hasExtension("GL_EXT_debug_marker"); + mHasDebugLabel = hasExtension("GL_EXT_debug_label"); + mHasTiledRendering = hasExtension("GL_QCOM_tiled_rendering"); + mHas1BitStencil = hasExtension("GL_OES_stencil1"); + mHas4BitStencil = hasExtension("GL_OES_stencil4"); + + mExtensions = strdup(buffer); +} + +Extensions::~Extensions() { + free(mExtensions); +} + +/////////////////////////////////////////////////////////////////////////////// +// Methods +/////////////////////////////////////////////////////////////////////////////// + +bool Extensions::hasExtension(const char* extension) const { + const String8 s(extension); + return mExtensionList.indexOf(s) >= 0; +} + +void Extensions::dump() const { + ALOGD("Supported extensions:\n%s", mExtensions); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h index bdaa3cc06aa8..a069a6aae691 100644 --- a/libs/hwui/Extensions.h +++ b/libs/hwui/Extensions.h @@ -17,62 +17,24 @@ #ifndef ANDROID_HWUI_EXTENSIONS_H #define ANDROID_HWUI_EXTENSIONS_H +#include <utils/Singleton.h> #include <utils/SortedVector.h> #include <utils/String8.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> -#include "Debug.h" - namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -// Debug -#if DEBUG_EXTENSIONS - #define EXT_LOGD(...) ALOGD(__VA_ARGS__) -#else - #define EXT_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// // Classes /////////////////////////////////////////////////////////////////////////////// -class Extensions { +class Extensions: public Singleton<Extensions> { public: - Extensions() { - const char* buffer = (const char*) glGetString(GL_EXTENSIONS); - const char* current = buffer; - const char* head = current; - EXT_LOGD("Available GL extensions:"); - do { - head = strchr(current, ' '); - String8 s(current, head ? head - current : strlen(current)); - if (s.length()) { - mExtensionList.add(s); - EXT_LOGD(" %s", s.string()); - } - current = head + 1; - } while (head); - - mHasNPot = hasExtension("GL_OES_texture_npot"); - mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch"); - mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer"); - mHasDebugMarker = hasExtension("GL_EXT_debug_marker"); - mHasDebugLabel = hasExtension("GL_EXT_debug_label"); - mHasTiledRendering = hasExtension("GL_QCOM_tiled_rendering"); - - mExtensions = strdup(buffer); - } - - ~Extensions() { - free(mExtensions); - } + Extensions(); + ~Extensions(); inline bool hasNPot() const { return mHasNPot; } inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; } @@ -80,17 +42,16 @@ public: inline bool hasDebugMarker() const { return mHasDebugMarker; } inline bool hasDebugLabel() const { return mHasDebugLabel; } inline bool hasTiledRendering() const { return mHasTiledRendering; } + inline bool has1BitStencil() const { return mHas1BitStencil; } + inline bool has4BitStencil() const { return mHas4BitStencil; } - bool hasExtension(const char* extension) const { - const String8 s(extension); - return mExtensionList.indexOf(s) >= 0; - } + bool hasExtension(const char* extension) const; - void dump() { - ALOGD("Supported extensions:\n%s", mExtensions); - } + void dump() const; private: + friend class Singleton<Extensions>; + SortedVector<String8> mExtensionList; char* mExtensions; @@ -101,6 +62,8 @@ private: bool mHasDebugMarker; bool mHasDebugLabel; bool mHasTiledRendering; + bool mHas1BitStencil; + bool mHas4BitStencil; }; // class Extensions }; // namespace uirenderer diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 154c0ecce5ed..78f9cf5f7f19 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -152,7 +152,7 @@ void GradientCache::getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info) { uint32_t width = 256 * (count - 1); - if (!Caches::getInstance().extensions.hasNPot()) { + if (!Extensions::getInstance().hasNPot()) { width = 1 << (31 - __builtin_clz(width)); } diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 79dbfb0fc3a5..9247b1da3df2 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -41,7 +41,7 @@ Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight) { renderer = NULL; displayList = NULL; fbo = 0; - stencil = 0; + stencil = NULL; debugDrawUpdate = false; Caches::getInstance().resourceCache.incrementRefcount(this); } @@ -87,8 +87,8 @@ bool Layer::resize(const uint32_t width, const uint32_t height) { } if (stencil) { - bindStencilRenderBuffer(); - allocateStencilRenderBuffer(); + stencil->bind(); + stencil->resize(desiredWidth, desiredHeight); if (glGetError() != GL_NO_ERROR) { setSize(oldWidth, oldHeight); @@ -108,8 +108,8 @@ void Layer::removeFbo(bool flush) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); - glDeleteRenderbuffers(1, &stencil); - stencil = 0; + delete stencil; + stencil = NULL; } if (fbo) { diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index e8a85fdf3dde..664b2f84b6f6 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -26,6 +26,7 @@ #include <SkXfermode.h> #include "Rect.h" +#include "RenderBuffer.h" #include "SkiaColorFilter.h" #include "Texture.h" #include "Vertex.h" @@ -86,11 +87,11 @@ struct Layer { deferredUpdateScheduled = true; } - inline uint32_t getWidth() { + inline uint32_t getWidth() const { return texture.width; } - inline uint32_t getHeight() { + inline uint32_t getHeight() const { return texture.height; } @@ -116,7 +117,7 @@ struct Layer { texture.blend = blend; } - inline bool isBlend() { + inline bool isBlend() const { return texture.blend; } @@ -129,11 +130,11 @@ struct Layer { this->mode = mode; } - inline int getAlpha() { + inline int getAlpha() const { return alpha; } - inline SkXfermode::Mode getMode() { + inline SkXfermode::Mode getMode() const { return mode; } @@ -141,7 +142,7 @@ struct Layer { this->empty = empty; } - inline bool isEmpty() { + inline bool isEmpty() const { return empty; } @@ -149,23 +150,29 @@ struct Layer { this->fbo = fbo; } - inline GLuint getFbo() { + inline GLuint getFbo() const { return fbo; } - inline void setStencilRenderBuffer(GLuint renderBuffer) { - this->stencil = renderBuffer; + inline void setStencilRenderBuffer(RenderBuffer* renderBuffer) { + if (RenderBuffer::isStencilBuffer(renderBuffer->getFormat())) { + this->stencil = renderBuffer; + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, stencil->getName()); + } else { + ALOGE("The specified render buffer is not a stencil buffer"); + } } - inline GLuint getStencilRenderBuffer() { + inline RenderBuffer* getStencilRenderBuffer() const { return stencil; } - inline GLuint getTexture() { + inline GLuint getTexture() const { return texture.id; } - inline GLenum getRenderTarget() { + inline GLenum getRenderTarget() const { return renderTarget; } @@ -181,7 +188,7 @@ struct Layer { texture.setFilter(filter, bindTexture, force, renderTarget); } - inline bool isCacheable() { + inline bool isCacheable() const { return cacheable; } @@ -189,7 +196,7 @@ struct Layer { this->cacheable = cacheable; } - inline bool isDirty() { + inline bool isDirty() const { return dirty; } @@ -197,7 +204,7 @@ struct Layer { this->dirty = dirty; } - inline bool isTextureLayer() { + inline bool isTextureLayer() const { return textureLayer; } @@ -205,21 +212,21 @@ struct Layer { this->textureLayer = textureLayer; } - inline SkiaColorFilter* getColorFilter() { + inline SkiaColorFilter* getColorFilter() const { return colorFilter; } ANDROID_API void setColorFilter(SkiaColorFilter* filter); - inline void bindTexture() { + inline void bindTexture() const { if (texture.id) { glBindTexture(renderTarget, texture.id); } } - inline void bindStencilRenderBuffer() { + inline void bindStencilRenderBuffer() const { if (stencil) { - glBindRenderbuffer(GL_RENDERBUFFER, stencil); + stencil->bind(); } } @@ -255,12 +262,6 @@ struct Layer { } } - inline void allocateStencilRenderBuffer() { - if (stencil) { - glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWidth(), getHeight()); - } - } - inline mat4& getTexTransform() { return texTransform; } @@ -317,10 +318,9 @@ private: GLuint fbo; /** - * Name of the render buffer used as the stencil buffer. If the - * name is 0, this layer does not have a stencil buffer. + * The render buffer used as the stencil buffer. */ - GLuint stencil; + RenderBuffer* stencil; /** * Indicates whether this layer has been used already. diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index c8a8ed441c43..bc660cd8c2a9 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -351,7 +351,7 @@ void LayerRenderer::flushLayer(Layer* layer) { if (layer && fbo) { // If possible, discard any enqueud operations on deferred // rendering architectures - if (Caches::getInstance().extensions.hasDiscardFramebuffer()) { + if (Extensions::getInstance().hasDiscardFramebuffer()) { GLuint previousFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo); if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 45569ace79d5..3cec87d6d229 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -109,7 +109,8 @@ static const Blender gBlendsSwap[] = { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { +OpenGLRenderer::OpenGLRenderer(): + mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) { mShader = NULL; mColorFilter = NULL; mHasShadow = false; @@ -216,7 +217,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa // If we know that we are going to redraw the entire framebuffer, // perform a discard to let the driver know we don't need to preserve // the back buffer for this frame. - if (mCaches.extensions.hasDiscardFramebuffer() && + if (mExtensions.hasDiscardFramebuffer() && left <= 0.0f && top <= 0.0f && right >= mWidth && bottom >= mHeight) { const bool isFbo = getTargetFbo() == 0; const GLenum attachments[] = { @@ -1119,7 +1120,7 @@ void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color, it.next(); } - drawColorRects(rects.array(), count, color, mode, true, dirty); + drawColorRects(rects.array(), count, color, mode, true, dirty, false); } void OpenGLRenderer::dirtyLayer(const float left, const float top, @@ -1269,15 +1270,12 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) { // attach the new render buffer then turn tiling back on endTiling(); - // TODO: See Layer::removeFbo(). The stencil renderbuffer should be cached - GLuint buffer; - glGenRenderbuffers(1, &buffer); + RenderBuffer* buffer = new RenderBuffer( + Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight()); + buffer->bind(); + buffer->allocate(); layer->setStencilRenderBuffer(buffer); - layer->bindStencilRenderBuffer(); - layer->allocateStencilRenderBuffer(); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer); startTiling(layer->clipRect, layer->layer.getHeight()); } @@ -1525,13 +1523,13 @@ void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) { void OpenGLRenderer::setupDrawShader() { if (mShader) { - mShader->describe(mDescription, mCaches.extensions); + mShader->describe(mDescription, mExtensions); } } void OpenGLRenderer::setupDrawColorFilter() { if (mColorFilter) { - mColorFilter->describe(mDescription, mCaches.extensions); + mColorFilter->describe(mDescription, mExtensions); } } @@ -3207,7 +3205,7 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint } status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color, - SkXfermode::Mode mode, bool ignoreTransform, bool dirty) { + SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) { float left = FLT_MAX; float top = FLT_MAX; @@ -3241,7 +3239,7 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color } } - if (count == 0 || quickReject(left, top, right, bottom)) { + if (count == 0 || (clip && quickReject(left, top, right, bottom))) { return DrawGlInfo::kStatusDone; } @@ -3386,7 +3384,7 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, // If the blend mode cannot be implemented using shaders, fall // back to the default SrcOver blend mode instead if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) { - if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) { + if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) { description.framebufferMode = mode; description.swapSrcDst = swapSrcDst; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 750b3d245bce..81af7b7b888b 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -566,9 +566,11 @@ private: * @param mode The Skia xfermode to use * @param ignoreTransform True if the current transform should be ignored * @param dirty True if calling this method should dirty the current layer + * @param clip True if the rects should be clipped, false otherwise */ status_t drawColorRects(const float* rects, int count, int color, - SkXfermode::Mode mode, bool ignoreTransform = false, bool dirty = true); + SkXfermode::Mode mode, bool ignoreTransform = false, + bool dirty = true, bool clip = true); /** * Draws the shape represented by the specified path texture. @@ -881,6 +883,7 @@ private: // Various caches Caches& mCaches; + Extensions& mExtensions; // List of rectangles to clear after saveLayer() is invoked Vector<Rect*> mLayers; diff --git a/libs/hwui/RenderBuffer.h b/libs/hwui/RenderBuffer.h new file mode 100644 index 000000000000..927f2659abd0 --- /dev/null +++ b/libs/hwui/RenderBuffer.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HWUI_RENDER_BUFFER_H +#define ANDROID_HWUI_RENDER_BUFFER_H + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +namespace android { +namespace uirenderer { + +/** + * Represents an OpenGL render buffer. Render buffers are attached + * to layers to perform stencil work. + */ +struct RenderBuffer { + /** + * Creates a new render buffer in the specified format and dimensions. + * The format must be one of the formats allowed by glRenderbufferStorage(). + */ + RenderBuffer(GLenum format, uint32_t width, uint32_t height): + mFormat(format), mWidth(width), mHeight(height), mAllocated(false) { + + glGenRenderbuffers(1, &mName); + } + + ~RenderBuffer() { + if (mName && mAllocated) { + glDeleteRenderbuffers(1, &mName); + } + } + + /** + * Returns the GL name of this render buffer. + */ + GLuint getName() const { + return mName; + } + + /** + * Returns the format of this render buffer. + */ + GLenum getFormat() const { + return mFormat; + } + + /** + * Binds this render buffer to the current GL context. + */ + void bind() const { + glBindRenderbuffer(GL_RENDERBUFFER, mName); + } + + /** + * Indicates whether this render buffer has allocated its + * storage. See allocate() and resize(). + */ + bool isAllocated() const { + return mAllocated; + } + + /** + * Allocates this render buffer's storage if needed. + * This method doesn't do anything if isAllocated() returns true. + */ + void allocate() { + if (!mAllocated) { + glRenderbufferStorage(GL_RENDERBUFFER, mFormat, mWidth, mHeight); + mAllocated = true; + } + } + + /** + * Resizes this render buffer. If the buffer was previously allocated, + * the storage is re-allocated wit the new specified dimensions. If the + * buffer wasn't previously allocated, the buffer remains unallocated. + */ + void resize(uint32_t width, uint32_t height) { + if (isAllocated() && (width != mWidth || height != mHeight)) { + glRenderbufferStorage(GL_RENDERBUFFER, mFormat, width, height); + } + + mWidth = width; + mHeight = height; + } + + /** + * Returns the width of the render buffer in pixels. + */ + uint32_t getWidth() const { + return mWidth; + } + + /** + * Returns the height of the render buffer in pixels. + */ + uint32_t getHeight() const { + return mHeight; + } + + /** + * Returns the size of this render buffer in bytes. + */ + uint32_t getSize() const { + // Round to the nearest byte + return (uint32_t) ((mWidth * mHeight * formatSize(mFormat)) / 8.0f + 0.5f); + } + + /** + * Returns the number of bits per component in the specified format. + * The format must be one of the formats allowed by glRenderbufferStorage(). + */ + static uint32_t formatSize(GLenum format) { + switch (format) { + case GL_STENCIL_INDEX8: + return 8; + case GL_STENCIL_INDEX1_OES: + return 1; + case GL_STENCIL_INDEX4_OES: + return 4; + case GL_DEPTH_COMPONENT16: + case GL_RGBA4: + case GL_RGB565: + case GL_RGB5_A1: + return 16; + } + return 0; + } + + /** + * Indicates whether the specified format represents a stencil buffer. + */ + static bool isStencilBuffer(GLenum format) { + switch (format) { + case GL_STENCIL_INDEX8: + case GL_STENCIL_INDEX1_OES: + case GL_STENCIL_INDEX4_OES: + return true; + } + return false; + } + +private: + GLenum mFormat; + + uint32_t mWidth; + uint32_t mHeight; + + bool mAllocated; + + GLuint mName; +}; // struct RenderBuffer + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_RENDER_BUFFER_H diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index 87ed825b8d2d..19a5db75b5df 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -183,6 +183,9 @@ const Rect& Snapshot::getLocalClip() { } void Snapshot::resetClip(float left, float top, float right, float bottom) { + // TODO: This is incorrect, when we start rendering into a new layer, + // we may have to modify the previous snapshot's clip rect and clip + // region if the previous restore() call did not restore the clip clipRect = &mClipRectRoot; clipRegion = &mClipRegionRoot; setClip(left, top, right, bottom); diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/Stencil.cpp index 4fcd51d6a7f4..ba2e6f2670e3 100644 --- a/libs/hwui/Stencil.cpp +++ b/libs/hwui/Stencil.cpp @@ -14,14 +14,23 @@ * limitations under the License. */ -#include <GLES2/gl2.h> - +#include "Extensions.h" #include "Properties.h" #include "Stencil.h" +#include <GLES2/gl2ext.h> + namespace android { namespace uirenderer { +#if DEBUG_STENCIL +#define STENCIL_WRITE_VALUE 0xff +#define STENCIL_MASK_VALUE 0xff +#else +#define STENCIL_WRITE_VALUE 0x1 +#define STENCIL_MASK_VALUE 0x1 +#endif + Stencil::Stencil(): mState(kDisabled) { } @@ -29,6 +38,18 @@ uint32_t Stencil::getStencilSize() { return STENCIL_BUFFER_SIZE; } +GLenum Stencil::getSmallestStencilFormat() { +#if !DEBUG_STENCIL + const Extensions& extensions = Extensions::getInstance(); + if (extensions.has1BitStencil()) { + return GL_STENCIL_INDEX1_OES; + } else if (extensions.has4BitStencil()) { + return GL_STENCIL_INDEX4_OES; + } +#endif + return GL_STENCIL_INDEX8; +} + void Stencil::clear() { glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); @@ -37,7 +58,7 @@ void Stencil::clear() { void Stencil::enableTest() { if (mState != kTest) { enable(); - glStencilFunc(GL_EQUAL, 0xff, 0xff); + glStencilFunc(GL_EQUAL, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE); // We only want to test, let's keep everything glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -48,7 +69,7 @@ void Stencil::enableTest() { void Stencil::enableWrite() { if (mState != kWrite) { enable(); - glStencilFunc(GL_ALWAYS, 0xff, 0xff); + glStencilFunc(GL_ALWAYS, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE); // The test always passes so the first two values are meaningless glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); diff --git a/libs/hwui/Stencil.h b/libs/hwui/Stencil.h index 2f8a66a54693..047f7ee111a0 100644 --- a/libs/hwui/Stencil.h +++ b/libs/hwui/Stencil.h @@ -21,6 +21,8 @@ #define LOG_TAG "OpenGLRenderer" #endif +#include <GLES2/gl2.h> + #include <cutils/compiler.h> namespace android { @@ -41,6 +43,11 @@ public: ANDROID_API static uint32_t getStencilSize(); /** + * Returns the smallest stencil format accepted by render buffers. + */ + static GLenum getSmallestStencilFormat(); + + /** * Clears the stencil buffer. */ void clear(); diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index abf2d98f1901..5cff5a552aed 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -219,7 +219,7 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege // We could also enable mipmapping if both bitmap dimensions are powers // of 2 but we'd have to deal with size changes. Let's keep this simple - const bool canMipMap = Caches::getInstance().extensions.hasNPot(); + const bool canMipMap = Extensions::getInstance().hasNPot(); // If the texture had mipmap enabled but not anymore, // force a glTexImage2D to discard the mipmap levels |