Loading core/java/android/view/GLES20Canvas.java +14 −3 Original line number Diff line number Diff line Loading @@ -248,6 +248,17 @@ class GLES20Canvas extends HardwareCanvas { private static native boolean nIsBackBufferPreserved(); /** * Disables v-sync. For performance testing only. * * @hide */ public static void disableVsync() { nDisableVsync(); } private static native void nDisableVsync(); @Override void onPreDraw(Rect dirty) { if (dirty != null) { Loading core/java/android/view/HardwareRenderer.java +26 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,16 @@ public abstract class HardwareRenderer { */ static final String RENDER_DIRTY_REGIONS_PROPERTY = "hwui.render_dirty_regions"; /** * System property used to enable or disable vsync. * The default value of this property is assumed to be false. * * Possible values: * "true", to disable vsync * "false", to enable vsync */ static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync"; /** * Turn on to draw dirty regions every other frame. */ Loading Loading @@ -303,6 +313,7 @@ public abstract class HardwareRenderer { boolean mDirtyRegions; final boolean mDirtyRegionsRequested; final boolean mVsyncDisabled; final int mGlVersion; final boolean mTranslucent; Loading @@ -314,10 +325,17 @@ public abstract class HardwareRenderer { GlRenderer(int glVersion, boolean translucent) { mGlVersion = glVersion; mTranslucent = translucent; final String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true"); //noinspection PointlessBooleanExpression,ConstantConditions mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty); mDirtyRegionsRequested = mDirtyRegions; final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false"); mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty); if (mVsyncDisabled) { Log.d(LOG_TAG, "Disabling v-sync"); } } /** Loading Loading @@ -764,6 +782,14 @@ public abstract class HardwareRenderer { } } @Override void setup(int width, int height) { super.setup(width, height); if (mVsyncDisabled) { GLES20Canvas.disableVsync(); } } @Override DisplayList createDisplayList(View v) { return new GLES20DisplayList(v); Loading core/jni/android_view_GLES20Canvas.cpp +18 −5 Original line number Diff line number Diff line Loading @@ -115,6 +115,18 @@ static jboolean android_view_GLES20Canvas_isBackBufferPreserved(JNIEnv* env, job return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED; } static void android_view_GLES20Canvas_disableVsync(JNIEnv* env, jobject clazz) { EGLDisplay display = eglGetCurrentDisplay(); eglGetError(); eglSwapInterval(display, 0); EGLint error = eglGetError(); if (error != EGL_SUCCESS) { RENDERER_LOGD("Could not disable v-sync (%x)", error); } } // ---------------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------------- Loading Loading @@ -621,7 +633,7 @@ static Layer* android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject if (layer) { jint* storage = env->GetIntArrayElements(layerInfo, NULL); storage[0] = layer->texture; storage[0] = layer->getTexture(); env->ReleaseIntArrayElements(layerInfo, storage, 0); } Loading @@ -634,8 +646,8 @@ static Layer* android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz, if (layer) { jint* storage = env->GetIntArrayElements(layerInfo, NULL); storage[0] = layer->width; storage[1] = layer->height; storage[0] = layer->getWidth(); storage[1] = layer->getHeight(); env->ReleaseIntArrayElements(layerInfo, storage, 0); } Loading @@ -647,8 +659,8 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz, LayerRenderer::resizeLayer(layer, width, height); jint* storage = env->GetIntArrayElements(layerInfo, NULL); storage[0] = layer->width; storage[1] = layer->height; storage[0] = layer->getWidth(); storage[1] = layer->getHeight(); env->ReleaseIntArrayElements(layerInfo, storage, 0); } Loading Loading @@ -722,6 +734,7 @@ static JNINativeMethod gMethods[] = { #ifdef USE_OPENGL_RENDERER { "nIsBackBufferPreserved", "()Z", (void*) android_view_GLES20Canvas_isBackBufferPreserved }, { "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer }, { "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync }, { "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer }, { "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer }, Loading libs/hwui/Layer.h +184 −47 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "Rect.h" #include "SkiaColorFilter.h" #include "Texture.h" #include "Vertex.h" namespace android { Loading @@ -40,14 +41,18 @@ namespace uirenderer { * A layer has dimensions and is backed by an OpenGL texture or FBO. */ struct Layer { Layer(const uint32_t layerWidth, const uint32_t layerHeight): width(layerWidth), height(layerHeight) { Layer(const uint32_t layerWidth, const uint32_t layerHeight) { mesh = NULL; meshIndices = NULL; meshElementCount = 0; isCacheable = true; isTextureLayer = false; cacheable = true; textureLayer = false; renderTarget = GL_TEXTURE_2D; texture.width = layerWidth; texture.height = layerHeight; colorFilter = NULL; firstFilter = true; firstWrap = true; } ~Layer() { Loading @@ -64,12 +69,152 @@ struct Layer { regionRect.set(bounds.leftTop().x, bounds.leftTop().y, bounds.rightBottom().x, bounds.rightBottom().y); const float texX = 1.0f / float(width); const float texY = 1.0f / float(height); const float texX = 1.0f / float(texture.width); const float texY = 1.0f / float(texture.height); const float height = layer.getHeight(); texCoords.set( regionRect.left * texX, (height - regionRect.top) * texY, regionRect.right * texX, (height - regionRect.bottom) * texY); regionRect.translate(layer.left, layer.top); } inline uint32_t getWidth() { return texture.width; } inline uint32_t getHeight() { return texture.height; } void setSize(uint32_t width, uint32_t height) { texture.width = width; texture.height = height; } inline void setBlend(bool blend) { texture.blend = blend; } inline bool isBlend() { return texture.blend; } inline void setAlpha(int alpha) { this->alpha = alpha; } inline void setAlpha(int alpha, SkXfermode::Mode mode) { this->alpha = alpha; this->mode = mode; } inline int getAlpha() { return alpha; } inline SkXfermode::Mode getMode() { return mode; } inline void setEmpty(bool empty) { this->empty = empty; } inline bool isEmpty() { return empty; } inline void setFbo(GLuint fbo) { this->fbo = fbo; } inline GLuint getFbo() { return fbo; } inline GLuint* getTexturePointer() { return &texture.id; } inline GLuint getTexture() { return texture.id; } inline GLenum getRenderTarget() { return renderTarget; } inline void setRenderTarget(GLenum renderTarget) { this->renderTarget = renderTarget; } void setWrap(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false) { if (firstWrap || force || wrapS != texture.wrapS || wrapT != texture.wrapT) { firstWrap = true; texture.setWrap(wrapS, wrapT); if (bindTexture) { glBindTexture(renderTarget, texture.id); } glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS); glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT); } } void setFilter(GLenum min, GLenum mag, bool bindTexture = false, bool force = false) { if (firstFilter || force || min != texture.minFilter || mag != texture.magFilter) { firstFilter = false; texture.setFilter(min, mag); if (bindTexture) { glBindTexture(renderTarget, texture.id); } glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min); glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag); } } inline bool isCacheable() { return cacheable; } inline void setCacheable(bool cacheable) { this->cacheable = cacheable; } inline bool isTextureLayer() { return textureLayer; } inline void setTextureLayer(bool textureLayer) { this->textureLayer = textureLayer; } inline SkiaColorFilter* getColorFilter() { return colorFilter; } inline void setColorFilter(SkiaColorFilter* filter) { colorFilter = filter; } inline void bindTexture() { glBindTexture(renderTarget, texture.id); } inline void generateTexture() { glGenTextures(1, &texture.id); } inline void deleteTexture() { if (texture.id) glDeleteTextures(1, &texture.id); } inline void allocateTexture(GLenum format, GLenum storage) { glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL); } inline mat4& getTexTransform() { return texTransform; } /** Loading @@ -82,23 +227,29 @@ struct Layer { Rect texCoords; /** * Name of the FBO used to render the layer. If the name is 0 * this layer is not backed by an FBO, but a simple texture. * Dirty region indicating what parts of the layer * have been drawn. */ GLuint fbo; Region region; /** * Opacity of the layer. * If the region is a rectangle, coordinates of the * region are stored here. */ int alpha; Rect regionRect; /** * Blending mode of the layer. * If the layer can be rendered as a mesh, this is non-null. */ SkXfermode::Mode mode; TextureVertex* mesh; uint16_t* meshIndices; GLsizei meshElementCount; private: /** * Indicates whether this layer should be blended. * Name of the FBO used to render the layer. If the name is 0 * this layer is not backed by an FBO, but a simple texture. */ bool blend; GLuint fbo; /** * Indicates whether this layer has been used already. Loading @@ -106,28 +257,25 @@ struct Layer { bool empty; /** * Name of the texture used to render the layer. * The texture backing this layer. */ GLuint texture; /** * Width of the layer texture. */ uint32_t width; Texture texture; /** * Height of the layer texture. * If set to true (by default), the layer can be reused. */ uint32_t height; bool cacheable; /** * Dirty region indicating what parts of the layer * have been drawn. * When set to true, this layer must be treated as a texture * layer. */ Region region; bool textureLayer; /** * If the region is a rectangle, coordinates of the * region are stored here. * Indicates the render target. */ Rect regionRect; GLenum renderTarget; /** * Color filter used to draw this layer. Optional. Loading @@ -135,32 +283,21 @@ struct Layer { SkiaColorFilter* colorFilter; /** * If the layer can be rendered as a mesh, this is non-null. */ TextureVertex* mesh; uint16_t* meshIndices; GLsizei meshElementCount; /** * If set to true (by default), the layer can be reused. * Opacity of the layer. */ bool isCacheable; int alpha; /** * When set to true, this layer must be treated as a texture * layer. * Blending mode of the layer. */ bool isTextureLayer; SkXfermode::Mode mode; /** * Optional texture coordinates transform. */ mat4 texTransform; /** * Indicates the render target. */ GLenum renderTarget; bool firstFilter; bool firstWrap; }; // struct Layer }; // namespace uirenderer Loading libs/hwui/LayerCache.cpp +22 −28 Original line number Diff line number Diff line Loading @@ -68,8 +68,8 @@ void LayerCache::setMaxSize(uint32_t maxSize) { void LayerCache::deleteLayer(Layer* layer) { if (layer) { mSize -= layer->width * layer->height * 4; glDeleteTextures(1, &layer->texture); mSize -= layer->getWidth() * layer->getHeight() * 4; layer->deleteTexture(); delete layer; } } Loading @@ -93,29 +93,23 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) { mCache.removeAt(index); layer = entry.mLayer; mSize -= layer->width * layer->height * 4; mSize -= layer->getWidth() * layer->getHeight() * 4; LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height); LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight()); } else { LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight); layer = new Layer(entry.mWidth, entry.mHeight); layer->blend = true; layer->empty = true; layer->fbo = 0; layer->colorFilter = NULL; glGenTextures(1, &layer->texture); glBindTexture(GL_TEXTURE_2D, layer->texture); layer->setBlend(true); layer->setEmpty(true); layer->setFbo(0); layer->generateTexture(); layer->bindTexture(); layer->setFilter(GL_NEAREST, GL_NEAREST); layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); #if DEBUG_LAYERS size_t size = mCache.size(); for (size_t i = 0; i < size; i++) { Loading @@ -133,30 +127,30 @@ bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t heigh // size already in the cache, and reuse it instead of creating a new one LayerEntry entry(width, height); if (entry.mWidth <= layer->width && entry.mHeight <= layer->height) { if (entry.mWidth <= layer->getWidth() && entry.mHeight <= layer->getHeight()) { return true; } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, layer->texture); uint32_t oldWidth = layer->getWidth(); uint32_t oldHeight = layer->getHeight(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); layer->bindTexture(); layer->setSize(entry.mWidth, entry.mHeight); layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); if (glGetError() != GL_NO_ERROR) { layer->setSize(oldWidth, oldHeight); return false; } layer->width = entry.mWidth; layer->height = entry.mHeight; return true; } bool LayerCache::put(Layer* layer) { if (!layer->isCacheable) return false; if (!layer->isCacheable()) return false; const uint32_t size = layer->width * layer->height * 4; const uint32_t size = layer->getWidth() * layer->getHeight() * 4; // Don't even try to cache a layer that's bigger than the cache if (size < mMaxSize) { // TODO: Use an LRU Loading Loading
core/java/android/view/GLES20Canvas.java +14 −3 Original line number Diff line number Diff line Loading @@ -248,6 +248,17 @@ class GLES20Canvas extends HardwareCanvas { private static native boolean nIsBackBufferPreserved(); /** * Disables v-sync. For performance testing only. * * @hide */ public static void disableVsync() { nDisableVsync(); } private static native void nDisableVsync(); @Override void onPreDraw(Rect dirty) { if (dirty != null) { Loading
core/java/android/view/HardwareRenderer.java +26 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,16 @@ public abstract class HardwareRenderer { */ static final String RENDER_DIRTY_REGIONS_PROPERTY = "hwui.render_dirty_regions"; /** * System property used to enable or disable vsync. * The default value of this property is assumed to be false. * * Possible values: * "true", to disable vsync * "false", to enable vsync */ static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync"; /** * Turn on to draw dirty regions every other frame. */ Loading Loading @@ -303,6 +313,7 @@ public abstract class HardwareRenderer { boolean mDirtyRegions; final boolean mDirtyRegionsRequested; final boolean mVsyncDisabled; final int mGlVersion; final boolean mTranslucent; Loading @@ -314,10 +325,17 @@ public abstract class HardwareRenderer { GlRenderer(int glVersion, boolean translucent) { mGlVersion = glVersion; mTranslucent = translucent; final String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true"); //noinspection PointlessBooleanExpression,ConstantConditions mDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty); mDirtyRegionsRequested = mDirtyRegions; final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false"); mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty); if (mVsyncDisabled) { Log.d(LOG_TAG, "Disabling v-sync"); } } /** Loading Loading @@ -764,6 +782,14 @@ public abstract class HardwareRenderer { } } @Override void setup(int width, int height) { super.setup(width, height); if (mVsyncDisabled) { GLES20Canvas.disableVsync(); } } @Override DisplayList createDisplayList(View v) { return new GLES20DisplayList(v); Loading
core/jni/android_view_GLES20Canvas.cpp +18 −5 Original line number Diff line number Diff line Loading @@ -115,6 +115,18 @@ static jboolean android_view_GLES20Canvas_isBackBufferPreserved(JNIEnv* env, job return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED; } static void android_view_GLES20Canvas_disableVsync(JNIEnv* env, jobject clazz) { EGLDisplay display = eglGetCurrentDisplay(); eglGetError(); eglSwapInterval(display, 0); EGLint error = eglGetError(); if (error != EGL_SUCCESS) { RENDERER_LOGD("Could not disable v-sync (%x)", error); } } // ---------------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------------- Loading Loading @@ -621,7 +633,7 @@ static Layer* android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject if (layer) { jint* storage = env->GetIntArrayElements(layerInfo, NULL); storage[0] = layer->texture; storage[0] = layer->getTexture(); env->ReleaseIntArrayElements(layerInfo, storage, 0); } Loading @@ -634,8 +646,8 @@ static Layer* android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz, if (layer) { jint* storage = env->GetIntArrayElements(layerInfo, NULL); storage[0] = layer->width; storage[1] = layer->height; storage[0] = layer->getWidth(); storage[1] = layer->getHeight(); env->ReleaseIntArrayElements(layerInfo, storage, 0); } Loading @@ -647,8 +659,8 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz, LayerRenderer::resizeLayer(layer, width, height); jint* storage = env->GetIntArrayElements(layerInfo, NULL); storage[0] = layer->width; storage[1] = layer->height; storage[0] = layer->getWidth(); storage[1] = layer->getHeight(); env->ReleaseIntArrayElements(layerInfo, storage, 0); } Loading Loading @@ -722,6 +734,7 @@ static JNINativeMethod gMethods[] = { #ifdef USE_OPENGL_RENDERER { "nIsBackBufferPreserved", "()Z", (void*) android_view_GLES20Canvas_isBackBufferPreserved }, { "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer }, { "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync }, { "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer }, { "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer }, Loading
libs/hwui/Layer.h +184 −47 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "Rect.h" #include "SkiaColorFilter.h" #include "Texture.h" #include "Vertex.h" namespace android { Loading @@ -40,14 +41,18 @@ namespace uirenderer { * A layer has dimensions and is backed by an OpenGL texture or FBO. */ struct Layer { Layer(const uint32_t layerWidth, const uint32_t layerHeight): width(layerWidth), height(layerHeight) { Layer(const uint32_t layerWidth, const uint32_t layerHeight) { mesh = NULL; meshIndices = NULL; meshElementCount = 0; isCacheable = true; isTextureLayer = false; cacheable = true; textureLayer = false; renderTarget = GL_TEXTURE_2D; texture.width = layerWidth; texture.height = layerHeight; colorFilter = NULL; firstFilter = true; firstWrap = true; } ~Layer() { Loading @@ -64,12 +69,152 @@ struct Layer { regionRect.set(bounds.leftTop().x, bounds.leftTop().y, bounds.rightBottom().x, bounds.rightBottom().y); const float texX = 1.0f / float(width); const float texY = 1.0f / float(height); const float texX = 1.0f / float(texture.width); const float texY = 1.0f / float(texture.height); const float height = layer.getHeight(); texCoords.set( regionRect.left * texX, (height - regionRect.top) * texY, regionRect.right * texX, (height - regionRect.bottom) * texY); regionRect.translate(layer.left, layer.top); } inline uint32_t getWidth() { return texture.width; } inline uint32_t getHeight() { return texture.height; } void setSize(uint32_t width, uint32_t height) { texture.width = width; texture.height = height; } inline void setBlend(bool blend) { texture.blend = blend; } inline bool isBlend() { return texture.blend; } inline void setAlpha(int alpha) { this->alpha = alpha; } inline void setAlpha(int alpha, SkXfermode::Mode mode) { this->alpha = alpha; this->mode = mode; } inline int getAlpha() { return alpha; } inline SkXfermode::Mode getMode() { return mode; } inline void setEmpty(bool empty) { this->empty = empty; } inline bool isEmpty() { return empty; } inline void setFbo(GLuint fbo) { this->fbo = fbo; } inline GLuint getFbo() { return fbo; } inline GLuint* getTexturePointer() { return &texture.id; } inline GLuint getTexture() { return texture.id; } inline GLenum getRenderTarget() { return renderTarget; } inline void setRenderTarget(GLenum renderTarget) { this->renderTarget = renderTarget; } void setWrap(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false) { if (firstWrap || force || wrapS != texture.wrapS || wrapT != texture.wrapT) { firstWrap = true; texture.setWrap(wrapS, wrapT); if (bindTexture) { glBindTexture(renderTarget, texture.id); } glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS); glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT); } } void setFilter(GLenum min, GLenum mag, bool bindTexture = false, bool force = false) { if (firstFilter || force || min != texture.minFilter || mag != texture.magFilter) { firstFilter = false; texture.setFilter(min, mag); if (bindTexture) { glBindTexture(renderTarget, texture.id); } glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min); glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag); } } inline bool isCacheable() { return cacheable; } inline void setCacheable(bool cacheable) { this->cacheable = cacheable; } inline bool isTextureLayer() { return textureLayer; } inline void setTextureLayer(bool textureLayer) { this->textureLayer = textureLayer; } inline SkiaColorFilter* getColorFilter() { return colorFilter; } inline void setColorFilter(SkiaColorFilter* filter) { colorFilter = filter; } inline void bindTexture() { glBindTexture(renderTarget, texture.id); } inline void generateTexture() { glGenTextures(1, &texture.id); } inline void deleteTexture() { if (texture.id) glDeleteTextures(1, &texture.id); } inline void allocateTexture(GLenum format, GLenum storage) { glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL); } inline mat4& getTexTransform() { return texTransform; } /** Loading @@ -82,23 +227,29 @@ struct Layer { Rect texCoords; /** * Name of the FBO used to render the layer. If the name is 0 * this layer is not backed by an FBO, but a simple texture. * Dirty region indicating what parts of the layer * have been drawn. */ GLuint fbo; Region region; /** * Opacity of the layer. * If the region is a rectangle, coordinates of the * region are stored here. */ int alpha; Rect regionRect; /** * Blending mode of the layer. * If the layer can be rendered as a mesh, this is non-null. */ SkXfermode::Mode mode; TextureVertex* mesh; uint16_t* meshIndices; GLsizei meshElementCount; private: /** * Indicates whether this layer should be blended. * Name of the FBO used to render the layer. If the name is 0 * this layer is not backed by an FBO, but a simple texture. */ bool blend; GLuint fbo; /** * Indicates whether this layer has been used already. Loading @@ -106,28 +257,25 @@ struct Layer { bool empty; /** * Name of the texture used to render the layer. * The texture backing this layer. */ GLuint texture; /** * Width of the layer texture. */ uint32_t width; Texture texture; /** * Height of the layer texture. * If set to true (by default), the layer can be reused. */ uint32_t height; bool cacheable; /** * Dirty region indicating what parts of the layer * have been drawn. * When set to true, this layer must be treated as a texture * layer. */ Region region; bool textureLayer; /** * If the region is a rectangle, coordinates of the * region are stored here. * Indicates the render target. */ Rect regionRect; GLenum renderTarget; /** * Color filter used to draw this layer. Optional. Loading @@ -135,32 +283,21 @@ struct Layer { SkiaColorFilter* colorFilter; /** * If the layer can be rendered as a mesh, this is non-null. */ TextureVertex* mesh; uint16_t* meshIndices; GLsizei meshElementCount; /** * If set to true (by default), the layer can be reused. * Opacity of the layer. */ bool isCacheable; int alpha; /** * When set to true, this layer must be treated as a texture * layer. * Blending mode of the layer. */ bool isTextureLayer; SkXfermode::Mode mode; /** * Optional texture coordinates transform. */ mat4 texTransform; /** * Indicates the render target. */ GLenum renderTarget; bool firstFilter; bool firstWrap; }; // struct Layer }; // namespace uirenderer Loading
libs/hwui/LayerCache.cpp +22 −28 Original line number Diff line number Diff line Loading @@ -68,8 +68,8 @@ void LayerCache::setMaxSize(uint32_t maxSize) { void LayerCache::deleteLayer(Layer* layer) { if (layer) { mSize -= layer->width * layer->height * 4; glDeleteTextures(1, &layer->texture); mSize -= layer->getWidth() * layer->getHeight() * 4; layer->deleteTexture(); delete layer; } } Loading @@ -93,29 +93,23 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) { mCache.removeAt(index); layer = entry.mLayer; mSize -= layer->width * layer->height * 4; mSize -= layer->getWidth() * layer->getHeight() * 4; LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height); LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight()); } else { LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight); layer = new Layer(entry.mWidth, entry.mHeight); layer->blend = true; layer->empty = true; layer->fbo = 0; layer->colorFilter = NULL; glGenTextures(1, &layer->texture); glBindTexture(GL_TEXTURE_2D, layer->texture); layer->setBlend(true); layer->setEmpty(true); layer->setFbo(0); layer->generateTexture(); layer->bindTexture(); layer->setFilter(GL_NEAREST, GL_NEAREST); layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); #if DEBUG_LAYERS size_t size = mCache.size(); for (size_t i = 0; i < size; i++) { Loading @@ -133,30 +127,30 @@ bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t heigh // size already in the cache, and reuse it instead of creating a new one LayerEntry entry(width, height); if (entry.mWidth <= layer->width && entry.mHeight <= layer->height) { if (entry.mWidth <= layer->getWidth() && entry.mHeight <= layer->getHeight()) { return true; } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, layer->texture); uint32_t oldWidth = layer->getWidth(); uint32_t oldHeight = layer->getHeight(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, entry.mWidth, entry.mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glActiveTexture(GL_TEXTURE0); layer->bindTexture(); layer->setSize(entry.mWidth, entry.mHeight); layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); if (glGetError() != GL_NO_ERROR) { layer->setSize(oldWidth, oldHeight); return false; } layer->width = entry.mWidth; layer->height = entry.mHeight; return true; } bool LayerCache::put(Layer* layer) { if (!layer->isCacheable) return false; if (!layer->isCacheable()) return false; const uint32_t size = layer->width * layer->height * 4; const uint32_t size = layer->getWidth() * layer->getHeight() * 4; // Don't even try to cache a layer that's bigger than the cache if (size < mMaxSize) { // TODO: Use an LRU Loading