Refactor blending and texture gl state

Change-Id: Ia6b3c8b2afd3dfcee7f3ce401d846b789612054a
This commit is contained in:
Chris Craik
2015-01-29 09:45:09 -08:00
parent 1b68ce327a
commit 44eb2c0086
26 changed files with 498 additions and 345 deletions

View File

@@ -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 \

View File

@@ -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;
}
@@ -347,70 +339,6 @@ void Caches::flush(FlushMode mode) {
glFinish();
}
///////////////////////////////////////////////////////////////////////////////
// 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
///////////////////////////////////////////////////////////////////////////////

View File

@@ -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"
@@ -58,20 +59,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

View File

@@ -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();

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -540,12 +540,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.
@@ -851,22 +845,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.

View File

@@ -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);

View File

@@ -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));

View File

@@ -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!

View File

@@ -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);

View File

@@ -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

View File

@@ -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:

View File

@@ -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,

View File

@@ -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 */

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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

View File

@@ -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);