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
|
|
|
#include "OpenGLRenderer.h"
|
2015-01-26 18:06:29 -08:00
|
|
|
|
2013-02-04 16:16:33 -08:00
|
|
|
#include "DeferredDisplayList.h"
|
2010-11-08 12:08:41 -08:00
|
|
|
#include "DisplayListRenderer.h"
|
2014-10-15 15:46:42 -04:00
|
|
|
#include "GammaFontRenderer.h"
|
2015-02-02 18:39:33 -08:00
|
|
|
#include "Glop.h"
|
|
|
|
#include "GlopBuilder.h"
|
2014-10-15 15:46:42 -04:00
|
|
|
#include "Patch.h"
|
2012-12-10 17:56:27 -08:00
|
|
|
#include "PathTessellator.h"
|
2012-09-24 11:37:12 -07:00
|
|
|
#include "Properties.h"
|
2014-10-15 15:46:42 -04:00
|
|
|
#include "RenderNode.h"
|
2015-02-02 18:39:33 -08:00
|
|
|
#include "renderstate/MeshState.h"
|
2015-01-26 18:06:29 -08:00
|
|
|
#include "renderstate/RenderState.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"
|
2010-12-08 18:34:42 -08:00
|
|
|
#include "Vector.h"
|
2013-12-03 10:38:55 -08:00
|
|
|
#include "VertexBuffer.h"
|
2014-10-15 15:46:42 -04:00
|
|
|
#include "utils/GLUtils.h"
|
2014-12-09 15:03:44 -05:00
|
|
|
#include "utils/PaintUtils.h"
|
2014-11-20 17:27:36 -08:00
|
|
|
#include "utils/TraceUtils.h"
|
2010-06-16 18:44:05 -07:00
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <SkCanvas.h>
|
|
|
|
#include <SkColor.h>
|
|
|
|
#include <SkShader.h>
|
|
|
|
#include <SkTypeface.h>
|
|
|
|
|
|
|
|
#include <utils/Log.h>
|
|
|
|
#include <utils/StopWatch.h>
|
|
|
|
|
|
|
|
#include <private/hwui/DrawGlInfo.h>
|
|
|
|
|
|
|
|
#include <ui/Rect.h>
|
|
|
|
|
2014-07-29 10:35:13 -07:00
|
|
|
#if DEBUG_DETAILED_EVENTS
|
|
|
|
#define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define EVENT_LOGD(...)
|
|
|
|
#endif
|
|
|
|
|
2015-02-11 13:17:06 -08:00
|
|
|
#define USE_GLOPS true
|
|
|
|
|
2010-06-16 18:44:05 -07:00
|
|
|
namespace android {
|
2010-06-24 19:30:36 -07:00
|
|
|
namespace uirenderer {
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Globals
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
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)
|
2014-10-10 13:38:16 -04:00
|
|
|
: mState(*this)
|
2014-07-23 18:19:28 -07:00
|
|
|
, mCaches(Caches::getInstance())
|
|
|
|
, mRenderState(renderState)
|
2015-01-26 18:06:29 -08:00
|
|
|
, mFrameStarted(false)
|
2014-07-23 18:19:28 -07:00
|
|
|
, mScissorOptimizationDisabled(false)
|
2014-09-18 16:05:35 -07:00
|
|
|
, mSuppressTiling(false)
|
|
|
|
, mFirstFrameAfterResize(true)
|
2014-09-08 11:26:26 -04:00
|
|
|
, mDirty(false)
|
2014-07-24 13:38:28 -07:00
|
|
|
, mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
|
2014-07-23 18:19:28 -07:00
|
|
|
, mLightRadius(FLT_MIN)
|
|
|
|
, mAmbientShadowAlpha(0)
|
|
|
|
, mSpotShadowAlpha(0) {
|
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
|
|
|
|
2015-02-02 18:39:33 -08:00
|
|
|
memcpy(mMeshVertices, kUnitQuadVertices, sizeof(kUnitQuadVertices));
|
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
|
|
|
}
|
|
|
|
|
2014-07-23 18:19:28 -07:00
|
|
|
void OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius,
|
|
|
|
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
|
|
|
|
mLightCenter = lightCenter;
|
|
|
|
mLightRadius = lightRadius;
|
|
|
|
mAmbientShadowAlpha = ambientShadowAlpha;
|
|
|
|
mSpotShadowAlpha = spotShadowAlpha;
|
|
|
|
}
|
|
|
|
|
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);
|
2014-09-18 16:05:35 -07:00
|
|
|
mFirstFrameAfterResize = true;
|
2012-09-18 15:40:58 -07:00
|
|
|
}
|
|
|
|
|
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();
|
2014-10-10 13:38:16 -04:00
|
|
|
mState.initializeSaveStack(left, top, right, bottom, mLightCenter);
|
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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::startFrame() {
|
|
|
|
if (mFrameStarted) return;
|
2013-03-26 15:05:58 -07:00
|
|
|
mFrameStarted = true;
|
2012-09-21 00:39:43 -07:00
|
|
|
|
2014-10-10 13:38:16 -04:00
|
|
|
mState.setDirtyClip(true);
|
2013-03-26 15:05:58 -07:00
|
|
|
|
|
|
|
discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
|
2012-09-11 17:17:07 -07:00
|
|
|
|
2014-10-10 13:38:16 -04:00
|
|
|
mRenderState.setViewport(mState.getWidth(), mState.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
|
2014-09-18 16:05:35 -07:00
|
|
|
mSuppressTiling = mCaches.hasRegisteredFunctors()
|
|
|
|
|| mFirstFrameAfterResize;
|
|
|
|
mFirstFrameAfterResize = false;
|
2012-09-27 17:55:46 -07:00
|
|
|
|
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);
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
clear(mTilingClip.left, mTilingClip.top,
|
2013-03-26 15:05:58 -07:00
|
|
|
mTilingClip.right, mTilingClip.bottom, mOpaque);
|
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::prepareDirty(float left, float top,
|
2013-03-26 15:05:58 -07:00
|
|
|
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) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mRenderState.blend().syncEnabled();
|
2013-03-26 15:05:58 -07:00
|
|
|
updateLayers();
|
|
|
|
} else {
|
2014-09-08 11:26:26 -04:00
|
|
|
startFrame();
|
2013-03-26 15:05:58 -07:00
|
|
|
}
|
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.
|
2015-02-05 10:12:38 -08:00
|
|
|
if (mCaches.extensions().hasDiscardFramebuffer() &&
|
2014-10-10 13:38:16 -04:00
|
|
|
left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
|
|
|
|
const bool isFbo = onGetTargetFbo() == 0;
|
2013-01-31 17:20:30 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
|
2014-10-27 12:38:48 -07:00
|
|
|
if (!opaque) {
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(true);
|
|
|
|
mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
|
2010-10-06 19:49:23 -07:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
|
|
|
return;
|
2012-05-22 14:07:07 -07:00
|
|
|
}
|
2012-06-06 19:03:58 -07:00
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().reset();
|
2012-05-22 14:07:07 -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
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
bool OpenGLRenderer::finish() {
|
2012-09-21 19:15:00 -07:00
|
|
|
renderOverdraw();
|
2012-09-19 17:25:38 -07:00
|
|
|
endTiling();
|
2014-12-09 16:54:03 -08:00
|
|
|
mTempPaths.clear();
|
|
|
|
|
2013-03-08 17:44:20 -08:00
|
|
|
// When finish() is invoked on FBO 0 we've reached the end
|
|
|
|
// of the current frame
|
2014-10-10 13:38:16 -04:00
|
|
|
if (onGetTargetFbo() == 0) {
|
2013-03-08 17:44:20 -08:00
|
|
|
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
|
|
|
|
|
|
|
mFrameStarted = false;
|
2014-09-08 11:26:26 -04:00
|
|
|
|
|
|
|
return reportAndClearDirty();
|
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
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().reset();
|
2012-09-18 15:40:58 -07:00
|
|
|
dirtyClip();
|
|
|
|
}
|
|
|
|
|
2014-11-22 00:35:09 +00:00
|
|
|
void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()) return;
|
2013-03-26 18:55:15 -07:00
|
|
|
|
2015-01-06 13:22:54 -08:00
|
|
|
Rect clip(mState.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-10-10 13:38:16 -04:00
|
|
|
bool prevDirtyClip = mState.getDirtyClip();
|
2013-08-26 11:23:46 -07:00
|
|
|
// setup GL state for functor
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.getDirtyClip()) {
|
2013-08-26 11:23:46 -07:00
|
|
|
setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
|
|
|
|
}
|
2015-01-26 18:06:29 -08:00
|
|
|
if (mRenderState.scissor().setEnabled(true) || 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-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2011-01-10 14:10:36 -08:00
|
|
|
}
|
|
|
|
|
2012-09-24 11:37:12 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Debug
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-07-29 10:35:13 -07:00
|
|
|
void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
|
|
|
|
#if DEBUG_DETAILED_EVENTS
|
|
|
|
const int BUFFER_SIZE = 256;
|
|
|
|
va_list ap;
|
|
|
|
char buf[BUFFER_SIZE];
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
vsnprintf(buf, BUFFER_SIZE, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
eventMark(buf);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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() {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mCaches.debugOverdraw && onGetTargetFbo() == 0) {
|
2013-03-21 14:39:04 -07:00
|
|
|
const Rect* clip = &mTilingClip;
|
2012-09-24 11:37:12 -07:00
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(true);
|
|
|
|
mRenderState.scissor().set(clip->left,
|
|
|
|
mState.firstSnapshot()->getViewportHeight() - clip->bottom,
|
|
|
|
clip->right - clip->left,
|
|
|
|
clip->bottom - clip->top);
|
2012-09-24 11:37:12 -07:00
|
|
|
|
2013-08-21 11:53:18 -07:00
|
|
|
// 1x overdraw
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.stencil().enableDebugTest(2);
|
2013-08-21 11:53:18 -07:00
|
|
|
drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
|
|
|
|
|
|
|
|
// 2x overdraw
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.stencil().enableDebugTest(3);
|
2013-08-21 11:53:18 -07:00
|
|
|
drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
|
|
|
|
|
|
|
|
// 3x overdraw
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.stencil().enableDebugTest(4);
|
2013-08-21 11:53:18 -07:00
|
|
|
drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
|
|
|
|
|
|
|
|
// 4x overdraw and higher
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.stencil().enableDebugTest(4, true);
|
2013-08-21 11:53:18 -07:00
|
|
|
drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
|
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.stencil().disable();
|
2012-09-24 11:37:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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)) {
|
2014-08-14 13:34:01 -07:00
|
|
|
layer->render(*this);
|
2013-03-26 15:05:58 -07:00
|
|
|
} else {
|
2014-08-14 13:34:01 -07:00
|
|
|
layer->defer(*this);
|
2013-03-26 15:05:58 -07:00
|
|
|
}
|
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++) {
|
2014-10-31 14:49:06 -07:00
|
|
|
Layer* layer = mLayerUpdates.itemAt(i).get();
|
2012-09-21 00:39:43 -07:00
|
|
|
updateLayer(layer, false);
|
|
|
|
}
|
|
|
|
|
2013-03-26 15:05:58 -07:00
|
|
|
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
|
|
|
|
mLayerUpdates.clear();
|
2014-10-10 13:38:16 -04:00
|
|
|
mRenderState.bindFramebuffer(onGetTargetFbo());
|
2013-03-26 15:05:58 -07:00
|
|
|
}
|
|
|
|
endMark();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::flushLayers() {
|
|
|
|
int count = mLayerUpdates.size();
|
|
|
|
if (count > 0) {
|
|
|
|
startMark("Apply Layer Updates");
|
|
|
|
|
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++) {
|
2014-11-18 10:49:23 -08:00
|
|
|
mLayerUpdates.itemAt(i)->flush();
|
2013-03-26 15:05:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mLayerUpdates.clear();
|
2014-10-10 13:38:16 -04:00
|
|
|
mRenderState.bindFramebuffer(onGetTargetFbo());
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-12 15:31:28 -07:00
|
|
|
void OpenGLRenderer::flushLayerUpdates() {
|
2014-11-18 10:49:23 -08:00
|
|
|
ATRACE_NAME("Update HW Layers");
|
2015-01-29 09:45:09 -08:00
|
|
|
mRenderState.blend().syncEnabled();
|
2013-06-12 15:31:28 -07:00
|
|
|
updateLayers();
|
|
|
|
flushLayers();
|
|
|
|
// Wait for all the layer updates to be executed
|
2015-01-21 07:46:37 -08:00
|
|
|
glFinish();
|
2013-06-12 15:31:28 -07:00
|
|
|
}
|
|
|
|
|
2014-09-04 17:40:05 -07:00
|
|
|
void OpenGLRenderer::markLayersAsBuildLayers() {
|
|
|
|
for (size_t i = 0; i < mLayerUpdates.size(); i++) {
|
|
|
|
mLayerUpdates[i]->wasBuildLayered = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
2014-09-24 11:29:43 -07:00
|
|
|
ATRACE_END(); // SaveLayer
|
2013-03-28 11:25:24 -07:00
|
|
|
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) {
|
2014-09-14 15:49:54 -07:00
|
|
|
// force matrix/clip isolation for layer
|
|
|
|
flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
|
|
|
|
|
2014-10-10 13:38:16 -04:00
|
|
|
const int count = mState.saveSnapshot(flags);
|
2010-06-28 17:42:46 -07:00
|
|
|
|
2014-10-10 13:38:16 -04:00
|
|
|
if (!mState.currentlyIgnored()) {
|
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
|
2015-01-06 13:22:54 -08:00
|
|
|
if (bounds.intersect(mState.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())) {
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->empty = fboLayer;
|
2013-03-26 18:55:15 -07:00
|
|
|
} else {
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer);
|
2013-03-26 18:55:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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) {
|
2014-10-10 13:38:16 -04:00
|
|
|
const int count = mState.saveSnapshot(flags);
|
2013-03-19 15:03:48 -07:00
|
|
|
|
2014-10-10 13:38:16 -04:00
|
|
|
if (!mState.currentlyIgnored() && (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-10-10 13:38:16 -04:00
|
|
|
if (!mState.currentlyIgnored()) {
|
|
|
|
writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
|
|
|
|
writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
|
|
|
|
writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
|
2014-12-22 14:28:49 -08:00
|
|
|
writableSnapshot()->roundRectClipState = nullptr;
|
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) {
|
2014-12-19 10:08:40 -08:00
|
|
|
LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
|
|
|
|
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-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()) {
|
2010-09-16 14:16:48 -07:00
|
|
|
return false;
|
|
|
|
}
|
2010-07-06 11:39:32 -07:00
|
|
|
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(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
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
|
|
|
|
writableSnapshot()->layer = layer;
|
2010-08-17 11:37:00 -07:00
|
|
|
|
2014-09-24 11:29:43 -07:00
|
|
|
ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
|
|
|
|
fboLayer ? "" : "unclipped ",
|
|
|
|
layer->getWidth(), layer->getHeight());
|
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(),
|
2014-12-22 14:28:49 -08:00
|
|
|
0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
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
|
2014-12-22 17:16:56 -08:00
|
|
|
mLayers.push_back(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
|
|
|
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->region = &writableSnapshot()->layer->region;
|
|
|
|
writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
|
|
|
|
writableSnapshot()->fbo = layer->getFbo();
|
|
|
|
writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
|
|
|
|
writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
|
|
|
|
writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
|
2014-12-22 14:28:49 -08:00
|
|
|
writableSnapshot()->roundRectClipState = nullptr;
|
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
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(true);
|
|
|
|
mRenderState.scissor().set(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;
|
2014-10-10 13:38:16 -04:00
|
|
|
mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
|
2014-12-22 14:28:49 -08:00
|
|
|
&clipRequired, nullptr, false); // safely ignore return, should never be rejected
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
|
2013-06-13 14:39:01 -07:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().unbindMeshBuffer();
|
2010-08-18 17:10:07 -07:00
|
|
|
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(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)
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->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-12-22 14:28:49 -08:00
|
|
|
layer->setConvexMask(nullptr);
|
2010-10-08 15:49:53 -07:00
|
|
|
if (!mCaches.layerCache.put(layer)) {
|
2014-12-19 10:08:40 -08:00
|
|
|
LAYER_LOGD("Deleting layer");
|
2014-12-22 14:28:49 -08:00
|
|
|
layer->decStrong(nullptr);
|
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
|
|
|
|
2015-02-05 10:12:38 -08:00
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
|
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
|
|
|
}
|
|
|
|
|
2010-10-27 18:57:51 -07:00
|
|
|
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
|
2014-07-29 10:35:13 -07:00
|
|
|
if (layer->isTextureLayer()) {
|
|
|
|
EVENT_LOGD("composeTextureLayerRect");
|
|
|
|
resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
|
|
|
|
drawTextureLayer(layer, rect);
|
|
|
|
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
|
|
|
|
} else {
|
|
|
|
EVENT_LOGD("composeHardwareLayerRect");
|
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,
|
2015-02-05 10:12:38 -08:00
|
|
|
GL_TRIANGLE_STRIP, kUnitQuadCount, 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);
|
|
|
|
}
|
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
|
|
|
|
*/
|
2014-10-10 13:38:16 -04:00
|
|
|
#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \
|
|
|
|
DRAW_COMMAND; \
|
|
|
|
if (CC_UNLIKELY(mCaches.debugOverdraw && onGetTargetFbo() == 0 && COND)) { \
|
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \
|
|
|
|
DRAW_COMMAND; \
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \
|
|
|
|
} \
|
2013-04-15 16:08:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#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) {
|
|
|
|
}
|
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
virtual bool asACustomShader(void** data) const override {
|
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 (data) {
|
|
|
|
*data = static_cast<void*>(mLayer);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
virtual bool isOpaque() const override {
|
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
|
|
|
return !mLayer->isBlend();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2014-11-22 00:35:09 +00:00
|
|
|
virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
|
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
|
|
|
LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
|
|
|
|
}
|
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
virtual void flatten(SkWriteBuffer&) const override {
|
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
|
|
|
LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
|
|
|
|
}
|
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
virtual Factory getFactory() const override {
|
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
|
|
|
LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
|
2014-12-22 14:28:49 -08:00
|
|
|
return nullptr;
|
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
|
|
|
}
|
|
|
|
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));
|
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
paint.setShader(nullptr);
|
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-07-29 10:35:13 -07:00
|
|
|
EVENT_LOGD("composeLayerRegion");
|
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++;
|
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
if (numQuads >= kMaxNumberOfQuads) {
|
2013-04-15 16:08:28 -07:00
|
|
|
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
|
2014-12-22 14:28:49 -08:00
|
|
|
GL_UNSIGNED_SHORT, nullptr));
|
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,
|
2014-12-22 14:28:49 -08:00
|
|
|
GL_UNSIGNED_SHORT, nullptr));
|
2014-04-15 16:18:08 -07:00
|
|
|
}
|
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) {
|
2015-01-06 13:22:54 -08:00
|
|
|
if (bounds.intersect(mState.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) {
|
2015-01-27 15:46:35 -08:00
|
|
|
GLsizei drawCount = min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
|
2013-07-22 13:57:50 -07:00
|
|
|
|
2013-08-15 16:57:57 -07:00
|
|
|
setupDrawIndexedVertices(&mesh[0].x);
|
2014-12-22 14:28:49 -08:00
|
|
|
glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr);
|
2013-07-22 13:57:50 -07:00
|
|
|
|
|
|
|
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-10-10 13:38:16 -04:00
|
|
|
if (!mState.currentlyIgnored()) {
|
2014-07-29 10:35:13 -07:00
|
|
|
EVENT_LOGD("clearLayerRegions");
|
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
|
2015-01-26 18:06:29 -08:00
|
|
|
bool scissorChanged = mRenderState.scissor().setEnabled(false);
|
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++) {
|
2014-12-22 17:16:56 -08:00
|
|
|
const Rect& bounds = mLayers[i];
|
2011-06-13 19:04:27 -07:00
|
|
|
|
2014-12-22 17:16:56 -08:00
|
|
|
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);
|
2011-06-13 19:04:27 -07:00
|
|
|
}
|
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
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
if (scissorChanged) mRenderState.scissor().setEnabled(true);
|
2011-06-13 19:04:27 -07:00
|
|
|
} else {
|
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) {
|
2015-01-06 13:22:54 -08:00
|
|
|
const Rect& currentClip = mState.currentClipRect();
|
2014-01-01 14:45:21 -08:00
|
|
|
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)
|
|
|
|
|
2015-01-06 13:22:54 -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;
|
2015-01-06 13:22:54 -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
|
2015-01-06 13:22:54 -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;
|
2015-01-06 13:22:54 -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) {
|
2015-01-06 13:22:54 -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);
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->alpha = state.mAlpha;
|
2013-12-30 15:32:54 -08:00
|
|
|
mDrawModifiers = state.mDrawModifiers;
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
|
2013-03-08 13:12:16 -08:00
|
|
|
|
2013-03-04 10:19:31 -08:00
|
|
|
if (state.mClipValid && !skipClipRestore) {
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
|
2013-05-31 11:38:03 -07:00
|
|
|
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) {
|
2014-12-22 14:28:49 -08:00
|
|
|
if (clipRect != nullptr) {
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
|
2013-05-31 11:38:03 -07:00
|
|
|
} else {
|
2014-10-10 13:38:16 -04:00
|
|
|
writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
|
2013-05-31 11:38:03 -07:00
|
|
|
}
|
2013-03-04 10:19:31 -08:00
|
|
|
dirtyClip();
|
2015-01-26 18:06:29 -08:00
|
|
|
bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled;
|
|
|
|
mRenderState.scissor().setEnabled(enableScissor);
|
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() {
|
2015-01-06 13:22:54 -08:00
|
|
|
Rect clip(mState.currentClipRect());
|
2010-10-15 13:57:28 -07:00
|
|
|
clip.snapToPixelBoundaries();
|
2011-12-14 19:23:32 -08:00
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
|
2012-07-17 17:32:48 -07:00
|
|
|
clip.getWidth(), clip.getHeight())) {
|
2014-10-10 13:38:16 -04:00
|
|
|
mState.setDirtyClip(false);
|
2012-07-17 17:32:48 -07:00
|
|
|
}
|
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(
|
2015-02-05 10:12:38 -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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-06 13:22:54 -08:00
|
|
|
static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform,
|
|
|
|
float x, float y) {
|
|
|
|
Vertex v;
|
|
|
|
v.x = x;
|
|
|
|
v.y = y;
|
|
|
|
transform.mapPoint(v.x, v.y);
|
|
|
|
rectangleVertices.push_back(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) {
|
|
|
|
Vertex v;
|
|
|
|
v.x = x;
|
|
|
|
v.y = y;
|
|
|
|
rectangleVertices.push_back(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) {
|
|
|
|
int count = rectangleList.getTransformedRectanglesCount();
|
|
|
|
std::vector<Vertex> rectangleVertices(count * 4);
|
|
|
|
Rect scissorBox = rectangleList.calculateBounds();
|
|
|
|
scissorBox.snapToPixelBoundaries();
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i));
|
|
|
|
const Matrix4& transform = tr.getTransform();
|
|
|
|
Rect bounds = tr.getBounds();
|
|
|
|
if (transform.rectToRect()) {
|
|
|
|
transform.mapRect(bounds);
|
|
|
|
if (!bounds.intersect(scissorBox)) {
|
|
|
|
bounds.setEmpty();
|
|
|
|
} else {
|
|
|
|
handlePointNoTransform(rectangleVertices, bounds.left, bounds.top);
|
|
|
|
handlePointNoTransform(rectangleVertices, bounds.right, bounds.top);
|
|
|
|
handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom);
|
|
|
|
handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
handlePoint(rectangleVertices, transform, bounds.left, bounds.top);
|
|
|
|
handlePoint(rectangleVertices, transform, bounds.right, bounds.top);
|
|
|
|
handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom);
|
|
|
|
handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom,
|
2015-01-06 13:22:54 -08:00
|
|
|
scissorBox.getWidth(), scissorBox.getHeight());
|
|
|
|
|
|
|
|
const SkPaint* paint = nullptr;
|
|
|
|
setupDraw();
|
|
|
|
setupDrawNoTexture();
|
|
|
|
setupDrawColor(0, 0xff * currentSnapshot()->alpha);
|
|
|
|
setupDrawShader(getShader(paint));
|
|
|
|
setupDrawColorFilter(getColorFilter(paint));
|
|
|
|
setupDrawBlending(paint);
|
|
|
|
setupDrawProgram();
|
|
|
|
setupDrawDirtyRegionsDisabled();
|
|
|
|
setupDrawModelView(kModelViewMode_Translate, false,
|
|
|
|
0.0f, 0.0f, 0.0f, 0.0f, true);
|
|
|
|
setupDrawColorUniforms(getShader(paint));
|
|
|
|
setupDrawShaderUniforms(getShader(paint));
|
|
|
|
setupDrawColorFilterUniforms(getColorFilter(paint));
|
|
|
|
|
|
|
|
issueIndexedQuadDraw(&rectangleVertices[0], rectangleVertices.size() / 4);
|
|
|
|
}
|
|
|
|
|
2013-01-15 18:51:42 -08:00
|
|
|
void OpenGLRenderer::setStencilFromClip() {
|
|
|
|
if (!mCaches.debugOverdraw) {
|
2015-01-06 13:22:54 -08:00
|
|
|
if (!currentSnapshot()->clipIsSimple()) {
|
|
|
|
int incrementThreshold;
|
2014-07-29 10:35:13 -07:00
|
|
|
EVENT_LOGD("setStencilFromClip - enabling");
|
|
|
|
|
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
|
2014-10-10 13:38:16 -04:00
|
|
|
mState.setDirtyClip(false);
|
2013-01-15 18:51:42 -08:00
|
|
|
|
|
|
|
ensureStencilBuffer();
|
|
|
|
|
2015-01-06 13:22:54 -08:00
|
|
|
const ClipArea& clipArea = currentSnapshot()->getClipArea();
|
2013-01-15 18:51:42 -08:00
|
|
|
|
2015-01-06 13:22:54 -08:00
|
|
|
bool isRectangleList = clipArea.isRectangleList();
|
|
|
|
if (isRectangleList) {
|
|
|
|
incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount();
|
|
|
|
} else {
|
|
|
|
incrementThreshold = 0;
|
|
|
|
}
|
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.stencil().enableWrite(incrementThreshold);
|
2015-01-06 13:22:54 -08:00
|
|
|
|
|
|
|
// Clean and update the stencil, but first make sure we restrict drawing
|
2013-01-15 18:51:42 -08:00
|
|
|
// to the region's bounds
|
2015-01-26 18:06:29 -08:00
|
|
|
bool resetScissor = mRenderState.scissor().setEnabled(true);
|
2013-01-15 18:51:42 -08:00
|
|
|
if (resetScissor) {
|
|
|
|
// The scissor was not set so we now need to update it
|
|
|
|
setScissorFromClip();
|
|
|
|
}
|
2015-01-06 13:22:54 -08:00
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.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);
|
|
|
|
|
2015-01-06 13:22:54 -08:00
|
|
|
if (isRectangleList) {
|
|
|
|
drawRectangleList(clipArea.getRectangleList());
|
|
|
|
} else {
|
|
|
|
// 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.
|
2013-01-15 18:51:42 -08:00
|
|
|
|
2015-01-06 13:22:54 -08:00
|
|
|
// 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
|
|
|
|
drawRegionRects(clipArea.getClipRegion(), paint, false);
|
|
|
|
}
|
2015-01-26 18:06:29 -08:00
|
|
|
if (resetScissor) mRenderState.scissor().setEnabled(false);
|
2014-05-05 19:09:33 -07:00
|
|
|
mSkipOutlineClip = storedSkipOutlineClip;
|
2013-01-15 18:51:42 -08:00
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.stencil().enableTest(incrementThreshold);
|
2013-02-25 14:15:37 -08:00
|
|
|
|
|
|
|
// Draw the region used to generate the stencil if the appropriate debug
|
|
|
|
// mode is enabled
|
2015-01-06 13:22:54 -08:00
|
|
|
// TODO: Implement for rectangle list clip areas
|
|
|
|
if (mCaches.debugStencilClip == Caches::kStencilShowRegion &&
|
|
|
|
!clipArea.isRectangleList()) {
|
2013-12-10 12:28:58 -05:00
|
|
|
paint.setColor(0x7f0000ff);
|
|
|
|
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
|
2015-01-06 13:22:54 -08:00
|
|
|
drawRegionRects(currentSnapshot()->getClipRegion(), paint);
|
2013-02-25 14:15:37 -08:00
|
|
|
}
|
2013-01-15 18:51:42 -08:00
|
|
|
} else {
|
2014-07-29 10:35:13 -07:00
|
|
|
EVENT_LOGD("setStencilFromClip - disabling");
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.stencil().disable();
|
2013-01-15 18:51:42 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
|
2014-05-05 19:09:33 -07:00
|
|
|
&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
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
|
2014-06-26 15:46:20 -07:00
|
|
|
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
|
|
|
|
2015-02-05 10:12:38 -08:00
|
|
|
void OpenGLRenderer::renderGlop(const Glop& glop) {
|
|
|
|
if (mState.getDirtyClip()) {
|
|
|
|
if (mRenderState.scissor().isEnabled()) {
|
|
|
|
setScissorFromClip();
|
|
|
|
}
|
|
|
|
|
|
|
|
setStencilFromClip();
|
|
|
|
}
|
|
|
|
mRenderState.render(glop);
|
2015-02-06 15:25:51 -08:00
|
|
|
|
|
|
|
if (!mRenderState.stencil().isWriteEnabled()) {
|
|
|
|
// TODO: specify more clearly when a draw should dirty the layer.
|
|
|
|
// is writing to the stencil the only time we should ignore this?
|
|
|
|
dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
|
2015-02-11 13:17:06 -08:00
|
|
|
mDirty = true;
|
2015-02-06 15:25:51 -08:00
|
|
|
}
|
2015-02-05 10:12:38 -08:00
|
|
|
}
|
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Drawing commands
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-07-29 10:35:13 -07:00
|
|
|
void OpenGLRenderer::setupDraw(bool clearLayer) {
|
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
|
2014-07-29 10:35:13 -07:00
|
|
|
if (clearLayer) clearLayerRegions();
|
2013-01-15 18:51:42 -08:00
|
|
|
// Make sure setScissor & setStencil happen at the beginning of
|
|
|
|
// this method
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.getDirtyClip()) {
|
2015-01-26 18:06:29 -08:00
|
|
|
if (mRenderState.scissor().isEnabled()) {
|
2013-02-21 11:30:22 -08:00
|
|
|
setScissorFromClip();
|
|
|
|
}
|
2014-07-29 10:35:13 -07:00
|
|
|
|
2014-11-24 21:08:15 +09: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;
|
2015-02-11 13:17:06 -08:00
|
|
|
mColor.a = mColor.r = mColor.g = mColor.b = 0.0f;
|
2010-12-13 18:24:33 -08:00
|
|
|
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
|
2015-02-05 10:12:38 -08:00
|
|
|
mDescription.hasDebugHighlight = !mCaches.debugOverdraw
|
|
|
|
&& mCaches.debugStencilClip == Caches::kStencilShowHighlight
|
|
|
|
&& mRenderState.stencil().isTestEnabled();
|
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() {
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().disableTexCoordsVertexArray();
|
2011-12-13 13:11:32 -08:00
|
|
|
}
|
|
|
|
|
2014-08-12 14:31:35 -07:00
|
|
|
void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
|
|
|
|
mDescription.hasVertexAlpha = true;
|
|
|
|
mDescription.useShadowAlphaInterp = useShadowAlphaInterp;
|
2011-04-13 17:58:08 -07:00
|
|
|
}
|
|
|
|
|
2010-12-14 20:13:35 -08:00
|
|
|
void OpenGLRenderer::setupDrawColor(int color, int alpha) {
|
2015-02-11 13:17:06 -08:00
|
|
|
mColor.a = alpha / 255.0f;
|
|
|
|
mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
|
|
|
|
mColor.g = mColor.a * ((color >> 8) & 0xFF) / 255.0f;
|
|
|
|
mColor.b = mColor.a * ((color ) & 0xFF) / 255.0f;
|
2010-12-13 18:24:33 -08:00
|
|
|
mColorSet = true;
|
2015-02-11 13:17:06 -08:00
|
|
|
mSetShaderColor = mDescription.setColorModulate(mColor.a);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
2010-12-14 15:55:39 -08:00
|
|
|
void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
|
2015-02-11 13:17:06 -08:00
|
|
|
mColor.a = alpha / 255.0f;
|
|
|
|
mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
|
|
|
|
mColor.g = mColor.a * ((color >> 8) & 0xFF) / 255.0f;
|
|
|
|
mColor.b = mColor.a * ((color ) & 0xFF) / 255.0f;
|
2010-12-14 15:55:39 -08:00
|
|
|
mColorSet = true;
|
2015-02-11 13:17:06 -08:00
|
|
|
mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a);
|
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) {
|
2015-02-11 13:17:06 -08:00
|
|
|
mColor.a = a;
|
|
|
|
mColor.r = r;
|
|
|
|
mColor.g = g;
|
|
|
|
mColor.b = b;
|
2010-12-13 18:24:33 -08:00
|
|
|
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) {
|
2014-12-22 14:28:49 -08:00
|
|
|
if (shader != nullptr) {
|
2015-02-05 10:12:38 -08:00
|
|
|
SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
|
2014-12-22 14:28:49 -08:00
|
|
|
if (filter == nullptr) {
|
2013-12-10 12:28:58 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkXfermode::Mode mode;
|
2014-12-22 14:28:49 -08:00
|
|
|
if (filter->asColorMode(nullptr, &mode)) {
|
2013-12-10 12:28:58 -05:00
|
|
|
mDescription.colorOp = ProgramDescription::kColorBlend;
|
|
|
|
mDescription.colorMode = mode;
|
2014-12-22 14:28:49 -08:00
|
|
|
} else if (filter->asColorMatrix(nullptr)) {
|
2013-12-10 12:28:58 -05:00
|
|
|
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) {
|
2015-02-11 13:17:06 -08:00
|
|
|
mColor.a = 1.0f;
|
|
|
|
mColor.r = mColor.g = mColor.b = 0.0f;
|
2011-06-13 19:04:27 -07:00
|
|
|
mSetShaderColor = mDescription.modulate = true;
|
2011-05-27 11:43:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
2014-12-09 15:03:44 -05:00
|
|
|
bool blend = layer->isBlend()
|
|
|
|
|| getLayerAlpha(layer) < 1.0f
|
2015-02-11 13:17:06 -08:00
|
|
|
|| (mColorSet && mColor.a < 1.0f)
|
2014-12-09 15:03:44 -05:00
|
|
|
|| PaintUtils::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);
|
2015-02-11 13:17:06 -08:00
|
|
|
blend |= (mColorSet && mColor.a < 1.0f)
|
2015-02-02 18:39:33 -08:00
|
|
|
|| (getShader(paint) && !getShader(paint)->isOpaque())
|
|
|
|
|| PaintUtils::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() {
|
2015-02-02 13:50:55 -08:00
|
|
|
mCaches.setProgram(mDescription);
|
2014-05-05 19:09:33 -07:00
|
|
|
if (mDescription.hasRoundRectClip) {
|
|
|
|
// TODO: avoid doing this repeatedly, stashing state pointer in program
|
2014-10-10 13:38:16 -04:00
|
|
|
const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
|
2014-07-29 12:50:14 -07:00
|
|
|
const Rect& innerRect = state->innerRect;
|
2015-02-02 13:50:55 -08:00
|
|
|
glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"),
|
2014-07-29 12:50:14 -07:00
|
|
|
innerRect.left, innerRect.top,
|
|
|
|
innerRect.right, innerRect.bottom);
|
2015-02-02 13:50:55 -08:00
|
|
|
glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"),
|
2014-05-05 19:09:33 -07:00
|
|
|
1, GL_FALSE, &state->matrix.data[0]);
|
2014-09-11 18:58:45 -07:00
|
|
|
|
|
|
|
// add half pixel to round out integer rect space to cover pixel centers
|
|
|
|
float roundedOutRadius = state->radius + 0.5f;
|
2015-02-02 13:50:55 -08:00
|
|
|
glUniform1f(mCaches.program().getUniform("roundRectRadius"),
|
2014-09-11 18:58:45 -07:00
|
|
|
roundedOutRadius);
|
2014-05-05 19:09:33 -07:00
|
|
|
}
|
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();
|
2015-02-02 13:50:55 -08:00
|
|
|
|
|
|
|
mCaches.program().set(currentSnapshot()->getOrthoMatrix(),
|
2014-12-22 14:28:49 -08:00
|
|
|
mModelViewMatrix, transformMatrix, offset);
|
2014-05-14 14:17:01 -07:00
|
|
|
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)) {
|
2015-02-11 13:17:06 -08:00
|
|
|
mCaches.program().setColor(mColor);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-14 15:55:39 -08:00
|
|
|
void OpenGLRenderer::setupDrawPureColorUniforms() {
|
2010-12-14 10:59:41 -08:00
|
|
|
if (mSetShaderColor) {
|
2015-02-11 13:17:06 -08:00
|
|
|
mCaches.program().setColor(mColor);
|
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) {
|
2014-12-22 14:28:49 -08:00
|
|
|
if (shader == nullptr) {
|
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
|
|
|
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
|
|
|
|
2015-02-05 10:12:38 -08:00
|
|
|
SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
|
|
|
|
mCaches.extensions(), *shader);
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
|
2014-12-22 14:28:49 -08:00
|
|
|
if (nullptr == filter) {
|
2013-12-10 12:28:58 -05:00
|
|
|
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;
|
2015-02-02 13:50:55 -08:00
|
|
|
glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a);
|
2013-12-10 12:28:58 -05:00
|
|
|
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;
|
|
|
|
|
2015-02-02 13:50:55 -08:00
|
|
|
glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1,
|
2013-12-10 12:28:58 -05:00
|
|
|
GL_FALSE, colorMatrix);
|
2015-02-02 13:50:55 -08:00
|
|
|
glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector);
|
2013-12-10 12:28:58 -05:00
|
|
|
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() {
|
2015-02-02 13:50:55 -08:00
|
|
|
mCaches.fontRenderer->setupProgram(mDescription, mCaches.program());
|
2012-07-16 17:04:24 -07:00
|
|
|
}
|
|
|
|
|
2010-12-13 18:24:33 -08:00
|
|
|
void OpenGLRenderer::setupDrawSimpleMesh() {
|
2015-01-27 15:46:35 -08:00
|
|
|
bool force = mRenderState.meshState().bindMeshBuffer();
|
2015-02-02 13:50:55 -08:00
|
|
|
mRenderState.meshState().bindPositionVertexPointer(force, nullptr);
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().unbindIndicesBuffer();
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setupDrawTexture(GLuint texture) {
|
2015-01-29 09:45:09 -08:00
|
|
|
if (texture) mCaches.textureState().bindTexture(texture);
|
2011-12-13 22:00:19 -08:00
|
|
|
mTextureUnit++;
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().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) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
|
2011-12-13 22:00:19 -08:00
|
|
|
mTextureUnit++;
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().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) {
|
2015-02-02 13:50:55 -08:00
|
|
|
glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1,
|
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
|
|
|
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) {
|
2015-01-27 15:46:35 -08:00
|
|
|
force = mRenderState.meshState().bindMeshBuffer(vbo);
|
2010-12-13 18:24:33 -08:00
|
|
|
} else {
|
2015-01-27 15:46:35 -08:00
|
|
|
force = mRenderState.meshState().unbindMeshBuffer();
|
2010-12-13 18:24:33 -08:00
|
|
|
}
|
2011-12-12 19:03:35 -08:00
|
|
|
|
2015-02-02 13:50:55 -08:00
|
|
|
mRenderState.meshState().bindPositionVertexPointer(force, vertices);
|
|
|
|
if (mCaches.program().texCoords >= 0) {
|
|
|
|
mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
|
2011-12-13 13:11:32 -08:00
|
|
|
}
|
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().unbindIndicesBuffer();
|
2011-12-13 13:11:32 -08:00
|
|
|
}
|
|
|
|
|
2014-01-02 16:46:18 -08:00
|
|
|
void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
|
|
|
|
const GLvoid* texCoords, const GLvoid* colors) {
|
2015-01-27 15:46:35 -08:00
|
|
|
bool force = mRenderState.meshState().unbindMeshBuffer();
|
2013-02-13 18:39:43 -08:00
|
|
|
GLsizei stride = sizeof(ColorTextureVertex);
|
|
|
|
|
2015-02-02 13:50:55 -08:00
|
|
|
mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride);
|
|
|
|
if (mCaches.program().texCoords >= 0) {
|
|
|
|
mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride);
|
2013-02-13 18:39:43 -08:00
|
|
|
}
|
2015-02-02 13:50:55 -08:00
|
|
|
int slot = mCaches.program().getAttrib("colors");
|
2013-02-13 18:39:43 -08:00
|
|
|
if (slot >= 0) {
|
|
|
|
glEnableVertexAttribArray(slot);
|
|
|
|
glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
|
|
|
|
}
|
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().unbindIndicesBuffer();
|
2013-02-13 18:39:43 -08:00
|
|
|
}
|
|
|
|
|
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
|
2015-01-27 15:46:35 -08:00
|
|
|
// use the default VBO found in RenderState
|
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) {
|
2015-01-27 15:46:35 -08:00
|
|
|
force = mRenderState.meshState().bindMeshBuffer(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
|
|
|
} else {
|
2015-01-27 15:46:35 -08:00
|
|
|
force = mRenderState.meshState().unbindMeshBuffer();
|
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
|
|
|
}
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().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
|
|
|
|
2015-02-02 13:50:55 -08:00
|
|
|
mRenderState.meshState().bindPositionVertexPointer(force, vertices);
|
|
|
|
if (mCaches.program().texCoords >= 0) {
|
|
|
|
mRenderState.meshState().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) {
|
2015-01-27 15:46:35 -08:00
|
|
|
bool force = mRenderState.meshState().unbindMeshBuffer();
|
|
|
|
mRenderState.meshState().bindQuadIndicesBuffer();
|
2015-02-02 13:50:55 -08:00
|
|
|
mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride);
|
2011-04-13 17:58:08 -07:00
|
|
|
}
|
|
|
|
|
2010-06-23 17:47:49 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Drawing
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
|
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)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
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);
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2013-02-04 16:16:33 -08:00
|
|
|
}
|
|
|
|
|
2014-12-17 11:10:28 -08:00
|
|
|
// Don't avoid overdraw when visualizing, since that makes it harder to
|
|
|
|
// debug where it's coming from, and when the problem occurs.
|
|
|
|
bool avoidOverdraw = !mCaches.debugOverdraw;
|
2015-01-06 13:22:54 -08:00
|
|
|
DeferredDisplayList deferredList(mState.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();
|
2014-09-08 11:26:26 -04:00
|
|
|
startFrame();
|
2013-03-26 15:05:58 -07:00
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
deferredList.flush(*this, dirty);
|
|
|
|
} else {
|
|
|
|
// Even if there is no drawing command(Ex: invisible),
|
|
|
|
// it still needs startFrame to clear buffer and start tiling.
|
|
|
|
startFrame();
|
2010-11-08 12:08:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-11 13:17:06 -08:00
|
|
|
void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
|
|
|
|
if (USE_GLOPS && (!paint || !paint->getShader())) {
|
|
|
|
Glop glop;
|
|
|
|
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
|
|
|
|
aBuilder.setMeshTexturedUnitQuad(texture->uvMapper, true)
|
|
|
|
.setFillTexturePaint(*texture, true, paint, currentSnapshot()->alpha)
|
|
|
|
.setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
|
|
|
|
.setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
|
|
|
|
.setRoundRectClipState(currentSnapshot()->roundRectClipState)
|
|
|
|
.build();
|
|
|
|
renderGlop(glop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float x = 0;
|
|
|
|
float y = 0;
|
2011-03-18 16:50:13 -07:00
|
|
|
|
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()) {
|
2015-02-11 13:17:06 -08:00
|
|
|
x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
y = (int) floorf(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 {
|
2015-02-11 13:17:06 -08:00
|
|
|
texture->setFilter(PaintUtils::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,
|
2015-01-27 15:46:35 -08:00
|
|
|
paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
|
2015-02-05 10:12:38 -08:00
|
|
|
GL_TRIANGLE_STRIP, kUnitQuadCount, 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-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
|
2014-01-02 17:13:34 -08:00
|
|
|
int bitmapCount, TextureVertex* vertices, bool pureTranslate,
|
|
|
|
const Rect& bounds, const SkPaint* paint) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(0);
|
2013-06-27 15:27:09 -07:00
|
|
|
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
|
2014-09-08 11:26:26 -04:00
|
|
|
if (!texture) return;
|
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);
|
2015-02-11 13:17:06 -08:00
|
|
|
texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::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
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2013-03-04 10:19:31 -08:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
|
2014-08-06 13:42:24 -07:00
|
|
|
if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2010-07-12 20:20:03 -07:00
|
|
|
}
|
|
|
|
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(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);
|
2014-09-08 11:26:26 -04:00
|
|
|
if (!texture) return;
|
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)) {
|
2015-02-11 13:17:06 -08:00
|
|
|
drawAlphaBitmap(texture, paint);
|
2013-01-04 12:26:18 -08:00
|
|
|
} else {
|
2015-02-11 13:17:06 -08:00
|
|
|
drawTextureRect(texture, paint);
|
2013-01-04 12:26:18 -08:00
|
|
|
}
|
2012-05-31 15:21:51 -07:00
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2012-05-14 19:44:40 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
|
2014-01-02 17:13:34 -08:00
|
|
|
const float* vertices, const int* colors, const SkPaint* paint) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (!vertices || mState.currentlyIgnored()) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2011-01-20 19:09:30 -08:00
|
|
|
}
|
|
|
|
|
2013-06-13 14:39:01 -07:00
|
|
|
// TODO: use quickReject on bounds from vertices
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(true);
|
2013-06-13 14:39:01 -07:00
|
|
|
|
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-12-22 17:16:56 -08:00
|
|
|
std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[count]);
|
|
|
|
ColorTextureVertex* vertex = &mesh[0];
|
2013-02-13 18:39:43 -08:00
|
|
|
|
2014-12-22 17:16:56 -08:00
|
|
|
std::unique_ptr<int[]> tempColors;
|
2013-02-13 18:39:43 -08:00
|
|
|
if (!colors) {
|
|
|
|
uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
|
2014-12-22 17:16:56 -08:00
|
|
|
tempColors.reset(new int[colorsCount]);
|
|
|
|
memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
|
|
|
|
colors = tempColors.get();
|
2013-02-13 18:39:43 -08:00
|
|
|
}
|
2012-10-16 11:08:44 -07:00
|
|
|
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(0);
|
2014-12-10 16:47:36 -08:00
|
|
|
Texture* texture = mRenderState.assetAtlas().getEntryTexture(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
|
|
|
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)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2012-10-16 11:08:44 -07:00
|
|
|
}
|
|
|
|
|
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) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
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-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);
|
2015-02-11 13:17:06 -08:00
|
|
|
texture->setFilter(PaintUtils::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();
|
2015-02-05 10:12:38 -08:00
|
|
|
setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
|
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);
|
|
|
|
|
2015-02-02 13:50:55 -08:00
|
|
|
int slot = mCaches.program().getAttrib("colors");
|
2013-02-13 18:39:43 -08:00
|
|
|
if (slot >= 0) {
|
|
|
|
glDisableVertexAttribArray(slot);
|
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2011-01-20 19:09:30 -08:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void 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)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2010-07-12 20:20:03 -07:00
|
|
|
}
|
|
|
|
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(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);
|
2014-09-08 11:26:26 -04:00
|
|
|
if (!texture) return;
|
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
|
|
|
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().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;
|
|
|
|
|
2015-02-11 13:17:06 -08:00
|
|
|
texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
|
2013-01-04 12:26:18 -08:00
|
|
|
ignoreTransform = true;
|
2010-12-06 18:07:02 -08:00
|
|
|
} else {
|
2015-02-11 13:17:06 -08:00
|
|
|
texture->setFilter(PaintUtils::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,
|
2015-02-05 10:12:38 -08:00
|
|
|
GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
|
2013-01-04 12:26:18 -08:00
|
|
|
} 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,
|
2015-02-05 10:12:38 -08:00
|
|
|
GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
|
2013-01-04 12:26:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2010-06-29 21:05:21 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
|
2014-01-02 17:13:34 -08:00
|
|
|
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)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2013-06-11 16:19:24 -07:00
|
|
|
}
|
|
|
|
|
2014-12-10 16:47:36 -08:00
|
|
|
AssetAtlas::Entry* entry = mRenderState.assetAtlas().getEntry(bitmap);
|
2013-06-11 16:19:24 -07:00
|
|
|
const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
|
|
|
|
right - left, bottom - top, patch);
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
|
2012-07-16 12:41:17 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
|
2014-01-02 17:13:34 -08:00
|
|
|
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)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2010-07-12 20:20:03 -07:00
|
|
|
}
|
|
|
|
|
2012-02-01 16:10:55 -08:00
|
|
|
if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(0);
|
2013-05-24 16:19:19 -07:00
|
|
|
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
|
2014-09-08 11:26:26 -04:00
|
|
|
if (!texture) return;
|
2013-02-28 12:15:35 -08:00
|
|
|
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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
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-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
|
2014-01-02 17:13:34 -08:00
|
|
|
TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(0);
|
2013-06-20 18:30:28 -07:00
|
|
|
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
|
2014-09-08 11:26:26 -04:00
|
|
|
if (!texture) return;
|
2013-06-20 18:30:28 -07:00
|
|
|
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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2013-06-20 18:30:28 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
|
2014-08-11 16:00:44 -07:00
|
|
|
const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
|
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
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2012-10-01 13:50:37 -07:00
|
|
|
}
|
|
|
|
|
2015-02-11 13:17:06 -08:00
|
|
|
if (USE_GLOPS && !paint->getShader()) {
|
2015-02-05 10:12:38 -08:00
|
|
|
Glop glop;
|
|
|
|
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
|
|
|
|
bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
|
|
|
|
bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
|
|
|
|
aBuilder.setMeshVertexBuffer(vertexBuffer, shadowInterp)
|
2015-02-11 13:17:06 -08:00
|
|
|
.setFillPaint(*paint, currentSnapshot()->alpha)
|
|
|
|
.setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
|
2015-02-05 10:12:38 -08:00
|
|
|
.setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
|
2015-02-11 13:17:06 -08:00
|
|
|
.setRoundRectClipState(currentSnapshot()->roundRectClipState)
|
2015-02-05 10:12:38 -08:00
|
|
|
.build();
|
|
|
|
renderGlop(glop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
|
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();
|
2015-02-05 10:12:38 -08:00
|
|
|
bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
|
2012-12-10 17:56:27 -08:00
|
|
|
|
2012-09-17 17:25:49 -07:00
|
|
|
setupDraw();
|
|
|
|
setupDrawNoTexture();
|
2014-08-12 14:31:35 -07:00
|
|
|
if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
|
2015-02-05 10:12:38 -08:00
|
|
|
setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->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-08-11 16:00:44 -07:00
|
|
|
setupDrawModelView(kModelViewMode_Translate, (displayFlags & kVertexBuffer_Offset),
|
|
|
|
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();
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().unbindMeshBuffer();
|
2015-02-02 13:50:55 -08:00
|
|
|
mRenderState.meshState().bindPositionVertexPointer(true, vertices,
|
|
|
|
isAA ? kAlphaVertexStride : kVertexStride);
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().resetTexCoordsVertexPointer();
|
2014-02-14 13:13:41 -08:00
|
|
|
|
2012-09-17 17:25:49 -07:00
|
|
|
int alphaSlot = -1;
|
|
|
|
if (isAA) {
|
2015-01-27 15:46:35 -08:00
|
|
|
void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
|
2015-02-02 13:50:55 -08:00
|
|
|
alphaSlot = mCaches.program().getAttrib("vtxAlpha");
|
2012-09-17 17:25:49 -07:00
|
|
|
// TODO: avoid enable/disable in back to back uses of the alpha attribute
|
2012-08-31 18:24:33 -07:00
|
|
|
glEnableVertexAttribArray(alphaSlot);
|
2015-01-27 15:46:35 -08:00
|
|
|
glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
|
2012-09-17 17:25:49 -07:00
|
|
|
}
|
2012-08-31 18:24:33 -07:00
|
|
|
|
2015-02-05 10:12:38 -08:00
|
|
|
if (meshFeatureFlags & VertexBuffer::kIndices) {
|
2015-01-27 15:46:35 -08:00
|
|
|
mRenderState.meshState().unbindIndicesBuffer();
|
2014-12-22 14:28:49 -08:00
|
|
|
glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
|
|
|
|
GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
|
2015-02-05 10:12:38 -08:00
|
|
|
} else {
|
|
|
|
mRenderState.meshState().unbindIndicesBuffer();
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
|
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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
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-09-08 11:26:26 -04:00
|
|
|
void 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-09-08 11:26:26 -04:00
|
|
|
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-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored() || count < 4) return;
|
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)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2013-02-08 13:46:40 -08:00
|
|
|
}
|
|
|
|
|
2014-08-11 16:00:44 -07:00
|
|
|
int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
|
2014-09-08 11:26:26 -04:00
|
|
|
drawVertexBuffer(buffer, paint, displayFlags);
|
2011-04-13 17:58:08 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored() || count < 2) return;
|
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)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2011-03-21 13:11:28 -07:00
|
|
|
}
|
|
|
|
|
2014-08-11 16:00:44 -07:00
|
|
|
int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
|
2014-09-08 11:26:26 -04:00
|
|
|
drawVertexBuffer(buffer, paint, displayFlags);
|
|
|
|
|
|
|
|
mDirty = true;
|
2011-03-21 13:11:28 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void 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-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()) return;
|
2010-11-03 19:58:32 -07:00
|
|
|
|
2015-01-06 13:22:54 -08:00
|
|
|
Rect clip(mState.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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2010-06-25 13:41:57 -07:00
|
|
|
}
|
2010-06-24 19:30:36 -07:00
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* paint) {
|
2014-09-08 11:26:26 -04:00
|
|
|
if (!texture) return;
|
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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2011-01-19 21:54:02 -08:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void 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-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()
|
2014-08-19 10:21:12 -07:00
|
|
|
|| quickRejectSetupScissor(left, top, right, bottom, p)
|
2014-12-09 15:03:44 -05:00
|
|
|
|| PaintUtils::paintWillNotDraw(*p)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2012-09-17 17:25:49 -07:00
|
|
|
}
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
if (p->getPathEffect() != nullptr) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(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);
|
2014-09-08 11:26:26 -04:00
|
|
|
drawShape(left, top, texture, p);
|
|
|
|
} else {
|
|
|
|
const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
|
|
|
|
*currentTransform(), *p, right - left, bottom - top, rx, ry);
|
|
|
|
drawVertexBuffer(left, top, *vertexBuffer, p);
|
2012-09-17 17:25:49 -07:00
|
|
|
}
|
2011-01-23 14:18:41 -08:00
|
|
|
}
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()
|
2014-08-19 10:21:12 -07:00
|
|
|
|| quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
|
2014-12-09 15:03:44 -05:00
|
|
|
|| PaintUtils::paintWillNotDraw(*p)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2012-09-17 17:25:49 -07:00
|
|
|
}
|
2014-12-22 14:28:49 -08:00
|
|
|
if (p->getPathEffect() != nullptr) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(0);
|
2013-03-15 19:06:39 -07:00
|
|
|
const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
|
2014-09-08 11:26:26 -04:00
|
|
|
drawShape(x - radius, y - radius, texture, p);
|
2012-09-25 12:00:29 -07:00
|
|
|
} else {
|
2014-09-08 11:26:26 -04:00
|
|
|
SkPath path;
|
|
|
|
if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
|
|
|
|
path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
|
|
|
|
} else {
|
|
|
|
path.addCircle(x, y, radius);
|
|
|
|
}
|
|
|
|
drawConvexPath(path, p);
|
2012-09-25 12:00:29 -07:00
|
|
|
}
|
2011-01-23 14:18:41 -08:00
|
|
|
}
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* p) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()
|
2014-08-19 10:21:12 -07:00
|
|
|
|| quickRejectSetupScissor(left, top, right, bottom, p)
|
2014-12-09 15:03:44 -05:00
|
|
|
|| PaintUtils::paintWillNotDraw(*p)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2012-09-17 17:25:49 -07:00
|
|
|
}
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
if (p->getPathEffect() != nullptr) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(0);
|
2013-03-15 19:06:39 -07:00
|
|
|
const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
|
2014-09-08 11:26:26 -04:00
|
|
|
drawShape(left, top, texture, p);
|
|
|
|
} else {
|
|
|
|
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.addOval(rect);
|
|
|
|
drawConvexPath(path, p);
|
2012-09-25 12:00:29 -07:00
|
|
|
}
|
2011-01-23 14:18:41 -08:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void 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-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()
|
2014-08-19 10:21:12 -07:00
|
|
|
|| quickRejectSetupScissor(left, top, right, bottom, p)
|
2014-12-09 15:03:44 -05:00
|
|
|
|| PaintUtils::paintWillNotDraw(*p)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2012-10-04 14:10:49 -07:00
|
|
|
}
|
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)
|
2014-12-22 14:28:49 -08:00
|
|
|
if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(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);
|
2014-09-08 11:26:26 -04:00
|
|
|
drawShape(left, top, texture, p);
|
|
|
|
return;
|
2012-10-04 14:10:49 -07:00
|
|
|
}
|
|
|
|
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();
|
|
|
|
}
|
2014-09-08 11:26:26 -04:00
|
|
|
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-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPaint* p) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()
|
2014-08-19 10:21:12 -07:00
|
|
|
|| quickRejectSetupScissor(left, top, right, bottom, p)
|
2014-12-09 15:03:44 -05:00
|
|
|
|| PaintUtils::paintWillNotDraw(*p)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
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
|
2014-12-22 14:28:49 -08:00
|
|
|
if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
|
2012-10-02 12:32:25 -07:00
|
|
|
p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(0);
|
2012-10-02 12:32:25 -07:00
|
|
|
const PathTexture* texture =
|
2013-03-15 19:06:39 -07:00
|
|
|
mCaches.pathCache.getRect(right - left, bottom - top, p);
|
2014-09-08 11:26:26 -04:00
|
|
|
drawShape(left, top, texture, p);
|
|
|
|
} else {
|
|
|
|
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);
|
|
|
|
drawConvexPath(path, p);
|
2012-10-02 12:32:25 -07:00
|
|
|
}
|
2014-09-08 11:26:26 -04:00
|
|
|
} else {
|
|
|
|
if (p->isAntiAlias() && !currentTransform()->isSimple()) {
|
|
|
|
SkPath path;
|
|
|
|
path.addRect(left, top, right, bottom);
|
|
|
|
drawConvexPath(path, p);
|
|
|
|
} else {
|
|
|
|
drawColorRect(left, top, right, bottom, p);
|
2012-10-02 12:32:25 -07:00
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2012-10-02 12:32:25 -07:00
|
|
|
}
|
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) {
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(0);
|
2012-07-19 22:48:17 -07:00
|
|
|
|
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-10-10 13:38:16 -04:00
|
|
|
const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * writableSnapshot()->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));
|
2015-01-27 15:46:35 -08:00
|
|
|
setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
|
2012-07-19 22:48:17 -07:00
|
|
|
|
2015-02-05 10:12:38 -08:00
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
|
2012-07-19 22:48:17 -07:00
|
|
|
}
|
|
|
|
|
2013-02-27 13:50:45 -08:00
|
|
|
bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
|
2014-10-10 13:38:16 -04:00
|
|
|
float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
|
2014-12-09 15:03:44 -05:00
|
|
|
return MathUtils::isZero(alpha)
|
|
|
|
&& PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
|
2013-02-27 13:50:45 -08:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
|
2014-01-02 17:13:34 -08:00
|
|
|
const float* positions, const SkPaint* paint) {
|
2014-12-22 14:28:49 -08:00
|
|
|
if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
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()) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2012-01-18 12:39:17 -08:00
|
|
|
}
|
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(true);
|
2013-06-13 14:39:01 -07:00
|
|
|
|
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
|
|
|
|
2015-01-06 13:22:54 -08:00
|
|
|
const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
|
2012-01-18 12:39:17 -08:00
|
|
|
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);
|
2015-01-06 13:22:54 -08:00
|
|
|
if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
|
2014-12-22 14:28:49 -08:00
|
|
|
positions, hasActiveLayer ? &bounds : nullptr, &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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-08-04 13:18:38 -07:00
|
|
|
* Input is a non-perspective, scaling transform. Generate a scale-only transform,
|
|
|
|
* with values rounded to the nearest int.
|
2014-07-01 17:56:52 -07:00
|
|
|
*/
|
|
|
|
float sx, sy;
|
|
|
|
transform.decomposeScale(sx, sy);
|
2014-08-04 13:18:38 -07:00
|
|
|
outMatrix->setScale(
|
|
|
|
roundf(fmaxf(1.0f, sx)),
|
|
|
|
roundf(fmaxf(1.0f, sy)));
|
|
|
|
return true;
|
2013-03-05 16:43:31 -08:00
|
|
|
}
|
|
|
|
|
2014-10-10 13:38:16 -04:00
|
|
|
int OpenGLRenderer::getSaveCount() const {
|
|
|
|
return mState.getSaveCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
int OpenGLRenderer::save(int flags) {
|
|
|
|
return mState.save(flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::restore() {
|
|
|
|
return mState.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::restoreToCount(int saveCount) {
|
|
|
|
return mState.restoreToCount(saveCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::translate(float dx, float dy, float dz) {
|
|
|
|
return mState.translate(dx, dy, dz);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::rotate(float degrees) {
|
|
|
|
return mState.rotate(degrees);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::scale(float sx, float sy) {
|
|
|
|
return mState.scale(sx, sy);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::skew(float sx, float sy) {
|
|
|
|
return mState.skew(sx, sy);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setMatrix(const Matrix4& matrix) {
|
|
|
|
mState.setMatrix(matrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
|
|
|
|
mState.concatMatrix(matrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
|
|
|
|
return mState.clipRect(left, top, right, bottom, op);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
|
|
|
|
return mState.clipPath(path, op);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
|
|
|
|
return mState.clipRegion(region, op);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
|
|
|
|
mState.setClippingOutline(allocator, outline);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
|
|
|
|
const Rect& rect, float radius, bool highPriority) {
|
|
|
|
mState.setClippingRoundRect(allocator, rect, radius, highPriority);
|
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void 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-12-22 14:28:49 -08:00
|
|
|
if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
|
2013-11-19 18:00:46 -08:00
|
|
|
quickRejectSetupScissor(bounds)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2013-05-31 11:38:03 -07:00
|
|
|
}
|
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
|
2015-01-06 13:22:54 -08:00
|
|
|
const Rect* clip = !pureTranslate ? nullptr : &mState.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,
|
2014-12-22 14:28:49 -08:00
|
|
|
positions, hasActiveLayer ? &layerBounds : nullptr, &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,
|
2014-12-22 14:28:49 -08:00
|
|
|
positions, hasActiveLayer ? &layerBounds : nullptr, &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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2010-07-21 21:33:20 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
|
2014-01-02 17:13:34 -08:00
|
|
|
const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
|
2014-12-22 14:28:49 -08:00
|
|
|
if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
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
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(true);
|
2013-06-13 14:39:01 -07: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());
|
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
|
|
|
|
2014-10-10 13:38:16 -04:00
|
|
|
const Rect* clip = &writableSnapshot()->getLocalClip();
|
2012-02-28 18:17:02 -08:00
|
|
|
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,
|
2014-12-22 14:28:49 -08:00
|
|
|
hOffset, vOffset, hasActiveLayer ? &bounds : nullptr, &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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2012-02-24 16:48:34 -08:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()) return;
|
2010-10-11 17:58:29 -07:00
|
|
|
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(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);
|
2014-09-08 11:26:26 -04:00
|
|
|
if (!texture) return;
|
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);
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2010-08-04 15:40:07 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
|
2012-09-18 15:40:58 -07:00
|
|
|
if (!layer) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2011-01-11 14:29:25 -08:00
|
|
|
}
|
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
mat4* transform = nullptr;
|
2012-10-17 18:18:35 -07:00
|
|
|
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;
|
2014-12-22 14:28:49 -08:00
|
|
|
const bool rejected = mState.calculateQuickRejectForScissor(
|
|
|
|
x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
|
|
|
|
&clipRequired, nullptr, 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();
|
|
|
|
}
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2012-09-18 15:40:58 -07:00
|
|
|
}
|
|
|
|
|
2014-07-29 10:35:13 -07:00
|
|
|
EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
|
|
|
|
x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
|
|
|
|
|
2012-11-29 17:52:58 -08:00
|
|
|
updateLayer(layer, true);
|
2012-03-02 13:37:47 -08:00
|
|
|
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
|
2015-01-29 09:45:09 -08:00
|
|
|
mCaches.textureState().activateTexture(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) {
|
2015-01-27 15:46:35 -08:00
|
|
|
GLsizei drawCount = min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
|
2013-07-22 13:57:50 -07:00
|
|
|
|
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,
|
2014-12-22 14:28:49 -08:00
|
|
|
glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
|
2013-07-22 13:57:50 -07:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2011-01-11 14:29:25 -08:00
|
|
|
}
|
|
|
|
|
2012-01-23 17:09:05 -08:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Draw filters
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2014-10-15 09:21:10 -04:00
|
|
|
void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
|
|
|
|
// We should never get here since we apply the draw filter when stashing
|
|
|
|
// the paints in the DisplayList.
|
|
|
|
LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
|
2012-01-23 17:09:05 -08:00
|
|
|
}
|
|
|
|
|
2010-07-12 20:20:03 -07:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Drawing implementation
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-01-02 17:13:34 -08:00
|
|
|
Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
|
2014-12-10 16:47:36 -08:00
|
|
|
Texture* texture = mRenderState.assetAtlas().getEntryTexture(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
|
|
|
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));
|
2015-01-27 15:46:35 -08:00
|
|
|
setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
|
2011-01-19 21:54:02 -08:00
|
|
|
|
2015-02-05 10:12:38 -08:00
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
|
2011-01-19 21:54:02 -08:00
|
|
|
}
|
|
|
|
|
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-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2013-01-04 19:05:13 -08:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
drawColorRects(rects, count, paint, false, true, true);
|
2012-12-03 12:34:51 -08:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawShadow(float casterAlpha,
|
2014-06-02 16:27:04 -07:00
|
|
|
const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
|
2014-10-10 13:38:16 -04:00
|
|
|
if (mState.currentlyIgnored()) return;
|
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.
|
2015-01-26 18:06:29 -08:00
|
|
|
mRenderState.scissor().setEnabled(true);
|
2013-10-25 18:30:17 -07:00
|
|
|
|
|
|
|
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-08-13 10:44:39 -07:00
|
|
|
// The caller has made sure casterAlpha > 0.
|
|
|
|
float ambientShadowAlpha = mAmbientShadowAlpha;
|
|
|
|
if (CC_UNLIKELY(mCaches.propertyAmbientShadowStrength >= 0)) {
|
|
|
|
ambientShadowAlpha = mCaches.propertyAmbientShadowStrength;
|
|
|
|
}
|
|
|
|
if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
|
|
|
|
paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
|
2014-08-12 14:31:35 -07:00
|
|
|
drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
|
2014-02-13 17:09:45 -08:00
|
|
|
}
|
|
|
|
|
2014-08-13 10:44:39 -07:00
|
|
|
float spotShadowAlpha = mSpotShadowAlpha;
|
|
|
|
if (CC_UNLIKELY(mCaches.propertySpotShadowStrength >= 0)) {
|
|
|
|
spotShadowAlpha = mCaches.propertySpotShadowStrength;
|
|
|
|
}
|
|
|
|
if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
|
|
|
|
paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
|
2014-08-12 14:31:35 -07:00
|
|
|
drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
|
2014-02-13 17:09:45 -08:00
|
|
|
}
|
2014-01-07 10:42:55 -08:00
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty=true;
|
2013-10-25 18:30:17 -07:00
|
|
|
}
|
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
|
2013-12-10 12:28:58 -05:00
|
|
|
bool ignoreTransform, bool dirty, bool clip) {
|
2013-03-05 10:27:35 -08:00
|
|
|
if (count == 0) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2013-03-05 10:27:35 -08:00
|
|
|
}
|
2012-12-03 12:34:51 -08:00
|
|
|
|
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)) {
|
2014-09-08 11:26:26 -04:00
|
|
|
return;
|
2013-02-04 13:50:16 -08:00
|
|
|
}
|
2013-01-04 19:05:13 -08:00
|
|
|
|
2015-02-11 13:17:06 -08:00
|
|
|
if (USE_GLOPS && !paint->getShader()) {
|
2015-02-06 15:25:51 -08:00
|
|
|
const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
|
|
|
|
Glop glop;
|
|
|
|
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
|
|
|
|
aBuilder.setMeshIndexedQuads(&mesh[0], count / 4)
|
2015-02-11 13:17:06 -08:00
|
|
|
.setFillPaint(*paint, currentSnapshot()->alpha)
|
|
|
|
.setTransformClip(currentSnapshot()->getOrthoMatrix(), transform, false)
|
2015-02-06 15:25:51 -08:00
|
|
|
.setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
|
2015-02-11 13:17:06 -08:00
|
|
|
.setRoundRectClipState(currentSnapshot()->roundRectClipState)
|
2015-02-06 15:25:51 -08:00
|
|
|
.build();
|
|
|
|
renderGlop(glop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int color = paint->getColor();
|
|
|
|
// If a shader is set, preserve only the alpha
|
|
|
|
if (getShader(paint)) {
|
|
|
|
color |= 0x00ffffff;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2014-09-08 11:26:26 -04:00
|
|
|
mDirty = true;
|
2013-01-04 19:05:13 -08:00
|
|
|
}
|
|
|
|
|
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) {
|
2015-02-05 10:12:38 -08:00
|
|
|
|
2015-02-11 13:17:06 -08:00
|
|
|
if (USE_GLOPS && !paint->getShader()) {
|
2015-02-05 10:12:38 -08:00
|
|
|
const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
|
|
|
|
Glop glop;
|
|
|
|
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
|
|
|
|
aBuilder.setMeshUnitQuad()
|
2015-02-11 13:17:06 -08:00
|
|
|
.setFillPaint(*paint, currentSnapshot()->alpha)
|
|
|
|
.setTransformClip(currentSnapshot()->getOrthoMatrix(), transform, false)
|
2015-02-05 10:12:38 -08:00
|
|
|
.setModelViewMapUnitToRect(Rect(left, top, right, bottom))
|
2015-02-11 13:17:06 -08:00
|
|
|
.setRoundRectClipState(currentSnapshot()->roundRectClipState)
|
2015-02-05 10:12:38 -08:00
|
|
|
.build();
|
|
|
|
renderGlop(glop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-10 12:28:58 -05:00
|
|
|
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
|
|
|
|
2015-02-05 10:12:38 -08:00
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
|
2010-09-17 15:31:32 -07:00
|
|
|
}
|
|
|
|
|
2015-02-11 13:17:06 -08:00
|
|
|
void OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) {
|
|
|
|
if (USE_GLOPS) {
|
|
|
|
Glop glop;
|
|
|
|
GlopBuilder aBuilder(mRenderState, mCaches, &glop);
|
|
|
|
aBuilder.setMeshTexturedUnitQuad(texture->uvMapper, false)
|
|
|
|
.setFillTexturePaint(*texture, false, paint, currentSnapshot()->alpha)
|
|
|
|
.setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
|
|
|
|
.setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
|
|
|
|
.setRoundRectClipState(currentSnapshot()->roundRectClipState)
|
|
|
|
.build();
|
|
|
|
renderGlop(glop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-11-30 20:21:23 -08:00
|
|
|
texture->setWrap(GL_CLAMP_TO_EDGE, true);
|
2010-10-25 18:03:28 -07:00
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
GLvoid* vertices = (GLvoid*) nullptr;
|
2015-01-27 15:46:35 -08:00
|
|
|
GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
|
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 (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())) {
|
2015-02-11 13:17:06 -08:00
|
|
|
const float x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
|
|
|
|
const float y = (int) floorf(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,
|
2015-02-05 10:12:38 -08:00
|
|
|
GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
|
2010-12-06 18:07:02 -08:00
|
|
|
} else {
|
2015-02-11 13:17:06 -08:00
|
|
|
texture->setFilter(PaintUtils::getFilter(paint), true);
|
|
|
|
drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint,
|
2015-02-05 10:12:38 -08:00
|
|
|
texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
|
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 (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);
|
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, nullptr);
|
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-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
|
|
|
|
2014-12-22 14:28:49 -08:00
|
|
|
int color = paint != nullptr ? paint->getColor() : 0;
|
2013-12-10 12:28:58 -05:00
|
|
|
int alpha;
|
|
|
|
SkXfermode::Mode mode;
|
|
|
|
getAlphaAndMode(paint, &alpha, &mode);
|
|
|
|
|
2013-01-04 12:26:18 -08:00
|
|
|
setupDraw();
|
|
|
|
setupDrawWithTexture(true);
|
2014-12-22 14:28:49 -08:00
|
|
|
if (paint != nullptr) {
|
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
|
|
|
|
2015-02-05 10:12:38 -08:00
|
|
|
if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
|
2014-05-05 19:09:33 -07:00
|
|
|
blend = true;
|
|
|
|
mDescription.hasRoundRectClip = true;
|
|
|
|
}
|
|
|
|
mSkipOutlineClip = true;
|
|
|
|
|
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)) {
|
2015-02-05 10:12:38 -08:00
|
|
|
if (CC_UNLIKELY(mCaches.extensions().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
|
|
|
|
2015-01-29 09:45:09 -08:00
|
|
|
mRenderState.blend().disable();
|
2012-01-03 14:13:39 -08:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
mode = SkXfermode::kSrcOver_Mode;
|
2010-09-09 14:42:43 -07:00
|
|
|
}
|
2012-01-03 14:13:39 -08:00
|
|
|
}
|
2015-01-29 09:45:09 -08:00
|
|
|
mRenderState.blend().enable(mode, swapSrcDst);
|
|
|
|
} else {
|
|
|
|
mRenderState.blend().disable();
|
2010-07-09 13:25:56 -07:00
|
|
|
}
|
2010-06-26 00:13:53 -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-12-22 14:28:49 -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
|