2010-06-16 18:44:05 -07:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2010 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.
|
|
|
|
*/
|
|
|
|
|
2010-06-22 13:11:24 -07:00
|
|
|
#define LOG_TAG "OpenGLRenderer"
|
2010-06-16 18:44:05 -07:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2010-06-26 00:13:53 -07:00
|
|
|
#include <SkCanvas.h>
|
2014-07-17 12:25:11 -07:00
|
|
|
#include <SkColor.h>
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
#include <SkShader.h>
|
2010-07-21 21:33:20 -07:00
|
|
|
#include <SkTypeface.h>
|
2010-06-27 22:59:20 -07:00
|
|
|
|
|
|
|
#include <utils/Log.h>
|
2010-09-24 18:39:22 -07:00
|
|
|
#include <utils/StopWatch.h>
|
2010-06-22 13:11:24 -07:00
|
|
|
|
2011-03-17 11:06:57 -07:00
|
|
|
#include <private/hwui/DrawGlInfo.h>
|
|
|
|
|
2010-10-27 18:57:51 -07:00
|
|
|
#include <ui/Rect.h>
|
|
|
|
|
2010-06-22 13:11:24 -07:00
|
|
|
#include "OpenGLRenderer.h"
|
2013-02-04 16:16:33 -08:00
|
|
|
#include "DeferredDisplayList.h"
|
2010-11-08 12:08:41 -08:00
|
|
|
#include "DisplayListRenderer.h"
|
2013-06-12 15:31:28 -07:00
|
|
|
#include "Fence.h"
|
2014-06-23 13:13:08 -07:00
|
|
|
#include "RenderState.h"
|
2012-12-10 17:56:27 -08:00
|
|
|
#include "PathTessellator.h"
|
2012-09-24 11:37:12 -07:00
|
|
|
#include "Properties.h"
|
2013-12-03 10:38:55 -08:00
|
|
|
#include "ShadowTessellator.h"
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
#include "SkiaShader.h"
|
2014-05-08 13:57:05 -07:00
|
|
|
#include "utils/GLUtils.h"
|
2010-12-08 18:34:42 -08:00
|
|
|
#include "Vector.h"
|
2013-12-03 10:38:55 -08:00
|
|
|
#include "VertexBuffer.h"
|
2010-06-16 18:44:05 -07:00
|
|
|
|
|
|
|
namespace android {
|
2010-06-24 19:30:36 -07:00
|
|
|
namespace uirenderer {
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Defines
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-09-16 20:49:46 -07:00
|
|
|
#define RAD_TO_DEG (180.0f / 3.14159265f)
|
|
|
|
#define MIN_ANGLE 0.001f
|
|
|
|
|
2012-07-12 18:01:00 -07:00
|
|
|
#define ALPHA_THRESHOLD 0
|
2010-10-11 17:58:29 -07:00
|
|
|
|
2014-02-28 12:26:34 -08:00
|
|
|
static GLenum getFilter(const SkPaint* paint) {
|
|
|
|
if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
|
|
|
|
return GL_LINEAR;
|
|
|
|
}
|
|
|
|
return GL_NEAREST;
|
|
|
|
}
|
2011-11-30 20:21:23 -08:00
|
|
|
|
2010-06-24 19:30:36 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Globals
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-07-29 14:37:42 -07:00
|
|
|
/**
|
|
|
|
* Structure mapping Skia xfermodes to OpenGL blending factors.
|
|
|
|
*/
|
|
|
|
struct Blender {
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
GLenum src;
|
|
|
|
GLenum dst;
|
|
|
|
}; // struct Blender
|
|
|
|
|
2010-06-28 17:12:22 -07:00
|
|
|
// 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[] = {
|
2011-09-08 15:33:03 -07:00
|
|
|
{ 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 },
|
2013-02-04 15:42:26 -05:00
|
|
|
{ SkXfermode::kModulate_Mode, GL_ZERO, GL_SRC_COLOR },
|
2011-09-08 15:33:03 -07:00
|
|
|
{ SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
|
2010-06-28 17:12:22 -07:00
|
|
|
};
|
2010-06-16 18:44:05 -07:00
|
|
|
|
2010-09-13 18:11:21 -07:00
|
|
|
// 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.
|
2010-09-10 19:20:06 -07:00
|
|
|
static const Blender gBlendsSwap[] = {
|
2011-09-08 15:33:03 -07:00
|
|
|
{ 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 },
|
2013-02-04 15:42:26 -05:00
|
|
|
{ SkXfermode::kModulate_Mode, GL_DST_COLOR, GL_ZERO },
|
2011-09-08 15:33:03 -07:00
|
|
|
{ SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
|
2010-09-10 19:20:06 -07:00
|
|
|
};
|
|
|
|
|
2013-07-22 13:57:50 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Functions
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
static inline T min(T a, T b) {
|
|
|
|
return a < b ? a : b;
|
|
|
|
}
|
|
|
|
|
2010-06-23 17:47:49 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructors/destructor
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-23 13:13:08 -07:00
|
|
|
OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
|
|
|
|
: mCaches(Caches::getInstance())
|
|
|
|
, mExtensions(Extensions::getInstance())
|
|
|
|
, mRenderState(renderState) {
|
2013-03-04 10:19:31 -08:00
|
|
|
// *set* draw modifiers to be 0
|
|
|
|
memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
|
2013-03-29 10:59:59 -07:00
|
|
|
mDrawModifiers.mOverrideLayerAlpha = 1.0f;
|
2010-06-28 17:12:22 -07:00
|
|
|
|
2010-07-27 17:39:27 -07:00
|
|
|
memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
|
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
mFrameStarted = false;
|
2013-05-03 14:24:16 -07:00
|
|
|
mCountOverdraw = false;
|
2012-09-24 11:37:12 -07:00
|
|
|
|
|
|
|
mScissorOptimizationDisabled = false;
|
2010-06-16 18:44:05 -07:00
|
|
|
}
|
|
|
|
|
2010-06-22 13:11:24 -07:00
|
|
|
OpenGLRenderer::~OpenGLRenderer() {
|
2010-09-22 16:10:57 -07:00
|
|
|
// The context has already been destroyed at this point, do not call
|
|
|
|
// GL APIs. All GL state should be kept in Caches.h
|
2010-06-16 18:44:05 -07:00
|
|
|
}
|
|
|
|
|
2012-09-24 11:37:12 -07:00
|
|
|
void OpenGLRenderer::initProperties() {
|
|
|
|
char property[PROPERTY_VALUE_MAX];
|
|
|
|
if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
|
|
|
|
mScissorOptimizationDisabled = !strcasecmp(property, "true");
|
|
|
|
INIT_LOGD(" Scissor optimization %s",
|
|
|
|
mScissorOptimizationDisabled ? "disabled" : "enabled");
|
|
|
|
} else {
|
|
|
|
INIT_LOGD(" Scissor optimization enabled");
|
|
|
|
}
|
2012-01-30 17:41:55 -08:00
|
|
|
}
|
|
|
|
|
2010-06-23 17:47:49 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Setup
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-05-20 18:10:25 -07:00
|
|
|
void OpenGLRenderer::onViewportInitialized() {
|
2012-09-18 15:40:58 -07:00
|
|
|
glDisable(GL_DITHER);
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
|
|
|
|
glEnableVertexAttribArray(Program::kBindingPosition);
|
|
|
|
}
|
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
void OpenGLRenderer::setupFrameState(float left, float top,
|
2013-01-29 17:26:25 -08:00
|
|
|
float right, float bottom, bool opaque) {
|
2010-11-11 15:36:56 -08:00
|
|
|
mCaches.clearGarbage();
|
|
|
|
|
2013-12-30 15:32:54 -08:00
|
|
|
initializeSaveStack(left, top, right, bottom);
|
2013-03-26 15:05:58 -07:00
|
|
|
mOpaque = opaque;
|
2013-03-21 14:39:04 -07:00
|
|
|
mTilingClip.set(left, top, right, bottom);
|
2013-03-26 15:05:58 -07:00
|
|
|
}
|
2012-05-22 14:07:07 -07:00
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
status_t OpenGLRenderer::startFrame() {
|
|
|
|
if (mFrameStarted) return DrawGlInfo::kStatusDone;
|
|
|
|
mFrameStarted = true;
|
2012-09-21 00:39:43 -07:00
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
mDirtyClip = true;
|
|
|
|
|
|
|
|
discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
|
2012-09-11 17:17:07 -07:00
|
|
|
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.setViewport(getWidth(), getHeight());
|
2011-01-24 16:33:45 -08:00
|
|
|
|
2012-09-27 17:55:46 -07:00
|
|
|
// Functors break the tiling extension in pretty spectacular ways
|
|
|
|
// This ensures we don't use tiling when a functor is going to be
|
|
|
|
// invoked during the frame
|
|
|
|
mSuppressTiling = mCaches.hasRegisteredFunctors();
|
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
startTilingCurrentClip(true);
|
2012-09-19 17:25:38 -07:00
|
|
|
|
2012-09-21 19:15:00 -07:00
|
|
|
debugOverdraw(true, true);
|
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
return clear(mTilingClip.left, mTilingClip.top,
|
|
|
|
mTilingClip.right, mTilingClip.bottom, mOpaque);
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t OpenGLRenderer::prepareDirty(float left, float top,
|
|
|
|
float right, float bottom, bool opaque) {
|
2013-05-03 14:24:16 -07:00
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
setupFrameState(left, top, right, bottom, opaque);
|
|
|
|
|
|
|
|
// Layer renderers will start the frame immediately
|
|
|
|
// The framebuffer renderer will first defer the display list
|
|
|
|
// for each layer and wait until the first drawing command
|
|
|
|
// to start the frame
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->fbo == 0) {
|
2013-03-26 15:05:58 -07:00
|
|
|
syncState();
|
|
|
|
updateLayers();
|
|
|
|
} else {
|
|
|
|
return startFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDone;
|
2012-10-18 15:05:02 -07:00
|
|
|
}
|
|
|
|
|
2013-01-03 13:08:57 -08:00
|
|
|
void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
|
|
|
|
// If we know that we are going to redraw the entire framebuffer,
|
|
|
|
// perform a discard to let the driver know we don't need to preserve
|
|
|
|
// the back buffer for this frame.
|
2013-02-06 16:51:04 -08:00
|
|
|
if (mExtensions.hasDiscardFramebuffer() &&
|
2013-12-30 15:32:54 -08:00
|
|
|
left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
|
2013-01-31 17:20:30 -08:00
|
|
|
const bool isFbo = getTargetFbo() == 0;
|
|
|
|
const GLenum attachments[] = {
|
|
|
|
isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
|
|
|
|
isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
|
2013-01-03 13:08:57 -08:00
|
|
|
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-18 15:05:02 -07:00
|
|
|
status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
|
2013-05-03 14:24:16 -07:00
|
|
|
if (!opaque || mCountOverdraw) {
|
2012-07-13 15:28:31 -07:00
|
|
|
mCaches.enableScissor();
|
2014-05-14 14:17:01 -07:00
|
|
|
mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top);
|
2010-10-06 19:49:23 -07:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
2012-06-06 19:03:58 -07:00
|
|
|
return DrawGlInfo::kStatusDrew;
|
2012-05-22 14:07:07 -07:00
|
|
|
}
|
2012-06-06 19:03:58 -07:00
|
|
|
|
2012-10-18 15:05:02 -07:00
|
|
|
mCaches.resetScissor();
|
2012-06-06 19:03:58 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2012-05-22 14:07:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::syncState() {
|
|
|
|
if (mCaches.blend) {
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
} else {
|
|
|
|
glDisable(GL_BLEND);
|
2010-10-06 19:49:23 -07:00
|
|
|
}
|
2010-06-22 18:56:38 -07:00
|
|
|
}
|
|
|
|
|
2014-07-02 19:36:56 +08:00
|
|
|
void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
|
2012-09-27 17:55:46 -07:00
|
|
|
if (!mSuppressTiling) {
|
2014-01-01 14:45:21 -08:00
|
|
|
const Snapshot* snapshot = currentSnapshot();
|
|
|
|
|
2013-12-30 15:32:54 -08:00
|
|
|
const Rect* clip = &mTilingClip;
|
2014-01-01 14:45:21 -08:00
|
|
|
if (snapshot->flags & Snapshot::kFlagFboTarget) {
|
|
|
|
clip = &(snapshot->layer->clipRect);
|
2012-09-27 17:55:46 -07:00
|
|
|
}
|
|
|
|
|
2014-07-02 19:36:56 +08:00
|
|
|
startTiling(*clip, getViewportHeight(), opaque, expand);
|
2013-01-29 17:26:25 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-02 19:36:56 +08:00
|
|
|
void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque, bool expand) {
|
2013-01-29 17:26:25 -08:00
|
|
|
if (!mSuppressTiling) {
|
2014-07-02 19:36:56 +08:00
|
|
|
if(expand) {
|
|
|
|
// Expand the startTiling region by 1
|
|
|
|
int leftNotZero = (clip.left > 0) ? 1 : 0;
|
|
|
|
int topNotZero = (windowHeight - clip.bottom > 0) ? 1 : 0;
|
|
|
|
|
|
|
|
mCaches.startTiling(
|
|
|
|
clip.left - leftNotZero,
|
|
|
|
windowHeight - clip.bottom - topNotZero,
|
|
|
|
clip.right - clip.left + leftNotZero + 1,
|
|
|
|
clip.bottom - clip.top + topNotZero + 1,
|
|
|
|
opaque);
|
|
|
|
} else {
|
|
|
|
mCaches.startTiling(clip.left, windowHeight - clip.bottom,
|
2013-02-14 18:03:37 -08:00
|
|
|
clip.right - clip.left, clip.bottom - clip.top, opaque);
|
2014-07-02 19:36:56 +08:00
|
|
|
}
|
2012-09-19 17:25:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::endTiling() {
|
2012-09-27 17:55:46 -07:00
|
|
|
if (!mSuppressTiling) mCaches.endTiling();
|
2012-09-19 17:25:38 -07:00
|
|
|
}
|
|
|
|
|
2010-09-16 14:16:48 -07:00
|
|
|
void OpenGLRenderer::finish() {
|
2012-09-21 19:15:00 -07:00
|
|
|
renderOverdraw();
|
2012-09-19 17:25:38 -07:00
|
|
|
endTiling();
|
|
|
|
|
2013-03-08 17:44:20 -08:00
|
|
|
// When finish() is invoked on FBO 0 we've reached the end
|
|
|
|
// of the current frame
|
|
|
|
if (getTargetFbo() == 0) {
|
|
|
|
mCaches.pathCache.trim();
|
2014-06-02 16:27:04 -07:00
|
|
|
mCaches.tessellationCache.trim();
|
2013-03-08 17:44:20 -08:00
|
|
|
}
|
|
|
|
|
2012-09-21 00:39:43 -07:00
|
|
|
if (!suppressErrorChecks()) {
|
2010-09-16 14:16:48 -07:00
|
|
|
#if DEBUG_OPENGL
|
2014-05-08 13:57:05 -07:00
|
|
|
GLUtils::dumpGLErrors();
|
2010-09-16 14:16:48 -07:00
|
|
|
#endif
|
2012-09-21 00:39:43 -07:00
|
|
|
|
2010-11-10 11:59:15 -08:00
|
|
|
#if DEBUG_MEMORY_USAGE
|
2010-11-10 19:01:29 -08:00
|
|
|
mCaches.dumpMemoryUsage();
|
2012-09-21 00:39:43 -07:00
|
|
|
#else
|
|
|
|
if (mCaches.getDebugLevel() & kDebugMemory) {
|
|
|
|
mCaches.dumpMemoryUsage();
|
|
|
|
}
|
2010-11-10 11:59:15 -08:00
|
|
|
#endif
|
2012-09-21 00:39:43 -07:00
|
|
|
}
|
2013-03-26 15:05:58 -07:00
|
|
|
|
2013-05-03 14:24:16 -07:00
|
|
|
if (mCountOverdraw) {
|
|
|
|
countOverdraw();
|
|
|
|
}
|
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
mFrameStarted = false;
|
2010-09-16 14:16:48 -07:00
|
|
|
}
|
|
|
|
|
2012-09-18 15:40:58 -07:00
|
|
|
void OpenGLRenderer::resumeAfterLayer() {
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.setViewport(getViewportWidth(), getViewportHeight());
|
|
|
|
mRenderState.bindFramebuffer(currentSnapshot()->fbo);
|
2012-09-21 19:15:00 -07:00
|
|
|
debugOverdraw(true, false);
|
2012-09-18 15:40:58 -07:00
|
|
|
|
|
|
|
mCaches.resetScissor();
|
|
|
|
dirtyClip();
|
|
|
|
}
|
|
|
|
|
2012-03-27 16:33:45 -07:00
|
|
|
status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
|
2013-03-26 18:55:15 -07:00
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
Rect clip(*currentClipRect());
|
2011-03-16 15:30:12 -07:00
|
|
|
clip.snapToPixelBoundaries();
|
|
|
|
|
2011-03-01 14:55:21 -08:00
|
|
|
// Since we don't know what the functor will draw, let's dirty
|
2014-01-01 14:45:21 -08:00
|
|
|
// the entire clip region
|
2011-03-01 14:55:21 -08:00
|
|
|
if (hasLayer()) {
|
|
|
|
dirtyLayerUnchecked(clip, getRegion());
|
|
|
|
}
|
|
|
|
|
2011-03-17 11:06:57 -07:00
|
|
|
DrawGlInfo info;
|
|
|
|
info.clipLeft = clip.left;
|
|
|
|
info.clipTop = clip.top;
|
|
|
|
info.clipRight = clip.right;
|
|
|
|
info.clipBottom = clip.bottom;
|
|
|
|
info.isLayer = hasLayer();
|
2014-05-14 14:17:01 -07:00
|
|
|
info.width = getViewportWidth();
|
|
|
|
info.height = getViewportHeight();
|
2014-01-01 14:45:21 -08:00
|
|
|
currentTransform()->copyTo(&info.transform[0]);
|
2011-03-16 15:30:12 -07:00
|
|
|
|
2014-06-23 13:13:08 -07:00
|
|
|
bool prevDirtyClip = mDirtyClip;
|
2013-08-26 11:23:46 -07:00
|
|
|
// setup GL state for functor
|
|
|
|
if (mDirtyClip) {
|
|
|
|
setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
|
|
|
|
}
|
2014-06-23 13:13:08 -07:00
|
|
|
if (mCaches.enableScissor() || prevDirtyClip) {
|
2013-09-10 13:12:09 -07:00
|
|
|
setScissorFromClip();
|
|
|
|
}
|
2013-08-26 11:23:46 -07:00
|
|
|
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
|
|
|
|
// Scissor may have been modified, reset dirty clip
|
|
|
|
dirtyClip();
|
2011-03-07 18:06:46 -08:00
|
|
|
|
2014-03-28 16:33:18 -07:00
|
|
|
return DrawGlInfo::kStatusDrew;
|
2011-01-10 14:10:36 -08:00
|
|
|
}
|
|
|
|
|
2012-09-24 11:37:12 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Debug
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-03-01 14:31:04 -08:00
|
|
|
void OpenGLRenderer::eventMark(const char* name) const {
|
|
|
|
mCaches.eventMark(0, name);
|
|
|
|
}
|
|
|
|
|
2012-09-24 11:37:12 -07:00
|
|
|
void OpenGLRenderer::startMark(const char* name) const {
|
|
|
|
mCaches.startMark(0, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::endMark() const {
|
|
|
|
mCaches.endMark();
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.debugOverdraw(enable, clear);
|
2012-09-24 11:37:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::renderOverdraw() {
|
|
|
|
if (mCaches.debugOverdraw && getTargetFbo() == 0) {
|
2013-03-21 14:39:04 -07:00
|
|
|
const Rect* clip = &mTilingClip;
|
2012-09-24 11:37:12 -07:00
|
|
|
|
|
|
|
mCaches.enableScissor();
|
2014-05-14 14:17:01 -07:00
|
|
|
mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
|
2012-09-24 11:37:12 -07:00
|
|
|
clip->right - clip->left, clip->bottom - clip->top);
|
|
|
|
|
2013-08-21 11:53:18 -07:00
|
|
|
// 1x overdraw
|
2012-09-24 11:37:12 -07:00
|
|
|
mCaches.stencil.enableDebugTest(2);
|
2013-08-21 11:53:18 -07:00
|
|
|
drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
|
|
|
|
|
|
|
|
// 2x overdraw
|
2012-09-24 11:37:12 -07:00
|
|
|
mCaches.stencil.enableDebugTest(3);
|
2013-08-21 11:53:18 -07:00
|
|
|
drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
|
|
|
|
|
|
|
|
// 3x overdraw
|
2012-09-24 11:37:12 -07:00
|
|
|
mCaches.stencil.enableDebugTest(4);
|
2013-08-21 11:53:18 -07:00
|
|
|
drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
|
|
|
|
|
|
|
|
// 4x overdraw and higher
|
2012-09-24 11:37:12 -07:00
|
|
|
mCaches.stencil.enableDebugTest(4, true);
|
2013-08-21 11:53:18 -07:00
|
|
|
drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
|
|
|
|
|
2012-09-24 11:37:12 -07:00
|
|
|
mCaches.stencil.disable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-03 14:24:16 -07:00
|
|
|
void OpenGLRenderer::countOverdraw() {
|
2013-12-30 15:32:54 -08:00
|
|
|
size_t count = getWidth() * getHeight();
|
2013-05-03 14:24:16 -07:00
|
|
|
uint32_t* buffer = new uint32_t[count];
|
2013-12-30 15:32:54 -08:00
|
|
|
glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
|
2013-05-03 14:24:16 -07:00
|
|
|
|
|
|
|
size_t total = 0;
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
total += buffer[i] & 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
mOverdraw = total / float(count);
|
|
|
|
|
|
|
|
delete[] buffer;
|
|
|
|
}
|
|
|
|
|
2012-09-21 00:39:43 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Layers
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
|
2014-06-20 16:01:00 -07:00
|
|
|
if (layer->deferredUpdateScheduled && layer->renderer
|
|
|
|
&& layer->renderNode.get() && layer->renderNode->isRenderable()) {
|
2013-06-12 15:31:28 -07:00
|
|
|
ATRACE_CALL();
|
|
|
|
|
2012-09-21 00:39:43 -07:00
|
|
|
Rect& dirty = layer->dirtyRect;
|
|
|
|
|
2012-09-21 19:15:00 -07:00
|
|
|
if (inFrame) {
|
|
|
|
endTiling();
|
|
|
|
debugOverdraw(false, false);
|
|
|
|
}
|
2012-09-21 00:39:43 -07:00
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
|
2013-03-29 12:37:16 -07:00
|
|
|
layer->render();
|
2013-03-26 15:05:58 -07:00
|
|
|
} else {
|
|
|
|
layer->defer();
|
|
|
|
}
|
2012-09-21 00:39:43 -07:00
|
|
|
|
|
|
|
if (inFrame) {
|
|
|
|
resumeAfterLayer();
|
2014-01-01 14:45:21 -08:00
|
|
|
startTilingCurrentClip();
|
2012-09-21 00:39:43 -07:00
|
|
|
}
|
|
|
|
|
2012-11-29 17:52:58 -08:00
|
|
|
layer->debugDrawUpdate = mCaches.debugLayersUpdates;
|
2013-04-15 16:08:28 -07:00
|
|
|
layer->hasDrawnSinceUpdate = false;
|
2012-09-21 00:39:43 -07:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::updateLayers() {
|
2013-03-26 15:05:58 -07:00
|
|
|
// If draw deferring is enabled this method will simply defer
|
|
|
|
// the display list of each individual layer. The layers remain
|
|
|
|
// in the layer updates list which will be cleared by flushLayers().
|
2012-09-21 00:39:43 -07:00
|
|
|
int count = mLayerUpdates.size();
|
|
|
|
if (count > 0) {
|
2013-03-26 15:05:58 -07:00
|
|
|
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
|
|
|
|
startMark("Layer Updates");
|
|
|
|
} else {
|
|
|
|
startMark("Defer Layer Updates");
|
|
|
|
}
|
2012-09-21 00:39:43 -07:00
|
|
|
|
2013-04-04 14:46:24 -07:00
|
|
|
// Note: it is very important to update the layers in order
|
|
|
|
for (int i = 0; i < count; i++) {
|
2012-09-21 00:39:43 -07:00
|
|
|
Layer* layer = mLayerUpdates.itemAt(i);
|
|
|
|
updateLayer(layer, false);
|
2013-03-26 15:05:58 -07:00
|
|
|
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
|
|
|
|
mCaches.resourceCache.decrementRefcount(layer);
|
|
|
|
}
|
2012-09-21 00:39:43 -07:00
|
|
|
}
|
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
|
|
|
|
mLayerUpdates.clear();
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.bindFramebuffer(getTargetFbo());
|
2013-03-26 15:05:58 -07:00
|
|
|
}
|
|
|
|
endMark();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::flushLayers() {
|
|
|
|
int count = mLayerUpdates.size();
|
|
|
|
if (count > 0) {
|
|
|
|
startMark("Apply Layer Updates");
|
|
|
|
char layerName[12];
|
|
|
|
|
2013-04-04 14:46:24 -07:00
|
|
|
// Note: it is very important to update the layers in order
|
|
|
|
for (int i = 0; i < count; i++) {
|
2013-03-26 15:05:58 -07:00
|
|
|
sprintf(layerName, "Layer #%d", i);
|
2013-03-29 12:37:16 -07:00
|
|
|
startMark(layerName);
|
|
|
|
|
2013-06-12 15:31:28 -07:00
|
|
|
ATRACE_BEGIN("flushLayer");
|
2013-03-29 12:37:16 -07:00
|
|
|
Layer* layer = mLayerUpdates.itemAt(i);
|
|
|
|
layer->flush();
|
2013-06-12 15:31:28 -07:00
|
|
|
ATRACE_END();
|
|
|
|
|
2013-03-29 12:37:16 -07:00
|
|
|
mCaches.resourceCache.decrementRefcount(layer);
|
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
endMark();
|
|
|
|
}
|
|
|
|
|
|
|
|
mLayerUpdates.clear();
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.bindFramebuffer(getTargetFbo());
|
2013-03-26 15:05:58 -07:00
|
|
|
|
2012-09-21 00:39:43 -07:00
|
|
|
endMark();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
|
|
|
|
if (layer) {
|
2013-03-29 12:37:16 -07:00
|
|
|
// Make sure we don't introduce duplicates.
|
|
|
|
// SortedVector would do this automatically but we need to respect
|
|
|
|
// the insertion order. The linear search is not an issue since
|
|
|
|
// this list is usually very short (typically one item, at most a few)
|
|
|
|
for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
|
|
|
|
if (mLayerUpdates.itemAt(i) == layer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2012-09-21 00:39:43 -07:00
|
|
|
mLayerUpdates.push_back(layer);
|
|
|
|
mCaches.resourceCache.incrementRefcount(layer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-17 13:14:51 -07:00
|
|
|
void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
|
|
|
|
if (layer) {
|
|
|
|
for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
|
|
|
|
if (mLayerUpdates.itemAt(i) == layer) {
|
|
|
|
mLayerUpdates.removeAt(i);
|
|
|
|
mCaches.resourceCache.decrementRefcount(layer);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-21 00:39:43 -07:00
|
|
|
void OpenGLRenderer::clearLayerUpdates() {
|
|
|
|
size_t count = mLayerUpdates.size();
|
|
|
|
if (count > 0) {
|
|
|
|
mCaches.resourceCache.lock();
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i));
|
|
|
|
}
|
|
|
|
mCaches.resourceCache.unlock();
|
|
|
|
mLayerUpdates.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-12 15:31:28 -07:00
|
|
|
void OpenGLRenderer::flushLayerUpdates() {
|
|
|
|
syncState();
|
|
|
|
updateLayers();
|
|
|
|
flushLayers();
|
|
|
|
// Wait for all the layer updates to be executed
|
|
|
|
AutoFence fence;
|
|
|
|
}
|
|
|
|
|
2010-06-23 17:47:49 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// State management
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-12-30 15:32:54 -08:00
|
|
|
void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
|
2014-05-14 14:17:01 -07:00
|
|
|
bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
|
2013-12-30 15:32:54 -08:00
|
|
|
bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
|
|
|
|
bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
|
2010-06-26 00:13:53 -07:00
|
|
|
|
2014-05-14 14:17:01 -07:00
|
|
|
if (restoreViewport) {
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.setViewport(getViewportWidth(), getViewportHeight());
|
2010-10-05 18:14:38 -07:00
|
|
|
}
|
|
|
|
|
2010-08-18 11:47:12 -07:00
|
|
|
if (restoreClip) {
|
2010-10-26 16:27:31 -07:00
|
|
|
dirtyClip();
|
2010-08-17 18:38:51 -07:00
|
|
|
}
|
2010-08-18 11:47:12 -07:00
|
|
|
|
2010-11-03 16:19:08 -07:00
|
|
|
if (restoreLayer) {
|
2013-03-28 11:25:24 -07:00
|
|
|
endMark(); // Savelayer
|
|
|
|
startMark("ComposeLayer");
|
2013-12-30 15:32:54 -08:00
|
|
|
composeLayer(removed, restored);
|
2013-03-28 11:25:24 -07:00
|
|
|
endMark();
|
2010-11-03 16:19:08 -07:00
|
|
|
}
|
2010-06-28 17:42:46 -07:00
|
|
|
}
|
2010-06-27 22:59:20 -07:00
|
|
|
|
2010-06-26 00:13:53 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Layers
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
|
2014-04-15 16:18:08 -07:00
|
|
|
const SkPaint* paint, int flags, const SkPath* convexMask) {
|
2010-10-05 18:14:38 -07:00
|
|
|
const int count = saveSnapshot(flags);
|
2010-06-28 17:42:46 -07:00
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
if (!currentSnapshot()->isIgnored()) {
|
2014-04-15 16:18:08 -07:00
|
|
|
createLayer(left, top, right, bottom, paint, flags, convexMask);
|
2010-10-11 17:58:29 -07:00
|
|
|
}
|
2010-06-28 17:42:46 -07:00
|
|
|
|
|
|
|
return count;
|
2010-06-26 00:13:53 -07:00
|
|
|
}
|
|
|
|
|
2013-03-19 15:03:48 -07:00
|
|
|
void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
|
|
|
|
const Rect untransformedBounds(bounds);
|
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
currentTransform()->mapRect(bounds);
|
2013-03-19 15:03:48 -07:00
|
|
|
|
|
|
|
// Layers only make sense if they are in the framebuffer's bounds
|
2014-01-01 14:45:21 -08:00
|
|
|
if (bounds.intersect(*currentClipRect())) {
|
2013-03-19 15:03:48 -07:00
|
|
|
// We cannot work with sub-pixels in this case
|
|
|
|
bounds.snapToPixelBoundaries();
|
|
|
|
|
|
|
|
// When the layer is not an FBO, we may use glCopyTexImage so we
|
|
|
|
// need to make sure the layer does not extend outside the bounds
|
|
|
|
// of the framebuffer
|
2014-05-15 13:21:28 -07:00
|
|
|
const Snapshot& previous = *(currentSnapshot()->previous);
|
|
|
|
Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
|
|
|
|
if (!bounds.intersect(previousViewport)) {
|
2013-03-19 15:03:48 -07:00
|
|
|
bounds.setEmpty();
|
|
|
|
} else if (fboLayer) {
|
|
|
|
clip.set(bounds);
|
|
|
|
mat4 inverse;
|
2014-01-01 14:45:21 -08:00
|
|
|
inverse.loadInverse(*currentTransform());
|
2013-03-19 15:03:48 -07:00
|
|
|
inverse.mapRect(clip);
|
|
|
|
clip.snapToPixelBoundaries();
|
|
|
|
if (clip.intersect(untransformedBounds)) {
|
|
|
|
clip.translate(-untransformedBounds.left, -untransformedBounds.top);
|
|
|
|
bounds.set(untransformedBounds);
|
|
|
|
} else {
|
|
|
|
clip.setEmpty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bounds.setEmpty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-26 18:55:15 -07:00
|
|
|
void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
|
|
|
|
bool fboLayer, int alpha) {
|
|
|
|
if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
|
|
|
|
bounds.getHeight() > mCaches.maxTextureSize ||
|
|
|
|
(fboLayer && clip.isEmpty())) {
|
|
|
|
mSnapshot->empty = fboLayer;
|
|
|
|
} else {
|
|
|
|
mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-19 15:03:48 -07:00
|
|
|
int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
|
2014-02-05 16:47:00 -05:00
|
|
|
const SkPaint* paint, int flags) {
|
2013-03-19 15:03:48 -07:00
|
|
|
const int count = saveSnapshot(flags);
|
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
|
2013-03-19 15:03:48 -07:00
|
|
|
// initialize the snapshot as though it almost represents an FBO layer so deferred draw
|
|
|
|
// operations will be able to store and restore the current clip and transform info, and
|
|
|
|
// quick rejection will be correct (for display lists)
|
|
|
|
|
|
|
|
Rect bounds(left, top, right, bottom);
|
|
|
|
Rect clip;
|
|
|
|
calculateLayerBoundsAndClip(bounds, clip, true);
|
2014-02-05 16:47:00 -05:00
|
|
|
updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
|
2013-03-19 15:03:48 -07:00
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
if (!currentSnapshot()->isIgnored()) {
|
2013-03-19 15:03:48 -07:00
|
|
|
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
|
|
|
|
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
|
2014-05-14 14:17:01 -07:00
|
|
|
mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
|
2014-05-05 19:09:33 -07:00
|
|
|
mSnapshot->roundRectClipState = NULL;
|
2013-03-19 15:03:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2010-09-13 18:00:09 -07:00
|
|
|
/**
|
|
|
|
* Layers are viewed by Skia are slightly different than layers in image editing
|
|
|
|
* programs (for instance.) When a layer is created, previously created layers
|
|
|
|
* and the frame buffer still receive every drawing command. For instance, if a
|
|
|
|
* layer is created and a shape intersecting the bounds of the layers and the
|
|
|
|
* framebuffer is draw, the shape will be drawn on both (unless the layer was
|
|
|
|
* created with the SkCanvas::kClipToLayer_SaveFlag flag.)
|
|
|
|
*
|
|
|
|
* A way to implement layers is to create an FBO for each layer, backed by an RGBA
|
|
|
|
* texture. Unfortunately, this is inefficient as it requires every primitive to
|
|
|
|
* be drawn n + 1 times, where n is the number of active layers. In practice this
|
|
|
|
* means, for every primitive:
|
|
|
|
* - Switch active frame buffer
|
|
|
|
* - Change viewport, clip and projection matrix
|
|
|
|
* - Issue the drawing
|
|
|
|
*
|
|
|
|
* Switching rendering target n + 1 times per drawn primitive is extremely costly.
|
2010-10-06 19:49:23 -07:00
|
|
|
* To avoid this, layers are implemented in a different way here, at least in the
|
|
|
|
* general case. FBOs are used, as an optimization, when the "clip to layer" flag
|
|
|
|
* is set. When this flag is set we can redirect all drawing operations into a
|
|
|
|
* single FBO.
|
2010-09-13 18:00:09 -07:00
|
|
|
*
|
|
|
|
* This implementation relies on the frame buffer being at least RGBA 8888. When
|
|
|
|
* a layer is created, only a texture is created, not an FBO. The content of the
|
|
|
|
* frame buffer contained within the layer's bounds is copied into this texture
|
2010-09-13 18:11:21 -07:00
|
|
|
* using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
|
2010-09-13 18:00:09 -07:00
|
|
|
* buffer and drawing continues as normal. This technique therefore treats the
|
|
|
|
* frame buffer as a scratch buffer for the layers.
|
|
|
|
*
|
|
|
|
* To compose the layers back onto the frame buffer, each layer texture
|
|
|
|
* (containing the original frame buffer data) is drawn as a simple quad over
|
|
|
|
* the frame buffer. The trick is that the quad is set as the composition
|
|
|
|
* destination in the blending equation, and the frame buffer becomes the source
|
|
|
|
* of the composition.
|
|
|
|
*
|
|
|
|
* Drawing layers with an alpha value requires an extra step before composition.
|
|
|
|
* An empty quad is drawn over the layer's region in the frame buffer. This quad
|
|
|
|
* is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
|
|
|
|
* quad is used to multiply the colors in the frame buffer. This is achieved by
|
|
|
|
* changing the GL blend functions for the GL_FUNC_ADD blend equation to
|
|
|
|
* GL_ZERO, GL_SRC_ALPHA.
|
|
|
|
*
|
|
|
|
* Because glCopyTexImage2D() can be slow, an alternative implementation might
|
|
|
|
* be use to draw a single clipped layer. The implementation described above
|
|
|
|
* is correct in every case.
|
2010-09-13 18:11:21 -07:00
|
|
|
*
|
|
|
|
* (1) The frame buffer is actually not cleared right away. To allow the GPU
|
|
|
|
* to potentially optimize series of calls to glCopyTexImage2D, the frame
|
|
|
|
* buffer is left untouched until the first drawing operation. Only when
|
|
|
|
* something actually gets drawn are the layers regions cleared.
|
2010-09-13 18:00:09 -07:00
|
|
|
*/
|
2012-08-28 17:43:28 -07:00
|
|
|
bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
|
2014-04-15 16:18:08 -07:00
|
|
|
const SkPaint* paint, int flags, const SkPath* convexMask) {
|
2010-10-05 18:14:38 -07:00
|
|
|
LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
|
2010-08-23 21:05:08 -07:00
|
|
|
LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
|
2010-07-06 11:39:32 -07:00
|
|
|
|
2010-10-05 18:14:38 -07:00
|
|
|
const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
|
|
|
|
|
2010-09-10 19:20:06 -07:00
|
|
|
// Window coordinates of the layer
|
2012-08-28 17:43:28 -07:00
|
|
|
Rect clip;
|
2010-09-01 15:13:49 -07:00
|
|
|
Rect bounds(left, top, right, bottom);
|
2013-03-19 15:03:48 -07:00
|
|
|
calculateLayerBoundsAndClip(bounds, clip, fboLayer);
|
2014-02-19 16:47:32 +00:00
|
|
|
updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
|
2010-10-11 17:58:29 -07:00
|
|
|
|
|
|
|
// Bail out if we won't draw in this snapshot
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored()) {
|
2010-09-16 14:16:48 -07:00
|
|
|
return false;
|
|
|
|
}
|
2010-07-06 11:39:32 -07:00
|
|
|
|
2011-12-13 14:55:06 -08:00
|
|
|
mCaches.activeTexture(0);
|
2014-06-23 13:13:08 -07:00
|
|
|
Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
|
2010-07-08 11:45:51 -07:00
|
|
|
if (!layer) {
|
|
|
|
return false;
|
2010-06-26 00:13:53 -07:00
|
|
|
}
|
|
|
|
|
2014-02-19 16:47:32 +00:00
|
|
|
layer->setPaint(paint);
|
2010-09-01 15:13:49 -07:00
|
|
|
layer->layer.set(bounds);
|
2011-07-07 20:50:11 -07:00
|
|
|
layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
|
|
|
|
bounds.getWidth() / float(layer->getWidth()), 0.0f);
|
2014-02-05 16:47:00 -05:00
|
|
|
|
2012-04-12 15:19:04 -07:00
|
|
|
layer->setBlend(true);
|
2012-10-18 15:05:02 -07:00
|
|
|
layer->setDirty(false);
|
2014-04-15 16:18:08 -07:00
|
|
|
layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
|
2010-07-06 11:39:32 -07:00
|
|
|
|
2010-08-17 18:38:51 -07:00
|
|
|
// Save the layer in the snapshot
|
2012-08-28 17:43:28 -07:00
|
|
|
mSnapshot->flags |= Snapshot::kFlagIsLayer;
|
|
|
|
mSnapshot->layer = layer;
|
2010-08-17 11:37:00 -07:00
|
|
|
|
2013-03-28 11:25:24 -07:00
|
|
|
startMark("SaveLayer");
|
2010-10-05 18:14:38 -07:00
|
|
|
if (fboLayer) {
|
2013-10-17 10:30:55 -07:00
|
|
|
return createFboLayer(layer, bounds, clip);
|
2010-10-05 18:14:38 -07:00
|
|
|
} else {
|
|
|
|
// Copy the framebuffer into the layer
|
2011-07-07 20:50:11 -07:00
|
|
|
layer->bindTexture();
|
2011-01-19 14:38:29 -08:00
|
|
|
if (!bounds.isEmpty()) {
|
2011-07-07 20:50:11 -07:00
|
|
|
if (layer->isEmpty()) {
|
2013-06-27 17:15:24 -07:00
|
|
|
// Workaround for some GL drivers. When reading pixels lying outside
|
|
|
|
// of the window we should get undefined values for those pixels.
|
|
|
|
// Unfortunately some drivers will turn the entire target texture black
|
|
|
|
// when reading outside of the window.
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
|
|
|
|
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
2011-07-07 20:50:11 -07:00
|
|
|
layer->setEmpty(false);
|
2011-01-19 14:38:29 -08:00
|
|
|
}
|
2011-03-14 18:05:08 -07:00
|
|
|
|
2014-05-14 14:17:01 -07:00
|
|
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
|
|
|
bounds.left, getViewportHeight() - bounds.bottom,
|
|
|
|
bounds.getWidth(), bounds.getHeight());
|
2013-06-27 17:15:24 -07:00
|
|
|
|
2011-06-13 19:04:27 -07:00
|
|
|
// Enqueue the buffer coordinates to clear the corresponding region later
|
|
|
|
mLayers.push(new Rect(bounds));
|
2010-10-22 17:49:18 -07:00
|
|
|
}
|
2010-10-05 18:14:38 -07:00
|
|
|
}
|
2010-07-01 11:05:42 -07:00
|
|
|
|
2010-06-28 17:42:46 -07:00
|
|
|
return true;
|
2010-06-26 00:13:53 -07:00
|
|
|
}
|
|
|
|
|
2013-10-17 10:30:55 -07:00
|
|
|
bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
|
2013-01-29 17:26:25 -08:00
|
|
|
layer->clipRect.set(clip);
|
2011-07-07 20:50:11 -07:00
|
|
|
layer->setFbo(mCaches.fboCache.get());
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2012-08-28 17:43:28 -07:00
|
|
|
mSnapshot->region = &mSnapshot->layer->region;
|
2014-05-14 14:17:01 -07:00
|
|
|
mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
|
2012-08-28 17:43:28 -07:00
|
|
|
mSnapshot->fbo = layer->getFbo();
|
|
|
|
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
|
|
|
|
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
|
2014-05-14 14:17:01 -07:00
|
|
|
mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
|
2014-05-05 19:09:33 -07:00
|
|
|
mSnapshot->roundRectClipState = NULL;
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2012-09-19 17:25:38 -07:00
|
|
|
endTiling();
|
2012-09-21 19:15:00 -07:00
|
|
|
debugOverdraw(false, false);
|
2010-10-27 18:57:51 -07:00
|
|
|
// Bind texture to FBO
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.bindFramebuffer(layer->getFbo());
|
2011-07-07 20:50:11 -07:00
|
|
|
layer->bindTexture();
|
2010-10-27 18:57:51 -07:00
|
|
|
|
|
|
|
// Initialize the texture if needed
|
2011-07-07 20:50:11 -07:00
|
|
|
if (layer->isEmpty()) {
|
2013-04-04 12:27:54 -07:00
|
|
|
layer->allocateTexture();
|
2011-07-07 20:50:11 -07:00
|
|
|
layer->setEmpty(false);
|
2010-10-27 18:57:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
2011-07-07 20:50:11 -07:00
|
|
|
layer->getTexture(), 0);
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2014-07-02 19:36:56 +08:00
|
|
|
// Expand the startTiling region by 1
|
|
|
|
startTilingCurrentClip(true, true);
|
2010-10-27 18:57:51 -07:00
|
|
|
|
|
|
|
// Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
|
2012-07-13 15:28:31 -07:00
|
|
|
mCaches.enableScissor();
|
2011-12-14 19:23:32 -08:00
|
|
|
mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
|
2010-10-27 18:57:51 -07:00
|
|
|
clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
|
|
|
dirtyClip();
|
|
|
|
|
|
|
|
// Change the ortho projection
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.setViewport(bounds.getWidth(), bounds.getHeight());
|
2010-10-27 18:57:51 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-09-13 18:00:09 -07:00
|
|
|
/**
|
|
|
|
* Read the documentation of createLayer() before doing anything in this method.
|
|
|
|
*/
|
2013-12-30 15:32:54 -08:00
|
|
|
void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
|
|
|
|
if (!removed.layer) {
|
2012-01-06 19:20:56 +00:00
|
|
|
ALOGE("Attempting to compose a layer that does not exist");
|
2010-08-17 11:37:00 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-30 15:32:54 -08:00
|
|
|
Layer* layer = removed.layer;
|
2013-01-15 18:51:42 -08:00
|
|
|
const Rect& rect = layer->layer;
|
2013-12-30 15:32:54 -08:00
|
|
|
const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
|
2010-10-05 18:14:38 -07:00
|
|
|
|
2013-06-13 14:39:01 -07:00
|
|
|
bool clipRequired = false;
|
2013-11-19 18:00:46 -08:00
|
|
|
calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
|
2014-05-05 19:09:33 -07:00
|
|
|
&clipRequired, NULL, false); // safely ignore return, should never be rejected
|
2013-06-13 14:39:01 -07:00
|
|
|
mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
|
|
|
|
|
2010-10-05 18:14:38 -07:00
|
|
|
if (fboLayer) {
|
2012-09-19 17:25:38 -07:00
|
|
|
endTiling();
|
|
|
|
|
2012-04-03 19:30:26 -07:00
|
|
|
// Detach the texture from the FBO
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
2013-01-15 18:51:42 -08:00
|
|
|
|
|
|
|
layer->removeFbo(false);
|
|
|
|
|
2010-10-05 18:14:38 -07:00
|
|
|
// Unbind current FBO and restore previous one
|
2014-06-23 13:13:08 -07:00
|
|
|
mRenderState.bindFramebuffer(restored.fbo);
|
2012-09-21 19:15:00 -07:00
|
|
|
debugOverdraw(true, false);
|
2012-09-19 17:25:38 -07:00
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
startTilingCurrentClip();
|
2010-10-05 18:14:38 -07:00
|
|
|
}
|
|
|
|
|
2011-07-07 20:50:11 -07:00
|
|
|
if (!fboLayer && layer->getAlpha() < 255) {
|
2013-12-10 12:28:58 -05:00
|
|
|
SkPaint layerPaint;
|
|
|
|
layerPaint.setAlpha(layer->getAlpha());
|
|
|
|
layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
|
|
|
|
layerPaint.setColorFilter(layer->getColorFilter());
|
|
|
|
|
|
|
|
drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
|
2010-10-27 18:57:51 -07:00
|
|
|
// Required below, composeLayerRect() will divide by 255
|
2011-07-07 20:50:11 -07:00
|
|
|
layer->setAlpha(255);
|
2010-09-10 19:20:06 -07:00
|
|
|
}
|
|
|
|
|
2010-10-18 14:06:08 -07:00
|
|
|
mCaches.unbindMeshBuffer();
|
2010-08-18 17:10:07 -07:00
|
|
|
|
2011-12-13 14:55:06 -08:00
|
|
|
mCaches.activeTexture(0);
|
2010-10-27 18:57:51 -07:00
|
|
|
|
|
|
|
// When the layer is stored in an FBO, we can save a bit of fillrate by
|
|
|
|
// drawing only the dirty region
|
2010-10-05 18:14:38 -07:00
|
|
|
if (fboLayer) {
|
2013-12-30 15:32:54 -08:00
|
|
|
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
|
2010-10-27 18:57:51 -07:00
|
|
|
composeLayerRegion(layer, rect);
|
2011-07-07 20:50:11 -07:00
|
|
|
} else if (!rect.isEmpty()) {
|
|
|
|
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
|
2013-11-04 06:30:25 +05:30
|
|
|
|
|
|
|
save(0);
|
|
|
|
// the layer contains screen buffer content that shouldn't be alpha modulated
|
|
|
|
// (and any necessary alpha modulation was handled drawing into the layer)
|
|
|
|
mSnapshot->alpha = 1.0f;
|
2011-07-07 20:50:11 -07:00
|
|
|
composeLayerRect(layer, rect, true);
|
2013-11-04 06:30:25 +05:30
|
|
|
restore();
|
2010-10-05 18:14:38 -07:00
|
|
|
}
|
2010-08-17 11:37:00 -07:00
|
|
|
|
2010-10-26 16:27:31 -07:00
|
|
|
dirtyClip();
|
|
|
|
|
2010-10-05 18:14:38 -07:00
|
|
|
// Failing to add the layer to the cache should happen only if the layer is too large
|
2014-04-15 16:18:08 -07:00
|
|
|
layer->setConvexMask(NULL);
|
2010-10-08 15:49:53 -07:00
|
|
|
if (!mCaches.layerCache.put(layer)) {
|
2010-08-17 11:37:00 -07:00
|
|
|
LAYER_LOGD("Deleting layer");
|
Fix occasional crash bug with layers
Launcher occasionally crashes with a stack trace indicating that the memory
of a Layer object is corrupt. It is possible for us to delete a Layer
structure and then, briefly, use it to draw a DisplayList again before
that DisplayList gets recreated (without the layer that got deleted).
When this happens, if the memory got corrupted, it's possible to crash.
The fix is to add Layer to the other objects which we currently refcount
(bitmaps, shaders, etc.). Then instead of deleting a Layer, we decrement the
refcount. We increment when creating it, then increment it again when it's
referenced from a DisplayList. Then we decrement the refcount instead of
deleting it, and decrement when we clear a DisplayList that refers to it.
Then when the refcount reaches 0, we delete it.
Issue #6994632 Native crash in launcher when trying to launch all apps screen
Change-Id: I0627be8d49bb2f9ba8d158a84b764bb4e7df934c
2012-09-14 15:31:25 -07:00
|
|
|
Caches::getInstance().resourceCache.decrementRefcount(layer);
|
2010-08-17 11:37:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
|
2013-06-19 12:17:01 -07:00
|
|
|
float alpha = getLayerAlpha(layer);
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
|
|
|
|
setupDraw();
|
2011-07-07 20:50:11 -07:00
|
|
|
if (layer->getRenderTarget() == GL_TEXTURE_2D) {
|
2011-05-02 17:24:22 -07:00
|
|
|
setupDrawWithTexture();
|
|
|
|
} else {
|
|
|
|
setupDrawWithExternalTexture();
|
|
|
|
}
|
|
|
|
setupDrawTextureTransform();
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
setupDrawColor(alpha, alpha, alpha, alpha);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(layer->getColorFilter());
|
|
|
|
setupDrawBlending(layer);
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
setupDrawProgram();
|
|
|
|
setupDrawPureColorUniforms();
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(layer->getColorFilter());
|
2011-07-07 20:50:11 -07:00
|
|
|
if (layer->getRenderTarget() == GL_TEXTURE_2D) {
|
|
|
|
setupDrawTexture(layer->getTexture());
|
2011-05-02 17:24:22 -07:00
|
|
|
} else {
|
2011-07-07 20:50:11 -07:00
|
|
|
setupDrawExternalTexture(layer->getTexture());
|
2011-05-02 17:24:22 -07:00
|
|
|
}
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentTransform()->isPureTranslate() &&
|
2014-02-25 18:50:17 -08:00
|
|
|
!layer->getForceFilter() &&
|
2011-07-07 21:05:04 -07:00
|
|
|
layer->getWidth() == (uint32_t) rect.getWidth() &&
|
|
|
|
layer->getHeight() == (uint32_t) rect.getHeight()) {
|
2014-01-01 14:45:21 -08:00
|
|
|
const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
|
2011-07-07 20:50:11 -07:00
|
|
|
|
2011-11-30 20:21:23 -08:00
|
|
|
layer->setFilter(GL_NEAREST);
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
|
|
|
|
x, y, x + rect.getWidth(), y + rect.getHeight(), true);
|
2011-07-07 20:50:11 -07:00
|
|
|
} else {
|
2011-11-30 20:21:23 -08:00
|
|
|
layer->setFilter(GL_LINEAR);
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
|
|
|
|
rect.left, rect.top, rect.right, rect.bottom);
|
2011-07-07 20:50:11 -07:00
|
|
|
}
|
|
|
|
setupDrawTextureTransformUniforms(layer->getTexTransform());
|
2013-08-15 16:57:57 -07:00
|
|
|
setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
|
|
|
|
}
|
|
|
|
|
2010-10-27 18:57:51 -07:00
|
|
|
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
|
2011-07-07 20:50:11 -07:00
|
|
|
if (!layer->isTextureLayer()) {
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
const Rect& texCoords = layer->texCoords;
|
|
|
|
resetDrawTextureTexCoords(texCoords.left, texCoords.top,
|
|
|
|
texCoords.right, texCoords.bottom);
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2011-07-07 20:50:11 -07:00
|
|
|
float x = rect.left;
|
|
|
|
float y = rect.top;
|
2014-01-01 14:45:21 -08:00
|
|
|
bool simpleTransform = currentTransform()->isPureTranslate() &&
|
2011-07-07 21:05:04 -07:00
|
|
|
layer->getWidth() == (uint32_t) rect.getWidth() &&
|
2011-07-08 11:57:29 -07:00
|
|
|
layer->getHeight() == (uint32_t) rect.getHeight();
|
|
|
|
|
|
|
|
if (simpleTransform) {
|
2011-07-07 20:50:11 -07:00
|
|
|
// When we're swapping, the layer is already in screen coordinates
|
|
|
|
if (!swap) {
|
2014-01-01 14:45:21 -08:00
|
|
|
x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
|
2011-07-07 20:50:11 -07:00
|
|
|
}
|
|
|
|
|
2011-11-30 20:21:23 -08:00
|
|
|
layer->setFilter(GL_NEAREST, true);
|
2011-07-07 20:50:11 -07:00
|
|
|
} else {
|
2011-11-30 20:21:23 -08:00
|
|
|
layer->setFilter(GL_LINEAR, true);
|
2011-07-07 20:50:11 -07:00
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
SkPaint layerPaint;
|
|
|
|
layerPaint.setAlpha(getLayerAlpha(layer) * 255);
|
|
|
|
layerPaint.setXfermodeMode(layer->getMode());
|
|
|
|
layerPaint.setColorFilter(layer->getColorFilter());
|
|
|
|
|
|
|
|
bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
|
2011-07-07 20:50:11 -07:00
|
|
|
drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
|
2013-12-10 12:28:58 -05:00
|
|
|
layer->getTexture(), &layerPaint, blend,
|
2013-08-15 16:57:57 -07:00
|
|
|
&mMeshVertices[0].x, &mMeshVertices[0].u,
|
2011-07-07 20:50:11 -07:00
|
|
|
GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
|
2010-10-27 18:57:51 -07:00
|
|
|
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
|
|
|
|
} else {
|
|
|
|
resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
|
|
|
|
drawTextureLayer(layer, rect);
|
|
|
|
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
|
|
|
|
}
|
2010-10-27 18:57:51 -07:00
|
|
|
}
|
|
|
|
|
2013-04-15 16:08:28 -07:00
|
|
|
/**
|
|
|
|
* Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
|
|
|
|
* hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
|
|
|
|
* operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
|
|
|
|
* by saveLayer's restore
|
|
|
|
*/
|
|
|
|
#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \
|
|
|
|
DRAW_COMMAND; \
|
|
|
|
if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
|
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \
|
|
|
|
DRAW_COMMAND; \
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
|
|
|
|
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
|
|
|
|
// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
|
|
|
|
class LayerShader : public SkShader {
|
|
|
|
public:
|
|
|
|
LayerShader(Layer* layer, const SkMatrix* localMatrix)
|
|
|
|
: INHERITED(localMatrix)
|
|
|
|
, mLayer(layer) {
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool asACustomShader(void** data) const {
|
|
|
|
if (data) {
|
|
|
|
*data = static_cast<void*>(mLayer);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool isOpaque() const {
|
|
|
|
return !mLayer->isBlend();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
|
|
|
|
LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void flatten(SkWriteBuffer&) const {
|
|
|
|
LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Factory getFactory() const {
|
|
|
|
LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
// Unowned.
|
|
|
|
Layer* mLayer;
|
|
|
|
typedef SkShader INHERITED;
|
|
|
|
};
|
|
|
|
|
2010-10-27 18:57:51 -07:00
|
|
|
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
|
2014-04-15 16:18:08 -07:00
|
|
|
if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
|
|
|
|
|
|
|
|
if (layer->getConvexMask()) {
|
|
|
|
save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
|
|
|
|
|
|
|
|
// clip to the area of the layer the mask can be larger
|
|
|
|
clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setAntiAlias(true);
|
|
|
|
paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
|
|
|
|
|
|
|
|
// create LayerShader to map SaveLayer content into subsequent draw
|
|
|
|
SkMatrix shaderMatrix;
|
|
|
|
shaderMatrix.setTranslate(rect.left, rect.bottom);
|
|
|
|
shaderMatrix.preScale(1, -1);
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
LayerShader layerShader(layer, &shaderMatrix);
|
|
|
|
paint.setShader(&layerShader);
|
2014-04-15 16:18:08 -07:00
|
|
|
|
|
|
|
// Since the drawing primitive is defined in local drawing space,
|
|
|
|
// we don't need to modify the draw matrix
|
|
|
|
const SkPath* maskPath = layer->getConvexMask();
|
|
|
|
DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
|
|
|
|
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
paint.setShader(NULL);
|
2014-04-15 16:18:08 -07:00
|
|
|
restore();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-10-27 18:57:51 -07:00
|
|
|
if (layer->region.isRect()) {
|
2011-04-27 14:21:41 -07:00
|
|
|
layer->setRegionAsRect();
|
|
|
|
|
2013-04-15 16:08:28 -07:00
|
|
|
DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
|
2011-04-27 14:21:41 -07:00
|
|
|
|
2010-10-27 18:57:51 -07:00
|
|
|
layer->region.clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
// standard Region based draw
|
|
|
|
size_t count;
|
|
|
|
const android::Rect* rects;
|
|
|
|
Region safeRegion;
|
|
|
|
if (CC_LIKELY(hasRectToRectTransform())) {
|
|
|
|
rects = layer->region.getArray(&count);
|
|
|
|
} else {
|
|
|
|
safeRegion = Region::createTJunctionFreeRegion(layer->region);
|
|
|
|
rects = safeRegion.getArray(&count);
|
|
|
|
}
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
const float alpha = getLayerAlpha(layer);
|
|
|
|
const float texX = 1.0f / float(layer->getWidth());
|
|
|
|
const float texY = 1.0f / float(layer->getHeight());
|
|
|
|
const float height = rect.getHeight();
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
setupDraw();
|
2013-01-15 18:51:42 -08:00
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
// We must get (and therefore bind) the region mesh buffer
|
|
|
|
// after we setup drawing in case we need to mess with the
|
|
|
|
// stencil buffer in setupDraw()
|
|
|
|
TextureVertex* mesh = mCaches.getRegionMesh();
|
|
|
|
uint32_t numQuads = 0;
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
setupDrawWithTexture();
|
|
|
|
setupDrawColor(alpha, alpha, alpha, alpha);
|
|
|
|
setupDrawColorFilter(layer->getColorFilter());
|
|
|
|
setupDrawBlending(layer);
|
|
|
|
setupDrawProgram();
|
|
|
|
setupDrawDirtyRegionsDisabled();
|
|
|
|
setupDrawPureColorUniforms();
|
|
|
|
setupDrawColorFilterUniforms(layer->getColorFilter());
|
|
|
|
setupDrawTexture(layer->getTexture());
|
|
|
|
if (currentTransform()->isPureTranslate()) {
|
|
|
|
const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
|
2011-07-07 20:50:11 -07:00
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
layer->setFilter(GL_NEAREST);
|
|
|
|
setupDrawModelView(kModelViewMode_Translate, false,
|
|
|
|
x, y, x + rect.getWidth(), y + rect.getHeight(), true);
|
|
|
|
} else {
|
|
|
|
layer->setFilter(GL_LINEAR);
|
|
|
|
setupDrawModelView(kModelViewMode_Translate, false,
|
|
|
|
rect.left, rect.top, rect.right, rect.bottom);
|
|
|
|
}
|
|
|
|
setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
const android::Rect* r = &rects[i];
|
|
|
|
|
|
|
|
const float u1 = r->left * texX;
|
|
|
|
const float v1 = (height - r->top) * texY;
|
|
|
|
const float u2 = r->right * texX;
|
|
|
|
const float v2 = (height - r->bottom) * texY;
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
// TODO: Reject quads outside of the clip
|
|
|
|
TextureVertex::set(mesh++, r->left, r->top, u1, v1);
|
|
|
|
TextureVertex::set(mesh++, r->right, r->top, u2, v1);
|
|
|
|
TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
|
|
|
|
TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
|
|
|
|
|
|
|
|
numQuads++;
|
|
|
|
|
|
|
|
if (numQuads >= gMaxNumberOfQuads) {
|
2013-04-15 16:08:28 -07:00
|
|
|
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
|
|
|
|
GL_UNSIGNED_SHORT, NULL));
|
2014-04-15 16:18:08 -07:00
|
|
|
numQuads = 0;
|
|
|
|
mesh = mCaches.getRegionMesh();
|
2010-10-27 18:57:51 -07:00
|
|
|
}
|
2014-04-15 16:18:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (numQuads > 0) {
|
|
|
|
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
|
|
|
|
GL_UNSIGNED_SHORT, NULL));
|
|
|
|
}
|
2010-10-27 18:57:51 -07:00
|
|
|
|
|
|
|
#if DEBUG_LAYERS_AS_REGIONS
|
2014-04-15 16:18:08 -07:00
|
|
|
drawRegionRectsDebug(layer->region);
|
2010-10-27 18:57:51 -07:00
|
|
|
#endif
|
|
|
|
|
2014-04-15 16:18:08 -07:00
|
|
|
layer->region.clear();
|
2010-10-27 18:57:51 -07:00
|
|
|
}
|
|
|
|
|
2011-02-01 22:59:58 -08:00
|
|
|
#if DEBUG_LAYERS_AS_REGIONS
|
2013-10-17 10:30:55 -07:00
|
|
|
void OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
|
2011-02-01 22:59:58 -08:00
|
|
|
size_t count;
|
|
|
|
const android::Rect* rects = region.getArray(&count);
|
|
|
|
|
|
|
|
uint32_t colors[] = {
|
|
|
|
0x7fff0000, 0x7f00ff00,
|
|
|
|
0x7f0000ff, 0x7fff00ff,
|
|
|
|
};
|
|
|
|
|
|
|
|
int offset = 0;
|
|
|
|
int32_t top = rects[0].top;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
if (top != rects[i].top) {
|
|
|
|
offset ^= 0x2;
|
|
|
|
top = rects[i].top;
|
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(colors[offset + (i & 0x1)]);
|
2011-02-01 22:59:58 -08:00
|
|
|
Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
|
2013-12-10 12:28:58 -05:00
|
|
|
drawColorRect(r.left, r.top, r.right, r.bottom, paint);
|
2011-02-01 22:59:58 -08:00
|
|
|
}
|
|
|
|
}
|
2013-10-17 10:30:55 -07:00
|
|
|
#endif
|
2011-02-01 22:59:58 -08:00
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
|
2013-01-15 18:51:42 -08:00
|
|
|
Vector<float> rects;
|
|
|
|
|
|
|
|
SkRegion::Iterator it(region);
|
|
|
|
while (!it.done()) {
|
|
|
|
const SkIRect& r = it.rect();
|
|
|
|
rects.push(r.fLeft);
|
|
|
|
rects.push(r.fTop);
|
|
|
|
rects.push(r.fRight);
|
|
|
|
rects.push(r.fBottom);
|
|
|
|
it.next();
|
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
|
2013-01-15 18:51:42 -08:00
|
|
|
}
|
|
|
|
|
2010-10-27 18:57:51 -07:00
|
|
|
void OpenGLRenderer::dirtyLayer(const float left, const float top,
|
|
|
|
const float right, const float bottom, const mat4 transform) {
|
2011-01-16 12:54:25 -08:00
|
|
|
if (hasLayer()) {
|
2010-10-27 18:57:51 -07:00
|
|
|
Rect bounds(left, top, right, bottom);
|
|
|
|
transform.mapRect(bounds);
|
2011-01-16 12:54:25 -08:00
|
|
|
dirtyLayerUnchecked(bounds, getRegion());
|
2010-10-27 18:57:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::dirtyLayer(const float left, const float top,
|
|
|
|
const float right, const float bottom) {
|
2011-01-16 12:54:25 -08:00
|
|
|
if (hasLayer()) {
|
2010-10-27 18:57:51 -07:00
|
|
|
Rect bounds(left, top, right, bottom);
|
2011-01-16 12:54:25 -08:00
|
|
|
dirtyLayerUnchecked(bounds, getRegion());
|
2011-01-14 20:07:20 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (bounds.intersect(*currentClipRect())) {
|
2011-01-14 20:07:20 -08:00
|
|
|
bounds.snapToPixelBoundaries();
|
|
|
|
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
|
|
|
|
if (!dirty.isEmpty()) {
|
|
|
|
region->orSelf(dirty);
|
2010-10-27 18:57:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-15 16:06:56 -08:00
|
|
|
void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
|
2013-07-22 13:57:50 -07:00
|
|
|
GLsizei elementsCount = quadsCount * 6;
|
|
|
|
while (elementsCount > 0) {
|
|
|
|
GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
|
|
|
|
|
2013-08-15 16:57:57 -07:00
|
|
|
setupDrawIndexedVertices(&mesh[0].x);
|
2013-07-22 13:57:50 -07:00
|
|
|
glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
|
|
|
|
|
|
|
|
elementsCount -= drawCount;
|
|
|
|
// Though there are 4 vertices in a quad, we use 6 indices per
|
|
|
|
// quad to draw with GL_TRIANGLES
|
|
|
|
mesh += (drawCount / 6) * 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-13 19:04:27 -07:00
|
|
|
void OpenGLRenderer::clearLayerRegions() {
|
|
|
|
const size_t count = mLayers.size();
|
|
|
|
if (count == 0) return;
|
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
if (!currentSnapshot()->isIgnored()) {
|
2011-06-13 19:04:27 -07:00
|
|
|
// Doing several glScissor/glClear here can negatively impact
|
|
|
|
// GPUs with a tiler architecture, instead we draw quads with
|
|
|
|
// the Clear blending mode
|
|
|
|
|
|
|
|
// The list contains bounds that have already been clipped
|
|
|
|
// against their initial clip rect, and the current clip
|
|
|
|
// is likely different so we need to disable clipping here
|
2012-07-17 17:32:48 -07:00
|
|
|
bool scissorChanged = mCaches.disableScissor();
|
2011-06-13 19:04:27 -07:00
|
|
|
|
2013-07-22 13:57:50 -07:00
|
|
|
Vertex mesh[count * 4];
|
2011-06-13 19:04:27 -07:00
|
|
|
Vertex* vertex = mesh;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
|
|
Rect* bounds = mLayers.itemAt(i);
|
|
|
|
|
|
|
|
Vertex::set(vertex++, bounds->left, bounds->top);
|
|
|
|
Vertex::set(vertex++, bounds->right, bounds->top);
|
|
|
|
Vertex::set(vertex++, bounds->left, bounds->bottom);
|
|
|
|
Vertex::set(vertex++, bounds->right, bounds->bottom);
|
|
|
|
|
|
|
|
delete bounds;
|
|
|
|
}
|
2013-02-11 18:01:20 -08:00
|
|
|
// We must clear the list of dirty rects before we
|
|
|
|
// call setupDraw() to prevent stencil setup to do
|
|
|
|
// the same thing again
|
|
|
|
mLayers.clear();
|
2011-06-13 19:04:27 -07:00
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
SkPaint clearPaint;
|
|
|
|
clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
|
|
|
|
|
2011-06-13 19:04:27 -07:00
|
|
|
setupDraw(false);
|
|
|
|
setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawBlending(&clearPaint, true);
|
2011-06-13 19:04:27 -07:00
|
|
|
setupDrawProgram();
|
|
|
|
setupDrawPureColorUniforms();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_Translate, false,
|
|
|
|
0.0f, 0.0f, 0.0f, 0.0f, true);
|
2011-06-13 19:04:27 -07:00
|
|
|
|
2013-11-15 16:06:56 -08:00
|
|
|
issueIndexedQuadDraw(&mesh[0], count);
|
2012-07-17 17:32:48 -07:00
|
|
|
|
|
|
|
if (scissorChanged) mCaches.enableScissor();
|
2011-06-13 19:04:27 -07:00
|
|
|
} else {
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
|
|
delete mLayers.itemAt(i);
|
|
|
|
}
|
2013-02-11 18:01:20 -08:00
|
|
|
mLayers.clear();
|
2011-06-13 19:04:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-04 16:16:33 -08:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// State Deferral
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-03-08 13:12:16 -08:00
|
|
|
bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
|
2014-01-01 14:45:21 -08:00
|
|
|
const Rect* currentClip = currentClipRect();
|
|
|
|
const mat4* currentMatrix = currentTransform();
|
2013-02-04 16:16:33 -08:00
|
|
|
|
2013-03-08 13:12:16 -08:00
|
|
|
if (stateDeferFlags & kStateDeferFlag_Draw) {
|
|
|
|
// state has bounds initialized in local coordinates
|
|
|
|
if (!state.mBounds.isEmpty()) {
|
2014-01-01 14:45:21 -08:00
|
|
|
currentMatrix->mapRect(state.mBounds);
|
2013-05-31 11:38:03 -07:00
|
|
|
Rect clippedBounds(state.mBounds);
|
2013-07-30 19:05:20 -07:00
|
|
|
// NOTE: if we ever want to use this clipping info to drive whether the scissor
|
|
|
|
// is used, it should more closely duplicate the quickReject logic (in how it uses
|
|
|
|
// snapToPixelBoundaries)
|
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
if(!clippedBounds.intersect(*currentClip)) {
|
2013-03-08 13:12:16 -08:00
|
|
|
// quick rejected
|
|
|
|
return true;
|
|
|
|
}
|
2013-05-31 11:38:03 -07:00
|
|
|
|
2013-06-14 13:43:58 -07:00
|
|
|
state.mClipSideFlags = kClipSide_None;
|
2014-01-01 14:45:21 -08:00
|
|
|
if (!currentClip->contains(state.mBounds)) {
|
2013-05-31 11:38:03 -07:00
|
|
|
int& flags = state.mClipSideFlags;
|
|
|
|
// op partially clipped, so record which sides are clipped for clip-aware merging
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentClip->left > state.mBounds.left) flags |= kClipSide_Left;
|
|
|
|
if (currentClip->top > state.mBounds.top) flags |= kClipSide_Top;
|
|
|
|
if (currentClip->right < state.mBounds.right) flags |= kClipSide_Right;
|
|
|
|
if (currentClip->bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
|
2013-05-31 11:38:03 -07:00
|
|
|
}
|
|
|
|
state.mBounds.set(clippedBounds);
|
2013-03-08 13:12:16 -08:00
|
|
|
} else {
|
2013-06-17 13:52:06 -07:00
|
|
|
// Empty bounds implies size unknown. Label op as conservatively clipped to disable
|
|
|
|
// overdraw avoidance (since we don't know what it overlaps)
|
|
|
|
state.mClipSideFlags = kClipSide_ConservativeFull;
|
2014-01-01 14:45:21 -08:00
|
|
|
state.mBounds.set(*currentClip);
|
2013-02-04 16:16:33 -08:00
|
|
|
}
|
2013-03-08 13:12:16 -08:00
|
|
|
}
|
|
|
|
|
2013-03-04 10:19:31 -08:00
|
|
|
state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
|
|
|
|
if (state.mClipValid) {
|
2014-01-01 14:45:21 -08:00
|
|
|
state.mClip.set(*currentClip);
|
2013-02-04 16:16:33 -08:00
|
|
|
}
|
|
|
|
|
2013-03-28 11:25:24 -07:00
|
|
|
// Transform, drawModifiers, and alpha always deferred, since they are used by state operations
|
|
|
|
// (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
|
2014-01-01 14:45:21 -08:00
|
|
|
state.mMatrix.load(*currentMatrix);
|
2013-03-28 11:25:24 -07:00
|
|
|
state.mDrawModifiers = mDrawModifiers;
|
2014-01-01 14:45:21 -08:00
|
|
|
state.mAlpha = currentSnapshot()->alpha;
|
2014-05-05 19:09:33 -07:00
|
|
|
|
|
|
|
// always store/restore, since it's just a pointer
|
|
|
|
state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
|
2013-02-04 16:16:33 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-03-04 10:19:31 -08:00
|
|
|
void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
|
2013-12-30 15:32:54 -08:00
|
|
|
setMatrix(state.mMatrix);
|
2013-03-28 11:25:24 -07:00
|
|
|
mSnapshot->alpha = state.mAlpha;
|
2013-12-30 15:32:54 -08:00
|
|
|
mDrawModifiers = state.mDrawModifiers;
|
2014-05-05 19:09:33 -07:00
|
|
|
mSnapshot->roundRectClipState = state.mRoundRectClipState;
|
2013-03-08 13:12:16 -08:00
|
|
|
|
2013-03-04 10:19:31 -08:00
|
|
|
if (state.mClipValid && !skipClipRestore) {
|
2013-05-31 11:38:03 -07:00
|
|
|
mSnapshot->setClip(state.mClip.left, state.mClip.top,
|
|
|
|
state.mClip.right, state.mClip.bottom);
|
2013-03-08 13:12:16 -08:00
|
|
|
dirtyClip();
|
|
|
|
}
|
2013-02-04 16:16:33 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 11:38:03 -07:00
|
|
|
/**
|
|
|
|
* Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
|
|
|
|
* in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
|
|
|
|
* least one op is clipped), or disabled entirely (because no merged op is clipped)
|
|
|
|
*
|
|
|
|
* This method should be called when restoreDisplayState() won't be restoring the clip
|
|
|
|
*/
|
|
|
|
void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
|
|
|
|
if (clipRect != NULL) {
|
|
|
|
mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
|
|
|
|
} else {
|
2013-12-30 15:32:54 -08:00
|
|
|
mSnapshot->setClip(0, 0, getWidth(), getHeight());
|
2013-05-31 11:38:03 -07:00
|
|
|
}
|
2013-03-04 10:19:31 -08:00
|
|
|
dirtyClip();
|
2013-05-31 11:38:03 -07:00
|
|
|
mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
|
2013-03-04 10:19:31 -08:00
|
|
|
}
|
|
|
|
|
2010-06-23 17:47:49 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Clipping
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-06-22 18:56:38 -07:00
|
|
|
void OpenGLRenderer::setScissorFromClip() {
|
2014-01-01 14:45:21 -08:00
|
|
|
Rect clip(*currentClipRect());
|
2010-10-15 13:57:28 -07:00
|
|
|
clip.snapToPixelBoundaries();
|
2011-12-14 19:23:32 -08:00
|
|
|
|
2014-05-14 14:17:01 -07:00
|
|
|
if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
|
2012-07-17 17:32:48 -07:00
|
|
|
clip.getWidth(), clip.getHeight())) {
|
|
|
|
mDirtyClip = false;
|
|
|
|
}
|
2010-06-24 19:30:36 -07:00
|
|
|
}
|
|
|
|
|
2013-01-15 18:51:42 -08:00
|
|
|
void OpenGLRenderer::ensureStencilBuffer() {
|
|
|
|
// Thanks to the mismatch between EGL and OpenGL ES FBO we
|
|
|
|
// cannot attach a stencil buffer to fbo0 dynamically. Let's
|
|
|
|
// just hope we have one when hasLayer() returns false.
|
|
|
|
if (hasLayer()) {
|
2014-01-01 14:45:21 -08:00
|
|
|
attachStencilBufferToLayer(currentSnapshot()->layer);
|
2013-01-15 18:51:42 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
|
|
|
|
// The layer's FBO is already bound when we reach this stage
|
|
|
|
if (!layer->getStencilRenderBuffer()) {
|
2013-01-29 17:26:25 -08:00
|
|
|
// GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
|
|
|
|
// is attached after we initiated tiling. We must turn it off,
|
|
|
|
// attach the new render buffer then turn tiling back on
|
|
|
|
endTiling();
|
|
|
|
|
2013-02-12 16:08:55 -08:00
|
|
|
RenderBuffer* buffer = mCaches.renderBufferCache.get(
|
2013-02-06 16:51:04 -08:00
|
|
|
Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
|
2013-01-15 18:51:42 -08:00
|
|
|
layer->setStencilRenderBuffer(buffer);
|
2013-01-29 17:26:25 -08:00
|
|
|
|
2013-01-31 17:45:55 -08:00
|
|
|
startTiling(layer->clipRect, layer->layer.getHeight());
|
2013-01-15 18:51:42 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setStencilFromClip() {
|
|
|
|
if (!mCaches.debugOverdraw) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (!currentSnapshot()->clipRegion->isEmpty()) {
|
2013-01-15 18:51:42 -08:00
|
|
|
// NOTE: The order here is important, we must set dirtyClip to false
|
|
|
|
// before any draw call to avoid calling back into this method
|
|
|
|
mDirtyClip = false;
|
|
|
|
|
|
|
|
ensureStencilBuffer();
|
|
|
|
|
|
|
|
mCaches.stencil.enableWrite();
|
|
|
|
|
2014-05-05 19:09:33 -07:00
|
|
|
// Clear and update the stencil, but first make sure we restrict drawing
|
2013-01-15 18:51:42 -08:00
|
|
|
// to the region's bounds
|
|
|
|
bool resetScissor = mCaches.enableScissor();
|
|
|
|
if (resetScissor) {
|
|
|
|
// The scissor was not set so we now need to update it
|
|
|
|
setScissorFromClip();
|
|
|
|
}
|
|
|
|
mCaches.stencil.clear();
|
2014-05-05 19:09:33 -07:00
|
|
|
|
|
|
|
// stash and disable the outline clip state, since stencil doesn't account for outline
|
|
|
|
bool storedSkipOutlineClip = mSkipOutlineClip;
|
|
|
|
mSkipOutlineClip = true;
|
2013-01-15 18:51:42 -08:00
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
SkPaint paint;
|
2014-07-17 12:25:11 -07:00
|
|
|
paint.setColor(SK_ColorBLACK);
|
2013-12-10 12:28:58 -05:00
|
|
|
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
|
|
|
|
2013-01-15 18:51:42 -08:00
|
|
|
// NOTE: We could use the region contour path to generate a smaller mesh
|
|
|
|
// Since we are using the stencil we could use the red book path
|
|
|
|
// drawing technique. It might increase bandwidth usage though.
|
|
|
|
|
|
|
|
// The last parameter is important: we are not drawing in the color buffer
|
|
|
|
// so we don't want to dirty the current layer, if any
|
2013-12-10 12:28:58 -05:00
|
|
|
drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
|
2014-05-05 19:09:33 -07:00
|
|
|
if (resetScissor) mCaches.disableScissor();
|
|
|
|
mSkipOutlineClip = storedSkipOutlineClip;
|
2013-01-15 18:51:42 -08:00
|
|
|
|
|
|
|
mCaches.stencil.enableTest();
|
2013-02-25 14:15:37 -08:00
|
|
|
|
|
|
|
// Draw the region used to generate the stencil if the appropriate debug
|
|
|
|
// mode is enabled
|
|
|
|
if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
|
2013-12-10 12:28:58 -05:00
|
|
|
paint.setColor(0x7f0000ff);
|
|
|
|
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
|
|
|
|
drawRegionRects(*(currentSnapshot()->clipRegion), paint);
|
2013-02-25 14:15:37 -08:00
|
|
|
}
|
2013-01-15 18:51:42 -08:00
|
|
|
} else {
|
|
|
|
mCaches.stencil.disable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-19 18:00:46 -08:00
|
|
|
/**
|
|
|
|
* Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
|
|
|
|
*
|
|
|
|
* @param paint if not null, the bounds will be expanded to account for stroke depending on paint
|
|
|
|
* style, and tessellated AA ramp
|
|
|
|
*/
|
|
|
|
bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* paint) {
|
2013-11-19 18:00:46 -08:00
|
|
|
bool snapOut = paint && paint->isAntiAlias();
|
2013-07-30 19:05:20 -07:00
|
|
|
|
2013-11-19 18:00:46 -08:00
|
|
|
if (paint && paint->getStyle() != SkPaint::kFill_Style) {
|
2012-09-25 12:00:29 -07:00
|
|
|
float outset = paint->getStrokeWidth() * 0.5f;
|
2013-11-19 18:00:46 -08:00
|
|
|
left -= outset;
|
|
|
|
top -= outset;
|
|
|
|
right += outset;
|
|
|
|
bottom += outset;
|
2012-09-25 12:00:29 -07:00
|
|
|
}
|
|
|
|
|
2014-05-05 19:09:33 -07:00
|
|
|
bool clipRequired = false;
|
|
|
|
bool roundRectClipRequired = false;
|
|
|
|
if (calculateQuickRejectForScissor(left, top, right, bottom,
|
|
|
|
&clipRequired, &roundRectClipRequired, snapOut)) {
|
2010-10-11 17:58:29 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-06-26 15:46:20 -07:00
|
|
|
// not quick rejected, so enable the scissor if clipRequired
|
|
|
|
mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
|
|
|
|
mSkipOutlineClip = !roundRectClipRequired;
|
2013-06-13 14:39:01 -07:00
|
|
|
return false;
|
2010-06-25 13:41:57 -07:00
|
|
|
}
|
|
|
|
|
2013-01-15 18:51:42 -08:00
|
|
|
void OpenGLRenderer::debugClip() {
|
2012-12-03 12:34:51 -08:00
|
|
|
#if DEBUG_CLIP_REGIONS
|
2014-06-26 15:46:20 -07:00
|
|
|
if (!currentSnapshot()->clipRegion->isEmpty()) {
|
2013-12-10 12:28:58 -05:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(0x7f00ff00);
|
|
|
|
drawRegionRects(*(currentSnapshot()->clipRegion, paint);
|
|
|
|
|
2013-01-15 18:51:42 -08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2012-12-03 12:34:51 -08:00
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Drawing commands
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2011-06-13 19:04:27 -07:00
|
|
|
void OpenGLRenderer::setupDraw(bool clear) {
|
2013-11-19 18:00:46 -08:00
|
|
|
// TODO: It would be best if we could do this before quickRejectSetupScissor()
|
2012-07-17 17:32:48 -07:00
|
|
|
// changes the scissor test state
|
2011-06-13 19:04:27 -07:00
|
|
|
if (clear) clearLayerRegions();
|
2013-01-15 18:51:42 -08:00
|
|
|
// Make sure setScissor & setStencil happen at the beginning of
|
|
|
|
// this method
|
2013-02-21 11:30:22 -08:00
|
|
|
if (mDirtyClip) {
|
|
|
|
if (mCaches.scissorEnabled) {
|
|
|
|
setScissorFromClip();
|
|
|
|
}
|
2013-01-15 18:51:42 -08:00
|
|
|
setStencilFromClip();
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
2013-02-25 14:15:37 -08:00
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
mDescription.reset();
|
2013-02-25 14:15:37 -08:00
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
mSetShaderColor = false;
|
|
|
|
mColorSet = false;
|
|
|
|
mColorA = mColorR = mColorG = mColorB = 0.0f;
|
|
|
|
mTextureUnit = 0;
|
|
|
|
mTrackDirtyRegions = true;
|
2013-02-25 14:15:37 -08:00
|
|
|
|
|
|
|
// Enable debug highlight when what we're about to draw is tested against
|
|
|
|
// the stencil buffer and if stencil highlight debugging is on
|
|
|
|
mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
|
|
|
|
mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
|
|
|
|
mCaches.stencil.isTestEnabled();
|
2013-05-03 14:24:16 -07:00
|
|
|
|
|
|
|
mDescription.emulateStencil = mCountOverdraw;
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
|
|
|
|
mDescription.hasTexture = true;
|
|
|
|
mDescription.hasAlpha8Texture = isAlpha8;
|
|
|
|
}
|
|
|
|
|
2013-02-13 18:39:43 -08:00
|
|
|
void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
|
|
|
|
mDescription.hasTexture = true;
|
|
|
|
mDescription.hasColors = true;
|
|
|
|
mDescription.hasAlpha8Texture = isAlpha8;
|
|
|
|
}
|
|
|
|
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
void OpenGLRenderer::setupDrawWithExternalTexture() {
|
|
|
|
mDescription.hasExternalTexture = true;
|
|
|
|
}
|
|
|
|
|
2011-12-13 13:11:32 -08:00
|
|
|
void OpenGLRenderer::setupDrawNoTexture() {
|
2013-02-13 18:39:43 -08:00
|
|
|
mCaches.disableTexCoordsVertexArray();
|
2011-12-13 13:11:32 -08:00
|
|
|
}
|
|
|
|
|
2012-09-17 17:25:49 -07:00
|
|
|
void OpenGLRenderer::setupDrawAA() {
|
2011-05-02 15:00:16 -07:00
|
|
|
mDescription.isAA = true;
|
2011-04-13 17:58:08 -07:00
|
|
|
}
|
|
|
|
|
2010-12-14 20:13:35 -08:00
|
|
|
void OpenGLRenderer::setupDrawColor(int color, int alpha) {
|
|
|
|
mColorA = alpha / 255.0f;
|
2013-01-04 12:26:18 -08:00
|
|
|
mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
|
|
|
|
mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f;
|
|
|
|
mColorB = mColorA * ((color ) & 0xFF) / 255.0f;
|
2010-12-13 18:24:33 -08:00
|
|
|
mColorSet = true;
|
2013-10-17 10:30:55 -07:00
|
|
|
mSetShaderColor = mDescription.setColorModulate(mColorA);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
2010-12-14 15:55:39 -08:00
|
|
|
void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
|
|
|
|
mColorA = alpha / 255.0f;
|
2013-01-04 12:26:18 -08:00
|
|
|
mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
|
|
|
|
mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f;
|
|
|
|
mColorB = mColorA * ((color ) & 0xFF) / 255.0f;
|
2010-12-14 15:55:39 -08:00
|
|
|
mColorSet = true;
|
2013-10-17 10:30:55 -07:00
|
|
|
mSetShaderColor = mDescription.setAlpha8ColorModulate(mColorR, mColorG, mColorB, mColorA);
|
2010-12-14 15:55:39 -08:00
|
|
|
}
|
|
|
|
|
2012-07-16 17:04:24 -07:00
|
|
|
void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
|
|
|
|
mCaches.fontRenderer->describe(mDescription, paint);
|
|
|
|
}
|
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
|
|
|
|
mColorA = a;
|
|
|
|
mColorR = r;
|
|
|
|
mColorG = g;
|
|
|
|
mColorB = b;
|
|
|
|
mColorSet = true;
|
2013-10-17 10:30:55 -07:00
|
|
|
mSetShaderColor = mDescription.setColorModulate(a);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
|
|
|
|
if (shader != NULL) {
|
|
|
|
SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
|
|
|
|
if (filter == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
if (filter->asColorMode(NULL, &mode)) {
|
|
|
|
mDescription.colorOp = ProgramDescription::kColorBlend;
|
|
|
|
mDescription.colorMode = mode;
|
|
|
|
} else if (filter->asColorMatrix(NULL)) {
|
|
|
|
mDescription.colorOp = ProgramDescription::kColorMatrix;
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-27 11:43:46 -07:00
|
|
|
void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
|
|
|
|
if (mColorSet && mode == SkXfermode::kClear_Mode) {
|
|
|
|
mColorA = 1.0f;
|
|
|
|
mColorR = mColorG = mColorB = 0.0f;
|
2011-06-13 19:04:27 -07:00
|
|
|
mSetShaderColor = mDescription.modulate = true;
|
2011-05-27 11:43:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
static bool isBlendedColorFilter(const SkColorFilter* filter) {
|
|
|
|
if (filter == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
|
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
|
|
|
|
SkXfermode::Mode mode = layer->getMode();
|
2011-05-27 11:43:46 -07:00
|
|
|
// When the blending mode is kClear_Mode, we need to use a modulate color
|
|
|
|
// argb=1,0,0,0
|
|
|
|
accountForClear(mode);
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
// TODO: check shader blending, once we have shader drawing support for layers.
|
2013-12-10 12:28:58 -05:00
|
|
|
bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
(mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter());
|
2013-02-04 16:16:33 -08:00
|
|
|
chooseBlending(blend, mode, mDescription, swapSrcDst);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
|
|
|
|
SkXfermode::Mode mode = getXfermodeDirect(paint);
|
2011-05-27 11:43:46 -07:00
|
|
|
// When the blending mode is kClear_Mode, we need to use a modulate color
|
|
|
|
// argb=1,0,0,0
|
|
|
|
accountForClear(mode);
|
2013-02-04 16:16:33 -08:00
|
|
|
blend |= (mColorSet && mColorA < 1.0f) ||
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
(getShader(paint) && !getShader(paint)->isOpaque()) ||
|
|
|
|
isBlendedColorFilter(getColorFilter(paint));
|
2013-02-04 16:16:33 -08:00
|
|
|
chooseBlending(blend, mode, mDescription, swapSrcDst);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setupDrawProgram() {
|
|
|
|
useProgram(mCaches.programCache.get(mDescription));
|
2014-05-05 19:09:33 -07:00
|
|
|
if (mDescription.hasRoundRectClip) {
|
|
|
|
// TODO: avoid doing this repeatedly, stashing state pointer in program
|
|
|
|
const RoundRectClipState* state = mSnapshot->roundRectClipState;
|
|
|
|
const Rect& innerRect = state->outlineInnerRect;
|
|
|
|
glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
|
|
|
|
innerRect.left, innerRect.top,
|
|
|
|
innerRect.right, innerRect.bottom);
|
|
|
|
glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
|
|
|
|
state->outlineRadius);
|
|
|
|
glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
|
|
|
|
1, GL_FALSE, &state->matrix.data[0]);
|
|
|
|
}
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
|
|
|
|
mTrackDirtyRegions = false;
|
|
|
|
}
|
|
|
|
|
2013-11-15 16:06:56 -08:00
|
|
|
void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
|
|
|
|
float left, float top, float right, float bottom, bool ignoreTransform) {
|
2014-05-08 14:28:26 -07:00
|
|
|
mModelViewMatrix.loadTranslate(left, top, 0.0f);
|
2013-11-15 16:06:56 -08:00
|
|
|
if (mode == kModelViewMode_TranslateAndScale) {
|
2014-05-08 14:28:26 -07:00
|
|
|
mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
2013-11-15 16:06:56 -08:00
|
|
|
|
2010-12-14 15:55:39 -08:00
|
|
|
bool dirty = right - left > 0.0f && bottom - top > 0.0f;
|
2014-05-14 14:17:01 -07:00
|
|
|
const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
|
|
|
|
mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
|
|
|
|
if (dirty && mTrackDirtyRegions) {
|
|
|
|
if (!ignoreTransform) {
|
|
|
|
dirtyLayer(left, top, right, bottom, *currentTransform());
|
|
|
|
} else {
|
|
|
|
dirtyLayer(left, top, right, bottom);
|
|
|
|
}
|
2010-12-14 15:55:39 -08:00
|
|
|
}
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
|
|
|
|
if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
|
2010-12-13 18:24:33 -08:00
|
|
|
mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-14 15:55:39 -08:00
|
|
|
void OpenGLRenderer::setupDrawPureColorUniforms() {
|
2010-12-14 10:59:41 -08:00
|
|
|
if (mSetShaderColor) {
|
2010-12-14 15:55:39 -08:00
|
|
|
mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
|
2010-12-14 10:59:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
|
|
|
|
if (shader == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ignoreTransform) {
|
|
|
|
// if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
|
|
|
|
// because it was built into modelView / the geometry, and the description needs to
|
|
|
|
// compensate.
|
|
|
|
mat4 modelViewWithoutTransform;
|
|
|
|
modelViewWithoutTransform.loadInverse(*currentTransform());
|
|
|
|
modelViewWithoutTransform.multiply(mModelViewMatrix);
|
|
|
|
mModelViewMatrix.load(modelViewWithoutTransform);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
|
|
|
|
SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
|
|
|
|
if (NULL == filter) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkColor color;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
if (filter->asColorMode(&color, &mode)) {
|
|
|
|
const int alpha = SkColorGetA(color);
|
|
|
|
const GLfloat a = alpha / 255.0f;
|
|
|
|
const GLfloat r = a * SkColorGetR(color) / 255.0f;
|
|
|
|
const GLfloat g = a * SkColorGetG(color) / 255.0f;
|
|
|
|
const GLfloat b = a * SkColorGetB(color) / 255.0f;
|
|
|
|
glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkScalar srcColorMatrix[20];
|
|
|
|
if (filter->asColorMatrix(srcColorMatrix)) {
|
|
|
|
|
|
|
|
float colorMatrix[16];
|
|
|
|
memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
|
|
|
|
memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
|
|
|
|
memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
|
|
|
|
memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
|
|
|
|
|
|
|
|
// Skia uses the range [0..255] for the addition vector, but we need
|
|
|
|
// the [0..1] range to apply the vector in GLSL
|
|
|
|
float colorVector[4];
|
|
|
|
colorVector[0] = srcColorMatrix[4] / 255.0f;
|
|
|
|
colorVector[1] = srcColorMatrix[9] / 255.0f;
|
|
|
|
colorVector[2] = srcColorMatrix[14] / 255.0f;
|
|
|
|
colorVector[3] = srcColorMatrix[19] / 255.0f;
|
|
|
|
|
|
|
|
glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
|
|
|
|
GL_FALSE, colorMatrix);
|
|
|
|
glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
|
|
|
|
return;
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
2013-12-10 12:28:58 -05:00
|
|
|
|
|
|
|
// it is an error if we ever get here
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
2012-07-16 17:04:24 -07:00
|
|
|
void OpenGLRenderer::setupDrawTextGammaUniforms() {
|
|
|
|
mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
|
|
|
|
}
|
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
void OpenGLRenderer::setupDrawSimpleMesh() {
|
2011-12-12 20:35:21 -08:00
|
|
|
bool force = mCaches.bindMeshBuffer();
|
2012-09-25 12:00:29 -07:00
|
|
|
mCaches.bindPositionVertexPointer(force, 0);
|
2011-12-13 13:11:32 -08:00
|
|
|
mCaches.unbindIndicesBuffer();
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setupDrawTexture(GLuint texture) {
|
2013-03-20 16:31:12 -07:00
|
|
|
if (texture) bindTexture(texture);
|
2011-12-13 22:00:19 -08:00
|
|
|
mTextureUnit++;
|
2011-12-13 13:11:32 -08:00
|
|
|
mCaches.enableTexCoordsVertexArray();
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
|
|
|
|
bindExternalTexture(texture);
|
2011-12-13 22:00:19 -08:00
|
|
|
mTextureUnit++;
|
2011-12-13 13:11:32 -08:00
|
|
|
mCaches.enableTexCoordsVertexArray();
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
}
|
|
|
|
|
2011-05-02 17:24:22 -07:00
|
|
|
void OpenGLRenderer::setupDrawTextureTransform() {
|
|
|
|
mDescription.hasTextureTransform = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
|
New widget: TextureView
Bug #4343984
TextureView can be used to render media content (video, OpenGL,
RenderScript) inside a View.
The key difference with SurfaceView is that TextureView does
not create a new Surface. This gives the ability to seamlessly
transform, animate, fade, etc. a TextureView, which was hard
if not impossible to do with a SurfaceView.
A TextureView also interacts perfectly with ScrollView,
ListView, etc. It allows application to embed media content
in a much more flexible way than before.
For instance, to render the camera preview at 50% opacity,
all you need to do is the following:
mTextureView.setAlpha(0.5f);
Camera c = Camera.open();
c.setPreviewTexture(mTextureView.getSurfaceTexture());
c.startPreview();
TextureView uses a SurfaceTexture to get the job done. More
APIs are required to make it easy to create OpenGL contexts
for a TextureView. It can currently be done with a bit of
JNI code.
Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
2011-04-28 18:40:04 -07:00
|
|
|
glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
|
|
|
|
GL_FALSE, &transform.data[0]);
|
|
|
|
}
|
|
|
|
|
2014-01-02 16:46:18 -08:00
|
|
|
void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
|
|
|
|
const GLvoid* texCoords, GLuint vbo) {
|
2011-12-12 20:35:21 -08:00
|
|
|
bool force = false;
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
if (!vertices || vbo) {
|
2011-12-12 20:35:21 -08:00
|
|
|
force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
|
2010-12-13 18:24:33 -08:00
|
|
|
} else {
|
2011-12-12 20:35:21 -08:00
|
|
|
force = mCaches.unbindMeshBuffer();
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
2011-12-12 19:03:35 -08:00
|
|
|
|
2012-09-25 12:00:29 -07:00
|
|
|
mCaches.bindPositionVertexPointer(force, vertices);
|
2011-12-13 13:11:32 -08:00
|
|
|
if (mCaches.currentProgram->texCoords >= 0) {
|
2012-09-25 12:00:29 -07:00
|
|
|
mCaches.bindTexCoordsVertexPointer(force, texCoords);
|
2011-12-13 13:11:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
mCaches.unbindIndicesBuffer();
|
|
|
|
}
|
|
|
|
|
2014-01-02 16:46:18 -08:00
|
|
|
void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
|
|
|
|
const GLvoid* texCoords, const GLvoid* colors) {
|
2013-02-13 18:39:43 -08:00
|
|
|
bool force = mCaches.unbindMeshBuffer();
|
|
|
|
GLsizei stride = sizeof(ColorTextureVertex);
|
|
|
|
|
|
|
|
mCaches.bindPositionVertexPointer(force, vertices, stride);
|
|
|
|
if (mCaches.currentProgram->texCoords >= 0) {
|
|
|
|
mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
|
|
|
|
}
|
|
|
|
int slot = mCaches.currentProgram->getAttrib("colors");
|
|
|
|
if (slot >= 0) {
|
|
|
|
glEnableVertexAttribArray(slot);
|
|
|
|
glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
|
|
|
|
}
|
|
|
|
|
|
|
|
mCaches.unbindIndicesBuffer();
|
|
|
|
}
|
|
|
|
|
2014-01-02 16:46:18 -08:00
|
|
|
void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
|
|
|
|
const GLvoid* texCoords, GLuint vbo) {
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
bool force = false;
|
|
|
|
// If vbo is != 0 we want to treat the vertices parameter as an offset inside
|
|
|
|
// a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
|
|
|
|
// use the default VBO found in Caches
|
|
|
|
if (!vertices || vbo) {
|
|
|
|
force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
|
|
|
|
} else {
|
|
|
|
force = mCaches.unbindMeshBuffer();
|
|
|
|
}
|
2014-02-14 13:13:41 -08:00
|
|
|
mCaches.bindQuadIndicesBuffer();
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
|
2012-09-25 12:00:29 -07:00
|
|
|
mCaches.bindPositionVertexPointer(force, vertices);
|
2011-12-13 13:11:32 -08:00
|
|
|
if (mCaches.currentProgram->texCoords >= 0) {
|
2012-09-25 12:00:29 -07:00
|
|
|
mCaches.bindTexCoordsVertexPointer(force, texCoords);
|
2010-12-14 20:13:35 -08:00
|
|
|
}
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
2013-07-22 13:57:50 -07:00
|
|
|
void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
|
2011-12-12 20:35:21 -08:00
|
|
|
bool force = mCaches.unbindMeshBuffer();
|
2014-02-14 13:13:41 -08:00
|
|
|
mCaches.bindQuadIndicesBuffer();
|
2012-09-25 12:00:29 -07:00
|
|
|
mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
|
2011-04-13 17:58:08 -07:00
|
|
|
}
|
|
|
|
|
2010-06-23 17:47:49 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Drawing
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-20 16:01:00 -07:00
|
|
|
status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
|
2013-04-10 07:43:29 -07:00
|
|
|
status_t status;
|
2010-11-08 12:08:41 -08:00
|
|
|
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
|
|
|
|
// will be performed by the display list itself
|
2014-06-20 16:01:00 -07:00
|
|
|
if (renderNode && renderNode->isRenderable()) {
|
2013-10-25 18:30:17 -07:00
|
|
|
// compute 3d ordering
|
2014-06-20 16:01:00 -07:00
|
|
|
renderNode->computeOrdering();
|
2013-03-19 15:03:48 -07:00
|
|
|
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
|
2013-04-10 07:43:29 -07:00
|
|
|
status = startFrame();
|
2013-03-08 13:12:16 -08:00
|
|
|
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
|
2014-06-20 16:01:00 -07:00
|
|
|
renderNode->replay(replayStruct, 0);
|
2013-04-10 07:43:29 -07:00
|
|
|
return status | replayStruct.mDrawGlStatus;
|
2013-02-04 16:16:33 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 11:38:03 -07:00
|
|
|
bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
|
2014-01-01 14:45:21 -08:00
|
|
|
DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
|
2013-03-08 13:12:16 -08:00
|
|
|
DeferStateStruct deferStruct(deferredList, *this, replayFlags);
|
2014-06-20 16:01:00 -07:00
|
|
|
renderNode->defer(deferStruct, 0);
|
2013-03-26 15:05:58 -07:00
|
|
|
|
|
|
|
flushLayers();
|
2013-04-10 07:43:29 -07:00
|
|
|
status = startFrame();
|
2013-03-26 15:05:58 -07:00
|
|
|
|
2013-10-25 18:30:17 -07:00
|
|
|
return deferredList.flush(*this, dirty) | status;
|
2010-11-08 12:08:41 -08:00
|
|
|
}
|
2011-03-14 18:05:08 -07:00
|
|
|
|
2012-03-26 16:45:05 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2010-11-08 12:08:41 -08:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
|
2013-01-04 12:26:18 -08:00
|
|
|
int color = paint != NULL ? paint->getColor() : 0;
|
|
|
|
|
2011-03-18 16:50:13 -07:00
|
|
|
float x = left;
|
|
|
|
float y = top;
|
|
|
|
|
2013-01-04 12:26:18 -08:00
|
|
|
texture->setWrap(GL_CLAMP_TO_EDGE, true);
|
|
|
|
|
2011-03-18 16:50:13 -07:00
|
|
|
bool ignoreTransform = false;
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentTransform()->isPureTranslate()) {
|
|
|
|
x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
|
2011-03-18 16:50:13 -07:00
|
|
|
ignoreTransform = true;
|
|
|
|
|
2013-01-04 12:26:18 -08:00
|
|
|
texture->setFilter(GL_NEAREST, true);
|
|
|
|
} else {
|
2014-02-28 12:26:34 -08:00
|
|
|
texture->setFilter(getFilter(paint), true);
|
2011-03-23 17:15:38 -07:00
|
|
|
}
|
2011-07-25 16:36:01 -07:00
|
|
|
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
// No need to check for a UV mapper on the texture object, only ARGB_8888
|
|
|
|
// bitmaps get packed in the atlas
|
2013-01-04 12:26:18 -08:00
|
|
|
drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
|
2013-12-10 12:28:58 -05:00
|
|
|
paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
|
2011-03-18 16:50:13 -07:00
|
|
|
}
|
|
|
|
|
2013-06-20 18:30:28 -07:00
|
|
|
/**
|
|
|
|
* Important note: this method is intended to draw batches of bitmaps and
|
|
|
|
* will not set the scissor enable or dirty the current layer, if any.
|
|
|
|
* The caller is responsible for properly dirtying the current layer.
|
|
|
|
*/
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
|
|
|
|
int bitmapCount, TextureVertex* vertices, bool pureTranslate,
|
|
|
|
const Rect& bounds, const SkPaint* paint) {
|
2013-03-04 10:19:31 -08:00
|
|
|
mCaches.activeTexture(0);
|
2013-06-27 15:27:09 -07:00
|
|
|
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
|
2013-03-04 10:19:31 -08:00
|
|
|
if (!texture) return DrawGlInfo::kStatusDone;
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
|
2013-03-04 10:19:31 -08:00
|
|
|
const AutoTexture autoCleanup(texture);
|
|
|
|
|
|
|
|
texture->setWrap(GL_CLAMP_TO_EDGE, true);
|
2014-02-28 12:26:34 -08:00
|
|
|
texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true);
|
2013-03-04 10:19:31 -08:00
|
|
|
|
|
|
|
const float x = (int) floorf(bounds.left + 0.5f);
|
|
|
|
const float y = (int) floorf(bounds.top + 0.5f);
|
2014-07-08 12:36:44 -04:00
|
|
|
if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
|
2013-03-04 10:19:31 -08:00
|
|
|
drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
|
2013-12-10 12:28:58 -05:00
|
|
|
texture->id, paint, &vertices[0].x, &vertices[0].u,
|
2013-11-15 16:06:56 -08:00
|
|
|
GL_TRIANGLES, bitmapCount * 6, true,
|
|
|
|
kModelViewMode_Translate, false);
|
2013-03-04 10:19:31 -08:00
|
|
|
} else {
|
|
|
|
drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
|
2013-12-10 12:28:58 -05:00
|
|
|
texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
|
2013-11-15 16:06:56 -08:00
|
|
|
GL_TRIANGLES, bitmapCount * 6, false, true, 0,
|
|
|
|
kModelViewMode_Translate, false);
|
2013-03-04 10:19:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, float left, float top,
|
|
|
|
const SkPaint* paint) {
|
2010-07-12 20:20:03 -07:00
|
|
|
const float right = left + bitmap->width();
|
|
|
|
const float bottom = top + bitmap->height();
|
|
|
|
|
2013-11-19 18:00:46 -08:00
|
|
|
if (quickRejectSetupScissor(left, top, right, bottom)) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2010-07-12 20:20:03 -07:00
|
|
|
}
|
|
|
|
|
2011-12-13 14:55:06 -08:00
|
|
|
mCaches.activeTexture(0);
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
Texture* texture = getTexture(bitmap);
|
2012-05-31 15:21:51 -07:00
|
|
|
if (!texture) return DrawGlInfo::kStatusDone;
|
2010-08-06 11:18:34 -07:00
|
|
|
const AutoTexture autoCleanup(texture);
|
|
|
|
|
2014-07-08 12:36:44 -04:00
|
|
|
if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
|
2011-03-18 16:50:13 -07:00
|
|
|
drawAlphaBitmap(texture, left, top, paint);
|
|
|
|
} else {
|
|
|
|
drawTextureRect(left, top, right, bottom, texture, paint);
|
|
|
|
}
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2010-06-30 19:21:21 -07:00
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* paint) {
|
2010-07-01 11:05:42 -07:00
|
|
|
Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
|
2013-12-10 12:28:58 -05:00
|
|
|
const mat4 transform(matrix);
|
2010-07-01 11:05:42 -07:00
|
|
|
transform.mapRect(r);
|
|
|
|
|
2013-11-19 18:00:46 -08:00
|
|
|
if (quickRejectSetupScissor(r.left, r.top, r.right, r.bottom)) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2010-07-12 20:20:03 -07:00
|
|
|
}
|
|
|
|
|
2011-12-13 14:55:06 -08:00
|
|
|
mCaches.activeTexture(0);
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
Texture* texture = getTexture(bitmap);
|
2012-05-31 15:21:51 -07:00
|
|
|
if (!texture) return DrawGlInfo::kStatusDone;
|
2010-08-06 11:18:34 -07:00
|
|
|
const AutoTexture autoCleanup(texture);
|
|
|
|
|
2010-10-27 18:57:51 -07:00
|
|
|
// This could be done in a cheaper way, all we need is pass the matrix
|
|
|
|
// to the vertex shader. The save/restore is a bit overkill.
|
|
|
|
save(SkCanvas::kMatrix_SaveFlag);
|
|
|
|
concatMatrix(matrix);
|
2014-07-08 12:36:44 -04:00
|
|
|
if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
|
2013-01-04 12:26:18 -08:00
|
|
|
drawAlphaBitmap(texture, 0.0f, 0.0f, paint);
|
|
|
|
} else {
|
|
|
|
drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
|
|
|
|
}
|
2010-10-27 18:57:51 -07:00
|
|
|
restore();
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2010-07-01 11:05:42 -07:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, float left, float top,
|
|
|
|
const SkPaint* paint) {
|
2012-05-14 19:44:40 -07:00
|
|
|
const float right = left + bitmap->width();
|
|
|
|
const float bottom = top + bitmap->height();
|
|
|
|
|
2013-11-19 18:00:46 -08:00
|
|
|
if (quickRejectSetupScissor(left, top, right, bottom)) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2012-05-14 19:44:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mCaches.activeTexture(0);
|
|
|
|
Texture* texture = mCaches.textureCache.getTransient(bitmap);
|
|
|
|
const AutoTexture autoCleanup(texture);
|
|
|
|
|
2014-07-08 12:36:44 -04:00
|
|
|
if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
|
2013-01-04 12:26:18 -08:00
|
|
|
drawAlphaBitmap(texture, left, top, paint);
|
|
|
|
} else {
|
|
|
|
drawTextureRect(left, top, right, bottom, texture, paint);
|
|
|
|
}
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2012-05-14 19:44:40 -07:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
|
|
|
|
const float* vertices, const int* colors, const SkPaint* paint) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (!vertices || currentSnapshot()->isIgnored()) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2011-01-20 19:09:30 -08:00
|
|
|
}
|
|
|
|
|
2013-06-13 14:39:01 -07:00
|
|
|
// TODO: use quickReject on bounds from vertices
|
|
|
|
mCaches.enableScissor();
|
|
|
|
|
2011-02-10 15:52:54 -08:00
|
|
|
float left = FLT_MAX;
|
|
|
|
float top = FLT_MAX;
|
|
|
|
float right = FLT_MIN;
|
|
|
|
float bottom = FLT_MIN;
|
|
|
|
|
2012-10-16 11:08:44 -07:00
|
|
|
const uint32_t count = meshWidth * meshHeight * 6;
|
2011-02-10 15:52:54 -08:00
|
|
|
|
2014-01-02 16:46:18 -08:00
|
|
|
Vector<ColorTextureVertex> mesh; // TODO: use C++11 unique_ptr
|
|
|
|
mesh.setCapacity(count);
|
|
|
|
ColorTextureVertex* vertex = mesh.editArray();
|
2013-02-13 18:39:43 -08:00
|
|
|
|
|
|
|
bool cleanupColors = false;
|
|
|
|
if (!colors) {
|
|
|
|
uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
|
2014-01-02 17:13:34 -08:00
|
|
|
int* newColors = new int[colorsCount];
|
|
|
|
memset(newColors, 0xff, colorsCount * sizeof(int));
|
|
|
|
colors = newColors;
|
2013-02-13 18:39:43 -08:00
|
|
|
cleanupColors = true;
|
|
|
|
}
|
2012-10-16 11:08:44 -07:00
|
|
|
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
mCaches.activeTexture(0);
|
|
|
|
Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
|
|
|
|
const UvMapper& mapper(getMapper(texture));
|
|
|
|
|
2011-01-20 19:09:30 -08:00
|
|
|
for (int32_t y = 0; y < meshHeight; y++) {
|
|
|
|
for (int32_t x = 0; x < meshWidth; x++) {
|
|
|
|
uint32_t i = (y * (meshWidth + 1) + x) * 2;
|
|
|
|
|
|
|
|
float u1 = float(x) / meshWidth;
|
|
|
|
float u2 = float(x + 1) / meshWidth;
|
|
|
|
float v1 = float(y) / meshHeight;
|
|
|
|
float v2 = float(y + 1) / meshHeight;
|
|
|
|
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
mapper.map(u1, v1, u2, v2);
|
|
|
|
|
2011-01-20 19:09:30 -08:00
|
|
|
int ax = i + (meshWidth + 1) * 2;
|
|
|
|
int ay = ax + 1;
|
|
|
|
int bx = i;
|
|
|
|
int by = bx + 1;
|
|
|
|
int cx = i + 2;
|
|
|
|
int cy = cx + 1;
|
|
|
|
int dx = i + (meshWidth + 1) * 2 + 2;
|
|
|
|
int dy = dx + 1;
|
|
|
|
|
2013-02-13 18:39:43 -08:00
|
|
|
ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
|
|
|
|
ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
|
|
|
|
ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
|
2011-01-20 19:09:30 -08:00
|
|
|
|
2013-02-13 18:39:43 -08:00
|
|
|
ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
|
|
|
|
ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
|
|
|
|
ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
|
2011-02-10 15:52:54 -08:00
|
|
|
|
2012-10-16 11:08:44 -07:00
|
|
|
left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
|
|
|
|
top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
|
|
|
|
right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
|
|
|
|
bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
|
2011-01-20 19:09:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-19 18:00:46 -08:00
|
|
|
if (quickRejectSetupScissor(left, top, right, bottom)) {
|
2013-02-13 18:39:43 -08:00
|
|
|
if (cleanupColors) delete[] colors;
|
2012-10-16 11:08:44 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
|
|
|
|
2013-02-13 18:39:43 -08:00
|
|
|
if (!texture) {
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
texture = mCaches.textureCache.get(bitmap);
|
|
|
|
if (!texture) {
|
|
|
|
if (cleanupColors) delete[] colors;
|
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
2013-02-13 18:39:43 -08:00
|
|
|
}
|
2012-10-16 11:08:44 -07:00
|
|
|
const AutoTexture autoCleanup(texture);
|
|
|
|
|
|
|
|
texture->setWrap(GL_CLAMP_TO_EDGE, true);
|
2014-02-28 12:26:34 -08:00
|
|
|
texture->setFilter(getFilter(paint), true);
|
2012-10-16 11:08:44 -07:00
|
|
|
|
|
|
|
int alpha;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &alpha, &mode);
|
|
|
|
|
2013-02-13 18:39:43 -08:00
|
|
|
float a = alpha / 255.0f;
|
|
|
|
|
2012-10-16 11:08:44 -07:00
|
|
|
if (hasLayer()) {
|
2014-01-01 14:45:21 -08:00
|
|
|
dirtyLayer(left, top, right, bottom, *currentTransform());
|
2011-02-10 15:52:54 -08:00
|
|
|
}
|
|
|
|
|
2013-02-13 18:39:43 -08:00
|
|
|
setupDraw();
|
|
|
|
setupDrawWithTextureAndColor();
|
|
|
|
setupDrawColor(a, a, a, a);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
|
|
|
setupDrawBlending(paint, true);
|
2013-02-13 18:39:43 -08:00
|
|
|
setupDrawProgram();
|
|
|
|
setupDrawDirtyRegionsDisabled();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
|
2013-02-13 18:39:43 -08:00
|
|
|
setupDrawTexture(texture->id);
|
|
|
|
setupDrawPureColorUniforms();
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
2013-08-15 16:57:57 -07:00
|
|
|
setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
|
2013-02-13 18:39:43 -08:00
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, count);
|
|
|
|
|
|
|
|
int slot = mCaches.currentProgram->getAttrib("colors");
|
|
|
|
if (slot >= 0) {
|
|
|
|
glDisableVertexAttribArray(slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cleanupColors) delete[] colors;
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2011-01-20 19:09:30 -08:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
|
2010-06-30 19:21:21 -07:00
|
|
|
float srcLeft, float srcTop, float srcRight, float srcBottom,
|
|
|
|
float dstLeft, float dstTop, float dstRight, float dstBottom,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* paint) {
|
2013-11-19 18:00:46 -08:00
|
|
|
if (quickRejectSetupScissor(dstLeft, dstTop, dstRight, dstBottom)) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2010-07-12 20:20:03 -07:00
|
|
|
}
|
|
|
|
|
2011-12-13 14:55:06 -08:00
|
|
|
mCaches.activeTexture(0);
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
Texture* texture = getTexture(bitmap);
|
2012-05-31 15:21:51 -07:00
|
|
|
if (!texture) return DrawGlInfo::kStatusDone;
|
2010-08-06 11:18:34 -07:00
|
|
|
const AutoTexture autoCleanup(texture);
|
2010-06-30 19:21:21 -07:00
|
|
|
|
|
|
|
const float width = texture->width;
|
|
|
|
const float height = texture->height;
|
2010-06-30 17:56:19 -07:00
|
|
|
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
float u1 = fmax(0.0f, srcLeft / width);
|
|
|
|
float v1 = fmax(0.0f, srcTop / height);
|
|
|
|
float u2 = fmin(1.0f, srcRight / width);
|
|
|
|
float v2 = fmin(1.0f, srcBottom / height);
|
|
|
|
|
|
|
|
getMapper(texture).map(u1, v1, u2, v2);
|
2010-06-30 17:56:19 -07:00
|
|
|
|
2010-10-18 14:06:08 -07:00
|
|
|
mCaches.unbindMeshBuffer();
|
2010-06-30 19:21:21 -07:00
|
|
|
resetDrawTextureTexCoords(u1, v1, u2, v2);
|
|
|
|
|
2011-11-30 20:21:23 -08:00
|
|
|
texture->setWrap(GL_CLAMP_TO_EDGE, true);
|
|
|
|
|
2013-01-04 12:26:18 -08:00
|
|
|
float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
|
|
|
|
float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
|
2010-12-06 18:07:02 -08:00
|
|
|
|
2013-01-04 12:26:18 -08:00
|
|
|
bool scaled = scaleX != 1.0f || scaleY != 1.0f;
|
|
|
|
// Apply a scale transform on the canvas only when a shader is in use
|
|
|
|
// Skia handles the ratio between the dst and src rects as a scale factor
|
|
|
|
// when a shader is set
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
bool useScaleTransform = getShader(paint) && scaled;
|
2013-01-04 12:26:18 -08:00
|
|
|
bool ignoreTransform = false;
|
2011-07-28 15:39:12 -07:00
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) {
|
|
|
|
float x = (int) floorf(dstLeft + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
float y = (int) floorf(dstTop + currentTransform()->getTranslateY() + 0.5f);
|
2013-01-04 12:26:18 -08:00
|
|
|
|
|
|
|
dstRight = x + (dstRight - dstLeft);
|
|
|
|
dstBottom = y + (dstBottom - dstTop);
|
|
|
|
|
|
|
|
dstLeft = x;
|
|
|
|
dstTop = y;
|
|
|
|
|
2014-02-28 12:26:34 -08:00
|
|
|
texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true);
|
2013-01-04 12:26:18 -08:00
|
|
|
ignoreTransform = true;
|
2010-12-06 18:07:02 -08:00
|
|
|
} else {
|
2014-02-28 12:26:34 -08:00
|
|
|
texture->setFilter(getFilter(paint), true);
|
2013-01-04 12:26:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CC_UNLIKELY(useScaleTransform)) {
|
|
|
|
save(SkCanvas::kMatrix_SaveFlag);
|
|
|
|
translate(dstLeft, dstTop);
|
|
|
|
scale(scaleX, scaleY);
|
|
|
|
|
|
|
|
dstLeft = 0.0f;
|
|
|
|
dstTop = 0.0f;
|
|
|
|
|
|
|
|
dstRight = srcRight - srcLeft;
|
|
|
|
dstBottom = srcBottom - srcTop;
|
|
|
|
}
|
|
|
|
|
2014-07-08 12:36:44 -04:00
|
|
|
if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
|
2013-01-04 12:26:18 -08:00
|
|
|
drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
|
2013-12-10 12:28:58 -05:00
|
|
|
texture->id, paint,
|
2013-08-15 16:57:57 -07:00
|
|
|
&mMeshVertices[0].x, &mMeshVertices[0].u,
|
2013-01-04 12:26:18 -08:00
|
|
|
GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
|
|
|
|
} else {
|
|
|
|
drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
|
2013-12-10 12:28:58 -05:00
|
|
|
texture->id, paint, texture->blend,
|
2013-08-15 16:57:57 -07:00
|
|
|
&mMeshVertices[0].x, &mMeshVertices[0].u,
|
2013-01-04 12:26:18 -08:00
|
|
|
GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CC_UNLIKELY(useScaleTransform)) {
|
|
|
|
restore();
|
2010-12-06 18:07:02 -08:00
|
|
|
}
|
2010-06-30 19:21:21 -07:00
|
|
|
|
|
|
|
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2010-06-29 21:05:21 -07:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
|
|
|
|
float left, float top, float right, float bottom, const SkPaint* paint) {
|
2013-11-19 18:00:46 -08:00
|
|
|
if (quickRejectSetupScissor(left, top, right, bottom)) {
|
2013-06-11 16:19:24 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
|
|
|
|
|
|
|
AssetAtlas::Entry* entry = mCaches.assetAtlas.getEntry(bitmap);
|
|
|
|
const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
|
|
|
|
right - left, bottom - top, patch);
|
|
|
|
|
2013-06-20 18:30:28 -07:00
|
|
|
return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
|
2012-07-16 12:41:17 -07:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
|
|
|
|
AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
|
|
|
|
const SkPaint* paint) {
|
2013-11-19 18:00:46 -08:00
|
|
|
if (quickRejectSetupScissor(left, top, right, bottom)) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2010-07-12 20:20:03 -07:00
|
|
|
}
|
|
|
|
|
2012-02-01 16:10:55 -08:00
|
|
|
if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
|
2013-02-28 12:15:35 -08:00
|
|
|
mCaches.activeTexture(0);
|
2013-05-24 16:19:19 -07:00
|
|
|
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
|
2013-02-28 12:15:35 -08:00
|
|
|
if (!texture) return DrawGlInfo::kStatusDone;
|
|
|
|
const AutoTexture autoCleanup(texture);
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
|
2013-02-28 12:15:35 -08:00
|
|
|
texture->setWrap(GL_CLAMP_TO_EDGE, true);
|
|
|
|
texture->setFilter(GL_LINEAR, true);
|
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
const bool pureTranslate = currentTransform()->isPureTranslate();
|
2010-10-27 18:57:51 -07:00
|
|
|
// Mark the current layer dirty where we are going to draw the patch
|
2011-01-24 20:40:18 -08:00
|
|
|
if (hasLayer() && mesh->hasEmptyQuads) {
|
2014-01-01 14:45:21 -08:00
|
|
|
const float offsetX = left + currentTransform()->getTranslateX();
|
|
|
|
const float offsetY = top + currentTransform()->getTranslateY();
|
2010-10-27 18:57:51 -07:00
|
|
|
const size_t count = mesh->quads.size();
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
2010-12-07 13:30:10 -08:00
|
|
|
const Rect& bounds = mesh->quads.itemAt(i);
|
2012-02-01 16:10:55 -08:00
|
|
|
if (CC_LIKELY(pureTranslate)) {
|
2011-02-04 14:00:42 -08:00
|
|
|
const float x = (int) floorf(bounds.left + offsetX + 0.5f);
|
|
|
|
const float y = (int) floorf(bounds.top + offsetY + 0.5f);
|
|
|
|
dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
|
2010-12-06 18:07:02 -08:00
|
|
|
} else {
|
2011-02-04 14:00:42 -08:00
|
|
|
dirtyLayer(left + bounds.left, top + bounds.top,
|
2014-01-01 14:45:21 -08:00
|
|
|
left + bounds.right, top + bounds.bottom, *currentTransform());
|
2010-12-06 18:07:02 -08:00
|
|
|
}
|
2010-10-27 18:57:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-15 16:06:56 -08:00
|
|
|
bool ignoreTransform = false;
|
2012-02-01 16:10:55 -08:00
|
|
|
if (CC_LIKELY(pureTranslate)) {
|
2014-01-01 14:45:21 -08:00
|
|
|
const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
|
2010-12-06 18:07:02 -08:00
|
|
|
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
right = x + right - left;
|
|
|
|
bottom = y + bottom - top;
|
2013-11-15 16:06:56 -08:00
|
|
|
left = x;
|
|
|
|
top = y;
|
|
|
|
ignoreTransform = true;
|
2010-12-06 18:07:02 -08:00
|
|
|
}
|
2013-12-10 12:28:58 -05:00
|
|
|
drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
|
|
|
|
texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
|
2013-11-15 16:06:56 -08:00
|
|
|
GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
|
|
|
|
mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
|
2010-10-15 17:55:25 -07:00
|
|
|
}
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2010-07-08 19:17:03 -07:00
|
|
|
}
|
|
|
|
|
2013-06-20 18:30:28 -07:00
|
|
|
/**
|
|
|
|
* Important note: this method is intended to draw batches of 9-patch objects and
|
|
|
|
* will not set the scissor enable or dirty the current layer, if any.
|
|
|
|
* The caller is responsible for properly dirtying the current layer.
|
|
|
|
*/
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
|
|
|
|
TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
|
2013-06-20 18:30:28 -07:00
|
|
|
mCaches.activeTexture(0);
|
|
|
|
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
|
|
|
|
if (!texture) return DrawGlInfo::kStatusDone;
|
|
|
|
const AutoTexture autoCleanup(texture);
|
|
|
|
|
|
|
|
texture->setWrap(GL_CLAMP_TO_EDGE, true);
|
|
|
|
texture->setFilter(GL_LINEAR, true);
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
|
|
|
|
texture->blend, &vertices[0].x, &vertices[0].u,
|
2013-11-15 16:06:56 -08:00
|
|
|
GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
|
2013-06-20 18:30:28 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
|
|
|
}
|
|
|
|
|
2014-06-02 16:27:04 -07:00
|
|
|
status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
|
2014-02-14 13:13:41 -08:00
|
|
|
const VertexBuffer& vertexBuffer, const SkPaint* paint, bool useOffset) {
|
2013-11-15 16:06:56 -08:00
|
|
|
// not missing call to quickReject/dirtyLayer, always done at a higher level
|
2013-05-08 18:35:44 -07:00
|
|
|
if (!vertexBuffer.getVertexCount()) {
|
2012-10-01 13:50:37 -07:00
|
|
|
// no vertices to draw
|
2012-12-10 17:56:27 -08:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2012-10-01 13:50:37 -07:00
|
|
|
}
|
|
|
|
|
2014-07-15 13:01:02 -07:00
|
|
|
Rect bounds(vertexBuffer.getBounds());
|
|
|
|
bounds.translate(translateX, translateY);
|
2014-06-02 16:27:04 -07:00
|
|
|
dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
|
|
|
|
|
2012-12-10 17:56:27 -08:00
|
|
|
int color = paint->getColor();
|
|
|
|
bool isAA = paint->isAntiAlias();
|
|
|
|
|
2012-09-17 17:25:49 -07:00
|
|
|
setupDraw();
|
|
|
|
setupDrawNoTexture();
|
|
|
|
if (isAA) setupDrawAA();
|
|
|
|
setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShader(getShader(paint));
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawBlending(paint, isAA);
|
2012-09-17 17:25:49 -07:00
|
|
|
setupDrawProgram();
|
2014-06-02 16:27:04 -07:00
|
|
|
setupDrawModelView(kModelViewMode_Translate, useOffset, translateX, translateY, 0, 0);
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawColorUniforms(getShader(paint));
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShaderUniforms(getShader(paint));
|
2011-05-12 09:06:00 -07:00
|
|
|
|
2013-12-03 10:38:55 -08:00
|
|
|
const void* vertices = vertexBuffer.getBuffer();
|
2012-09-17 17:25:49 -07:00
|
|
|
bool force = mCaches.unbindMeshBuffer();
|
2012-09-25 12:00:29 -07:00
|
|
|
mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
|
2012-09-17 17:25:49 -07:00
|
|
|
mCaches.resetTexCoordsVertexPointer();
|
2014-02-14 13:13:41 -08:00
|
|
|
|
2012-08-31 18:24:33 -07:00
|
|
|
|
2012-09-17 17:25:49 -07:00
|
|
|
int alphaSlot = -1;
|
|
|
|
if (isAA) {
|
|
|
|
void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
|
|
|
|
alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
|
|
|
|
// TODO: avoid enable/disable in back to back uses of the alpha attribute
|
2012-08-31 18:24:33 -07:00
|
|
|
glEnableVertexAttribArray(alphaSlot);
|
|
|
|
glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
|
2012-09-17 17:25:49 -07:00
|
|
|
}
|
2012-08-31 18:24:33 -07:00
|
|
|
|
2014-06-02 16:27:04 -07:00
|
|
|
const VertexBuffer::Mode mode = vertexBuffer.getMode();
|
|
|
|
if (mode == VertexBuffer::kStandard) {
|
2014-02-14 13:13:41 -08:00
|
|
|
mCaches.unbindIndicesBuffer();
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
|
2014-06-02 16:27:04 -07:00
|
|
|
} else if (mode == VertexBuffer::kOnePolyRingShadow) {
|
2014-03-11 16:52:30 -07:00
|
|
|
mCaches.bindShadowIndicesBuffer();
|
|
|
|
glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
|
2014-06-02 16:27:04 -07:00
|
|
|
} else if (mode == VertexBuffer::kTwoPolyRingShadow) {
|
2014-02-14 13:13:41 -08:00
|
|
|
mCaches.bindShadowIndicesBuffer();
|
2014-03-11 16:52:30 -07:00
|
|
|
glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
|
2014-02-14 13:13:41 -08:00
|
|
|
}
|
2012-04-04 11:38:54 -07:00
|
|
|
|
2012-09-17 17:25:49 -07:00
|
|
|
if (isAA) {
|
2012-08-31 18:24:33 -07:00
|
|
|
glDisableVertexAttribArray(alphaSlot);
|
2012-07-18 17:15:41 -07:00
|
|
|
}
|
2012-12-10 17:56:27 -08:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2011-05-12 09:06:00 -07:00
|
|
|
}
|
|
|
|
|
2011-05-06 12:06:34 -07:00
|
|
|
/**
|
2012-12-10 17:56:27 -08:00
|
|
|
* Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
|
|
|
|
* that of AA lines in the drawLines() function. We expand the convex path by a half pixel in
|
|
|
|
* screen space in all directions. However, instead of using a fragment shader to compute the
|
|
|
|
* translucency of the color from its position, we simply use a varying parameter to define how far
|
|
|
|
* a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
|
|
|
|
*
|
|
|
|
* Doesn't yet support joins, caps, or path effects.
|
2011-05-06 12:06:34 -07:00
|
|
|
*/
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
|
2012-12-10 17:56:27 -08:00
|
|
|
VertexBuffer vertexBuffer;
|
|
|
|
// TODO: try clipping large paths to viewport
|
2014-01-01 14:45:21 -08:00
|
|
|
PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
|
2014-06-02 16:27:04 -07:00
|
|
|
return drawVertexBuffer(vertexBuffer, paint);
|
2012-12-10 17:56:27 -08:00
|
|
|
}
|
2012-04-04 11:38:54 -07:00
|
|
|
|
2012-12-10 17:56:27 -08:00
|
|
|
/**
|
|
|
|
* We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
|
|
|
|
* and additional geometry for defining an alpha slope perimeter.
|
|
|
|
*
|
|
|
|
* Using GL_LINES can be difficult because the rasterization rules for those lines produces some
|
|
|
|
* unexpected results, and may vary between hardware devices. Previously we used a varying-base
|
|
|
|
* in-shader alpha region, but found it to be taxing on some GPUs.
|
|
|
|
*
|
|
|
|
* TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
|
|
|
|
* memory transfer by removing need for degenerate vertices.
|
|
|
|
*/
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored() || count < 4) return DrawGlInfo::kStatusDone;
|
2012-04-04 11:38:54 -07:00
|
|
|
|
2012-12-10 17:56:27 -08:00
|
|
|
count &= ~0x3; // round down to nearest four
|
2012-04-04 11:38:54 -07:00
|
|
|
|
2012-12-10 17:56:27 -08:00
|
|
|
VertexBuffer buffer;
|
2014-06-02 16:27:04 -07:00
|
|
|
PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
|
|
|
|
const Rect& bounds = buffer.getBounds();
|
2013-02-08 13:46:40 -08:00
|
|
|
|
2014-06-02 16:27:04 -07:00
|
|
|
if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
|
2013-02-08 13:46:40 -08:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
|
|
|
|
2012-12-10 17:56:27 -08:00
|
|
|
bool useOffset = !paint->isAntiAlias();
|
2014-06-02 16:27:04 -07:00
|
|
|
return drawVertexBuffer(buffer, paint, useOffset);
|
2011-04-13 17:58:08 -07:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored() || count < 2) return DrawGlInfo::kStatusDone;
|
2011-03-21 13:11:28 -07:00
|
|
|
|
2013-05-08 18:35:44 -07:00
|
|
|
count &= ~0x1; // round down to nearest two
|
2012-04-04 11:38:54 -07:00
|
|
|
|
2013-05-08 18:35:44 -07:00
|
|
|
VertexBuffer buffer;
|
2014-06-02 16:27:04 -07:00
|
|
|
PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
|
2012-04-04 11:38:54 -07:00
|
|
|
|
2014-06-02 16:27:04 -07:00
|
|
|
const Rect& bounds = buffer.getBounds();
|
|
|
|
if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
|
2013-05-08 18:35:44 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2011-03-21 13:11:28 -07:00
|
|
|
}
|
|
|
|
|
2013-05-08 18:35:44 -07:00
|
|
|
bool useOffset = !paint->isAntiAlias();
|
2014-06-02 16:27:04 -07:00
|
|
|
return drawVertexBuffer(buffer, paint, useOffset);
|
2011-03-21 13:11:28 -07:00
|
|
|
}
|
|
|
|
|
2012-05-31 15:21:51 -07:00
|
|
|
status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
|
2010-11-03 19:58:32 -07:00
|
|
|
// No need to check against the clip, we fill the clip region
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
|
2010-11-03 19:58:32 -07:00
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
Rect clip(*currentClipRect());
|
2010-10-22 17:49:18 -07:00
|
|
|
clip.snapToPixelBoundaries();
|
2010-12-13 18:24:33 -08:00
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(color);
|
|
|
|
paint.setXfermodeMode(mode);
|
|
|
|
|
|
|
|
drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2010-06-25 13:41:57 -07:00
|
|
|
}
|
2010-06-24 19:30:36 -07:00
|
|
|
|
2012-05-31 15:21:51 -07:00
|
|
|
status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* paint) {
|
2012-05-31 15:21:51 -07:00
|
|
|
if (!texture) return DrawGlInfo::kStatusDone;
|
2011-01-19 21:54:02 -08:00
|
|
|
const AutoTexture autoCleanup(texture);
|
|
|
|
|
|
|
|
const float x = left + texture->left - texture->offset;
|
|
|
|
const float y = top + texture->top - texture->offset;
|
|
|
|
|
|
|
|
drawPathTexture(texture, x, y, paint);
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2011-01-19 21:54:02 -08:00
|
|
|
}
|
|
|
|
|
2012-05-31 15:21:51 -07:00
|
|
|
status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
|
2014-01-02 17:13:34 -08:00
|
|
|
float rx, float ry, const SkPaint* p) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
|
2013-03-20 16:31:12 -07:00
|
|
|
(p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
|
2012-09-17 17:25:49 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2012-09-25 12:00:29 -07:00
|
|
|
if (p->getPathEffect() != 0) {
|
2012-09-17 17:25:49 -07:00
|
|
|
mCaches.activeTexture(0);
|
2013-03-15 19:06:39 -07:00
|
|
|
const PathTexture* texture = mCaches.pathCache.getRoundRect(
|
2012-09-17 17:25:49 -07:00
|
|
|
right - left, bottom - top, rx, ry, p);
|
|
|
|
return drawShape(left, top, texture, p);
|
|
|
|
}
|
|
|
|
|
2014-06-17 13:47:05 -07:00
|
|
|
const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
|
|
|
|
*currentTransform(), *p, right - left, bottom - top, rx, ry);
|
2014-06-02 16:27:04 -07:00
|
|
|
return drawVertexBuffer(left, top, *vertexBuffer, p);
|
2011-01-23 14:18:41 -08:00
|
|
|
}
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(x - radius, y - radius,
|
2013-03-20 16:31:12 -07:00
|
|
|
x + radius, y + radius, p) ||
|
|
|
|
(p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
|
2012-09-17 17:25:49 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
2012-09-25 12:00:29 -07:00
|
|
|
if (p->getPathEffect() != 0) {
|
2012-09-17 17:25:49 -07:00
|
|
|
mCaches.activeTexture(0);
|
2013-03-15 19:06:39 -07:00
|
|
|
const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
|
2012-09-17 17:25:49 -07:00
|
|
|
return drawShape(x - radius, y - radius, texture, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
SkPath path;
|
2012-09-25 12:00:29 -07:00
|
|
|
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
|
|
|
|
path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
|
|
|
|
} else {
|
|
|
|
path.addCircle(x, y, radius);
|
|
|
|
}
|
2012-12-10 17:56:27 -08:00
|
|
|
return drawConvexPath(path, p);
|
2011-01-23 14:18:41 -08:00
|
|
|
}
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2012-05-31 15:21:51 -07:00
|
|
|
status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* p) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
|
2013-03-20 16:31:12 -07:00
|
|
|
(p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
|
2012-09-17 17:25:49 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2012-09-25 12:00:29 -07:00
|
|
|
if (p->getPathEffect() != 0) {
|
2012-09-17 17:25:49 -07:00
|
|
|
mCaches.activeTexture(0);
|
2013-03-15 19:06:39 -07:00
|
|
|
const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
|
2012-09-17 17:25:49 -07:00
|
|
|
return drawShape(left, top, texture, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
SkPath path;
|
|
|
|
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
|
2012-09-25 12:00:29 -07:00
|
|
|
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
|
|
|
|
rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
|
|
|
|
}
|
2012-09-17 17:25:49 -07:00
|
|
|
path.addOval(rect);
|
2012-12-10 17:56:27 -08:00
|
|
|
return drawConvexPath(path, p);
|
2011-01-23 14:18:41 -08:00
|
|
|
}
|
|
|
|
|
2012-05-31 15:21:51 -07:00
|
|
|
status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
|
2014-01-02 17:13:34 -08:00
|
|
|
float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
|
2013-03-20 16:31:12 -07:00
|
|
|
(p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
|
2012-10-04 14:10:49 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
2011-01-23 16:15:02 -08:00
|
|
|
|
2012-10-04 14:10:49 -07:00
|
|
|
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
|
2012-12-10 17:56:27 -08:00
|
|
|
if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
|
2012-10-04 14:10:49 -07:00
|
|
|
mCaches.activeTexture(0);
|
2013-03-15 19:06:39 -07:00
|
|
|
const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
|
2012-10-04 14:10:49 -07:00
|
|
|
startAngle, sweepAngle, useCenter, p);
|
|
|
|
return drawShape(left, top, texture, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
|
|
|
|
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
|
|
|
|
rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
SkPath path;
|
|
|
|
if (useCenter) {
|
|
|
|
path.moveTo(rect.centerX(), rect.centerY());
|
|
|
|
}
|
|
|
|
path.arcTo(rect, startAngle, sweepAngle, !useCenter);
|
|
|
|
if (useCenter) {
|
|
|
|
path.close();
|
|
|
|
}
|
2012-12-10 17:56:27 -08:00
|
|
|
return drawConvexPath(path, p);
|
2011-01-23 16:15:02 -08:00
|
|
|
}
|
|
|
|
|
2012-10-02 12:32:25 -07:00
|
|
|
// See SkPaintDefaults.h
|
|
|
|
#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
|
|
|
|
const SkPaint* p) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored() || quickRejectSetupScissor(left, top, right, bottom, p) ||
|
2013-03-20 16:31:12 -07:00
|
|
|
(p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2010-07-12 20:20:03 -07:00
|
|
|
}
|
|
|
|
|
2012-09-17 17:25:49 -07:00
|
|
|
if (p->getStyle() != SkPaint::kFill_Style) {
|
2012-10-02 12:32:25 -07:00
|
|
|
// only fill style is supported by drawConvexPath, since others have to handle joins
|
|
|
|
if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
|
|
|
|
p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
|
|
|
|
mCaches.activeTexture(0);
|
|
|
|
const PathTexture* texture =
|
2013-03-15 19:06:39 -07:00
|
|
|
mCaches.pathCache.getRect(right - left, bottom - top, p);
|
2012-10-02 12:32:25 -07:00
|
|
|
return drawShape(left, top, texture, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
SkPath path;
|
|
|
|
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
|
|
|
|
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
|
|
|
|
rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
|
|
|
|
}
|
|
|
|
path.addRect(rect);
|
2012-12-10 17:56:27 -08:00
|
|
|
return drawConvexPath(path, p);
|
2010-06-28 17:12:22 -07:00
|
|
|
}
|
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
if (p->isAntiAlias() && !currentTransform()->isSimple()) {
|
2012-09-17 17:25:49 -07:00
|
|
|
SkPath path;
|
|
|
|
path.addRect(left, top, right, bottom);
|
2012-12-10 17:56:27 -08:00
|
|
|
return drawConvexPath(path, p);
|
2011-05-12 09:06:00 -07:00
|
|
|
} else {
|
2013-12-10 12:28:58 -05:00
|
|
|
drawColorRect(left, top, right, bottom, p);
|
2012-12-10 17:56:27 -08:00
|
|
|
return DrawGlInfo::kStatusDrew;
|
2011-05-12 09:06:00 -07:00
|
|
|
}
|
2010-06-25 13:41:57 -07:00
|
|
|
}
|
2010-06-24 19:30:36 -07:00
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
|
|
|
|
int bytesCount, int count, const float* positions,
|
2013-12-10 12:28:58 -05:00
|
|
|
FontRenderer& fontRenderer, int alpha, float x, float y) {
|
2012-07-19 22:48:17 -07:00
|
|
|
mCaches.activeTexture(0);
|
|
|
|
|
2014-03-31 13:52:39 -04:00
|
|
|
TextShadow textShadow;
|
|
|
|
if (!getTextShadow(paint, &textShadow)) {
|
|
|
|
LOG_ALWAYS_FATAL("failed to query shadow attributes");
|
|
|
|
}
|
|
|
|
|
2012-07-19 22:48:17 -07:00
|
|
|
// NOTE: The drop shadow will not perform gamma correction
|
|
|
|
// if shader-based correction is enabled
|
|
|
|
mCaches.dropShadowCache.setFontRenderer(fontRenderer);
|
|
|
|
const ShadowTexture* shadow = mCaches.dropShadowCache.get(
|
2014-03-31 13:52:39 -04:00
|
|
|
paint, text, bytesCount, count, textShadow.radius, positions);
|
2013-04-08 19:40:31 -07:00
|
|
|
// If the drop shadow exceeds the max texture size or couldn't be
|
|
|
|
// allocated, skip drawing
|
|
|
|
if (!shadow) return;
|
2012-07-19 22:48:17 -07:00
|
|
|
const AutoTexture autoCleanup(shadow);
|
|
|
|
|
2014-03-31 13:52:39 -04:00
|
|
|
const float sx = x - shadow->left + textShadow.dx;
|
|
|
|
const float sy = y - shadow->top + textShadow.dy;
|
2012-07-19 22:48:17 -07:00
|
|
|
|
2014-03-31 13:52:39 -04:00
|
|
|
const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
if (getShader(paint)) {
|
2014-03-31 13:52:39 -04:00
|
|
|
textShadow.color = SK_ColorWHITE;
|
2012-07-19 22:48:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
setupDraw();
|
|
|
|
setupDrawWithTexture(true);
|
2014-03-31 13:52:39 -04:00
|
|
|
setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShader(getShader(paint));
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawBlending(paint, true);
|
2012-07-19 22:48:17 -07:00
|
|
|
setupDrawProgram();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
|
|
|
|
sx, sy, sx + shadow->width, sy + shadow->height);
|
2012-07-19 22:48:17 -07:00
|
|
|
setupDrawTexture(shadow->id);
|
|
|
|
setupDrawPureColorUniforms();
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShaderUniforms(getShader(paint));
|
2012-07-19 22:48:17 -07:00
|
|
|
setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
|
|
|
|
}
|
|
|
|
|
2013-02-27 13:50:45 -08:00
|
|
|
bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
|
2014-03-31 13:52:39 -04:00
|
|
|
float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
|
2013-02-27 13:50:45 -08:00
|
|
|
return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
|
|
|
|
}
|
|
|
|
|
2012-05-31 15:21:51 -07:00
|
|
|
status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
|
2014-01-02 17:13:34 -08:00
|
|
|
const float* positions, const SkPaint* paint) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2012-01-17 17:39:26 -08:00
|
|
|
}
|
|
|
|
|
2012-01-18 12:39:17 -08:00
|
|
|
// NOTE: Skia does not support perspective transform on drawPosText yet
|
2014-01-01 14:45:21 -08:00
|
|
|
if (!currentTransform()->isSimple()) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2012-01-18 12:39:17 -08:00
|
|
|
}
|
|
|
|
|
2013-06-13 14:39:01 -07:00
|
|
|
mCaches.enableScissor();
|
|
|
|
|
2012-01-18 12:39:17 -08:00
|
|
|
float x = 0.0f;
|
|
|
|
float y = 0.0f;
|
2014-01-01 14:45:21 -08:00
|
|
|
const bool pureTranslate = currentTransform()->isPureTranslate();
|
2012-01-18 12:39:17 -08:00
|
|
|
if (pureTranslate) {
|
2014-01-01 14:45:21 -08:00
|
|
|
x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
|
2012-01-18 12:39:17 -08:00
|
|
|
}
|
|
|
|
|
2012-07-13 18:25:35 -07:00
|
|
|
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
|
2014-07-01 17:56:52 -07:00
|
|
|
fontRenderer.setFont(paint, SkMatrix::I());
|
2012-01-18 12:39:17 -08:00
|
|
|
|
|
|
|
int alpha;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &alpha, &mode);
|
|
|
|
|
2014-03-31 13:52:39 -04:00
|
|
|
if (CC_UNLIKELY(hasTextShadow(paint))) {
|
2013-01-08 11:15:30 -08:00
|
|
|
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
|
2013-12-10 12:28:58 -05:00
|
|
|
alpha, 0.0f, 0.0f);
|
2012-07-19 22:48:17 -07:00
|
|
|
}
|
|
|
|
|
2012-01-18 12:39:17 -08:00
|
|
|
// Pick the appropriate texture filtering
|
2014-01-01 14:45:21 -08:00
|
|
|
bool linearFilter = currentTransform()->changesBounds();
|
2012-01-18 12:39:17 -08:00
|
|
|
if (pureTranslate && !linearFilter) {
|
|
|
|
linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
|
|
|
|
}
|
2013-03-20 16:31:12 -07:00
|
|
|
fontRenderer.setTextureFiltering(linearFilter);
|
2012-01-18 12:39:17 -08:00
|
|
|
|
|
|
|
const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
|
|
|
|
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
|
|
|
|
|
2012-02-01 16:10:55 -08:00
|
|
|
const bool hasActiveLayer = hasLayer();
|
2012-01-18 12:39:17 -08:00
|
|
|
|
2013-06-25 14:25:17 -07:00
|
|
|
TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
|
2012-01-18 12:39:17 -08:00
|
|
|
if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
|
2013-03-20 16:31:12 -07:00
|
|
|
positions, hasActiveLayer ? &bounds : NULL, &functor)) {
|
2012-01-18 12:39:17 -08:00
|
|
|
if (hasActiveLayer) {
|
|
|
|
if (!pureTranslate) {
|
2014-01-01 14:45:21 -08:00
|
|
|
currentTransform()->mapRect(bounds);
|
2012-01-18 12:39:17 -08:00
|
|
|
}
|
|
|
|
dirtyLayerUnchecked(bounds, getRegion());
|
|
|
|
}
|
|
|
|
}
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2012-01-17 17:39:26 -08:00
|
|
|
}
|
|
|
|
|
2014-07-01 17:56:52 -07:00
|
|
|
bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
|
2013-03-05 16:43:31 -08:00
|
|
|
if (CC_LIKELY(transform.isPureTranslate())) {
|
2014-07-01 17:56:52 -07:00
|
|
|
outMatrix->setIdentity();
|
|
|
|
return false;
|
|
|
|
} else if (CC_UNLIKELY(transform.isPerspective())) {
|
|
|
|
outMatrix->setIdentity();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Input is a non-perspective, scaling transform. Generate a scale-only transform, based upon
|
|
|
|
* bucketed scale values. Special case for 'extra raster buckets' - disable filtration in the
|
|
|
|
* case of an exact match, and isSimple() transform
|
|
|
|
*/
|
|
|
|
float sx, sy;
|
|
|
|
transform.decomposeScale(sx, sy);
|
|
|
|
|
|
|
|
float bestSx = roundf(fmaxf(1.0f, sx));
|
|
|
|
float bestSy = roundf(fmaxf(1.0f, sy));
|
|
|
|
bool filter = true;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < mCaches.propertyExtraRasterBuckets.size(); i++) {
|
|
|
|
float bucket = mCaches.propertyExtraRasterBuckets[i];
|
|
|
|
if (sx == bucket && sy == bucket) {
|
|
|
|
bestSx = bestSy = bucket;
|
|
|
|
filter = !transform.isSimple(); // disable filter, if simple
|
|
|
|
break;
|
2013-03-05 16:43:31 -08:00
|
|
|
}
|
2014-07-01 17:56:52 -07:00
|
|
|
|
|
|
|
if (fabs(bucket - sx) < fabs(bestSx - sx)) bestSx = sx;
|
|
|
|
if (fabs(bucket - sy) < fabs(bestSy - sy)) bestSy = sy;
|
2013-03-05 16:43:31 -08:00
|
|
|
}
|
2014-07-01 17:56:52 -07:00
|
|
|
|
|
|
|
outMatrix->setScale(bestSx, bestSy);
|
|
|
|
return filter;
|
2013-03-05 16:43:31 -08:00
|
|
|
}
|
|
|
|
|
2013-05-03 16:35:54 -07:00
|
|
|
status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
|
2014-01-02 17:13:34 -08:00
|
|
|
const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
|
2013-03-04 10:19:31 -08:00
|
|
|
DrawOpMode drawOpMode) {
|
|
|
|
|
|
|
|
if (drawOpMode == kDrawOpMode_Immediate) {
|
2013-05-31 11:38:03 -07:00
|
|
|
// The checks for corner-case ignorable text and quick rejection is only done for immediate
|
|
|
|
// drawing as ops from DeferredDisplayList are already filtered for these
|
2014-01-01 14:45:21 -08:00
|
|
|
if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) ||
|
2013-11-19 18:00:46 -08:00
|
|
|
quickRejectSetupScissor(bounds)) {
|
2013-05-31 11:38:03 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
2011-12-01 20:08:50 -08:00
|
|
|
}
|
|
|
|
|
2010-12-06 18:47:50 -08:00
|
|
|
const float oldX = x;
|
|
|
|
const float oldY = y;
|
2013-03-05 16:43:31 -08:00
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
const mat4& transform = *currentTransform();
|
2013-03-05 16:43:31 -08:00
|
|
|
const bool pureTranslate = transform.isPureTranslate();
|
2013-02-26 19:10:14 -08:00
|
|
|
|
2012-02-01 16:10:55 -08:00
|
|
|
if (CC_LIKELY(pureTranslate)) {
|
2013-03-05 16:43:31 -08:00
|
|
|
x = (int) floorf(x + transform.getTranslateX() + 0.5f);
|
|
|
|
y = (int) floorf(y + transform.getTranslateY() + 0.5f);
|
2010-12-06 18:07:02 -08:00
|
|
|
}
|
|
|
|
|
2010-12-14 15:55:39 -08:00
|
|
|
int alpha;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &alpha, &mode);
|
2010-10-15 16:06:03 -07:00
|
|
|
|
2013-02-26 19:10:14 -08:00
|
|
|
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
|
|
|
|
|
2014-03-31 13:52:39 -04:00
|
|
|
if (CC_UNLIKELY(hasTextShadow(paint))) {
|
2014-07-01 17:56:52 -07:00
|
|
|
fontRenderer.setFont(paint, SkMatrix::I());
|
2013-02-26 19:10:14 -08:00
|
|
|
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
|
2013-12-10 12:28:58 -05:00
|
|
|
alpha, oldX, oldY);
|
2010-08-13 19:39:53 -07:00
|
|
|
}
|
|
|
|
|
2013-03-04 11:14:26 -08:00
|
|
|
const bool hasActiveLayer = hasLayer();
|
|
|
|
|
2013-03-05 16:43:31 -08:00
|
|
|
// We only pass a partial transform to the font renderer. That partial
|
|
|
|
// matrix defines how glyphs are rasterized. Typically we want glyphs
|
|
|
|
// to be rasterized at their final size on screen, which means the partial
|
|
|
|
// matrix needs to take the scale factor into account.
|
|
|
|
// When a partial matrix is used to transform glyphs during rasterization,
|
|
|
|
// the mesh is generated with the inverse transform (in the case of scale,
|
|
|
|
// the mesh is generated at 1.0 / scale for instance.) This allows us to
|
|
|
|
// apply the full transform matrix at draw time in the vertex shader.
|
|
|
|
// Applying the full matrix in the shader is the easiest way to handle
|
|
|
|
// rotation and perspective and allows us to always generated quads in the
|
|
|
|
// font renderer which greatly simplifies the code, clipping in particular.
|
2014-07-01 17:56:52 -07:00
|
|
|
SkMatrix fontTransform;
|
|
|
|
bool linearFilter = findBestFontTransform(transform, &fontTransform)
|
|
|
|
|| fabs(y - (int) y) > 0.0f
|
|
|
|
|| fabs(x - (int) x) > 0.0f;
|
2013-03-05 10:27:35 -08:00
|
|
|
fontRenderer.setFont(paint, fontTransform);
|
2013-03-20 16:31:12 -07:00
|
|
|
fontRenderer.setTextureFiltering(linearFilter);
|
2010-07-30 19:18:16 -07:00
|
|
|
|
2013-03-05 16:43:31 -08:00
|
|
|
// TODO: Implement better clipping for scaled/rotated text
|
2014-01-01 14:45:21 -08:00
|
|
|
const Rect* clip = !pureTranslate ? NULL : currentClipRect();
|
2013-05-03 16:35:54 -07:00
|
|
|
Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
|
2010-10-27 18:57:51 -07:00
|
|
|
|
2012-07-23 15:22:52 -07:00
|
|
|
bool status;
|
2013-06-25 14:25:17 -07:00
|
|
|
TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
|
2013-03-04 10:19:31 -08:00
|
|
|
|
|
|
|
// don't call issuedrawcommand, do it at end of batch
|
|
|
|
bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
|
2012-09-28 13:55:44 -07:00
|
|
|
if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
|
2012-07-30 15:50:00 -07:00
|
|
|
SkPaint paintCopy(*paint);
|
|
|
|
paintCopy.setTextAlign(SkPaint::kLeft_Align);
|
|
|
|
status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
|
2013-05-03 16:35:54 -07:00
|
|
|
positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
|
2012-07-23 15:22:52 -07:00
|
|
|
} else {
|
2012-07-30 15:50:00 -07:00
|
|
|
status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
|
2013-05-03 16:35:54 -07:00
|
|
|
positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
|
2012-07-23 15:22:52 -07:00
|
|
|
}
|
2012-08-06 14:51:10 -07:00
|
|
|
|
2013-03-04 10:19:31 -08:00
|
|
|
if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
|
2013-03-05 16:43:31 -08:00
|
|
|
if (!pureTranslate) {
|
2013-05-03 16:35:54 -07:00
|
|
|
transform.mapRect(layerBounds);
|
2013-02-28 12:15:35 -08:00
|
|
|
}
|
2013-05-03 16:35:54 -07:00
|
|
|
dirtyLayerUnchecked(layerBounds, getRegion());
|
2010-10-27 18:57:51 -07:00
|
|
|
}
|
2010-07-21 21:33:20 -07:00
|
|
|
|
2013-10-17 10:30:55 -07:00
|
|
|
drawTextDecorations(totalAdvance, oldX, oldY, paint);
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2010-07-21 21:33:20 -07:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
|
|
|
|
const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2012-02-24 17:54:07 -08:00
|
|
|
}
|
|
|
|
|
2013-06-13 14:39:01 -07:00
|
|
|
// TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
|
|
|
|
mCaches.enableScissor();
|
|
|
|
|
2012-07-13 18:25:35 -07:00
|
|
|
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
|
2014-07-01 17:56:52 -07:00
|
|
|
fontRenderer.setFont(paint, SkMatrix::I());
|
2013-03-20 16:31:12 -07:00
|
|
|
fontRenderer.setTextureFiltering(true);
|
2012-02-24 17:54:07 -08:00
|
|
|
|
|
|
|
int alpha;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &alpha, &mode);
|
2013-06-25 14:25:17 -07:00
|
|
|
TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
|
2012-02-28 18:17:02 -08:00
|
|
|
|
|
|
|
const Rect* clip = &mSnapshot->getLocalClip();
|
|
|
|
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
|
2012-02-24 17:54:07 -08:00
|
|
|
|
2012-02-28 18:17:02 -08:00
|
|
|
const bool hasActiveLayer = hasLayer();
|
|
|
|
|
|
|
|
if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
|
2013-06-25 14:25:17 -07:00
|
|
|
hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
|
2012-02-28 18:17:02 -08:00
|
|
|
if (hasActiveLayer) {
|
2014-01-01 14:45:21 -08:00
|
|
|
currentTransform()->mapRect(bounds);
|
2012-02-28 18:17:02 -08:00
|
|
|
dirtyLayerUnchecked(bounds, getRegion());
|
|
|
|
}
|
|
|
|
}
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2012-02-24 16:48:34 -08:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
|
2010-10-11 17:58:29 -07:00
|
|
|
|
2011-12-13 14:55:06 -08:00
|
|
|
mCaches.activeTexture(0);
|
2010-08-04 15:40:07 -07:00
|
|
|
|
2010-08-23 21:05:08 -07:00
|
|
|
const PathTexture* texture = mCaches.pathCache.get(path, paint);
|
2012-05-31 15:21:51 -07:00
|
|
|
if (!texture) return DrawGlInfo::kStatusDone;
|
2010-08-06 11:18:34 -07:00
|
|
|
const AutoTexture autoCleanup(texture);
|
2010-08-04 15:40:07 -07:00
|
|
|
|
2010-08-18 17:10:07 -07:00
|
|
|
const float x = texture->left - texture->offset;
|
|
|
|
const float y = texture->top - texture->offset;
|
|
|
|
|
2011-01-19 21:54:02 -08:00
|
|
|
drawPathTexture(texture, x, y, paint);
|
2012-05-31 15:21:51 -07:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2010-08-04 15:40:07 -07:00
|
|
|
}
|
|
|
|
|
2013-03-15 17:24:33 -07:00
|
|
|
status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
|
2012-09-18 15:40:58 -07:00
|
|
|
if (!layer) {
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
2011-01-11 14:29:25 -08:00
|
|
|
}
|
|
|
|
|
2012-10-17 18:18:35 -07:00
|
|
|
mat4* transform = NULL;
|
|
|
|
if (layer->isTextureLayer()) {
|
|
|
|
transform = &layer->getTransform();
|
|
|
|
if (!transform->isIdentity()) {
|
2014-04-15 16:18:08 -07:00
|
|
|
save(SkCanvas::kMatrix_SaveFlag);
|
2013-12-30 15:32:54 -08:00
|
|
|
concatMatrix(*transform);
|
2012-10-17 18:18:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-13 14:39:01 -07:00
|
|
|
bool clipRequired = false;
|
2013-11-19 18:00:46 -08:00
|
|
|
const bool rejected = calculateQuickRejectForScissor(x, y,
|
2014-05-05 19:09:33 -07:00
|
|
|
x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
|
2012-08-06 14:51:10 -07:00
|
|
|
|
2012-09-18 15:40:58 -07:00
|
|
|
if (rejected) {
|
2012-10-17 18:18:35 -07:00
|
|
|
if (transform && !transform->isIdentity()) {
|
|
|
|
restore();
|
|
|
|
}
|
2012-09-18 15:40:58 -07:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
|
|
|
|
2012-11-29 17:52:58 -08:00
|
|
|
updateLayer(layer, true);
|
2012-03-02 13:37:47 -08:00
|
|
|
|
2013-06-13 14:39:01 -07:00
|
|
|
mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
|
2011-12-13 14:55:06 -08:00
|
|
|
mCaches.activeTexture(0);
|
2011-01-11 14:29:25 -08:00
|
|
|
|
2012-02-01 16:10:55 -08:00
|
|
|
if (CC_LIKELY(!layer->region.isEmpty())) {
|
2011-01-22 00:32:12 -08:00
|
|
|
if (layer->region.isRect()) {
|
2013-04-15 16:08:28 -07:00
|
|
|
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
|
|
|
|
composeLayerRect(layer, layer->regionRect));
|
2011-01-22 00:32:12 -08:00
|
|
|
} else if (layer->mesh) {
|
2013-12-10 12:28:58 -05:00
|
|
|
|
2013-03-29 10:59:59 -07:00
|
|
|
const float a = getLayerAlpha(layer);
|
2011-01-22 00:32:12 -08:00
|
|
|
setupDraw();
|
|
|
|
setupDrawWithTexture();
|
2011-01-24 20:40:18 -08:00
|
|
|
setupDrawColor(a, a, a, a);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(layer->getColorFilter());
|
|
|
|
setupDrawBlending(layer);
|
2011-01-22 00:32:12 -08:00
|
|
|
setupDrawProgram();
|
|
|
|
setupDrawPureColorUniforms();
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(layer->getColorFilter());
|
2011-07-07 20:50:11 -07:00
|
|
|
setupDrawTexture(layer->getTexture());
|
2014-01-01 14:45:21 -08:00
|
|
|
if (CC_LIKELY(currentTransform()->isPureTranslate())) {
|
|
|
|
int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
|
2011-07-07 20:50:11 -07:00
|
|
|
|
2011-11-30 20:21:23 -08:00
|
|
|
layer->setFilter(GL_NEAREST);
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
|
2012-08-06 14:51:10 -07:00
|
|
|
tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
|
2011-07-07 20:50:11 -07:00
|
|
|
} else {
|
2011-11-30 20:21:23 -08:00
|
|
|
layer->setFilter(GL_LINEAR);
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_Translate, false, x, y,
|
2011-07-07 20:50:11 -07:00
|
|
|
x + layer->layer.getWidth(), y + layer->layer.getHeight());
|
|
|
|
}
|
2011-01-22 00:32:12 -08:00
|
|
|
|
2013-07-22 13:57:50 -07:00
|
|
|
TextureVertex* mesh = &layer->mesh[0];
|
|
|
|
GLsizei elementsCount = layer->meshElementCount;
|
|
|
|
|
|
|
|
while (elementsCount > 0) {
|
|
|
|
GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
|
|
|
|
|
2013-08-15 16:57:57 -07:00
|
|
|
setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
|
2013-07-22 13:57:50 -07:00
|
|
|
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
|
|
|
|
glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
|
|
|
|
|
|
|
|
elementsCount -= drawCount;
|
|
|
|
// Though there are 4 vertices in a quad, we use 6 indices per
|
|
|
|
// quad to draw with GL_TRIANGLES
|
|
|
|
mesh += (drawCount / 6) * 4;
|
|
|
|
}
|
2011-01-22 00:32:12 -08:00
|
|
|
|
2011-02-01 22:59:58 -08:00
|
|
|
#if DEBUG_LAYERS_AS_REGIONS
|
2013-10-17 10:30:55 -07:00
|
|
|
drawRegionRectsDebug(layer->region);
|
2011-02-01 22:59:58 -08:00
|
|
|
#endif
|
2011-01-22 00:32:12 -08:00
|
|
|
}
|
2012-08-06 14:51:10 -07:00
|
|
|
|
2012-11-29 17:52:58 -08:00
|
|
|
if (layer->debugDrawUpdate) {
|
|
|
|
layer->debugDrawUpdate = false;
|
2013-12-10 12:28:58 -05:00
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(0x7f00ff00);
|
|
|
|
drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
|
2012-08-06 14:51:10 -07:00
|
|
|
}
|
2011-01-16 12:54:25 -08:00
|
|
|
}
|
2013-04-15 16:08:28 -07:00
|
|
|
layer->hasDrawnSinceUpdate = true;
|
2012-05-31 15:21:51 -07:00
|
|
|
|
2012-10-17 18:18:35 -07:00
|
|
|
if (transform && !transform->isIdentity()) {
|
|
|
|
restore();
|
|
|
|
}
|
|
|
|
|
2012-05-31 15:21:51 -07:00
|
|
|
return DrawGlInfo::kStatusDrew;
|
2011-01-11 14:29:25 -08:00
|
|
|
}
|
|
|
|
|
2012-01-23 17:09:05 -08:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Draw filters
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void OpenGLRenderer::resetPaintFilter() {
|
2013-03-04 10:19:31 -08:00
|
|
|
// when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
|
|
|
|
// comparison, see MergingDrawBatch::canMergeWith
|
2013-02-04 16:16:33 -08:00
|
|
|
mDrawModifiers.mHasDrawFilter = false;
|
2013-03-04 10:19:31 -08:00
|
|
|
mDrawModifiers.mPaintFilterClearBits = 0;
|
|
|
|
mDrawModifiers.mPaintFilterSetBits = 0;
|
2012-01-23 17:09:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
|
2013-02-04 16:16:33 -08:00
|
|
|
mDrawModifiers.mHasDrawFilter = true;
|
|
|
|
mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
|
|
|
|
mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
|
2012-01-23 17:09:05 -08:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* OpenGLRenderer::filterPaint(const SkPaint* paint) {
|
2013-02-27 11:53:12 -08:00
|
|
|
if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
|
|
|
|
return paint;
|
|
|
|
}
|
2012-01-23 17:09:05 -08:00
|
|
|
|
|
|
|
uint32_t flags = paint->getFlags();
|
|
|
|
|
|
|
|
mFilteredPaint = *paint;
|
2013-02-04 16:16:33 -08:00
|
|
|
mFilteredPaint.setFlags((flags & ~mDrawModifiers.mPaintFilterClearBits) |
|
|
|
|
mDrawModifiers.mPaintFilterSetBits);
|
2012-01-23 17:09:05 -08:00
|
|
|
|
|
|
|
return &mFilteredPaint;
|
|
|
|
}
|
|
|
|
|
2010-07-12 20:20:03 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Drawing implementation
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
|
|
|
|
if (!texture) {
|
|
|
|
return mCaches.textureCache.get(bitmap);
|
|
|
|
}
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
2011-01-19 21:54:02 -08:00
|
|
|
void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
|
2014-01-02 17:13:34 -08:00
|
|
|
float x, float y, const SkPaint* paint) {
|
2013-11-19 18:00:46 -08:00
|
|
|
if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
|
2011-01-19 21:54:02 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int alpha;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &alpha, &mode);
|
|
|
|
|
|
|
|
setupDraw();
|
|
|
|
setupDrawWithTexture(true);
|
|
|
|
setupDrawAlpha8Color(paint->getColor(), alpha);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShader(getShader(paint));
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawBlending(paint, true);
|
2011-01-19 21:54:02 -08:00
|
|
|
setupDrawProgram();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
|
|
|
|
x, y, x + texture->width, y + texture->height);
|
2011-01-19 21:54:02 -08:00
|
|
|
setupDrawTexture(texture->id);
|
|
|
|
setupDrawPureColorUniforms();
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShaderUniforms(getShader(paint));
|
2011-01-19 21:54:02 -08:00
|
|
|
setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
|
|
|
|
}
|
|
|
|
|
2010-09-10 19:20:06 -07:00
|
|
|
// Same values used by Skia
|
2010-08-16 20:26:20 -07:00
|
|
|
#define kStdStrikeThru_Offset (-6.0f / 21.0f)
|
|
|
|
#define kStdUnderline_Offset (1.0f / 9.0f)
|
|
|
|
#define kStdUnderline_Thickness (1.0f / 18.0f)
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
|
|
|
|
const SkPaint* paint) {
|
2010-08-16 20:26:20 -07:00
|
|
|
// Handle underline and strike-through
|
|
|
|
uint32_t flags = paint->getFlags();
|
|
|
|
if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
|
2011-06-01 14:52:00 -07:00
|
|
|
SkPaint paintCopy(*paint);
|
2010-08-16 20:26:20 -07:00
|
|
|
|
2012-02-01 16:10:55 -08:00
|
|
|
if (CC_LIKELY(underlineWidth > 0.0f)) {
|
2011-06-01 14:52:00 -07:00
|
|
|
const float textSize = paintCopy.getTextSize();
|
2011-01-23 13:32:12 -08:00
|
|
|
const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
|
2010-08-16 20:26:20 -07:00
|
|
|
|
2012-07-30 15:50:00 -07:00
|
|
|
const float left = x;
|
2010-08-16 20:26:20 -07:00
|
|
|
float top = 0.0f;
|
2010-09-22 19:49:04 -07:00
|
|
|
|
2011-01-23 13:32:12 -08:00
|
|
|
int linesCount = 0;
|
|
|
|
if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
|
|
|
|
if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
|
|
|
|
|
|
|
|
const int pointsCount = 4 * linesCount;
|
2010-09-22 19:49:04 -07:00
|
|
|
float points[pointsCount];
|
|
|
|
int currentPoint = 0;
|
2010-08-16 20:26:20 -07:00
|
|
|
|
|
|
|
if (flags & SkPaint::kUnderlineText_Flag) {
|
|
|
|
top = y + textSize * kStdUnderline_Offset;
|
2010-09-22 19:49:04 -07:00
|
|
|
points[currentPoint++] = left;
|
|
|
|
points[currentPoint++] = top;
|
|
|
|
points[currentPoint++] = left + underlineWidth;
|
|
|
|
points[currentPoint++] = top;
|
2010-08-16 20:26:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & SkPaint::kStrikeThruText_Flag) {
|
|
|
|
top = y + textSize * kStdStrikeThru_Offset;
|
2010-09-22 19:49:04 -07:00
|
|
|
points[currentPoint++] = left;
|
|
|
|
points[currentPoint++] = top;
|
|
|
|
points[currentPoint++] = left + underlineWidth;
|
|
|
|
points[currentPoint++] = top;
|
2010-08-16 20:26:20 -07:00
|
|
|
}
|
2010-09-22 19:49:04 -07:00
|
|
|
|
2011-06-01 14:52:00 -07:00
|
|
|
paintCopy.setStrokeWidth(strokeWidth);
|
2010-09-22 19:49:04 -07:00
|
|
|
|
2011-06-01 14:52:00 -07:00
|
|
|
drawLines(&points[0], pointsCount, &paintCopy);
|
2010-08-16 20:26:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored()) {
|
2013-01-04 19:05:13 -08:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
return drawColorRects(rects, count, paint, false, true, true);
|
2012-12-03 12:34:51 -08:00
|
|
|
}
|
|
|
|
|
2014-03-11 12:20:17 -07:00
|
|
|
static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& transformZ) {
|
|
|
|
// map z coordinate with true 3d matrix
|
|
|
|
point.z = transformZ.mapZ(point);
|
|
|
|
|
|
|
|
// map x,y coordinates with draw/Skia matrix
|
|
|
|
transformXY.mapPoint(point.x, point.y);
|
|
|
|
}
|
|
|
|
|
2014-06-02 16:27:04 -07:00
|
|
|
status_t OpenGLRenderer::drawShadow(float casterAlpha,
|
|
|
|
const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
|
2014-01-01 14:45:21 -08:00
|
|
|
if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
|
2013-10-25 18:30:17 -07:00
|
|
|
|
2014-01-26 13:43:53 -08:00
|
|
|
// TODO: use quickRejectWithScissor. For now, always force enable scissor.
|
2013-10-25 18:30:17 -07:00
|
|
|
mCaches.enableScissor();
|
|
|
|
|
|
|
|
SkPaint paint;
|
2013-12-15 17:10:19 -08:00
|
|
|
paint.setAntiAlias(true); // want to use AlphaVertex
|
2013-10-25 18:30:17 -07:00
|
|
|
|
2014-06-02 16:27:04 -07:00
|
|
|
if (ambientShadowVertexBuffer && mCaches.propertyAmbientShadowStrength > 0) {
|
2014-02-21 17:13:45 -08:00
|
|
|
paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
|
2014-06-02 16:27:04 -07:00
|
|
|
drawVertexBuffer(*ambientShadowVertexBuffer, &paint);
|
2014-02-13 17:09:45 -08:00
|
|
|
}
|
|
|
|
|
2014-06-02 16:27:04 -07:00
|
|
|
if (spotShadowVertexBuffer && mCaches.propertySpotShadowStrength > 0) {
|
2014-02-21 17:13:45 -08:00
|
|
|
paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0);
|
2014-06-02 16:27:04 -07:00
|
|
|
drawVertexBuffer(*spotShadowVertexBuffer, &paint);
|
2014-02-13 17:09:45 -08:00
|
|
|
}
|
2014-01-07 10:42:55 -08:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
2013-10-25 18:30:17 -07:00
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
|
|
|
|
bool ignoreTransform, bool dirty, bool clip) {
|
2013-03-05 10:27:35 -08:00
|
|
|
if (count == 0) {
|
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
2012-12-03 12:34:51 -08:00
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
int color = paint->getColor();
|
|
|
|
// If a shader is set, preserve only the alpha
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
if (getShader(paint)) {
|
2013-12-10 12:28:58 -05:00
|
|
|
color |= 0x00ffffff;
|
|
|
|
}
|
|
|
|
|
2013-01-04 19:05:13 -08:00
|
|
|
float left = FLT_MAX;
|
|
|
|
float top = FLT_MAX;
|
|
|
|
float right = FLT_MIN;
|
|
|
|
float bottom = FLT_MIN;
|
|
|
|
|
2013-07-22 13:57:50 -07:00
|
|
|
Vertex mesh[count];
|
2013-01-04 19:05:13 -08:00
|
|
|
Vertex* vertex = mesh;
|
|
|
|
|
2012-11-26 18:30:17 -08:00
|
|
|
for (int index = 0; index < count; index += 4) {
|
2013-01-04 19:05:13 -08:00
|
|
|
float l = rects[index + 0];
|
|
|
|
float t = rects[index + 1];
|
|
|
|
float r = rects[index + 2];
|
|
|
|
float b = rects[index + 3];
|
|
|
|
|
2013-03-05 10:27:35 -08:00
|
|
|
Vertex::set(vertex++, l, t);
|
|
|
|
Vertex::set(vertex++, r, t);
|
|
|
|
Vertex::set(vertex++, l, b);
|
|
|
|
Vertex::set(vertex++, r, b);
|
2013-01-04 19:05:13 -08:00
|
|
|
|
2013-03-05 10:27:35 -08:00
|
|
|
left = fminf(left, l);
|
|
|
|
top = fminf(top, t);
|
|
|
|
right = fmaxf(right, r);
|
|
|
|
bottom = fmaxf(bottom, b);
|
2013-01-04 19:05:13 -08:00
|
|
|
}
|
|
|
|
|
2013-11-19 18:00:46 -08:00
|
|
|
if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
|
2013-02-04 13:50:16 -08:00
|
|
|
return DrawGlInfo::kStatusDone;
|
|
|
|
}
|
2013-01-04 19:05:13 -08:00
|
|
|
|
|
|
|
setupDraw();
|
|
|
|
setupDrawNoTexture();
|
2014-01-01 14:45:21 -08:00
|
|
|
setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShader(getShader(paint));
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
|
|
|
setupDrawBlending(paint);
|
2013-01-04 19:05:13 -08:00
|
|
|
setupDrawProgram();
|
|
|
|
setupDrawDirtyRegionsDisabled();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_Translate, false,
|
|
|
|
0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawColorUniforms(getShader(paint));
|
|
|
|
setupDrawShaderUniforms(getShader(paint));
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
2013-01-04 19:05:13 -08:00
|
|
|
|
2013-01-15 18:51:42 -08:00
|
|
|
if (dirty && hasLayer()) {
|
2014-01-01 14:45:21 -08:00
|
|
|
dirtyLayer(left, top, right, bottom, *currentTransform());
|
2013-01-04 19:05:13 -08:00
|
|
|
}
|
|
|
|
|
2013-11-15 16:06:56 -08:00
|
|
|
issueIndexedQuadDraw(&mesh[0], count / 4);
|
2013-01-04 19:05:13 -08:00
|
|
|
|
|
|
|
return DrawGlInfo::kStatusDrew;
|
|
|
|
}
|
|
|
|
|
2010-06-28 17:12:22 -07:00
|
|
|
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
|
2013-12-10 12:28:58 -05:00
|
|
|
const SkPaint* paint, bool ignoreTransform) {
|
|
|
|
int color = paint->getColor();
|
2010-07-14 19:18:51 -07:00
|
|
|
// If a shader is set, preserve only the alpha
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
if (getShader(paint)) {
|
2010-07-14 19:18:51 -07:00
|
|
|
color |= 0x00ffffff;
|
|
|
|
}
|
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
setupDraw();
|
2011-12-13 13:11:32 -08:00
|
|
|
setupDrawNoTexture();
|
2014-01-01 14:45:21 -08:00
|
|
|
setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShader(getShader(paint));
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
|
|
|
setupDrawBlending(paint);
|
2010-12-13 18:24:33 -08:00
|
|
|
setupDrawProgram();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(kModelViewMode_TranslateAndScale, false,
|
|
|
|
left, top, right, bottom, ignoreTransform);
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawColorUniforms(getShader(paint));
|
|
|
|
setupDrawShaderUniforms(getShader(paint), ignoreTransform);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
2010-12-13 18:24:33 -08:00
|
|
|
setupDrawSimpleMesh();
|
2010-09-17 15:31:32 -07:00
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
|
|
|
|
}
|
|
|
|
|
2010-07-09 13:25:56 -07:00
|
|
|
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
|
2014-01-02 17:13:34 -08:00
|
|
|
Texture* texture, const SkPaint* paint) {
|
2011-11-30 20:21:23 -08:00
|
|
|
texture->setWrap(GL_CLAMP_TO_EDGE, true);
|
2010-10-25 18:03:28 -07:00
|
|
|
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
GLvoid* vertices = (GLvoid*) NULL;
|
|
|
|
GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
|
|
|
|
|
|
|
|
if (texture->uvMapper) {
|
2013-08-15 16:57:57 -07:00
|
|
|
vertices = &mMeshVertices[0].x;
|
|
|
|
texCoords = &mMeshVertices[0].u;
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
|
|
|
|
Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
|
|
|
|
texture->uvMapper->map(uvs);
|
|
|
|
|
|
|
|
resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
|
|
|
|
}
|
|
|
|
|
2014-01-01 14:45:21 -08:00
|
|
|
if (CC_LIKELY(currentTransform()->isPureTranslate())) {
|
|
|
|
const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
|
2010-12-06 18:07:02 -08:00
|
|
|
|
2011-11-30 20:21:23 -08:00
|
|
|
texture->setFilter(GL_NEAREST, true);
|
2010-12-06 18:07:02 -08:00
|
|
|
drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
|
2013-12-10 12:28:58 -05:00
|
|
|
paint, texture->blend, vertices, texCoords,
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
GL_TRIANGLE_STRIP, gMeshCount, false, true);
|
2010-12-06 18:07:02 -08:00
|
|
|
} else {
|
2014-02-28 12:26:34 -08:00
|
|
|
texture->setFilter(getFilter(paint), true);
|
2013-12-10 12:28:58 -05:00
|
|
|
drawTextureMesh(left, top, right, bottom, texture->id, paint,
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (texture->uvMapper) {
|
|
|
|
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
|
2010-12-06 18:07:02 -08:00
|
|
|
}
|
2010-06-22 13:11:24 -07:00
|
|
|
}
|
|
|
|
|
2010-07-08 19:17:03 -07:00
|
|
|
void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
|
2013-12-10 12:28:58 -05:00
|
|
|
GLuint texture, const SkPaint* paint, bool blend,
|
2010-09-15 18:11:50 -07:00
|
|
|
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
|
2013-11-15 16:06:56 -08:00
|
|
|
bool swapSrcDst, bool ignoreTransform, GLuint vbo,
|
|
|
|
ModelViewMode modelViewMode, bool dirty) {
|
2010-09-12 13:02:16 -07:00
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
int a;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &a, &mode);
|
|
|
|
const float alpha = a / 255.0f;
|
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
setupDraw();
|
|
|
|
setupDrawWithTexture();
|
|
|
|
setupDrawColor(alpha, alpha, alpha, alpha);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
|
|
|
setupDrawBlending(paint, blend, swapSrcDst);
|
2010-12-13 18:24:33 -08:00
|
|
|
setupDrawProgram();
|
2013-01-04 12:26:18 -08:00
|
|
|
if (!dirty) setupDrawDirtyRegionsDisabled();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
|
2013-01-04 12:26:18 -08:00
|
|
|
setupDrawTexture(texture);
|
2010-12-14 15:55:39 -08:00
|
|
|
setupDrawPureColorUniforms();
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
2010-12-13 18:24:33 -08:00
|
|
|
setupDrawMesh(vertices, texCoords, vbo);
|
2010-08-02 18:50:22 -07:00
|
|
|
|
2010-09-15 18:11:50 -07:00
|
|
|
glDrawArrays(drawMode, 0, elementsCount);
|
2010-07-09 13:25:56 -07:00
|
|
|
}
|
|
|
|
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
|
2013-12-10 12:28:58 -05:00
|
|
|
GLuint texture, const SkPaint* paint, bool blend,
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
|
2013-11-15 16:06:56 -08:00
|
|
|
bool swapSrcDst, bool ignoreTransform, GLuint vbo,
|
|
|
|
ModelViewMode modelViewMode, bool dirty) {
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
int a;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &a, &mode);
|
|
|
|
const float alpha = a / 255.0f;
|
|
|
|
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
setupDraw();
|
|
|
|
setupDrawWithTexture();
|
|
|
|
setupDrawColor(alpha, alpha, alpha, alpha);
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
|
|
|
setupDrawBlending(paint, blend, swapSrcDst);
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
setupDrawProgram();
|
|
|
|
if (!dirty) setupDrawDirtyRegionsDisabled();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
setupDrawTexture(texture);
|
|
|
|
setupDrawPureColorUniforms();
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
Pack preloaded framework assets in a texture atlas
When the Android runtime starts, the system preloads a series of assets
in the Zygote process. These assets are shared across all processes.
Unfortunately, each one of these assets is later uploaded in its own
OpenGL texture, once per process. This wastes memory and generates
unnecessary OpenGL state changes.
This CL introduces an asset server that provides an atlas to all processes.
Note: bitmaps used by skia shaders are *not* sampled from the atlas.
It's an uncommon use case and would require extra texture transforms
in the GL shaders.
WHAT IS THE ASSETS ATLAS
The "assets atlas" is a single, shareable graphic buffer that contains
all the system's preloaded bitmap drawables (this includes 9-patches.)
The atlas is made of two distinct objects: the graphic buffer that
contains the actual pixels and the map which indicates where each
preloaded bitmap can be found in the atlas (essentially a pair of
x and y coordinates.)
HOW IS THE ASSETS ATLAS GENERATED
Because we need to support a wide variety of devices and because it
is easy to change the list of preloaded drawables, the atlas is
generated at runtime, during the startup phase of the system process.
There are several steps that lead to the atlas generation:
1. If the device is booting for the first time, or if the device was
updated, we need to find the best atlas configuration. To do so,
the atlas service tries a number of width, height and algorithm
variations that allows us to pack as many assets as possible while
using as little memory as possible. Once a best configuration is found,
it gets written to disk in /data/system/framework_atlas
2. Given a best configuration (algorithm variant, dimensions and
number of bitmaps that can be packed in the atlas), the atlas service
packs all the preloaded bitmaps into a single graphic buffer object.
3. The packing is done using Skia in a temporary native bitmap. The
Skia bitmap is then copied into the graphic buffer using OpenGL ES
to benefit from texture swizzling.
HOW PROCESSES USE THE ATLAS
Whenever a process' hardware renderer initializes its EGL context,
it queries the atlas service for the graphic buffer and the map.
It is important to remember that both the context and the map will
be valid for the lifetime of the hardware renderer (if the system
process goes down, all apps get killed as well.)
Every time the hardware renderer needs to render a bitmap, it first
checks whether the bitmap can be found in the assets atlas. When
the bitmap is part of the atlas, texture coordinates are remapped
appropriately before rendering.
Change-Id: I8eaecf53e7f6a33d90da3d0047c5ceec89ea3af0
2013-04-17 18:54:38 -07:00
|
|
|
setupDrawMeshIndices(vertices, texCoords, vbo);
|
|
|
|
|
|
|
|
glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
|
|
|
|
}
|
|
|
|
|
2013-01-04 12:26:18 -08:00
|
|
|
void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
|
2013-12-10 12:28:58 -05:00
|
|
|
GLuint texture, const SkPaint* paint,
|
2013-01-04 12:26:18 -08:00
|
|
|
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
|
2013-11-15 16:06:56 -08:00
|
|
|
bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
|
2013-01-04 12:26:18 -08:00
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
int color = paint != NULL ? paint->getColor() : 0;
|
|
|
|
int alpha;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &alpha, &mode);
|
|
|
|
|
2013-01-04 12:26:18 -08:00
|
|
|
setupDraw();
|
|
|
|
setupDrawWithTexture(true);
|
2013-12-10 12:28:58 -05:00
|
|
|
if (paint != NULL) {
|
2013-01-04 12:26:18 -08:00
|
|
|
setupDrawAlpha8Color(color, alpha);
|
|
|
|
}
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShader(getShader(paint));
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawBlending(paint, true);
|
2013-01-04 12:26:18 -08:00
|
|
|
setupDrawProgram();
|
|
|
|
if (!dirty) setupDrawDirtyRegionsDisabled();
|
2013-11-15 16:06:56 -08:00
|
|
|
setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
|
2013-01-04 12:26:18 -08:00
|
|
|
setupDrawTexture(texture);
|
|
|
|
setupDrawPureColorUniforms();
|
2013-12-10 12:28:58 -05:00
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
Inspect SkShader to determine hw shader.
Instead of duplicating internal info about SkShader, inspect the
SkShader installed on the SkPaint.
core/java/android/view/GLES20Canvas.java:
Remove setupModifiers, nResetModifiers, and nSetupShader.
core/jni/android/graphics/Shader.cpp:
Remove calls to create/destroy the (previously) attached SkiaShader.
core/jni/android_view_GLES20Canvas.cpp:
Remove native code for setupShader and resetModifiers.
graphics/java/android/graphics/BitmapShader.java:
graphics/java/android/graphics/ComposeShader.java:
graphics/java/android/graphics/LinearGradient.java:
graphics/java/android/graphics/RadialGradient.java:
graphics/java/android/graphics/Shader.java:
graphics/java/android/graphics/SweepGradient.java:
Remove code keeping track of native SkiaShader.
libs/hwui/Caches.h:
Include Extensions.h.
libs/hwui/DeferredDisplayList.cpp:
Compare shaders on the paint, instead of on DrawModifiers.
libs/hwui/DisplayList.cpp:
libs/hwui/DisplayList.h:
Remove vector of SkiaShaders.
libs/hwui/DisplayListOp.h:
Access the SkShader on mPaint.
Remove SetupShaderOp and ResetShaderOp.
libs/hwui/DisplayListRenderer.cpp:
libs/hwui/DisplayListRenderer.h:
Remove resetShader, setupShader, refShader, and mShaderMap.
libs/hwui/FontRenderer.cpp:
Pass SkShader to setupDrawShader and setupDrawShaderUniforms.
libs/hwui/OpenGLRenderer.cpp:
libs/hwui/OpenGLRenderer.h:
Add LayerShader, a class inheriting from SkShader, to mimic the
behavior of SkiaLayerShader. Unlike SkiaLayerShader, it can be set on
the SkPaint so it can be inspected later.
Set a LayerShader instead of a SkiaLayerShader.
setupDrawShader and setupDrawShaderUniforms now inspect an SkShader
passed in.
Inspect SkShader instead of mDrawModifiers.mShader.
Remove resetShader and setupShader.
setupDrawColorUniforms now takes a boolean indicating whether there is
a shader.
Add an inline function for accessing the SkShader on an SkPaint.
In setupDrawBlending(Layer*, bool), do not check the shader (which will
never be set), but do check whether the color filter may change the
alpha (newly fixed behavior).
In setupDrawBlending(SkPaint, ...), check the SkShader and whether the
color filter affects alpha (the latter is new behavior).
libs/hwui/Renderer.h:
Remove pure virtual functions setupShader and resetShader.
libs/hwui/ResourceCache.cpp:
libs/hwui/ResourceCache.h:
Remove functions for refing/unrefing shaders.
libs/hwui/SkiaShader.cpp:
libs/hwui/SkiaShader.h:
Much of this code was redundant and has been removed.
Convert structs into class with nothing but static functions for
calling describe/setupProgram.
libs/hwui/TextureCache.cpp:
libs/hwui/TextureCache.h:
Use the SkPixelRef as the key to the bitmap Lru cache, since shader
inspection will provide a different SkBitmap pointer (though it will
hold the correct SkPixelRef with the correct generation ID).
tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java:
tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java:
Update manual test to have more shaders: radial, sweep, compose,
invalid compose.
BUG:10650594
Change-Id: Iaa7189178bda1c55f96da044d2a9fa602ba36034
2014-05-05 12:50:38 -04:00
|
|
|
setupDrawShaderUniforms(getShader(paint), ignoreTransform);
|
2013-01-04 12:26:18 -08:00
|
|
|
setupDrawMesh(vertices, texCoords);
|
|
|
|
|
|
|
|
glDrawArrays(drawMode, 0, elementsCount);
|
|
|
|
}
|
|
|
|
|
2010-09-09 14:42:43 -07:00
|
|
|
void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
|
2010-09-10 19:20:06 -07:00
|
|
|
ProgramDescription& description, bool swapSrcDst) {
|
2014-05-05 19:09:33 -07:00
|
|
|
|
|
|
|
if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
|
|
|
|
blend = true;
|
|
|
|
mDescription.hasRoundRectClip = true;
|
|
|
|
}
|
|
|
|
mSkipOutlineClip = true;
|
|
|
|
|
2013-05-03 14:24:16 -07:00
|
|
|
if (mCountOverdraw) {
|
|
|
|
if (!mCaches.blend) glEnable(GL_BLEND);
|
|
|
|
if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) {
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
mCaches.blend = true;
|
|
|
|
mCaches.lastSrcMode = GL_ONE;
|
|
|
|
mCaches.lastDstMode = GL_ONE;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-07-09 13:25:56 -07:00
|
|
|
blend = blend || mode != SkXfermode::kSrcOver_Mode;
|
2012-04-25 20:02:53 -07:00
|
|
|
|
2010-07-09 13:25:56 -07:00
|
|
|
if (blend) {
|
2012-01-03 14:13:39 -08:00
|
|
|
// These blend modes are not supported by OpenGL directly and have
|
|
|
|
// to be implemented using shaders. Since the shader will perform
|
|
|
|
// the blending, turn blending off here
|
|
|
|
// If the blend mode cannot be implemented using shaders, fall
|
|
|
|
// back to the default SrcOver blend mode instead
|
2012-08-07 19:09:57 -07:00
|
|
|
if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
|
2013-02-06 16:51:04 -08:00
|
|
|
if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
|
2010-09-09 14:42:43 -07:00
|
|
|
description.framebufferMode = mode;
|
2010-09-10 19:20:06 -07:00
|
|
|
description.swapSrcDst = swapSrcDst;
|
2010-09-09 14:42:43 -07:00
|
|
|
|
2012-01-03 14:13:39 -08:00
|
|
|
if (mCaches.blend) {
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
mCaches.blend = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
mode = SkXfermode::kSrcOver_Mode;
|
2010-09-09 14:42:43 -07:00
|
|
|
}
|
2012-01-03 14:13:39 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2010-07-09 13:25:56 -07:00
|
|
|
}
|
2010-08-23 21:05:08 -07:00
|
|
|
} else if (mCaches.blend) {
|
2010-07-09 13:25:56 -07:00
|
|
|
glDisable(GL_BLEND);
|
|
|
|
}
|
2010-08-23 21:05:08 -07:00
|
|
|
mCaches.blend = blend;
|
2010-06-26 00:13:53 -07:00
|
|
|
}
|
|
|
|
|
2010-07-29 14:37:42 -07:00
|
|
|
bool OpenGLRenderer::useProgram(Program* program) {
|
2010-07-14 19:18:51 -07:00
|
|
|
if (!program->isInUse()) {
|
2010-08-23 21:05:08 -07:00
|
|
|
if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
|
2010-07-14 19:18:51 -07:00
|
|
|
program->use();
|
2010-08-23 21:05:08 -07:00
|
|
|
mCaches.currentProgram = program;
|
2010-07-12 20:20:03 -07:00
|
|
|
return false;
|
2010-07-12 14:41:06 -07:00
|
|
|
}
|
2010-07-12 20:20:03 -07:00
|
|
|
return true;
|
2010-07-12 14:41:06 -07:00
|
|
|
}
|
|
|
|
|
2010-06-28 17:12:22 -07:00
|
|
|
void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
|
2010-07-27 17:39:27 -07:00
|
|
|
TextureVertex* v = &mMeshVertices[0];
|
2010-07-09 13:25:56 -07:00
|
|
|
TextureVertex::setUV(v++, u1, v1);
|
|
|
|
TextureVertex::setUV(v++, u2, v1);
|
|
|
|
TextureVertex::setUV(v++, u1, v2);
|
|
|
|
TextureVertex::setUV(v++, u2, v2);
|
2010-06-30 19:21:21 -07:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
|
2012-07-16 12:41:17 -07:00
|
|
|
getAlphaAndModeDirect(paint, alpha, mode);
|
2013-03-29 10:59:59 -07:00
|
|
|
if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
|
|
|
|
// if drawing a layer, ignore the paint's alpha
|
2013-05-03 17:42:27 -07:00
|
|
|
*alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
|
2013-03-29 10:59:59 -07:00
|
|
|
}
|
2014-01-01 14:45:21 -08:00
|
|
|
*alpha *= currentSnapshot()->alpha;
|
2010-06-28 17:12:22 -07:00
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
|
2013-03-29 10:59:59 -07:00
|
|
|
float alpha;
|
|
|
|
if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
|
|
|
|
alpha = mDrawModifiers.mOverrideLayerAlpha;
|
|
|
|
} else {
|
|
|
|
alpha = layer->getAlpha() / 255.0f;
|
|
|
|
}
|
2014-01-01 14:45:21 -08:00
|
|
|
return alpha * currentSnapshot()->alpha;
|
2013-03-29 10:59:59 -07:00
|
|
|
}
|
|
|
|
|
2010-06-24 19:30:36 -07:00
|
|
|
}; // namespace uirenderer
|
2010-06-16 18:44:05 -07:00
|
|
|
}; // namespace android
|