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
This commit is contained in:
@@ -14,6 +14,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
|
||||
DisplayListLogBuffer.cpp \
|
||||
DisplayListRenderer.cpp \
|
||||
Dither.cpp \
|
||||
Extensions.cpp \
|
||||
FboCache.cpp \
|
||||
GradientCache.cpp \
|
||||
Layer.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
87
libs/hwui/Extensions.cpp
Normal file
87
libs/hwui/Extensions.cpp
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
171
libs/hwui/RenderBuffer.h
Normal file
171
libs/hwui/RenderBuffer.h
Normal file
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#define LOG_TAG "OpenGLRenderer"
|
||||
#endif
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include <cutils/compiler.h>
|
||||
|
||||
namespace android {
|
||||
@@ -40,6 +42,11 @@ public:
|
||||
*/
|
||||
ANDROID_API static uint32_t getStencilSize();
|
||||
|
||||
/**
|
||||
* Returns the smallest stencil format accepted by render buffers.
|
||||
*/
|
||||
static GLenum getSmallestStencilFormat();
|
||||
|
||||
/**
|
||||
* Clears the stencil buffer.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user