summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libs/hwui/Android.common.mk2
-rw-r--r--libs/hwui/Caches.cpp86
-rw-r--r--libs/hwui/Caches.h72
-rw-r--r--libs/hwui/Dither.cpp15
-rw-r--r--libs/hwui/Dither.h4
-rw-r--r--libs/hwui/FontRenderer.cpp16
-rw-r--r--libs/hwui/GradientCache.cpp2
-rw-r--r--libs/hwui/Image.cpp4
-rw-r--r--libs/hwui/Layer.cpp6
-rw-r--r--libs/hwui/LayerRenderer.cpp10
-rw-r--r--libs/hwui/OpenGLRenderer.cpp122
-rwxr-xr-xlibs/hwui/OpenGLRenderer.h22
-rw-r--r--libs/hwui/PathCache.cpp4
-rw-r--r--libs/hwui/PixelBuffer.cpp10
-rw-r--r--libs/hwui/SkiaShader.cpp8
-rw-r--r--libs/hwui/TextDropShadowCache.cpp2
-rw-r--r--libs/hwui/Texture.cpp52
-rw-r--r--libs/hwui/TextureCache.cpp2
-rw-r--r--libs/hwui/font/CacheTexture.cpp6
-rw-r--r--libs/hwui/renderstate/Blend.cpp121
-rw-r--r--libs/hwui/renderstate/Blend.h46
-rw-r--r--libs/hwui/renderstate/RenderState.cpp25
-rw-r--r--libs/hwui/renderstate/RenderState.h12
-rw-r--r--libs/hwui/renderstate/TextureState.cpp103
-rw-r--r--libs/hwui/renderstate/TextureState.h88
-rw-r--r--libs/hwui/renderthread/EglManager.cpp3
26 files changed, 498 insertions, 345 deletions
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index 7c1a724..de9ef06 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -7,11 +7,13 @@ LOCAL_CLANG_CFLAGS += \
LOCAL_SRC_FILES := \
font/CacheTexture.cpp \
font/Font.cpp \
+ renderstate/Blend.cpp \
renderstate/MeshState.cpp \
renderstate/PixelBufferState.cpp \
renderstate/RenderState.cpp \
renderstate/Scissor.cpp \
renderstate/Stencil.cpp \
+ renderstate/TextureState.cpp \
renderthread/CanvasContext.cpp \
renderthread/DrawFrameTask.cpp \
renderthread/EglManager.cpp \
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 1fb8092..cef2c84 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -49,6 +49,7 @@ Caches* Caches::sInstance = nullptr;
Caches::Caches(RenderState& renderState)
: patchCache(renderState)
+ , dither(*this)
, mRenderState(&renderState)
, mExtensions(Extensions::getInstance())
, mInitialized(false) {
@@ -71,13 +72,8 @@ bool Caches::init() {
ATRACE_NAME("Caches::init");
- glActiveTexture(gTextureUnits[0]);
- mTextureUnit = 0;
mRegionMesh = nullptr;
- blend = false;
- lastSrcMode = GL_ZERO;
- lastDstMode = GL_ZERO;
currentProgram = nullptr;
mFunctorsCount = 0;
@@ -90,8 +86,8 @@ bool Caches::init() {
mInitialized = true;
- resetBoundTextures();
- mPixelBufferState.reset(new PixelBufferState());
+ mPixelBufferState = new PixelBufferState();
+ mTextureState = new TextureState();
return true;
}
@@ -122,12 +118,6 @@ void Caches::initExtensions() {
}
void Caches::initConstraints() {
- GLint maxTextureUnits;
- glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
- if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
- ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
- }
-
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
}
@@ -216,8 +206,10 @@ void Caches::terminate() {
clearGarbage();
- mPixelBufferState.release();
-
+ delete mPixelBufferState;
+ mPixelBufferState = nullptr;
+ delete mTextureState;
+ mTextureState = nullptr;
mInitialized = false;
}
@@ -348,70 +340,6 @@ void Caches::flush(FlushMode mode) {
}
///////////////////////////////////////////////////////////////////////////////
-// Textures
-///////////////////////////////////////////////////////////////////////////////
-
-void Caches::activeTexture(GLuint textureUnit) {
- if (mTextureUnit != textureUnit) {
- glActiveTexture(gTextureUnits[textureUnit]);
- mTextureUnit = textureUnit;
- }
-}
-
-void Caches::resetActiveTexture() {
- mTextureUnit = -1;
-}
-
-void Caches::bindTexture(GLuint texture) {
- if (mBoundTextures[mTextureUnit] != texture) {
- glBindTexture(GL_TEXTURE_2D, texture);
- mBoundTextures[mTextureUnit] = texture;
- }
-}
-
-void Caches::bindTexture(GLenum target, GLuint texture) {
- if (target == GL_TEXTURE_2D) {
- bindTexture(texture);
- } else {
- // GLConsumer directly calls glBindTexture() with
- // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
- // since the cached state could be stale
- glBindTexture(target, texture);
- }
-}
-
-void Caches::deleteTexture(GLuint texture) {
- // When glDeleteTextures() is called on a currently bound texture,
- // OpenGL ES specifies that the texture is then considered unbound
- // Consider the following series of calls:
- //
- // glGenTextures -> creates texture name 2
- // glBindTexture(2)
- // glDeleteTextures(2) -> 2 is now unbound
- // glGenTextures -> can return 2 again
- //
- // If we don't call glBindTexture(2) after the second glGenTextures
- // call, any texture operation will be performed on the default
- // texture (name=0)
-
- unbindTexture(texture);
-
- glDeleteTextures(1, &texture);
-}
-
-void Caches::resetBoundTextures() {
- memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
-}
-
-void Caches::unbindTexture(GLuint texture) {
- for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
- if (mBoundTextures[i] == texture) {
- mBoundTextures[i] = 0;
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Tiling
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 8d23833..f6d3476 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -33,6 +33,7 @@
#include "PathCache.h"
#include "RenderBufferCache.h"
#include "renderstate/PixelBufferState.h"
+#include "renderstate/TextureState.h"
#include "ResourceCache.h"
#include "TessellationCache.h"
#include "TextDropShadowCache.h"
@@ -59,20 +60,6 @@ namespace uirenderer {
class GammaFontRenderer;
///////////////////////////////////////////////////////////////////////////////
-// Globals
-///////////////////////////////////////////////////////////////////////////////
-
-// GL ES 2.0 defines that at least 16 texture units must be supported
-#define REQUIRED_TEXTURE_UNITS_COUNT 3
-
-// Must define as many texture units as specified by REQUIRED_TEXTURE_UNITS_COUNT
-static const GLenum gTextureUnits[] = {
- GL_TEXTURE0,
- GL_TEXTURE1,
- GL_TEXTURE2
-};
-
-///////////////////////////////////////////////////////////////////////////////
// Caches
///////////////////////////////////////////////////////////////////////////////
@@ -155,49 +142,6 @@ public:
void deleteLayerDeferred(Layer* layer);
- /**
- * Activate the specified texture unit. The texture unit must
- * be specified using an integer number (0 for GL_TEXTURE0 etc.)
- */
- void activeTexture(GLuint textureUnit);
-
- /**
- * Invalidate the cached value of the active texture unit.
- */
- void resetActiveTexture();
-
- /**
- * Binds the specified texture as a GL_TEXTURE_2D texture.
- * All texture bindings must be performed with this method or
- * bindTexture(GLenum, GLuint).
- */
- void bindTexture(GLuint texture);
-
- /**
- * Binds the specified texture with the specified render target.
- * All texture bindings must be performed with this method or
- * bindTexture(GLuint).
- */
- void bindTexture(GLenum target, GLuint texture);
-
- /**
- * Deletes the specified texture and clears it from the cache
- * of bound textures.
- * All textures must be deleted using this method.
- */
- void deleteTexture(GLuint texture);
-
- /**
- * Signals that the cache of bound textures should be cleared.
- * Other users of the context may have altered which textures are bound.
- */
- void resetBoundTextures();
-
- /**
- * Clear the cache of bound textures.
- */
- void unbindTexture(GLuint texture);
-
void startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard);
void endTiling();
@@ -218,9 +162,6 @@ public:
void registerFunctors(uint32_t functorCount);
void unregisterFunctors(uint32_t functorCount);
- bool blend;
- GLenum lastSrcMode;
- GLenum lastDstMode;
Program* currentProgram;
bool drawDeferDisabled;
@@ -278,7 +219,8 @@ public:
int propertyAmbientShadowStrength;
int propertySpotShadowStrength;
- PixelBufferState& pixelBuffer() { return *mPixelBufferState; }
+ PixelBufferState& pixelBufferState() { return *mPixelBufferState; }
+ TextureState& textureState() { return *mTextureState; }
private:
enum OverdrawColorSet {
@@ -305,9 +247,8 @@ private:
RenderState* mRenderState;
- std::unique_ptr<PixelBufferState> mPixelBufferState; // TODO: move to RenderState
-
- GLuint mTextureUnit;
+ PixelBufferState* mPixelBufferState = nullptr; // TODO: move to RenderState
+ TextureState* mTextureState = nullptr; // TODO: move to RenderState
Extensions& mExtensions;
@@ -322,9 +263,6 @@ private:
uint32_t mFunctorsCount;
- // Caches texture bindings for the GL_TEXTURE_2D target
- GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
-
OverdrawColorSet mOverdrawDebugColorSet;
}; // class Caches
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 12d9389..d637ec1 100644
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -24,7 +24,10 @@ namespace uirenderer {
// Lifecycle
///////////////////////////////////////////////////////////////////////////////
-Dither::Dither(): mCaches(nullptr), mInitialized(false), mDitherTexture(0) {
+Dither::Dither(Caches& caches)
+ : mCaches(caches)
+ , mInitialized(false)
+ , mDitherTexture(0) {
}
void Dither::bindDitherTexture() {
@@ -32,7 +35,7 @@ void Dither::bindDitherTexture() {
bool useFloatTexture = Extensions::getInstance().hasFloatTextures();
glGenTextures(1, &mDitherTexture);
- mCaches->bindTexture(mDitherTexture);
+ mCaches.textureState().bindTexture(mDitherTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -71,13 +74,13 @@ void Dither::bindDitherTexture() {
mInitialized = true;
} else {
- mCaches->bindTexture(mDitherTexture);
+ mCaches.textureState().bindTexture(mDitherTexture);
}
}
void Dither::clear() {
if (mInitialized) {
- mCaches->deleteTexture(mDitherTexture);
+ mCaches.textureState().deleteTexture(mDitherTexture);
mInitialized = false;
}
}
@@ -87,10 +90,8 @@ void Dither::clear() {
///////////////////////////////////////////////////////////////////////////////
void Dither::setupProgram(Program* program, GLuint* textureUnit) {
- if (!mCaches) mCaches = &Caches::getInstance();
-
GLuint textureSlot = (*textureUnit)++;
- mCaches->activeTexture(textureSlot);
+ mCaches.textureState().activateTexture(textureSlot);
bindDitherTexture();
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
index 092ebf2..38633af 100644
--- a/libs/hwui/Dither.h
+++ b/libs/hwui/Dither.h
@@ -36,7 +36,7 @@ class Program;
*/
class Dither {
public:
- Dither();
+ Dither(Caches& caches);
void clear();
void setupProgram(Program* program, GLuint* textureUnit);
@@ -44,7 +44,7 @@ public:
private:
void bindDitherTexture();
- Caches* mCaches;
+ Caches& mCaches;
bool mInitialized;
GLuint mDitherTexture;
};
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 193474f..6dcd3e1 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -284,7 +284,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
uint32_t cacheWidth = cacheTexture->getWidth();
if (!cacheTexture->getPixelBuffer()) {
- Caches::getInstance().activeTexture(0);
+ Caches::getInstance().textureState().activateTexture(0);
// Large-glyph texture memory is allocated only as needed
cacheTexture->allocateTexture();
}
@@ -397,7 +397,7 @@ CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum for
CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
if (allocate) {
- Caches::getInstance().activeTexture(0);
+ Caches::getInstance().textureState().activateTexture(0);
cacheTexture->allocateTexture();
cacheTexture->allocateMesh();
}
@@ -443,8 +443,8 @@ void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheText
if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
if (cacheTexture->getTextureId() != lastTextureId) {
lastTextureId = cacheTexture->getTextureId();
- caches.activeTexture(0);
- caches.bindTexture(lastTextureId);
+ caches.textureState().activateTexture(0);
+ caches.textureState().bindTexture(lastTextureId);
}
if (cacheTexture->upload()) {
@@ -470,7 +470,7 @@ void FontRenderer::checkTextureUpdate() {
checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
// Unbind any PBO we might have used to update textures
- caches.pixelBuffer().unbind();
+ caches.pixelBufferState().unbind();
// Reset to default unpack row length to avoid affecting texture
// uploads in other parts of the renderer
@@ -507,11 +507,11 @@ void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
forceRebind = renderState.meshState().unbindMeshBuffer();
}
- caches.activeTexture(0);
+ caches.textureState().activateTexture(0);
first = false;
}
- caches.bindTexture(texture->getTextureId());
+ caches.textureState().bindTexture(texture->getTextureId());
texture->setLinearFiltering(mLinearFiltering, false);
TextureVertex* mesh = texture->mesh();
@@ -649,7 +649,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
// Unbind any PBO we might have used
- Caches::getInstance().pixelBuffer().unbind();
+ Caches::getInstance().pixelBufferState().unbind();
blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
}
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 0987d9b..416b0b3 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -285,7 +285,7 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, Texture*
memcpy(pixels + rowBytes, pixels, rowBytes);
glGenTextures(1, &texture->id);
- Caches::getInstance().bindTexture(texture->id);
+ Caches::getInstance().textureState().bindTexture(texture->id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (mUseFloatTexture) {
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
index edf3930..a31c546 100644
--- a/libs/hwui/Image.cpp
+++ b/libs/hwui/Image.cpp
@@ -39,7 +39,7 @@ Image::Image(sp<GraphicBuffer> buffer) {
} else {
// Create a 2D texture to sample from the EGLImage
glGenTextures(1, &mTexture);
- Caches::getInstance().bindTexture(mTexture);
+ Caches::getInstance().textureState().bindTexture(mTexture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
GLenum status = GL_NO_ERROR;
@@ -54,7 +54,7 @@ Image::~Image() {
eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), mImage);
mImage = EGL_NO_IMAGE_KHR;
- Caches::getInstance().deleteTexture(mTexture);
+ Caches::getInstance().textureState().deleteTexture(mTexture);
mTexture = 0;
}
}
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 7a4b830..7a026ef 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -134,7 +134,7 @@ bool Layer::resize(const uint32_t width, const uint32_t height) {
setSize(desiredWidth, desiredHeight);
if (fbo) {
- caches.activeTexture(0);
+ caches.textureState().activateTexture(0);
bindTexture();
allocateTexture();
@@ -195,7 +195,7 @@ void Layer::setColorFilter(SkColorFilter* filter) {
void Layer::bindTexture() const {
if (texture.id) {
- caches.bindTexture(renderTarget, texture.id);
+ caches.textureState().bindTexture(renderTarget, texture.id);
}
}
@@ -219,7 +219,7 @@ void Layer::deleteTexture() {
}
void Layer::clearTexture() {
- caches.unbindTexture(texture.id);
+ caches.textureState().unbindTexture(texture.id);
texture.id = 0;
}
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 076251f..d2f9a94 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -196,7 +196,7 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width
return nullptr;
}
- caches.activeTexture(0);
+ caches.textureState().activateTexture(0);
Layer* layer = caches.layerCache.get(renderState, width, height);
if (!layer) {
ALOGW("Could not obtain a layer");
@@ -283,7 +283,7 @@ Layer* LayerRenderer::createTextureLayer(RenderState& renderState) {
layer->region.clear();
layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
- Caches::getInstance().activeTexture(0);
+ Caches::getInstance().textureState().activateTexture(0);
layer->generateTexture();
return layer;
@@ -412,8 +412,8 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap*
glGenTextures(1, &texture);
if ((error = glGetError()) != GL_NO_ERROR) goto error;
- caches.activeTexture(0);
- caches.bindTexture(texture);
+ caches.textureState().activateTexture(0);
+ caches.textureState().bindTexture(texture);
glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
@@ -475,7 +475,7 @@ error:
renderState.bindFramebuffer(previousFbo);
layer->setAlpha(alpha, mode);
layer->setFbo(previousLayerFbo);
- caches.deleteTexture(texture);
+ caches.textureState().deleteTexture(texture);
caches.fboCache.put(fbo);
renderState.setViewport(previousViewportWidth, previousViewportHeight);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 42b246c..2378337 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -71,55 +71,6 @@ static GLenum getFilter(const SkPaint* paint) {
// Globals
///////////////////////////////////////////////////////////////////////////////
-/**
- * Structure mapping Skia xfermodes to OpenGL blending factors.
- */
-struct Blender {
- SkXfermode::Mode mode;
- GLenum src;
- GLenum dst;
-}; // struct Blender
-
-// In this array, the index of each Blender equals the value of the first
-// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
-static const Blender gBlends[] = {
- { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
- { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
- { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
- { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
- { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
- { SkXfermode::kModulate_Mode, GL_ZERO, GL_SRC_COLOR },
- { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
-};
-
-// This array contains the swapped version of each SkXfermode. For instance
-// this array's SrcOver blending mode is actually DstOver. You can refer to
-// createLayer() for more information on the purpose of this array.
-static const Blender gBlendsSwap[] = {
- { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE },
- { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO },
- { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA },
- { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
- { SkXfermode::kModulate_Mode, GL_DST_COLOR, GL_ZERO },
- { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
-};
///////////////////////////////////////////////////////////////////////////////
// Functions
@@ -234,7 +185,7 @@ void OpenGLRenderer::prepareDirty(float left, float top,
// for each layer and wait until the first drawing command
// to start the frame
if (currentSnapshot()->fbo == 0) {
- syncState();
+ mRenderState.blend().syncEnabled();
updateLayers();
} else {
startFrame();
@@ -267,14 +218,6 @@ void OpenGLRenderer::clear(float left, float top, float right, float bottom, boo
mRenderState.scissor().reset();
}
-void OpenGLRenderer::syncState() {
- if (mCaches.blend) {
- glEnable(GL_BLEND);
- } else {
- glDisable(GL_BLEND);
- }
-}
-
void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
if (!mSuppressTiling) {
const Snapshot* snapshot = currentSnapshot();
@@ -559,7 +502,7 @@ void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
void OpenGLRenderer::flushLayerUpdates() {
ATRACE_NAME("Update HW Layers");
- syncState();
+ mRenderState.blend().syncEnabled();
updateLayers();
flushLayers();
// Wait for all the layer updates to be executed
@@ -756,7 +699,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
return false;
}
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
if (!layer) {
return false;
@@ -896,7 +839,7 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto
mRenderState.meshState().unbindMeshBuffer();
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
// When the layer is stored in an FBO, we can save a bit of fillrate by
// drawing only the dirty region
@@ -1898,13 +1841,13 @@ void OpenGLRenderer::setupDrawSimpleMesh() {
}
void OpenGLRenderer::setupDrawTexture(GLuint texture) {
- if (texture) bindTexture(texture);
+ if (texture) mCaches.textureState().bindTexture(texture);
mTextureUnit++;
mRenderState.meshState().enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
- bindExternalTexture(texture);
+ mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
mTextureUnit++;
mRenderState.meshState().enableTexCoordsVertexArray();
}
@@ -2050,7 +1993,7 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top,
void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
int bitmapCount, TextureVertex* vertices, bool pureTranslate,
const Rect& bounds, const SkPaint* paint) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
if (!texture) return;
@@ -2081,7 +2024,7 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
return;
}
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = getTexture(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -2122,7 +2065,7 @@ void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int m
colors = tempColors.get();
}
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
const UvMapper& mapper(getMapper(texture));
@@ -2217,7 +2160,7 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
return;
}
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = getTexture(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -2317,7 +2260,7 @@ void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
}
if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -2371,7 +2314,7 @@ void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
*/
void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -2556,7 +2499,7 @@ void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bot
}
if (p->getPathEffect() != nullptr) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.getRoundRect(
right - left, bottom - top, rx, ry, p);
drawShape(left, top, texture, p);
@@ -2574,7 +2517,7 @@ void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p
return;
}
if (p->getPathEffect() != nullptr) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
drawShape(x - radius, y - radius, texture, p);
} else {
@@ -2597,7 +2540,7 @@ void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
}
if (p->getPathEffect() != nullptr) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
drawShape(left, top, texture, p);
} else {
@@ -2621,7 +2564,7 @@ void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
startAngle, sweepAngle, useCenter, p);
drawShape(left, top, texture, p);
@@ -2658,7 +2601,7 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
// only fill style is supported by drawConvexPath, since others have to handle joins
if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture =
mCaches.pathCache.getRect(right - left, bottom - top, p);
drawShape(left, top, texture, p);
@@ -2687,7 +2630,7 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
int bytesCount, int count, const float* positions,
FontRenderer& fontRenderer, int alpha, float x, float y) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
TextShadow textShadow;
if (!getTextShadow(paint, &textShadow)) {
@@ -3001,7 +2944,7 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
if (mState.currentlyIgnored()) return;
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.get(path, paint);
if (!texture) return;
@@ -3046,7 +2989,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
updateLayer(layer, true);
mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
if (CC_LIKELY(!layer->region.isEmpty())) {
if (layer->region.isRect()) {
@@ -3485,33 +3428,16 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
description.framebufferMode = mode;
description.swapSrcDst = swapSrcDst;
- if (mCaches.blend) {
- glDisable(GL_BLEND);
- mCaches.blend = false;
- }
-
+ mRenderState.blend().disable();
return;
} else {
mode = SkXfermode::kSrcOver_Mode;
}
}
-
- if (!mCaches.blend) {
- glEnable(GL_BLEND);
- }
-
- GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
- GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
-
- if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
- glBlendFunc(sourceMode, destMode);
- mCaches.lastSrcMode = sourceMode;
- mCaches.lastDstMode = destMode;
- }
- } else if (mCaches.blend) {
- glDisable(GL_BLEND);
+ mRenderState.blend().enable(mode, swapSrcDst);
+ } else {
+ mRenderState.blend().disable();
}
- mCaches.blend = blend;
}
bool OpenGLRenderer::useProgram(Program* program) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 94054ff..cf6f0c8 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -541,12 +541,6 @@ private:
void discardFramebuffer(float left, float top, float right, float bottom);
/**
- * Ensures the state of the renderer is the same as the state of
- * the GL context.
- */
- void syncState();
-
- /**
* Tells the GPU what part of the screen is about to be redrawn.
* This method will use the current layer space clip rect.
* This method needs to be invoked every time getTargetFbo() is
@@ -852,22 +846,6 @@ private:
bool canSkipText(const SkPaint* paint) const;
/**
- * Binds the specified texture. The texture unit must have been selected
- * prior to calling this method.
- */
- inline void bindTexture(GLuint texture) {
- mCaches.bindTexture(texture);
- }
-
- /**
- * Binds the specified EGLImage texture. The texture unit must have been selected
- * prior to calling this method.
- */
- inline void bindExternalTexture(GLuint texture) {
- mCaches.bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
- }
-
- /**
* Enable or disable blending as necessary. This function sets the appropriate
* blend function based on the specified xfermode.
*/
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index cc7f88d..d6eff85 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -230,7 +230,7 @@ void PathCache::removeTexture(PathTexture* texture) {
}
if (texture->id) {
- Caches::getInstance().deleteTexture(texture->id);
+ Caches::getInstance().textureState().deleteTexture(texture->id);
}
delete texture;
}
@@ -312,7 +312,7 @@ void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) {
glGenTextures(1, &texture->id);
- Caches::getInstance().bindTexture(texture->id);
+ Caches::getInstance().textureState().bindTexture(texture->id);
// Textures are Alpha8
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 62eb68c..9665a68 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -101,9 +101,9 @@ GpuPixelBuffer::GpuPixelBuffer(GLenum format,
, mCaches(Caches::getInstance()){
glGenBuffers(1, &mBuffer);
- mCaches.pixelBuffer().bind(mBuffer);
+ mCaches.pixelBufferState().bind(mBuffer);
glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW);
- mCaches.pixelBuffer().unbind();
+ mCaches.pixelBufferState().unbind();
}
GpuPixelBuffer::~GpuPixelBuffer() {
@@ -112,7 +112,7 @@ GpuPixelBuffer::~GpuPixelBuffer() {
uint8_t* GpuPixelBuffer::map(AccessMode mode) {
if (mAccessMode == kAccessMode_None) {
- mCaches.pixelBuffer().bind(mBuffer);
+ mCaches.pixelBufferState().bind(mBuffer);
mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
#if DEBUG_OPENGL
if (!mMappedPointer) {
@@ -131,7 +131,7 @@ uint8_t* GpuPixelBuffer::map(AccessMode mode) {
void GpuPixelBuffer::unmap() {
if (mAccessMode != kAccessMode_None) {
if (mMappedPointer) {
- mCaches.pixelBuffer().bind(mBuffer);
+ mCaches.pixelBufferState().bind(mBuffer);
GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
if (status == GL_FALSE) {
ALOGE("Corrupted GPU pixel buffer");
@@ -148,7 +148,7 @@ uint8_t* GpuPixelBuffer::getMappedPointer() const {
void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
// If the buffer is not mapped, unmap() will not bind it
- mCaches.pixelBuffer().bind(mBuffer);
+ mCaches.pixelBufferState().bind(mBuffer);
unmap();
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 2c09344..e13c861 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -57,7 +57,7 @@ static inline void bindUniformColor(int slot, uint32_t color) {
}
static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
- caches->bindTexture(texture->id);
+ caches->textureState().bindTexture(texture->id);
texture->setWrapST(wrapS, wrapT);
}
@@ -176,7 +176,7 @@ void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
}
GLuint textureSlot = (*textureUnit)++;
- caches->activeTexture(textureSlot);
+ caches->textureState().activateTexture(textureSlot);
const float width = layer->getWidth();
const float height = layer->getHeight();
@@ -270,7 +270,7 @@ void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
}
GLuint textureSlot = (*textureUnit)++;
- Caches::getInstance().activeTexture(textureSlot);
+ Caches::getInstance().textureState().activateTexture(textureSlot);
BitmapShaderInfo shaderInfo;
if (!bitmapShaderHelper(caches, nullptr, &shaderInfo, extensions, bitmap, xy)) {
@@ -392,7 +392,7 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri
shader.asAGradient(&gradInfo);
}
GLuint textureSlot = (*textureUnit)++;
- caches->activeTexture(textureSlot);
+ caches->textureState().activateTexture(textureSlot);
#ifndef SK_SCALAR_IS_FLOAT
#error Need to convert gradInfo.fColorOffsets to float!
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 4ec298d..c2e88f3 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -207,7 +207,7 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* text,
glGenTextures(1, &texture->id);
- caches.bindTexture(texture->id);
+ caches.textureState().bindTexture(texture->id);
// Textures are Alpha8
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 58fd972..512f5cf 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -24,18 +24,44 @@
namespace android {
namespace uirenderer {
-Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0),
- cleanup(false), bitmapSize(0), mipMap(false), uvMapper(nullptr), isInUse(false),
- mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
- mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
- mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) {
+Texture::Texture()
+ : id(0)
+ , generation(0)
+ , blend(false)
+ , width(0)
+ , height(0)
+ , cleanup(false)
+ , bitmapSize(0)
+ , mipMap(false)
+ , uvMapper(nullptr)
+ , isInUse(false)
+ , mWrapS(GL_CLAMP_TO_EDGE)
+ , mWrapT(GL_CLAMP_TO_EDGE)
+ , mMinFilter(GL_NEAREST)
+ , mMagFilter(GL_NEAREST)
+ , mFirstFilter(true)
+ , mFirstWrap(true)
+ , mCaches(Caches::getInstance()) {
}
-Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0),
- cleanup(false), bitmapSize(0), mipMap(false), uvMapper(nullptr), isInUse(false),
- mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
- mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
- mFirstFilter(true), mFirstWrap(true), mCaches(caches) {
+Texture::Texture(Caches& caches)
+ : id(0)
+ , generation(0)
+ , blend(false)
+ , width(0)
+ , height(0)
+ , cleanup(false)
+ , bitmapSize(0)
+ , mipMap(false)
+ , uvMapper(nullptr)
+ , isInUse(false)
+ , mWrapS(GL_CLAMP_TO_EDGE)
+ , mWrapT(GL_CLAMP_TO_EDGE)
+ , mMinFilter(GL_NEAREST)
+ , mMagFilter(GL_NEAREST)
+ , mFirstFilter(true)
+ , mFirstWrap(true)
+ , mCaches(caches) {
}
void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force,
@@ -48,7 +74,7 @@ void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force
mWrapT = wrapT;
if (bindTexture) {
- mCaches.bindTexture(renderTarget, id);
+ mCaches.textureState().bindTexture(renderTarget, id);
}
glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
@@ -66,7 +92,7 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for
mMagFilter = mag;
if (bindTexture) {
- mCaches.bindTexture(renderTarget, id);
+ mCaches.textureState().bindTexture(renderTarget, id);
}
if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
@@ -77,7 +103,7 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for
}
void Texture::deleteTexture() const {
- mCaches.deleteTexture(id);
+ mCaches.textureState().deleteTexture(id);
}
}; // namespace uirenderer
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 524f206..fe8fb5b 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -296,7 +296,7 @@ void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, boo
texture->width = bitmap->width();
texture->height = bitmap->height();
- Caches::getInstance().bindTexture(texture->id);
+ Caches::getInstance().textureState().bindTexture(texture->id);
switch (bitmap->colorType()) {
case kAlpha_8_SkColorType:
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 128e392..53fa0dc 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -157,7 +157,7 @@ void CacheTexture::releaseTexture() {
mTexture = nullptr;
}
if (mTextureId) {
- mCaches.deleteTexture(mTextureId);
+ mCaches.textureState().deleteTexture(mTextureId);
mTextureId = 0;
}
mDirty = false;
@@ -169,7 +169,7 @@ void CacheTexture::setLinearFiltering(bool linearFiltering, bool bind) {
mLinearFiltering = linearFiltering;
const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
- if (bind) mCaches.bindTexture(getTextureId());
+ if (bind) mCaches.textureState().bindTexture(getTextureId());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
}
@@ -189,7 +189,7 @@ void CacheTexture::allocateTexture() {
if (!mTextureId) {
glGenTextures(1, &mTextureId);
- mCaches.bindTexture(mTextureId);
+ mCaches.textureState().bindTexture(mTextureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Initialize texture dimensions
glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
new file mode 100644
index 0000000..3e7b721
--- /dev/null
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 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 <renderstate/Blend.h>
+#include "Program.h"
+
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure mapping Skia xfermodes to OpenGL blending factors.
+ */
+struct Blender {
+ SkXfermode::Mode mode;
+ GLenum src;
+ GLenum dst;
+};
+
+// In this array, the index of each Blender equals the value of the first
+// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
+const Blender kBlends[] = {
+ { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
+ { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
+ { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+ { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
+ { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+ { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
+ { SkXfermode::kModulate_Mode, GL_ZERO, GL_SRC_COLOR },
+ { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
+};
+
+// This array contains the swapped version of each SkXfermode. For instance
+// this array's SrcOver blending mode is actually DstOver. You can refer to
+// createLayer() for more information on the purpose of this array.
+const Blender kBlendsSwap[] = {
+ { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE },
+ { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO },
+ { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+ { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA },
+ { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+ { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
+ { SkXfermode::kModulate_Mode, GL_DST_COLOR, GL_ZERO },
+ { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
+};
+
+Blend::Blend()
+ : mEnabled(false)
+ , mSrcMode(GL_ZERO)
+ , mDstMode(GL_ZERO) {
+ // gl blending off by default
+}
+
+void Blend::enable(SkXfermode::Mode mode, bool swapSrcDst) {
+ // enable
+ if (!mEnabled) {
+ glEnable(GL_BLEND);
+ mEnabled = true;
+ }
+
+ // select blend mode
+ GLenum sourceMode = swapSrcDst ? kBlendsSwap[mode].src : kBlends[mode].src;
+ GLenum destMode = swapSrcDst ? kBlendsSwap[mode].dst : kBlends[mode].dst;
+
+ if (sourceMode != mSrcMode || destMode != mSrcMode) {
+ glBlendFunc(sourceMode, destMode);
+ mSrcMode = sourceMode;
+ mDstMode = destMode;
+ }
+}
+
+void Blend::disable() {
+ if (mEnabled) {
+ glDisable(GL_BLEND);
+ mEnabled = false;
+ }
+}
+
+void Blend::invalidate() {
+ syncEnabled();
+ mSrcMode = mDstMode = GL_ZERO;
+}
+
+void Blend::syncEnabled() {
+ if (mEnabled) {
+ glEnable(GL_BLEND);
+ } else {
+ glDisable(GL_BLEND);
+ }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
new file mode 100644
index 0000000..b82b477
--- /dev/null
+++ b/libs/hwui/renderstate/Blend.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_BLEND_H
+#define RENDERSTATE_BLEND_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class Blend {
+ friend class RenderState;
+public:
+ void enable(SkXfermode::Mode mode, bool swapSrcDst);
+ void disable();
+ void syncEnabled();
+private:
+ Blend();
+ void invalidate();
+ bool mEnabled;
+ GLenum mSrcMode;
+ GLenum mDstMode;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index e4c8745..f913cd9 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -23,10 +23,6 @@ namespace uirenderer {
RenderState::RenderState(renderthread::RenderThread& thread)
: mRenderThread(thread)
- , mCaches(nullptr)
- , mMeshState(nullptr)
- , mScissor(nullptr)
- , mStencil(nullptr)
, mViewportWidth(0)
, mViewportHeight(0)
, mFramebuffer(0) {
@@ -34,13 +30,14 @@ RenderState::RenderState(renderthread::RenderThread& thread)
}
RenderState::~RenderState() {
- LOG_ALWAYS_FATAL_IF(mMeshState || mScissor || mStencil,
+ LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
"State object lifecycle not managed correctly");
}
void RenderState::onGLContextCreated() {
- LOG_ALWAYS_FATAL_IF(mMeshState || mScissor || mStencil,
+ LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
"State object lifecycle not managed correctly");
+ mBlend = new Blend();
mMeshState = new MeshState();
mScissor = new Scissor();
mStencil = new Stencil();
@@ -92,6 +89,10 @@ void RenderState::onGLContextDestroyed() {
std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
mAssetAtlas.terminate();
+ mCaches->terminate();
+
+ delete mBlend;
+ mBlend = nullptr;
delete mMeshState;
mMeshState = nullptr;
delete mScissor;
@@ -132,7 +133,7 @@ void RenderState::interruptForFunctorInvoke() {
mCaches->currentProgram = nullptr;
}
}
- mCaches->resetActiveTexture();
+ mCaches->textureState().resetActiveTexture();
meshState().unbindMeshBuffer();
meshState().unbindIndicesBuffer();
meshState().resetVertexPointers();
@@ -148,14 +149,10 @@ void RenderState::resumeFromFunctorInvoke() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
scissor().invalidate();
+ blend().invalidate();
- mCaches->activeTexture(0);
- mCaches->resetBoundTextures();
-
- mCaches->blend = true;
- glEnable(GL_BLEND);
- glBlendFunc(mCaches->lastSrcMode, mCaches->lastDstMode);
- glBlendEquation(GL_FUNC_ADD);
+ mCaches->textureState().activateTexture(0);
+ mCaches->textureState().resetBoundTextures();
}
void RenderState::debugOverdraw(bool enable, bool clear) {
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index d1ee64a..4180f44 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -24,7 +24,7 @@
#include <utils/RefBase.h>
#include <private/hwui/DrawGlInfo.h>
-
+#include <renderstate/Blend.h>
#include "AssetAtlas.h"
#include "Caches.h"
#include "renderstate/MeshState.h"
@@ -84,6 +84,7 @@ public:
void postDecStrong(VirtualLightRefBase* object);
AssetAtlas& assetAtlas() { return mAssetAtlas; }
+ Blend& blend() { return *mBlend; }
MeshState& meshState() { return *mMeshState; }
Scissor& scissor() { return *mScissor; }
Stencil& stencil() { return *mStencil; }
@@ -100,11 +101,12 @@ private:
renderthread::RenderThread& mRenderThread;
- Caches* mCaches;
+ Caches* mCaches = nullptr;
- MeshState* mMeshState;
- Scissor* mScissor;
- Stencil* mStencil;
+ Blend* mBlend = nullptr;
+ MeshState* mMeshState = nullptr;
+ Scissor* mScissor = nullptr;
+ Stencil* mStencil = nullptr;
AssetAtlas mAssetAtlas;
std::set<Layer*> mActiveLayers;
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
new file mode 100644
index 0000000..1a638d2
--- /dev/null
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 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 <renderstate/TextureState.h>
+
+namespace android {
+namespace uirenderer {
+
+// Must define as many texture units as specified by kTextureUnitsCount
+const GLenum kTextureUnits[] = {
+ GL_TEXTURE0,
+ GL_TEXTURE1,
+ GL_TEXTURE2
+};
+
+TextureState::TextureState()
+ : mTextureUnit(0) {
+ glActiveTexture(kTextureUnits[0]);
+ resetBoundTextures();
+
+ GLint maxTextureUnits;
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+ LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
+ "At least %d texture units are required!", kTextureUnitsCount);
+}
+
+void TextureState::activateTexture(GLuint textureUnit) {
+ if (mTextureUnit != textureUnit) {
+ glActiveTexture(kTextureUnits[textureUnit]);
+ mTextureUnit = textureUnit;
+ }
+}
+
+void TextureState::resetActiveTexture() {
+ mTextureUnit = -1;
+}
+
+void TextureState::bindTexture(GLuint texture) {
+ if (mBoundTextures[mTextureUnit] != texture) {
+ glBindTexture(GL_TEXTURE_2D, texture);
+ mBoundTextures[mTextureUnit] = texture;
+ }
+}
+
+void TextureState::bindTexture(GLenum target, GLuint texture) {
+ if (target == GL_TEXTURE_2D) {
+ bindTexture(texture);
+ } else {
+ // GLConsumer directly calls glBindTexture() with
+ // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
+ // since the cached state could be stale
+ glBindTexture(target, texture);
+ }
+}
+
+void TextureState::deleteTexture(GLuint texture) {
+ // When glDeleteTextures() is called on a currently bound texture,
+ // OpenGL ES specifies that the texture is then considered unbound
+ // Consider the following series of calls:
+ //
+ // glGenTextures -> creates texture name 2
+ // glBindTexture(2)
+ // glDeleteTextures(2) -> 2 is now unbound
+ // glGenTextures -> can return 2 again
+ //
+ // If we don't call glBindTexture(2) after the second glGenTextures
+ // call, any texture operation will be performed on the default
+ // texture (name=0)
+
+ unbindTexture(texture);
+
+ glDeleteTextures(1, &texture);
+}
+
+void TextureState::resetBoundTextures() {
+ for (int i = 0; i < kTextureUnitsCount; i++) {
+ mBoundTextures[i] = 0;
+ }
+}
+
+void TextureState::unbindTexture(GLuint texture) {
+ for (int i = 0; i < kTextureUnitsCount; i++) {
+ if (mBoundTextures[i] == texture) {
+ mBoundTextures[i] = 0;
+ }
+ }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
new file mode 100644
index 0000000..5a57b9f
--- /dev/null
+++ b/libs/hwui/renderstate/TextureState.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_TEXTURESTATE_H
+#define RENDERSTATE_TEXTURESTATE_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class TextureState {
+ friend class Caches; // TODO: move to RenderState
+public:
+ /**
+ * Activate the specified texture unit. The texture unit must
+ * be specified using an integer number (0 for GL_TEXTURE0 etc.)
+ */
+ void activateTexture(GLuint textureUnit);
+
+ /**
+ * Invalidate the cached value of the active texture unit.
+ */
+ void resetActiveTexture();
+
+ /**
+ * Binds the specified texture as a GL_TEXTURE_2D texture.
+ * All texture bindings must be performed with this method or
+ * bindTexture(GLenum, GLuint).
+ */
+ void bindTexture(GLuint texture);
+
+ /**
+ * Binds the specified texture with the specified render target.
+ * All texture bindings must be performed with this method or
+ * bindTexture(GLuint).
+ */
+ void bindTexture(GLenum target, GLuint texture);
+
+ /**
+ * Deletes the specified texture and clears it from the cache
+ * of bound textures.
+ * All textures must be deleted using this method.
+ */
+ void deleteTexture(GLuint texture);
+
+ /**
+ * Signals that the cache of bound textures should be cleared.
+ * Other users of the context may have altered which textures are bound.
+ */
+ void resetBoundTextures();
+
+ /**
+ * Clear the cache of bound textures.
+ */
+ void unbindTexture(GLuint texture);
+private:
+ // total number of texture units available for use
+ static const int kTextureUnitsCount = 3;
+
+ TextureState();
+ GLuint mTextureUnit;
+
+ // Caches texture bindings for the GL_TEXTURE_2D target
+ GLuint mBoundTextures[kTextureUnitsCount];
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index c4feb41..f2337cb 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -214,9 +214,6 @@ void EglManager::destroy() {
if (mEglDisplay == EGL_NO_DISPLAY) return;
usePBufferSurface();
- if (Caches::hasInstance()) {
- Caches::getInstance().terminate();
- }
mRenderThread.renderState().onGLContextDestroyed();
eglDestroyContext(mEglDisplay, mEglContext);