Add a RenderBuffer object to store stencil buffers.
Bug #7146141
This change is needed to add a render buffer cache to avoid
creating and destroying stencil buffers on every frame.
This change also allows the renderer to use a 1 bit or 4 bit
stencil buffer whenever possible.
Finally this change fixes a bug introduced by a previous CL
which causes the stencil buffer to not be updated in certain
conditions. The fix relies on a new optional parameter in
drawColorRects() that can be used to avoid performing a
quickReject on rectangles generated by the clip region.
Change-Id: I2f55a8e807009887b276a83cde9f53fd5c01199f
diff --git a/libs/hwui/RenderBuffer.h b/libs/hwui/RenderBuffer.h
new file mode 100644
index 0000000..927f265
--- /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