Format the world (or just HWUI)
Test: No code changes, just ran through clang-format Change-Id: Id23aa4ec7eebc0446fe3a30260f33e7fd455bb8c
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
|
||||
// For the whole polygon, the sum of all the deltas b/t normals is 2 * M_PI,
|
||||
// therefore, the maximum number of extra vertices will be twice bigger.
|
||||
#define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
|
||||
#define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
|
||||
|
||||
// For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
|
||||
#define CORNER_RADIANS_DIVISOR (M_PI / EXTRA_CORNER_VERTEX_PER_PI)
|
||||
@@ -36,9 +36,9 @@
|
||||
*/
|
||||
#define EXTRA_EDGE_VERTEX_PER_PI 50
|
||||
|
||||
#define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
|
||||
#define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
|
||||
|
||||
#define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
|
||||
#define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
|
||||
|
||||
/**
|
||||
* Other constants:
|
||||
@@ -56,8 +56,8 @@
|
||||
#include "Vertex.h"
|
||||
#include "VertexBuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utils/Log.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
@@ -67,8 +67,8 @@ namespace uirenderer {
|
||||
*/
|
||||
inline Vector2 getNormalFromVertices(const Vector3* vertices, int current, int next) {
|
||||
// Convert from Vector3 to Vector2 first.
|
||||
Vector2 currentVertex = { vertices[current].x, vertices[current].y };
|
||||
Vector2 nextVertex = { vertices[next].x, vertices[next].y };
|
||||
Vector2 currentVertex = {vertices[current].x, vertices[current].y};
|
||||
Vector2 nextVertex = {vertices[next].x, vertices[next].y};
|
||||
|
||||
return ShadowTessellator::calculateNormal(currentVertex, nextVertex);
|
||||
}
|
||||
@@ -79,24 +79,24 @@ inline float getAlphaFromFactoredZ(float factoredZ) {
|
||||
return 1.0 / (1 + std::max(factoredZ, 0.0f));
|
||||
}
|
||||
|
||||
inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike,
|
||||
const Vector3& secondVertex, const Vector3& centroid) {
|
||||
Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
|
||||
inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike, const Vector3& secondVertex,
|
||||
const Vector3& centroid) {
|
||||
Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
|
||||
secondSpike.normalize();
|
||||
|
||||
int result = ShadowTessellator::getExtraVertexNumber(secondSpike, *currentSpike,
|
||||
EDGE_RADIANS_DIVISOR);
|
||||
EDGE_RADIANS_DIVISOR);
|
||||
*currentSpike = secondSpike;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Given the caster's vertex count, compute all the buffers size depending on
|
||||
// whether or not the caster is opaque.
|
||||
inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount,
|
||||
int* totalUmbraCount, int casterVertexCount, bool isCasterOpaque) {
|
||||
inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount, int* totalUmbraCount,
|
||||
int casterVertexCount, bool isCasterOpaque) {
|
||||
// Compute the size of the vertex buffer.
|
||||
int outerVertexCount = casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER +
|
||||
MAX_EXTRA_EDGE_VERTEX_NUMBER;
|
||||
int outerVertexCount =
|
||||
casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER + MAX_EXTRA_EDGE_VERTEX_NUMBER;
|
||||
int innerVertexCount = casterVertexCount + MAX_EXTRA_EDGE_VERTEX_NUMBER;
|
||||
*totalVertexCount = outerVertexCount + innerVertexCount;
|
||||
|
||||
@@ -163,44 +163,42 @@ inline bool needsExtraForEdge(float firstAlpha, float secondAlpha) {
|
||||
* | |
|
||||
* (V3)-----------------------------------(V2)
|
||||
*/
|
||||
void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
|
||||
float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
|
||||
void AmbientShadow::createAmbientShadow(bool isCasterOpaque, const Vector3* casterVertices,
|
||||
int casterVertexCount, const Vector3& centroid3d,
|
||||
float heightFactor, float geomFactor,
|
||||
VertexBuffer& shadowVertexBuffer) {
|
||||
shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
|
||||
|
||||
// In order to computer the outer vertices in one loop, we need pre-compute
|
||||
// the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
|
||||
// for vertex 0.
|
||||
Vector2 previousNormal = getNormalFromVertices(casterVertices,
|
||||
casterVertexCount - 1 , 0);
|
||||
Vector2 currentSpike = {casterVertices[0].x - centroid3d.x,
|
||||
casterVertices[0].y - centroid3d.y};
|
||||
Vector2 previousNormal = getNormalFromVertices(casterVertices, casterVertexCount - 1, 0);
|
||||
Vector2 currentSpike = {casterVertices[0].x - centroid3d.x, casterVertices[0].y - centroid3d.y};
|
||||
currentSpike.normalize();
|
||||
float currentAlpha = getAlphaFromFactoredZ(casterVertices[0].z * heightFactor);
|
||||
|
||||
// Preparing all the output data.
|
||||
int totalVertexCount, totalIndexCount, totalUmbraCount;
|
||||
computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount,
|
||||
casterVertexCount, isCasterOpaque);
|
||||
AlphaVertex* shadowVertices =
|
||||
shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
|
||||
computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount, casterVertexCount,
|
||||
isCasterOpaque);
|
||||
AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
|
||||
int vertexBufferIndex = 0;
|
||||
uint16_t* indexBuffer = shadowVertexBuffer.allocIndices<uint16_t>(totalIndexCount);
|
||||
int indexBufferIndex = 0;
|
||||
uint16_t umbraVertices[totalUmbraCount];
|
||||
int umbraIndex = 0;
|
||||
|
||||
for (int i = 0; i < casterVertexCount; i++) {
|
||||
for (int i = 0; i < casterVertexCount; i++) {
|
||||
// Corner: first figure out the extra vertices we need for the corner.
|
||||
const Vector3& innerVertex = casterVertices[i];
|
||||
Vector2 currentNormal = getNormalFromVertices(casterVertices, i,
|
||||
(i + 1) % casterVertexCount);
|
||||
Vector2 currentNormal =
|
||||
getNormalFromVertices(casterVertices, i, (i + 1) % casterVertexCount);
|
||||
|
||||
int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(currentNormal,
|
||||
previousNormal, CORNER_RADIANS_DIVISOR);
|
||||
int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(
|
||||
currentNormal, previousNormal, CORNER_RADIANS_DIVISOR);
|
||||
|
||||
float expansionDist = innerVertex.z * heightFactor * geomFactor;
|
||||
const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
|
||||
const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
|
||||
#if DEBUG_SHADOW
|
||||
ALOGD("cornerSlicesNumber is %d", cornerSlicesNumber);
|
||||
#endif
|
||||
@@ -212,9 +210,8 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
if (!isCasterOpaque) {
|
||||
umbraVertices[umbraIndex++] = vertexBufferIndex;
|
||||
}
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
|
||||
casterVertices[i].x, casterVertices[i].y,
|
||||
currentAlpha);
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], casterVertices[i].x,
|
||||
casterVertices[i].y, currentAlpha);
|
||||
|
||||
const Vector3& innerStart = casterVertices[i];
|
||||
|
||||
@@ -225,8 +222,7 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
// This will create vertices from [0, cornerSlicesNumber] inclusively,
|
||||
// which means minimally 2 vertices even without the extra ones.
|
||||
for (int j = 0; j <= cornerSlicesNumber; j++) {
|
||||
Vector2 averageNormal =
|
||||
previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
|
||||
Vector2 averageNormal = previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
|
||||
averageNormal /= cornerSlicesNumber;
|
||||
averageNormal.normalize();
|
||||
Vector2 outerVertex;
|
||||
@@ -235,8 +231,8 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
|
||||
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
|
||||
indexBuffer[indexBufferIndex++] = currentInnerVertexIndex;
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x,
|
||||
outerVertex.y, OUTER_ALPHA);
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x, outerVertex.y,
|
||||
OUTER_ALPHA);
|
||||
|
||||
if (j == 0) {
|
||||
outerStart = outerVertex;
|
||||
@@ -257,8 +253,8 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
outerNext.y = innerNext.y + currentNormal.y * expansionDist;
|
||||
|
||||
// Compute the angle and see how many extra points we need.
|
||||
int extraVerticesNumber = getEdgeExtraAndUpdateSpike(¤tSpike,
|
||||
innerNext, centroid3d);
|
||||
int extraVerticesNumber =
|
||||
getEdgeExtraAndUpdateSpike(¤tSpike, innerNext, centroid3d);
|
||||
#if DEBUG_SHADOW
|
||||
ALOGD("extraVerticesNumber %d for edge %d", extraVerticesNumber, i);
|
||||
#endif
|
||||
@@ -269,20 +265,20 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
for (int k = 1; k < extraVerticesNumber; k++) {
|
||||
int startWeight = extraVerticesNumber - k;
|
||||
Vector2 currentOuter =
|
||||
(outerLast * startWeight + outerNext * k) / extraVerticesNumber;
|
||||
(outerLast * startWeight + outerNext * k) / extraVerticesNumber;
|
||||
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentOuter.x,
|
||||
currentOuter.y, OUTER_ALPHA);
|
||||
currentOuter.y, OUTER_ALPHA);
|
||||
|
||||
if (!isCasterOpaque) {
|
||||
umbraVertices[umbraIndex++] = vertexBufferIndex;
|
||||
}
|
||||
Vector3 currentInner =
|
||||
(innerStart * startWeight + innerNext * k) / extraVerticesNumber;
|
||||
(innerStart * startWeight + innerNext * k) / extraVerticesNumber;
|
||||
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentInner.x,
|
||||
currentInner.y,
|
||||
getAlphaFromFactoredZ(currentInner.z * heightFactor));
|
||||
currentInner.y,
|
||||
getAlphaFromFactoredZ(currentInner.z * heightFactor));
|
||||
}
|
||||
}
|
||||
currentAlpha = nextAlpha;
|
||||
@@ -293,11 +289,10 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
|
||||
if (!isCasterOpaque) {
|
||||
// Add the centroid as the last one in the vertex buffer.
|
||||
float centroidOpacity =
|
||||
getAlphaFromFactoredZ(centroid3d.z * heightFactor);
|
||||
float centroidOpacity = getAlphaFromFactoredZ(centroid3d.z * heightFactor);
|
||||
int centroidIndex = vertexBufferIndex;
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x,
|
||||
centroid3d.y, centroidOpacity);
|
||||
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x, centroid3d.y,
|
||||
centroidOpacity);
|
||||
|
||||
for (int i = 0; i < umbraIndex; i++) {
|
||||
// Note that umbraVertices[0] is always 0.
|
||||
@@ -322,7 +317,7 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
#if DEBUG_SHADOW
|
||||
for (int i = 0; i < vertexBufferIndex; i++) {
|
||||
ALOGD("vertexBuffer i %d, (%f, %f %f)", i, shadowVertices[i].x, shadowVertices[i].y,
|
||||
shadowVertices[i].alpha);
|
||||
shadowVertices[i].alpha);
|
||||
}
|
||||
for (int i = 0; i < indexBufferIndex; i++) {
|
||||
ALOGD("indexBuffer i %d, indexBuffer[i] %d", i, indexBuffer[i]);
|
||||
@@ -330,5 +325,5 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
|
||||
#endif
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -31,12 +31,12 @@ class VertexBuffer;
|
||||
*/
|
||||
class AmbientShadow {
|
||||
public:
|
||||
static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly,
|
||||
int polyLength, const Vector3& centroid3d, float heightFactor,
|
||||
float geomFactor, VertexBuffer& shadowVertexBuffer);
|
||||
}; // AmbientShadow
|
||||
static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly, int polyLength,
|
||||
const Vector3& centroid3d, float heightFactor, float geomFactor,
|
||||
VertexBuffer& shadowVertexBuffer);
|
||||
}; // AmbientShadow
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_AMBIENT_SHADOW_H
|
||||
#endif // ANDROID_HWUI_AMBIENT_SHADOW_H
|
||||
|
||||
@@ -26,11 +26,9 @@ AnimationContext::AnimationContext(renderthread::TimeLord& clock)
|
||||
: mClock(clock)
|
||||
, mCurrentFrameAnimations(*this)
|
||||
, mNextFrameAnimations(*this)
|
||||
, mFrameTimeMs(0) {
|
||||
}
|
||||
, mFrameTimeMs(0) {}
|
||||
|
||||
AnimationContext::~AnimationContext() {
|
||||
}
|
||||
AnimationContext::~AnimationContext() {}
|
||||
|
||||
void AnimationContext::destroy() {
|
||||
startFrame(TreeInfo::MODE_RT_ONLY);
|
||||
@@ -39,7 +37,7 @@ void AnimationContext::destroy() {
|
||||
AnimatorManager& animators = current->mRenderNode->animators();
|
||||
animators.endAllActiveAnimators();
|
||||
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current,
|
||||
"endAllAnimators failed to remove from current frame list!");
|
||||
"endAllAnimators failed to remove from current frame list!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +54,7 @@ void AnimationContext::addAnimationHandle(AnimationHandle* handle) {
|
||||
|
||||
void AnimationContext::startFrame(TreeInfo::TraversalMode mode) {
|
||||
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle,
|
||||
"Missed running animations last frame!");
|
||||
"Missed running animations last frame!");
|
||||
AnimationHandle* head = mNextFrameAnimations.mNextHandle;
|
||||
if (head) {
|
||||
mNextFrameAnimations.mNextHandle = nullptr;
|
||||
@@ -73,20 +71,17 @@ void AnimationContext::runRemainingAnimations(TreeInfo& info) {
|
||||
animators.pushStaging();
|
||||
animators.animateNoDamage(info);
|
||||
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current,
|
||||
"Animate failed to remove from current frame list!");
|
||||
"Animate failed to remove from current frame list!");
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationContext::callOnFinished(BaseRenderNodeAnimator* animator,
|
||||
AnimationListener* listener) {
|
||||
AnimationListener* listener) {
|
||||
listener->onAnimationFinished(animator);
|
||||
}
|
||||
|
||||
AnimationHandle::AnimationHandle(AnimationContext& context)
|
||||
: mContext(context)
|
||||
, mPreviousHandle(nullptr)
|
||||
, mNextHandle(nullptr) {
|
||||
}
|
||||
: mContext(context), mPreviousHandle(nullptr), mNextHandle(nullptr) {}
|
||||
|
||||
AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& context)
|
||||
: mRenderNode(&animatingNode)
|
||||
@@ -98,7 +93,7 @@ AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& co
|
||||
|
||||
AnimationHandle::~AnimationHandle() {
|
||||
LOG_ALWAYS_FATAL_IF(mPreviousHandle || mNextHandle,
|
||||
"AnimationHandle destroyed while still animating!");
|
||||
"AnimationHandle destroyed while still animating!");
|
||||
}
|
||||
|
||||
void AnimationHandle::notifyAnimationsRan() {
|
||||
@@ -112,7 +107,7 @@ void AnimationHandle::notifyAnimationsRan() {
|
||||
|
||||
void AnimationHandle::release() {
|
||||
LOG_ALWAYS_FATAL_IF(mRenderNode->animators().hasAnimators(),
|
||||
"Releasing the handle for an RenderNode with outstanding animators!");
|
||||
"Releasing the handle for an RenderNode with outstanding animators!");
|
||||
removeFromList();
|
||||
mRenderNode->animators().setAnimationHandle(nullptr);
|
||||
delete this;
|
||||
|
||||
@@ -43,6 +43,7 @@ class RenderNode;
|
||||
*/
|
||||
class AnimationHandle {
|
||||
PREVENT_COPY_AND_ASSIGN(AnimationHandle);
|
||||
|
||||
public:
|
||||
AnimationContext& context() { return mContext; }
|
||||
|
||||
@@ -74,14 +75,14 @@ private:
|
||||
|
||||
class AnimationContext {
|
||||
PREVENT_COPY_AND_ASSIGN(AnimationContext);
|
||||
|
||||
public:
|
||||
ANDROID_API explicit AnimationContext(renderthread::TimeLord& clock);
|
||||
ANDROID_API virtual ~AnimationContext();
|
||||
|
||||
nsecs_t frameTimeMs() { return mFrameTimeMs; }
|
||||
bool hasAnimations() {
|
||||
return mCurrentFrameAnimations.mNextHandle
|
||||
|| mNextFrameAnimations.mNextHandle;
|
||||
return mCurrentFrameAnimations.mNextHandle || mNextFrameAnimations.mNextHandle;
|
||||
}
|
||||
|
||||
// Will always add to the next frame list, which is swapped when
|
||||
@@ -96,7 +97,8 @@ public:
|
||||
// as part of the standard RenderNode:prepareTree pass.
|
||||
ANDROID_API virtual void runRemainingAnimations(TreeInfo& info);
|
||||
|
||||
ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener);
|
||||
ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator,
|
||||
AnimationListener* listener);
|
||||
|
||||
ANDROID_API virtual void destroy();
|
||||
|
||||
|
||||
@@ -44,16 +44,14 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
|
||||
, mDuration(300)
|
||||
, mStartDelay(0)
|
||||
, mMayRunAsync(true)
|
||||
, mPlayTime(0) {
|
||||
}
|
||||
, mPlayTime(0) {}
|
||||
|
||||
BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
|
||||
}
|
||||
BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {}
|
||||
|
||||
void BaseRenderNodeAnimator::checkMutable() {
|
||||
// Should be impossible to hit as the Java-side also has guards for this
|
||||
LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
|
||||
"Animator has already been started!");
|
||||
"Animator has already been started!");
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
|
||||
@@ -119,34 +117,36 @@ void BaseRenderNodeAnimator::end() {
|
||||
|
||||
void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
|
||||
switch (request) {
|
||||
case Request::Start:
|
||||
mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
|
||||
mPlayTime : 0;
|
||||
mPlayState = PlayState::Running;
|
||||
mPendingActionUponFinish = Action::None;
|
||||
break;
|
||||
case Request::Reverse:
|
||||
mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
|
||||
mPlayTime : mDuration;
|
||||
mPlayState = PlayState::Reversing;
|
||||
mPendingActionUponFinish = Action::None;
|
||||
break;
|
||||
case Request::Reset:
|
||||
mPlayTime = 0;
|
||||
mPlayState = PlayState::Finished;
|
||||
mPendingActionUponFinish = Action::Reset;
|
||||
break;
|
||||
case Request::Cancel:
|
||||
mPlayState = PlayState::Finished;
|
||||
mPendingActionUponFinish = Action::None;
|
||||
break;
|
||||
case Request::End:
|
||||
mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
|
||||
mPlayState = PlayState::Finished;
|
||||
mPendingActionUponFinish = Action::End;
|
||||
break;
|
||||
default:
|
||||
LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
|
||||
case Request::Start:
|
||||
mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
|
||||
? mPlayTime
|
||||
: 0;
|
||||
mPlayState = PlayState::Running;
|
||||
mPendingActionUponFinish = Action::None;
|
||||
break;
|
||||
case Request::Reverse:
|
||||
mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
|
||||
? mPlayTime
|
||||
: mDuration;
|
||||
mPlayState = PlayState::Reversing;
|
||||
mPendingActionUponFinish = Action::None;
|
||||
break;
|
||||
case Request::Reset:
|
||||
mPlayTime = 0;
|
||||
mPlayState = PlayState::Finished;
|
||||
mPendingActionUponFinish = Action::Reset;
|
||||
break;
|
||||
case Request::Cancel:
|
||||
mPlayState = PlayState::Finished;
|
||||
mPendingActionUponFinish = Action::None;
|
||||
break;
|
||||
case Request::End:
|
||||
mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
|
||||
mPlayState = PlayState::Finished;
|
||||
mPendingActionUponFinish = Action::End;
|
||||
break;
|
||||
default:
|
||||
LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -182,8 +182,8 @@ void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
|
||||
|
||||
if (mStagingPlayState == PlayState::Finished) {
|
||||
callOnFinishedListener(context);
|
||||
} else if (mStagingPlayState == PlayState::Running
|
||||
|| mStagingPlayState == PlayState::Reversing) {
|
||||
} else if (mStagingPlayState == PlayState::Running ||
|
||||
mStagingPlayState == PlayState::Reversing) {
|
||||
bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
|
||||
if (prevFramePlayState != mStagingPlayState) {
|
||||
transitionToRunning(context);
|
||||
@@ -197,7 +197,7 @@ void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
|
||||
if (mPlayState == PlayState::Reversing) {
|
||||
// Reverse is not supported for animations with a start delay, so here we
|
||||
// assume no start delay.
|
||||
mStartTime = currentFrameTime - (mDuration - mPlayTime);
|
||||
mStartTime = currentFrameTime - (mDuration - mPlayTime);
|
||||
} else {
|
||||
// Animation should play forward
|
||||
if (mPlayTime == 0) {
|
||||
@@ -223,9 +223,9 @@ void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
|
||||
}
|
||||
mStartTime = frameTimeMs + mStartDelay;
|
||||
if (mStartTime < 0) {
|
||||
ALOGW("Ended up with a really weird start time of %" PRId64
|
||||
" with frame time %" PRId64 " and start delay %" PRId64,
|
||||
mStartTime, frameTimeMs, mStartDelay);
|
||||
ALOGW("Ended up with a really weird start time of %" PRId64 " with frame time %" PRId64
|
||||
" and start delay %" PRId64,
|
||||
mStartTime, frameTimeMs, mStartDelay);
|
||||
// Set to 0 so that the animate() basically instantly finishes
|
||||
mStartTime = 0;
|
||||
}
|
||||
@@ -247,7 +247,7 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
|
||||
updatePlayTime(mDuration);
|
||||
}
|
||||
// Reset pending action.
|
||||
mPendingActionUponFinish = Action ::None;
|
||||
mPendingActionUponFinish = Action::None;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
|
||||
|
||||
float fraction = 1.0f;
|
||||
if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
|
||||
fraction = mPlayTime / (float) mDuration;
|
||||
fraction = mPlayTime / (float)mDuration;
|
||||
}
|
||||
fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
|
||||
|
||||
@@ -308,35 +308,35 @@ void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
|
||||
************************************************************/
|
||||
|
||||
struct RenderPropertyAnimator::PropertyAccessors {
|
||||
RenderNode::DirtyPropertyMask dirtyMask;
|
||||
GetFloatProperty getter;
|
||||
SetFloatProperty setter;
|
||||
RenderNode::DirtyPropertyMask dirtyMask;
|
||||
GetFloatProperty getter;
|
||||
SetFloatProperty setter;
|
||||
};
|
||||
|
||||
// Maps RenderProperty enum to accessors
|
||||
const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
|
||||
{RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
|
||||
{RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
|
||||
{RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
|
||||
{RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
|
||||
{RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
|
||||
{RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
|
||||
{RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
|
||||
{RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
|
||||
{RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
|
||||
{RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
|
||||
{RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
|
||||
{RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
|
||||
{RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX,
|
||||
&RenderProperties::setTranslationX},
|
||||
{RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY,
|
||||
&RenderProperties::setTranslationY},
|
||||
{RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ,
|
||||
&RenderProperties::setTranslationZ},
|
||||
{RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX},
|
||||
{RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY},
|
||||
{RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation},
|
||||
{RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX},
|
||||
{RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY},
|
||||
{RenderNode::X, &RenderProperties::getX, &RenderProperties::setX},
|
||||
{RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY},
|
||||
{RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ},
|
||||
{RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha},
|
||||
};
|
||||
|
||||
RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
|
||||
: BaseRenderNodeAnimator(finalValue)
|
||||
, mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
|
||||
}
|
||||
: BaseRenderNodeAnimator(finalValue), mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {}
|
||||
|
||||
void RenderPropertyAnimator::onAttached() {
|
||||
if (!mHasStartValue
|
||||
&& mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
|
||||
if (!mHasStartValue && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
|
||||
setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
|
||||
}
|
||||
}
|
||||
@@ -385,11 +385,9 @@ void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
|
||||
* CanvasPropertyPrimitiveAnimator
|
||||
************************************************************/
|
||||
|
||||
CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
|
||||
CanvasPropertyPrimitive* property, float finalValue)
|
||||
: BaseRenderNodeAnimator(finalValue)
|
||||
, mProperty(property) {
|
||||
}
|
||||
CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
|
||||
float finalValue)
|
||||
: BaseRenderNodeAnimator(finalValue), mProperty(property) {}
|
||||
|
||||
float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
|
||||
return mProperty->value;
|
||||
@@ -407,50 +405,44 @@ uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
|
||||
* CanvasPropertySkPaintAnimator
|
||||
************************************************************/
|
||||
|
||||
CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
|
||||
CanvasPropertyPaint* property, PaintField field, float finalValue)
|
||||
: BaseRenderNodeAnimator(finalValue)
|
||||
, mProperty(property)
|
||||
, mField(field) {
|
||||
}
|
||||
CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
|
||||
PaintField field, float finalValue)
|
||||
: BaseRenderNodeAnimator(finalValue), mProperty(property), mField(field) {}
|
||||
|
||||
float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
|
||||
switch (mField) {
|
||||
case STROKE_WIDTH:
|
||||
return mProperty->value.getStrokeWidth();
|
||||
case ALPHA:
|
||||
return mProperty->value.getAlpha();
|
||||
case STROKE_WIDTH:
|
||||
return mProperty->value.getStrokeWidth();
|
||||
case ALPHA:
|
||||
return mProperty->value.getAlpha();
|
||||
}
|
||||
LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
|
||||
LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint8_t to_uint8(float value) {
|
||||
int c = (int) (value + .5f);
|
||||
return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
|
||||
int c = (int)(value + .5f);
|
||||
return static_cast<uint8_t>(c < 0 ? 0 : c > 255 ? 255 : c);
|
||||
}
|
||||
|
||||
void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
|
||||
switch (mField) {
|
||||
case STROKE_WIDTH:
|
||||
mProperty->value.setStrokeWidth(value);
|
||||
return;
|
||||
case ALPHA:
|
||||
mProperty->value.setAlpha(to_uint8(value));
|
||||
return;
|
||||
case STROKE_WIDTH:
|
||||
mProperty->value.setStrokeWidth(value);
|
||||
return;
|
||||
case ALPHA:
|
||||
mProperty->value.setAlpha(to_uint8(value));
|
||||
return;
|
||||
}
|
||||
LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
|
||||
LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
|
||||
}
|
||||
|
||||
uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
|
||||
return RenderNode::DISPLAY_LIST;
|
||||
}
|
||||
|
||||
RevealAnimator::RevealAnimator(int centerX, int centerY,
|
||||
float startValue, float finalValue)
|
||||
: BaseRenderNodeAnimator(finalValue)
|
||||
, mCenterX(centerX)
|
||||
, mCenterY(centerY) {
|
||||
RevealAnimator::RevealAnimator(int centerX, int centerY, float startValue, float finalValue)
|
||||
: BaseRenderNodeAnimator(finalValue), mCenterX(centerX), mCenterY(centerY) {
|
||||
setStartValue(startValue);
|
||||
}
|
||||
|
||||
@@ -459,8 +451,7 @@ float RevealAnimator::getValue(RenderNode* target) const {
|
||||
}
|
||||
|
||||
void RevealAnimator::setValue(RenderNode* target, float value) {
|
||||
target->animatorProperties().mutableRevealClip().set(true,
|
||||
mCenterX, mCenterY, value);
|
||||
target->animatorProperties().mutableRevealClip().set(true, mCenterX, mCenterY, value);
|
||||
}
|
||||
|
||||
uint32_t RevealAnimator::dirtyMask() {
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
#ifndef ANIMATOR_H
|
||||
#define ANIMATOR_H
|
||||
|
||||
#include <memory>
|
||||
#include <cutils/compiler.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/StrongPointer.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <memory>
|
||||
|
||||
#include "utils/Macros.h"
|
||||
|
||||
@@ -40,6 +40,7 @@ class RenderProperties;
|
||||
class AnimationListener : public VirtualLightRefBase {
|
||||
public:
|
||||
ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
|
||||
|
||||
protected:
|
||||
ANDROID_API virtual ~AnimationListener() {}
|
||||
};
|
||||
@@ -52,6 +53,7 @@ enum class RepeatMode {
|
||||
|
||||
class BaseRenderNodeAnimator : public VirtualLightRefBase {
|
||||
PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
|
||||
|
||||
public:
|
||||
ANDROID_API void setStartValue(float value);
|
||||
ANDROID_API void setInterpolator(Interpolator* interpolator);
|
||||
@@ -59,13 +61,9 @@ public:
|
||||
ANDROID_API nsecs_t duration() { return mDuration; }
|
||||
ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
|
||||
ANDROID_API nsecs_t startDelay() { return mStartDelay; }
|
||||
ANDROID_API void setListener(AnimationListener* listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
ANDROID_API void setListener(AnimationListener* listener) { mListener = listener; }
|
||||
AnimationListener* listener() { return mListener.get(); }
|
||||
ANDROID_API void setAllowRunningAsync(bool mayRunAsync) {
|
||||
mMayRunAsync = mayRunAsync;
|
||||
}
|
||||
ANDROID_API void setAllowRunningAsync(bool mayRunAsync) { mMayRunAsync = mayRunAsync; }
|
||||
bool mayRunAsync() { return mMayRunAsync; }
|
||||
ANDROID_API void start();
|
||||
ANDROID_API virtual void reset();
|
||||
@@ -86,8 +84,9 @@ public:
|
||||
// an animation on RenderThread.
|
||||
ANDROID_API nsecs_t getRemainingPlayTime();
|
||||
|
||||
bool isRunning() { return mPlayState == PlayState::Running
|
||||
|| mPlayState == PlayState::Reversing; }
|
||||
bool isRunning() {
|
||||
return mPlayState == PlayState::Running || mPlayState == PlayState::Reversing;
|
||||
}
|
||||
bool isFinished() { return mPlayState == PlayState::Finished; }
|
||||
float finalValue() { return mFinalValue; }
|
||||
|
||||
@@ -158,13 +157,7 @@ protected:
|
||||
sp<AnimationListener> mListener;
|
||||
|
||||
private:
|
||||
enum class Request {
|
||||
Start,
|
||||
Reverse,
|
||||
Reset,
|
||||
Cancel,
|
||||
End
|
||||
};
|
||||
enum class Request { Start, Reverse, Reset, Cancel, End };
|
||||
|
||||
// Defines different actions upon finish.
|
||||
enum class Action {
|
||||
@@ -229,13 +222,14 @@ private:
|
||||
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
|
||||
public:
|
||||
ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
|
||||
float finalValue);
|
||||
float finalValue);
|
||||
|
||||
ANDROID_API virtual uint32_t dirtyMask();
|
||||
|
||||
protected:
|
||||
virtual float getValue(RenderNode* target) const override;
|
||||
virtual void setValue(RenderNode* target, float value) override;
|
||||
|
||||
private:
|
||||
sp<CanvasPropertyPrimitive> mProperty;
|
||||
};
|
||||
@@ -247,14 +241,15 @@ public:
|
||||
ALPHA,
|
||||
};
|
||||
|
||||
ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
|
||||
PaintField field, float finalValue);
|
||||
ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, PaintField field,
|
||||
float finalValue);
|
||||
|
||||
ANDROID_API virtual uint32_t dirtyMask();
|
||||
|
||||
protected:
|
||||
virtual float getValue(RenderNode* target) const override;
|
||||
virtual void setValue(RenderNode* target, float value) override;
|
||||
|
||||
private:
|
||||
sp<CanvasPropertyPaint> mProperty;
|
||||
PaintField mField;
|
||||
@@ -262,8 +257,7 @@ private:
|
||||
|
||||
class RevealAnimator : public BaseRenderNodeAnimator {
|
||||
public:
|
||||
ANDROID_API RevealAnimator(int centerX, int centerY,
|
||||
float startValue, float finalValue);
|
||||
ANDROID_API RevealAnimator(int centerX, int centerY, float startValue, float finalValue);
|
||||
|
||||
ANDROID_API virtual uint32_t dirtyMask();
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Animator.h"
|
||||
#include "AnimationContext.h"
|
||||
#include "Animator.h"
|
||||
#include "DamageAccumulator.h"
|
||||
#include "RenderNode.h"
|
||||
|
||||
@@ -31,10 +31,7 @@ static void detach(sp<BaseRenderNodeAnimator>& animator) {
|
||||
animator->detach();
|
||||
}
|
||||
|
||||
AnimatorManager::AnimatorManager(RenderNode& parent)
|
||||
: mParent(parent)
|
||||
, mAnimationHandle(nullptr) {
|
||||
}
|
||||
AnimatorManager::AnimatorManager(RenderNode& parent) : mParent(parent), mAnimationHandle(nullptr) {}
|
||||
|
||||
AnimatorManager::~AnimatorManager() {
|
||||
for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
|
||||
@@ -58,22 +55,22 @@ void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
|
||||
|
||||
void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
|
||||
mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
|
||||
mNewAnimators.end());
|
||||
mNewAnimators.end());
|
||||
}
|
||||
|
||||
void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
|
||||
LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
|
||||
mAnimationHandle = handle;
|
||||
LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(),
|
||||
"Lost animation handle on %p (%s) with outstanding animators!",
|
||||
&mParent, mParent.getName());
|
||||
"Lost animation handle on %p (%s) with outstanding animators!", &mParent,
|
||||
mParent.getName());
|
||||
}
|
||||
|
||||
void AnimatorManager::pushStaging() {
|
||||
if (mNewAnimators.size()) {
|
||||
if (CC_UNLIKELY(!mAnimationHandle)) {
|
||||
ALOGW("Trying to start new animators on %p (%s) without an animation handle!",
|
||||
&mParent, mParent.getName());
|
||||
ALOGW("Trying to start new animators on %p (%s) without an animation handle!", &mParent,
|
||||
mParent.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,7 +97,7 @@ public:
|
||||
AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
|
||||
: mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
|
||||
|
||||
bool operator() (sp<BaseRenderNodeAnimator>& animator) {
|
||||
bool operator()(sp<BaseRenderNodeAnimator>& animator) {
|
||||
*mDirtyMask |= animator->dirtyMask();
|
||||
bool remove = animator->animate(mContext);
|
||||
if (remove) {
|
||||
@@ -172,17 +169,15 @@ class EndActiveAnimatorsFunctor {
|
||||
public:
|
||||
explicit EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
|
||||
|
||||
void operator() (sp<BaseRenderNodeAnimator>& animator) {
|
||||
animator->forceEndNow(mContext);
|
||||
}
|
||||
void operator()(sp<BaseRenderNodeAnimator>& animator) { animator->forceEndNow(mContext); }
|
||||
|
||||
private:
|
||||
AnimationContext& mContext;
|
||||
};
|
||||
|
||||
void AnimatorManager::endAllActiveAnimators() {
|
||||
ALOGD("endAllActiveAnimators on %p (%s) with handle %p",
|
||||
&mParent, mParent.getName(), mAnimationHandle);
|
||||
ALOGD("endAllActiveAnimators on %p (%s) with handle %p", &mParent, mParent.getName(),
|
||||
mAnimationHandle);
|
||||
EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
|
||||
for_each(mAnimators.begin(), mAnimators.end(), functor);
|
||||
mAnimators.clear();
|
||||
|
||||
@@ -34,6 +34,7 @@ class TreeInfo;
|
||||
// Responsible for managing the animators for a single RenderNode
|
||||
class AnimatorManager {
|
||||
PREVENT_COPY_AND_ASSIGN(AnimatorManager);
|
||||
|
||||
public:
|
||||
explicit AnimatorManager(RenderNode& parent);
|
||||
~AnimatorManager();
|
||||
@@ -68,8 +69,8 @@ private:
|
||||
AnimationHandle* mAnimationHandle;
|
||||
|
||||
// To improve the efficiency of resizing & removing from the vector
|
||||
std::vector< sp<BaseRenderNodeAnimator> > mNewAnimators;
|
||||
std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
|
||||
std::vector<sp<BaseRenderNodeAnimator> > mNewAnimators;
|
||||
std::vector<sp<BaseRenderNodeAnimator> > mAnimators;
|
||||
};
|
||||
|
||||
} /* namespace uirenderer */
|
||||
|
||||
@@ -23,29 +23,28 @@
|
||||
#include "GlopBuilder.h"
|
||||
#include "Patch.h"
|
||||
#include "PathTessellator.h"
|
||||
#include "VertexBuffer.h"
|
||||
#include "renderstate/OffscreenBufferPool.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "utils/GLUtils.h"
|
||||
#include "VertexBuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <SkPaintDefaults.h>
|
||||
#include <SkPathOps.h>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
static void storeTexturedRect(TextureVertex* vertices, const Rect& bounds) {
|
||||
vertices[0] = { bounds.left, bounds.top, 0, 0 };
|
||||
vertices[1] = { bounds.right, bounds.top, 1, 0 };
|
||||
vertices[2] = { bounds.left, bounds.bottom, 0, 1 };
|
||||
vertices[3] = { bounds.right, bounds.bottom, 1, 1 };
|
||||
vertices[0] = {bounds.left, bounds.top, 0, 0};
|
||||
vertices[1] = {bounds.right, bounds.top, 1, 0};
|
||||
vertices[2] = {bounds.left, bounds.bottom, 0, 1};
|
||||
vertices[3] = {bounds.right, bounds.bottom, 1, 1};
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
|
||||
const MergedBakedOpList& opList) {
|
||||
|
||||
const MergedBakedOpList& opList) {
|
||||
const BakedOpState& firstState = *(opList.states[0]);
|
||||
Bitmap* bitmap = (static_cast<const BitmapOp*>(opList.states[0]->op))->bitmap;
|
||||
|
||||
@@ -70,7 +69,8 @@ void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
|
||||
}
|
||||
|
||||
const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
|
||||
? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
|
||||
? TextureFillFlags::IsAlphaMaskTexture
|
||||
: TextureFillFlags::None;
|
||||
Glop glop;
|
||||
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
|
||||
.setRoundRectClipState(firstState.roundRectClipState)
|
||||
@@ -85,7 +85,7 @@ void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
|
||||
const MergedBakedOpList& opList) {
|
||||
const MergedBakedOpList& opList) {
|
||||
const PatchOp& firstOp = *(static_cast<const PatchOp*>(opList.states[0]->op));
|
||||
const BakedOpState& firstState = *(opList.states[0]);
|
||||
|
||||
@@ -99,8 +99,8 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
|
||||
|
||||
// TODO: cache mesh lookups
|
||||
const Patch* opMesh = renderer.caches().patchCache.get(
|
||||
op.bitmap->width(), op.bitmap->height(),
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
|
||||
op.bitmap->width(), op.bitmap->height(), op.unmappedBounds.getWidth(),
|
||||
op.unmappedBounds.getHeight(), op.patch);
|
||||
totalVertices += opMesh->verticesCount;
|
||||
}
|
||||
|
||||
@@ -120,9 +120,8 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
|
||||
|
||||
// TODO: cache mesh lookups
|
||||
const Patch* opMesh = renderer.caches().patchCache.get(
|
||||
op.bitmap->width(), op.bitmap->height(),
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
|
||||
|
||||
op.bitmap->width(), op.bitmap->height(), op.unmappedBounds.getWidth(),
|
||||
op.unmappedBounds.getHeight(), op.patch);
|
||||
|
||||
uint32_t vertexCount = opMesh->verticesCount;
|
||||
if (vertexCount == 0) continue;
|
||||
@@ -130,17 +129,16 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
|
||||
// We use the bounds to know where to translate our vertices
|
||||
// Using patchOp->state.mBounds wouldn't work because these
|
||||
// bounds are clipped
|
||||
const float tx = floorf(state.computedState.transform.getTranslateX()
|
||||
+ op.unmappedBounds.left + 0.5f);
|
||||
const float ty = floorf(state.computedState.transform.getTranslateY()
|
||||
+ op.unmappedBounds.top + 0.5f);
|
||||
const float tx = floorf(state.computedState.transform.getTranslateX() +
|
||||
op.unmappedBounds.left + 0.5f);
|
||||
const float ty = floorf(state.computedState.transform.getTranslateY() +
|
||||
op.unmappedBounds.top + 0.5f);
|
||||
|
||||
// Copy & transform all the vertices for the current operation
|
||||
TextureVertex* opVertices = opMesh->vertices.get();
|
||||
for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
|
||||
TextureVertex::set(vertex++,
|
||||
opVertices->x + tx, opVertices->y + ty,
|
||||
opVertices->u, opVertices->v);
|
||||
TextureVertex::set(vertex++, opVertices->x + tx, opVertices->y + ty, opVertices->u,
|
||||
opVertices->v);
|
||||
}
|
||||
|
||||
// Dirty the current layer if possible. When the 9-patch does not
|
||||
@@ -148,16 +146,16 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
|
||||
// dirty rect to the object's bounds.
|
||||
if (dirtyRenderTarget) {
|
||||
if (!opMesh->hasEmptyQuads) {
|
||||
renderer.dirtyRenderTarget(Rect(tx, ty,
|
||||
tx + op.unmappedBounds.getWidth(), ty + op.unmappedBounds.getHeight()));
|
||||
renderer.dirtyRenderTarget(Rect(tx, ty, tx + op.unmappedBounds.getWidth(),
|
||||
ty + op.unmappedBounds.getHeight()));
|
||||
} else {
|
||||
const size_t count = opMesh->quads.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const Rect& quadBounds = opMesh->quads[i];
|
||||
const float x = tx + quadBounds.left;
|
||||
const float y = ty + quadBounds.top;
|
||||
renderer.dirtyRenderTarget(Rect(x, y,
|
||||
x + quadBounds.getWidth(), y + quadBounds.getHeight()));
|
||||
renderer.dirtyRenderTarget(
|
||||
Rect(x, y, x + quadBounds.getWidth(), y + quadBounds.getHeight()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,7 +163,6 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
|
||||
indexCount += opMesh->indexCount;
|
||||
}
|
||||
|
||||
|
||||
Texture* texture = renderer.caches().textureCache.get(firstOp.bitmap);
|
||||
if (!texture) return;
|
||||
const AutoTexture autoCleanup(texture);
|
||||
@@ -188,8 +185,8 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
|
||||
renderer.renderGlop(nullptr, clip, glop);
|
||||
}
|
||||
|
||||
static void renderTextShadow(BakedOpRenderer& renderer,
|
||||
const TextOp& op, const BakedOpState& textOpState) {
|
||||
static void renderTextShadow(BakedOpRenderer& renderer, const TextOp& op,
|
||||
const BakedOpState& textOpState) {
|
||||
if (CC_LIKELY(!PaintUtils::hasTextShadow(op.paint))) return;
|
||||
|
||||
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
|
||||
@@ -225,7 +222,7 @@ static void renderTextShadow(BakedOpRenderer& renderer,
|
||||
// Bounds should be same as text op, but with dx/dy offset and radius outset
|
||||
// applied in local space.
|
||||
auto& transform = textOpState.computedState.transform;
|
||||
Rect shadowBounds = op.unmappedBounds; // STROKE
|
||||
Rect shadowBounds = op.unmappedBounds; // STROKE
|
||||
const bool expandForStroke = op.paint->getStyle() != SkPaint::kFill_Style;
|
||||
if (expandForStroke) {
|
||||
shadowBounds.outset(op.paint->getStrokeWidth() * 0.5f);
|
||||
@@ -234,13 +231,12 @@ static void renderTextShadow(BakedOpRenderer& renderer,
|
||||
shadowBounds.outset(textShadow.radius, textShadow.radius);
|
||||
transform.mapRect(shadowBounds);
|
||||
if (CC_UNLIKELY(expandForStroke &&
|
||||
(!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
|
||||
(!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
|
||||
shadowBounds.outset(0.5f);
|
||||
}
|
||||
|
||||
auto clipState = textOpState.computedState.clipState;
|
||||
if (clipState->mode != ClipMode::Rectangle
|
||||
|| !clipState->rect.contains(shadowBounds)) {
|
||||
if (clipState->mode != ClipMode::Rectangle || !clipState->rect.contains(shadowBounds)) {
|
||||
// need clip, so pass it and clip bounds
|
||||
shadowBounds.doIntersect(clipState->rect);
|
||||
} else {
|
||||
@@ -251,13 +247,10 @@ static void renderTextShadow(BakedOpRenderer& renderer,
|
||||
renderer.renderGlop(&shadowBounds, clipState, glop);
|
||||
}
|
||||
|
||||
enum class TextRenderType {
|
||||
Defer,
|
||||
Flush
|
||||
};
|
||||
enum class TextRenderType { Defer, Flush };
|
||||
|
||||
static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state,
|
||||
const ClipBase* renderClip, TextRenderType renderType) {
|
||||
const ClipBase* renderClip, TextRenderType renderType) {
|
||||
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
|
||||
float x = op.x;
|
||||
float y = op.y;
|
||||
@@ -285,23 +278,23 @@ static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedO
|
||||
// font renderer which greatly simplifies the code, clipping in particular.
|
||||
float sx, sy;
|
||||
transform.decomposeScale(sx, sy);
|
||||
fontRenderer.setFont(op.paint, SkMatrix::MakeScale(
|
||||
roundf(std::max(1.0f, sx)),
|
||||
roundf(std::max(1.0f, sy))));
|
||||
fontRenderer.setFont(op.paint, SkMatrix::MakeScale(roundf(std::max(1.0f, sx)),
|
||||
roundf(std::max(1.0f, sy))));
|
||||
fontRenderer.setTextureFiltering(true);
|
||||
}
|
||||
Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
|
||||
|
||||
int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha;
|
||||
SkBlendMode mode = PaintUtils::getBlendModeDirect(op.paint);
|
||||
TextDrawFunctor functor(&renderer, &state, renderClip,
|
||||
x, y, pureTranslate, alpha, mode, op.paint);
|
||||
TextDrawFunctor functor(&renderer, &state, renderClip, x, y, pureTranslate, alpha, mode,
|
||||
op.paint);
|
||||
|
||||
bool forceFinish = (renderType == TextRenderType::Flush);
|
||||
bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
|
||||
const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect() : nullptr;
|
||||
fontRenderer.renderPosText(op.paint, localOpClip, op.glyphs, op.glyphCount, x, y,
|
||||
op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish);
|
||||
fontRenderer.renderPosText(op.paint, localOpClip, op.glyphs, op.glyphCount, x, y, op.positions,
|
||||
mustDirtyRenderTarget ? &layerBounds : nullptr, &functor,
|
||||
forceFinish);
|
||||
|
||||
if (mustDirtyRenderTarget) {
|
||||
if (!pureTranslate) {
|
||||
@@ -312,7 +305,7 @@ static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedO
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
|
||||
const MergedBakedOpList& opList) {
|
||||
const MergedBakedOpList& opList) {
|
||||
for (size_t i = 0; i < opList.count; i++) {
|
||||
const BakedOpState& state = *(opList.states[i]);
|
||||
const TextOp& op = *(static_cast<const TextOp*>(state.op));
|
||||
@@ -324,26 +317,27 @@ void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
|
||||
for (size_t i = 0; i < opList.count; i++) {
|
||||
const BakedOpState& state = *(opList.states[i]);
|
||||
const TextOp& op = *(static_cast<const TextOp*>(state.op));
|
||||
TextRenderType renderType = (i + 1 == opList.count)
|
||||
? TextRenderType::Flush : TextRenderType::Defer;
|
||||
TextRenderType renderType =
|
||||
(i + 1 == opList.count) ? TextRenderType::Flush : TextRenderType::Defer;
|
||||
renderText(renderer, op, state, clip, renderType);
|
||||
}
|
||||
}
|
||||
|
||||
namespace VertexBufferRenderFlags {
|
||||
enum {
|
||||
Offset = 0x1,
|
||||
ShadowInterp = 0x2,
|
||||
};
|
||||
enum {
|
||||
Offset = 0x1,
|
||||
ShadowInterp = 0x2,
|
||||
};
|
||||
}
|
||||
|
||||
static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
|
||||
const VertexBuffer& vertexBuffer, float translateX, float translateY,
|
||||
const SkPaint& paint, int vertexBufferRenderFlags) {
|
||||
const VertexBuffer& vertexBuffer, float translateX, float translateY,
|
||||
const SkPaint& paint, int vertexBufferRenderFlags) {
|
||||
if (CC_LIKELY(vertexBuffer.getVertexCount())) {
|
||||
bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
|
||||
const int transformFlags = vertexBufferRenderFlags & VertexBufferRenderFlags::Offset
|
||||
? TransformFlags::OffsetByFudgeFactor : 0;
|
||||
? TransformFlags::OffsetByFudgeFactor
|
||||
: 0;
|
||||
|
||||
Glop glop;
|
||||
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
|
||||
@@ -358,24 +352,23 @@ static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& st
|
||||
}
|
||||
|
||||
static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& state,
|
||||
const SkPath& path, const SkPaint& paint) {
|
||||
const SkPath& path, const SkPaint& paint) {
|
||||
VertexBuffer vertexBuffer;
|
||||
// TODO: try clipping large paths to viewport
|
||||
PathTessellator::tessellatePath(path, &paint, state.computedState.transform, vertexBuffer);
|
||||
renderVertexBuffer(renderer, state, vertexBuffer, 0.0f, 0.0f, paint, 0);
|
||||
}
|
||||
|
||||
static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state,
|
||||
float xOffset, float yOffset, PathTexture& texture, const SkPaint& paint) {
|
||||
static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state, float xOffset,
|
||||
float yOffset, PathTexture& texture, const SkPaint& paint) {
|
||||
Rect dest(texture.width(), texture.height());
|
||||
dest.translate(xOffset + texture.left - texture.offset,
|
||||
yOffset + texture.top - texture.offset);
|
||||
dest.translate(xOffset + texture.left - texture.offset, yOffset + texture.top - texture.offset);
|
||||
Glop glop;
|
||||
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
|
||||
.setRoundRectClipState(state.roundRectClipState)
|
||||
.setMeshTexturedUnitQuad(nullptr)
|
||||
.setFillPathTexturePaint(texture, paint, state.alpha)
|
||||
.setTransform(state.computedState.transform, TransformFlags::None)
|
||||
.setTransform(state.computedState.transform, TransformFlags::None)
|
||||
.setModelViewMapUnitToRect(dest)
|
||||
.build();
|
||||
renderer.renderGlop(state, glop);
|
||||
@@ -390,18 +383,18 @@ SkRect getBoundsOfFill(const RecordedOp& op) {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op,
|
||||
const BakedOpState& state) {
|
||||
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
|
||||
if (op.paint->getStyle() != SkPaint::kStroke_Style
|
||||
|| op.paint->getPathEffect() != nullptr
|
||||
|| op.useCenter) {
|
||||
if (op.paint->getStyle() != SkPaint::kStroke_Style || op.paint->getPathEffect() != nullptr ||
|
||||
op.useCenter) {
|
||||
PathTexture* texture = renderer.caches().pathCache.getArc(
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(),
|
||||
op.startAngle, op.sweepAngle, op.useCenter, op.paint);
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.startAngle,
|
||||
op.sweepAngle, op.useCenter, op.paint);
|
||||
const AutoTexture holder(texture);
|
||||
if (CC_LIKELY(holder.texture)) {
|
||||
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
*texture, *(op.paint));
|
||||
*texture, *(op.paint));
|
||||
}
|
||||
} else {
|
||||
SkRect rect = getBoundsOfFill(op);
|
||||
@@ -417,13 +410,15 @@ void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, cons
|
||||
}
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op,
|
||||
const BakedOpState& state) {
|
||||
Texture* texture = renderer.getTexture(op.bitmap);
|
||||
if (!texture) return;
|
||||
const AutoTexture autoCleanup(texture);
|
||||
|
||||
const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
|
||||
? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
|
||||
? TextureFillFlags::IsAlphaMaskTexture
|
||||
: TextureFillFlags::None;
|
||||
Glop glop;
|
||||
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
|
||||
.setRoundRectClipState(state.roundRectClipState)
|
||||
@@ -435,7 +430,8 @@ void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op
|
||||
renderer.renderGlop(state, glop);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op,
|
||||
const BakedOpState& state) {
|
||||
Texture* texture = renderer.caches().textureCache.get(op.bitmap);
|
||||
if (!texture) {
|
||||
return;
|
||||
@@ -495,13 +491,14 @@ void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMe
|
||||
.setRoundRectClipState(state.roundRectClipState)
|
||||
.setMeshColoredTexturedMesh(mesh.get(), elementCount)
|
||||
.setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
|
||||
.setTransform(state.computedState.transform, TransformFlags::None)
|
||||
.setTransform(state.computedState.transform, TransformFlags::None)
|
||||
.setModelViewOffsetRect(0, 0, op.unmappedBounds)
|
||||
.build();
|
||||
renderer.renderGlop(state, glop);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op,
|
||||
const BakedOpState& state) {
|
||||
Texture* texture = renderer.getTexture(op.bitmap);
|
||||
if (!texture) return;
|
||||
const AutoTexture autoCleanup(texture);
|
||||
@@ -512,9 +509,10 @@ void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRe
|
||||
std::min(1.0f, op.src.bottom / texture->height()));
|
||||
|
||||
const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
|
||||
? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
|
||||
const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth())
|
||||
&& MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight());
|
||||
? TextureFillFlags::IsAlphaMaskTexture
|
||||
: TextureFillFlags::None;
|
||||
const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth()) &&
|
||||
MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight());
|
||||
Glop glop;
|
||||
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
|
||||
.setRoundRectClipState(state.roundRectClipState)
|
||||
@@ -526,7 +524,8 @@ void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRe
|
||||
renderer.renderGlop(state, glop);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op,
|
||||
const BakedOpState& state) {
|
||||
SkPaint paint;
|
||||
paint.setColor(op.color);
|
||||
paint.setBlendMode(op.mode);
|
||||
@@ -542,26 +541,29 @@ void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op,
|
||||
renderer.renderGlop(state, glop);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op,
|
||||
const BakedOpState& state) {
|
||||
renderer.renderFunctor(op, state);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op,
|
||||
const BakedOpState& state) {
|
||||
VertexBuffer buffer;
|
||||
PathTessellator::tessellateLines(op.points, op.floatCount, op.paint,
|
||||
state.computedState.transform, buffer);
|
||||
state.computedState.transform, buffer);
|
||||
int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset;
|
||||
renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op,
|
||||
const BakedOpState& state) {
|
||||
if (op.paint->getPathEffect() != nullptr) {
|
||||
PathTexture* texture = renderer.caches().pathCache.getOval(
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
|
||||
const AutoTexture holder(texture);
|
||||
if (CC_LIKELY(holder.texture)) {
|
||||
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
*texture, *(op.paint));
|
||||
*texture, *(op.paint));
|
||||
}
|
||||
} else {
|
||||
SkPath path;
|
||||
@@ -577,7 +579,8 @@ void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, co
|
||||
}
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op,
|
||||
const BakedOpState& state) {
|
||||
// 9 patches are built for stretching - always filter
|
||||
int textureFillFlags = TextureFillFlags::ForceFilter;
|
||||
if (op.bitmap->colorType() == kAlpha_8_SkColorType) {
|
||||
@@ -585,9 +588,9 @@ void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op,
|
||||
}
|
||||
|
||||
// TODO: avoid redoing the below work each frame:
|
||||
const Patch* mesh = renderer.caches().patchCache.get(
|
||||
op.bitmap->width(), op.bitmap->height(),
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
|
||||
const Patch* mesh = renderer.caches().patchCache.get(op.bitmap->width(), op.bitmap->height(),
|
||||
op.unmappedBounds.getWidth(),
|
||||
op.unmappedBounds.getHeight(), op.patch);
|
||||
|
||||
Texture* texture = renderer.caches().textureCache.get(op.bitmap);
|
||||
if (CC_LIKELY(texture)) {
|
||||
@@ -598,14 +601,16 @@ void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op,
|
||||
.setMeshPatchQuads(*mesh)
|
||||
.setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
|
||||
.setTransform(state.computedState.transform, TransformFlags::None)
|
||||
.setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
.setModelViewOffsetRectSnap(
|
||||
op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
|
||||
.build();
|
||||
renderer.renderGlop(state, glop);
|
||||
}
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op,
|
||||
const BakedOpState& state) {
|
||||
PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint);
|
||||
const AutoTexture holder(texture);
|
||||
if (CC_LIKELY(holder.texture)) {
|
||||
@@ -615,10 +620,11 @@ void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, co
|
||||
}
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op,
|
||||
const BakedOpState& state) {
|
||||
VertexBuffer buffer;
|
||||
PathTessellator::tessellatePoints(op.points, op.floatCount, op.paint,
|
||||
state.computedState.transform, buffer);
|
||||
state.computedState.transform, buffer);
|
||||
int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset;
|
||||
renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags);
|
||||
}
|
||||
@@ -626,20 +632,21 @@ void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op
|
||||
// See SkPaintDefaults.h
|
||||
#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
|
||||
|
||||
void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op,
|
||||
const BakedOpState& state) {
|
||||
if (op.paint->getStyle() != SkPaint::kFill_Style) {
|
||||
// only fill + default miter is supported by drawConvexPath, since others must handle joins
|
||||
static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed");
|
||||
if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr
|
||||
|| op.paint->getStrokeJoin() != SkPaint::kMiter_Join
|
||||
|| op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) {
|
||||
PathTexture* texture = renderer.caches().pathCache.getRect(
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
|
||||
const AutoTexture holder(texture);
|
||||
if (CC_LIKELY(holder.texture)) {
|
||||
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
*texture, *(op.paint));
|
||||
}
|
||||
if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr ||
|
||||
op.paint->getStrokeJoin() != SkPaint::kMiter_Join ||
|
||||
op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) {
|
||||
PathTexture* texture = renderer.caches().pathCache.getRect(
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
|
||||
const AutoTexture holder(texture);
|
||||
if (CC_LIKELY(holder.texture)) {
|
||||
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
*texture, *(op.paint));
|
||||
}
|
||||
} else {
|
||||
SkPath path;
|
||||
path.addRect(getBoundsOfFill(op));
|
||||
@@ -665,29 +672,31 @@ void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, co
|
||||
}
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op,
|
||||
const BakedOpState& state) {
|
||||
if (op.paint->getPathEffect() != nullptr) {
|
||||
PathTexture* texture = renderer.caches().pathCache.getRoundRect(
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(),
|
||||
op.rx, op.ry, op.paint);
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry,
|
||||
op.paint);
|
||||
const AutoTexture holder(texture);
|
||||
if (CC_LIKELY(holder.texture)) {
|
||||
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
*texture, *(op.paint));
|
||||
*texture, *(op.paint));
|
||||
}
|
||||
} else {
|
||||
const VertexBuffer* buffer = renderer.caches().tessellationCache.getRoundRect(
|
||||
state.computedState.transform, *(op.paint),
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
|
||||
renderVertexBuffer(renderer, state, *buffer,
|
||||
op.unmappedBounds.left, op.unmappedBounds.top, *(op.paint), 0);
|
||||
state.computedState.transform, *(op.paint), op.unmappedBounds.getWidth(),
|
||||
op.unmappedBounds.getHeight(), op.rx, op.ry);
|
||||
renderVertexBuffer(renderer, state, *buffer, op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
*(op.paint), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha,
|
||||
const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
|
||||
const VertexBuffer* ambientShadowVertexBuffer,
|
||||
const VertexBuffer* spotShadowVertexBuffer) {
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true); // want to use AlphaVertex
|
||||
paint.setAntiAlias(true); // want to use AlphaVertex
|
||||
|
||||
// The caller has made sure casterAlpha > 0.
|
||||
uint8_t ambientShadowAlpha = renderer.getLightInfo().ambientShadowAlpha;
|
||||
@@ -696,8 +705,8 @@ static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, f
|
||||
}
|
||||
if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
|
||||
paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha));
|
||||
renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0,
|
||||
paint, VertexBufferRenderFlags::ShadowInterp);
|
||||
renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0, paint,
|
||||
VertexBufferRenderFlags::ShadowInterp);
|
||||
}
|
||||
|
||||
uint8_t spotShadowAlpha = renderer.getLightInfo().spotShadowAlpha;
|
||||
@@ -706,17 +715,19 @@ static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, f
|
||||
}
|
||||
if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
|
||||
paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha));
|
||||
renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0,
|
||||
paint, VertexBufferRenderFlags::ShadowInterp);
|
||||
renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0, paint,
|
||||
VertexBufferRenderFlags::ShadowInterp);
|
||||
}
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op,
|
||||
const BakedOpState& state) {
|
||||
TessellationCache::vertexBuffer_pair_t buffers = op.shadowTask->getResult();
|
||||
renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op,
|
||||
const BakedOpState& state) {
|
||||
Glop glop;
|
||||
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
|
||||
.setRoundRectClipState(state.roundRectClipState)
|
||||
@@ -728,12 +739,14 @@ void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleR
|
||||
renderer.renderGlop(state, glop);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op,
|
||||
const BakedOpState& state) {
|
||||
renderTextShadow(renderer, op, state);
|
||||
renderText(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op,
|
||||
const BakedOpState& state) {
|
||||
// Note: can't trust clipSideFlags since we record with unmappedBounds == clip.
|
||||
// TODO: respect clipSideFlags, once we record with bounds
|
||||
auto renderTargetClip = state.computedState.clipState;
|
||||
@@ -746,14 +759,14 @@ void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPa
|
||||
|
||||
int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha;
|
||||
SkBlendMode mode = PaintUtils::getBlendModeDirect(op.paint);
|
||||
TextDrawFunctor functor(&renderer, &state, renderTargetClip,
|
||||
0.0f, 0.0f, false, alpha, mode, op.paint);
|
||||
TextDrawFunctor functor(&renderer, &state, renderTargetClip, 0.0f, 0.0f, false, alpha, mode,
|
||||
op.paint);
|
||||
|
||||
bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
|
||||
const Rect localSpaceClip = state.computedState.computeLocalSpaceClip();
|
||||
if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip, op.glyphs, op.glyphCount,
|
||||
op.path, op.hOffset, op.vOffset,
|
||||
mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) {
|
||||
if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip, op.glyphs, op.glyphCount, op.path,
|
||||
op.hOffset, op.vOffset,
|
||||
mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) {
|
||||
if (mustDirtyRenderTarget) {
|
||||
// manually dirty render target, since TextDrawFunctor won't
|
||||
state.computedState.transform.mapRect(layerBounds);
|
||||
@@ -762,7 +775,8 @@ void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPa
|
||||
}
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op,
|
||||
const BakedOpState& state) {
|
||||
GlLayer* layer = static_cast<GlLayer*>(op.layerHandle->backingLayer());
|
||||
if (!layer) {
|
||||
return;
|
||||
@@ -772,16 +786,17 @@ void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const Textur
|
||||
Glop glop;
|
||||
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
|
||||
.setRoundRectClipState(state.roundRectClipState)
|
||||
.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
|
||||
.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
|
||||
.setFillTextureLayer(*(layer), alpha)
|
||||
.setTransform(state.computedState.transform, TransformFlags::None)
|
||||
.setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(layer->getWidth(), layer->getHeight()))
|
||||
.setModelViewMapUnitToRectOptionalSnap(tryToSnap,
|
||||
Rect(layer->getWidth(), layer->getHeight()))
|
||||
.build();
|
||||
renderer.renderGlop(state, glop);
|
||||
}
|
||||
|
||||
void renderRectForLayer(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state,
|
||||
int color, SkBlendMode mode, SkColorFilter* colorFilter) {
|
||||
int color, SkBlendMode mode, SkColorFilter* colorFilter) {
|
||||
SkPaint paint;
|
||||
paint.setColor(color);
|
||||
paint.setBlendMode(mode);
|
||||
@@ -790,7 +805,8 @@ void renderRectForLayer(BakedOpRenderer& renderer, const LayerOp& op, const Bake
|
||||
BakedOpDispatcher::onRectOp(renderer, rectOp, state);
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op,
|
||||
const BakedOpState& state) {
|
||||
// Note that we don't use op->paint in this function - it's never set on a LayerOp
|
||||
OffscreenBuffer* buffer = *op.layerHandle;
|
||||
|
||||
@@ -801,9 +817,11 @@ void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op,
|
||||
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
|
||||
.setRoundRectClipState(state.roundRectClipState)
|
||||
.setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount)
|
||||
.setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
|
||||
.setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode,
|
||||
Blend::ModeOrderSwap::NoSwap)
|
||||
.setTransform(state.computedState.transform, TransformFlags::None)
|
||||
.setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
.setModelViewOffsetRectSnap(
|
||||
op.unmappedBounds.left, op.unmappedBounds.top,
|
||||
Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
|
||||
.build();
|
||||
renderer.renderGlop(state, glop);
|
||||
@@ -812,23 +830,24 @@ void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op,
|
||||
buffer->hasRenderedSinceRepaint = true;
|
||||
if (CC_UNLIKELY(Properties::debugLayersUpdates)) {
|
||||
// render debug layer highlight
|
||||
renderRectForLayer(renderer, op, state,
|
||||
0x7f00ff00, SkBlendMode::kSrcOver, nullptr);
|
||||
renderRectForLayer(renderer, op, state, 0x7f00ff00, SkBlendMode::kSrcOver, nullptr);
|
||||
} else if (CC_UNLIKELY(Properties::debugOverdraw)) {
|
||||
// render transparent to increment overdraw for repaint area
|
||||
renderRectForLayer(renderer, op, state,
|
||||
SK_ColorTRANSPARENT, SkBlendMode::kSrcOver, nullptr);
|
||||
renderRectForLayer(renderer, op, state, SK_ColorTRANSPARENT, SkBlendMode::kSrcOver,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onCopyToLayerOp(BakedOpRenderer& renderer, const CopyToLayerOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onCopyToLayerOp(BakedOpRenderer& renderer, const CopyToLayerOp& op,
|
||||
const BakedOpState& state) {
|
||||
LOG_ALWAYS_FATAL_IF(*(op.layerHandle) != nullptr, "layer already exists!");
|
||||
*(op.layerHandle) = renderer.copyToLayer(state.computedState.clippedBounds);
|
||||
LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "layer copy failed");
|
||||
}
|
||||
|
||||
void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyFromLayerOp& op, const BakedOpState& state) {
|
||||
void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyFromLayerOp& op,
|
||||
const BakedOpState& state) {
|
||||
LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "no layer to draw underneath!");
|
||||
if (!state.computedState.clippedBounds.isEmpty()) {
|
||||
if (op.paint && op.paint->getAlpha() < 255) {
|
||||
@@ -836,7 +855,8 @@ void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyF
|
||||
layerPaint.setAlpha(op.paint->getAlpha());
|
||||
layerPaint.setBlendMode(SkBlendMode::kDstIn);
|
||||
layerPaint.setColorFilter(sk_ref_sp(op.paint->getColorFilter()));
|
||||
RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr, &layerPaint);
|
||||
RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr,
|
||||
&layerPaint);
|
||||
BakedOpDispatcher::onRectOp(renderer, rectOp, state);
|
||||
}
|
||||
|
||||
@@ -855,5 +875,5 @@ void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyF
|
||||
renderer.renderState().layerPool().putOrDelete(*op.layerHandle);
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -33,21 +33,20 @@ namespace uirenderer {
|
||||
*/
|
||||
class BakedOpDispatcher {
|
||||
public:
|
||||
// Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
|
||||
// Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
|
||||
#define X(Type) \
|
||||
static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
|
||||
static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
|
||||
MAP_MERGEABLE_OPS(X)
|
||||
#undef X
|
||||
|
||||
// Declares all "onBitmapOp(...)" style methods for every op type
|
||||
// Declares all "onBitmapOp(...)" style methods for every op type
|
||||
#define X(Type) \
|
||||
static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
|
||||
static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
|
||||
MAP_RENDERABLE_OPS(X)
|
||||
#undef X
|
||||
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_BAKED_OP_DISPATCHER_H
|
||||
#endif // ANDROID_HWUI_BAKED_OP_DISPATCHER_H
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
#include "Caches.h"
|
||||
#include "Glop.h"
|
||||
#include "GlopBuilder.h"
|
||||
#include "VertexBuffer.h"
|
||||
#include "renderstate/OffscreenBufferPool.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "utils/GLUtils.h"
|
||||
#include "VertexBuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace uirenderer {
|
||||
OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
|
||||
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
|
||||
|
||||
OffscreenBuffer* buffer = mRenderState.layerPool().get(
|
||||
mRenderState, width, height, mWideColorGamut);
|
||||
OffscreenBuffer* buffer =
|
||||
mRenderState.layerPool().get(mRenderState, width, height, mWideColorGamut);
|
||||
startRepaintLayer(buffer, Rect(width, height));
|
||||
return buffer;
|
||||
}
|
||||
@@ -46,13 +46,13 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
|
||||
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
|
||||
|
||||
// subtract repaintRect from region, since it will be regenerated
|
||||
if (repaintRect.contains(0, 0,
|
||||
offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight)) {
|
||||
if (repaintRect.contains(0, 0, offscreenBuffer->viewportWidth,
|
||||
offscreenBuffer->viewportHeight)) {
|
||||
// repaint full layer, so throw away entire region
|
||||
offscreenBuffer->region.clear();
|
||||
} else {
|
||||
offscreenBuffer->region.subtractSelf(android::Rect(repaintRect.left, repaintRect.top,
|
||||
repaintRect.right, repaintRect.bottom));
|
||||
repaintRect.right, repaintRect.bottom));
|
||||
}
|
||||
|
||||
mRenderTarget.offscreenBuffer = offscreenBuffer;
|
||||
@@ -64,16 +64,14 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
|
||||
|
||||
// attach the texture to the FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
offscreenBuffer->texture.id(), 0);
|
||||
offscreenBuffer->texture.id(), 0);
|
||||
GL_CHECKPOINT(LOW);
|
||||
|
||||
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
LOG_ALWAYS_FATAL_IF(status != GL_FRAMEBUFFER_COMPLETE,
|
||||
"framebuffer incomplete, status %d, textureId %d, size %dx%d",
|
||||
status,
|
||||
offscreenBuffer->texture.id(),
|
||||
offscreenBuffer->texture.width(),
|
||||
offscreenBuffer->texture.height());
|
||||
"framebuffer incomplete, status %d, textureId %d, size %dx%d", status,
|
||||
offscreenBuffer->texture.id(), offscreenBuffer->texture.width(),
|
||||
offscreenBuffer->texture.height());
|
||||
|
||||
// Change the viewport & ortho projection
|
||||
setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
|
||||
@@ -92,7 +90,7 @@ void BakedOpRenderer::endLayer() {
|
||||
mRenderTarget.lastStencilClip = nullptr;
|
||||
|
||||
mRenderTarget.offscreenBuffer->updateMeshFromRegion();
|
||||
mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
|
||||
mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
|
||||
|
||||
// Detach the texture from the FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
@@ -104,14 +102,14 @@ void BakedOpRenderer::endLayer() {
|
||||
OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) {
|
||||
const uint32_t width = area.getWidth();
|
||||
const uint32_t height = area.getHeight();
|
||||
OffscreenBuffer* buffer = mRenderState.layerPool().get(
|
||||
mRenderState, width, height, mWideColorGamut);
|
||||
OffscreenBuffer* buffer =
|
||||
mRenderState.layerPool().get(mRenderState, width, height, mWideColorGamut);
|
||||
if (!area.isEmpty() && width != 0 && height != 0) {
|
||||
mCaches.textureState().activateTexture(0);
|
||||
mCaches.textureState().bindTexture(buffer->texture.id());
|
||||
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
||||
area.left, mRenderTarget.viewportHeight - area.bottom, width, height);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, area.left,
|
||||
mRenderTarget.viewportHeight - area.bottom, width, height);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
@@ -177,7 +175,7 @@ void BakedOpRenderer::clearColorBuffer(const Rect& rect) {
|
||||
// Requested rect is subset of viewport - scissor to it to avoid over-clearing
|
||||
mRenderState.scissor().setEnabled(true);
|
||||
mRenderState.scissor().set(rect.left, mRenderTarget.viewportHeight - rect.bottom,
|
||||
rect.getWidth(), rect.getHeight());
|
||||
rect.getWidth(), rect.getHeight());
|
||||
}
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
|
||||
@@ -222,8 +220,7 @@ void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* pa
|
||||
|
||||
// clears and re-fills stencil with provided rendertarget space quads,
|
||||
// and then put stencil into test mode
|
||||
void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
|
||||
int incrementThreshold) {
|
||||
void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices, int incrementThreshold) {
|
||||
mRenderState.stencil().enableWrite(incrementThreshold);
|
||||
mRenderState.stencil().clear();
|
||||
Glop glop;
|
||||
@@ -239,7 +236,8 @@ void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
|
||||
}
|
||||
|
||||
void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
|
||||
LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList, "can't rectlist clip without rectlist");
|
||||
LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList,
|
||||
"can't rectlist clip without rectlist");
|
||||
auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
|
||||
int quadCount = rectList.getTransformedRectanglesCount();
|
||||
std::vector<Vertex> rectangleVertices;
|
||||
@@ -253,7 +251,7 @@ void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
|
||||
transform.mapRect(bounds);
|
||||
bounds.doIntersect(clip->rect);
|
||||
if (bounds.isEmpty()) {
|
||||
continue; // will be outside of scissor, skip
|
||||
continue; // will be outside of scissor, skip
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,11 +307,11 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
|
||||
if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
|
||||
OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
|
||||
mRenderTarget.stencil = mCaches.renderBufferCache.get(
|
||||
Stencil::getLayerStencilFormat(),
|
||||
layer->texture.width(), layer->texture.height());
|
||||
Stencil::getLayerStencilFormat(), layer->texture.width(),
|
||||
layer->texture.height());
|
||||
// stencil is bound + allocated - associate it with current FBO
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, mRenderTarget.stencil->getName());
|
||||
GL_RENDERBUFFER, mRenderTarget.stencil->getName());
|
||||
}
|
||||
|
||||
if (clip->mode == ClipMode::RectangleList) {
|
||||
@@ -344,17 +342,15 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
|
||||
}
|
||||
|
||||
void BakedOpRenderer::renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip,
|
||||
const Glop& glop) {
|
||||
const Glop& glop) {
|
||||
prepareRender(dirtyBounds, clip);
|
||||
// Disable blending if this is the first draw to the main framebuffer, in case app has defined
|
||||
// transparency where it doesn't make sense - as first draw in opaque window. Note that we only
|
||||
// apply this improvement when the blend mode is SRC_OVER - other modes (e.g. CLEAR) can be
|
||||
// valid draws that affect other content (e.g. draw CLEAR, then draw DST_OVER)
|
||||
bool overrideDisableBlending = !mHasDrawn
|
||||
&& mOpaque
|
||||
&& !mRenderTarget.frameBufferId
|
||||
&& glop.blend.src == GL_ONE
|
||||
&& glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA;
|
||||
bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId &&
|
||||
glop.blend.src == GL_ONE &&
|
||||
glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA;
|
||||
mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
|
||||
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
|
||||
}
|
||||
@@ -383,5 +379,5 @@ void BakedOpRenderer::dirtyRenderTarget(const Rect& uiDirty) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -46,23 +46,20 @@ public:
|
||||
*/
|
||||
struct LightInfo {
|
||||
LightInfo() : LightInfo(0, 0) {}
|
||||
LightInfo(uint8_t ambientShadowAlpha,
|
||||
uint8_t spotShadowAlpha)
|
||||
: ambientShadowAlpha(ambientShadowAlpha)
|
||||
, spotShadowAlpha(spotShadowAlpha) {}
|
||||
LightInfo(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha)
|
||||
: ambientShadowAlpha(ambientShadowAlpha), spotShadowAlpha(spotShadowAlpha) {}
|
||||
uint8_t ambientShadowAlpha;
|
||||
uint8_t spotShadowAlpha;
|
||||
};
|
||||
|
||||
BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, bool wideColorGamut,
|
||||
const LightInfo& lightInfo)
|
||||
const LightInfo& lightInfo)
|
||||
: mGlopReceiver(DefaultGlopReceiver)
|
||||
, mRenderState(renderState)
|
||||
, mCaches(caches)
|
||||
, mOpaque(opaque)
|
||||
, mWideColorGamut(wideColorGamut)
|
||||
, mLightInfo(lightInfo) {
|
||||
}
|
||||
, mLightInfo(lightInfo) {}
|
||||
|
||||
RenderState& renderState() { return mRenderState; }
|
||||
Caches& caches() { return mCaches; }
|
||||
@@ -79,9 +76,7 @@ public:
|
||||
const LightInfo& getLightInfo() const { return mLightInfo; }
|
||||
|
||||
void renderGlop(const BakedOpState& state, const Glop& glop) {
|
||||
renderGlop(&state.computedState.clippedBounds,
|
||||
state.computedState.getClipIfNeeded(),
|
||||
glop);
|
||||
renderGlop(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded(), glop);
|
||||
}
|
||||
void renderFunctor(const FunctorOp& op, const BakedOpState& state);
|
||||
|
||||
@@ -97,15 +92,17 @@ public:
|
||||
|
||||
// simple draw methods, to be used for end frame decoration
|
||||
void drawRect(float left, float top, float right, float bottom, const SkPaint* paint) {
|
||||
float ltrb[4] = { left, top, right, bottom };
|
||||
float ltrb[4] = {left, top, right, bottom};
|
||||
drawRects(ltrb, 4, paint);
|
||||
}
|
||||
void drawRects(const float* rects, int count, const SkPaint* paint);
|
||||
|
||||
protected:
|
||||
GlopReceiver mGlopReceiver;
|
||||
|
||||
private:
|
||||
static void DefaultGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
|
||||
const ClipBase* clip, const Glop& glop) {
|
||||
const ClipBase* clip, const Glop& glop) {
|
||||
renderer.renderGlopImpl(dirtyBounds, clip, glop);
|
||||
}
|
||||
void renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
|
||||
@@ -148,5 +145,5 @@ private:
|
||||
const LightInfo mLightInfo;
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -31,7 +31,8 @@ static int computeClipSideFlags(const Rect& clip, const Rect& bounds) {
|
||||
}
|
||||
|
||||
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) {
|
||||
const RecordedOp& recordedOp, bool expandForStroke,
|
||||
bool expandForPathTexture) {
|
||||
// resolvedMatrix = parentMatrix * localMatrix
|
||||
transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
|
||||
|
||||
@@ -44,16 +45,16 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
|
||||
clippedBounds.outset(1);
|
||||
}
|
||||
transform.mapRect(clippedBounds);
|
||||
if (CC_UNLIKELY(expandForStroke
|
||||
&& (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
|
||||
if (CC_UNLIKELY(expandForStroke &&
|
||||
(!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
|
||||
// account for hairline stroke when stroke may be < 1 scaled pixel
|
||||
// Non translate || strokeWidth < 1 is conservative, but will cover all cases
|
||||
clippedBounds.outset(0.5f);
|
||||
}
|
||||
|
||||
// resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
|
||||
clipState = snapshot.serializeIntersectedClip(allocator,
|
||||
recordedOp.localClip, *(snapshot.transform));
|
||||
clipState = snapshot.serializeIntersectedClip(allocator, recordedOp.localClip,
|
||||
*(snapshot.transform));
|
||||
LOG_ALWAYS_FATAL_IF(!clipState, "must clip!");
|
||||
|
||||
const Rect& clipRect = clipState->rect;
|
||||
@@ -85,7 +86,7 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
|
||||
}
|
||||
|
||||
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const Matrix4& localTransform, const ClipBase* localClip) {
|
||||
const Matrix4& localTransform, const ClipBase* localClip) {
|
||||
transform.loadMultiply(*snapshot.transform, localTransform);
|
||||
clipState = snapshot.serializeIntersectedClip(allocator, localClip, *(snapshot.transform));
|
||||
clippedBounds = clipState->rect;
|
||||
@@ -109,11 +110,11 @@ ResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& d
|
||||
clippedBounds.doIntersect(clipRect->rect);
|
||||
}
|
||||
|
||||
BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
|
||||
Snapshot& snapshot, const RecordedOp& recordedOp) {
|
||||
BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp) {
|
||||
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
|
||||
BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
|
||||
allocator, snapshot, recordedOp, false, false);
|
||||
BakedOpState* bakedState =
|
||||
allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp, false, false);
|
||||
if (bakedState->computedState.clippedBounds.isEmpty()) {
|
||||
// bounds are empty, so op is rejected
|
||||
allocator.rewindIfLastAlloc(bakedState);
|
||||
@@ -122,21 +123,23 @@ BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
|
||||
return bakedState;
|
||||
}
|
||||
|
||||
BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator,
|
||||
Snapshot& snapshot, const RecordedOp& recordedOp) {
|
||||
BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp) {
|
||||
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
|
||||
return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
|
||||
}
|
||||
|
||||
BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
|
||||
Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
|
||||
bool expandForPathTexture) {
|
||||
BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp,
|
||||
StrokeBehavior strokeBehavior,
|
||||
bool expandForPathTexture) {
|
||||
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
|
||||
bool expandForStroke = (strokeBehavior == StrokeBehavior::Forced
|
||||
|| (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style));
|
||||
bool expandForStroke =
|
||||
(strokeBehavior == StrokeBehavior::Forced ||
|
||||
(recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style));
|
||||
|
||||
BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
|
||||
allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture);
|
||||
allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture);
|
||||
if (bakedState->computedState.clippedBounds.isEmpty()) {
|
||||
// bounds are empty, so op is rejected
|
||||
// NOTE: this won't succeed if a clip was allocated
|
||||
@@ -146,26 +149,25 @@ BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
|
||||
return bakedState;
|
||||
}
|
||||
|
||||
BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator,
|
||||
Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
|
||||
BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const ShadowOp* shadowOpPtr) {
|
||||
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
|
||||
|
||||
// clip isn't empty, so construct the op
|
||||
return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
|
||||
}
|
||||
|
||||
BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator,
|
||||
const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
|
||||
BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator, const ClipRect* clip,
|
||||
const Rect& dstRect, const RecordedOp& recordedOp) {
|
||||
return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
|
||||
}
|
||||
|
||||
void BakedOpState::setupOpacity(const SkPaint* paint) {
|
||||
computedState.opaqueOverClippedBounds = computedState.transform.isSimple()
|
||||
&& computedState.clipState->mode == ClipMode::Rectangle
|
||||
&& MathUtils::areEqual(alpha, 1.0f)
|
||||
&& !roundRectClipState
|
||||
&& PaintUtils::isOpaquePaint(paint);
|
||||
computedState.opaqueOverClippedBounds = computedState.transform.isSimple() &&
|
||||
computedState.clipState->mode == ClipMode::Rectangle &&
|
||||
MathUtils::areEqual(alpha, 1.0f) &&
|
||||
!roundRectClipState && PaintUtils::isOpaquePaint(paint);
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -26,22 +26,22 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
namespace OpClipSideFlags {
|
||||
enum {
|
||||
None = 0x0,
|
||||
Left = 0x1,
|
||||
Top = 0x2,
|
||||
Right = 0x4,
|
||||
Bottom = 0x8,
|
||||
Full = 0xF,
|
||||
// ConservativeFull = 0x1F needed?
|
||||
};
|
||||
enum {
|
||||
None = 0x0,
|
||||
Left = 0x1,
|
||||
Top = 0x2,
|
||||
Right = 0x4,
|
||||
Bottom = 0x8,
|
||||
Full = 0xF,
|
||||
// ConservativeFull = 0x1F needed?
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds a list of BakedOpStates of ops that can be drawn together
|
||||
*/
|
||||
struct MergedBakedOpList {
|
||||
const BakedOpState*const* states;
|
||||
const BakedOpState* const* states;
|
||||
size_t count;
|
||||
int clipSideFlags;
|
||||
Rect clip;
|
||||
@@ -53,11 +53,12 @@ struct MergedBakedOpList {
|
||||
class ResolvedRenderState {
|
||||
public:
|
||||
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture);
|
||||
const RecordedOp& recordedOp, bool expandForStroke,
|
||||
bool expandForPathTexture);
|
||||
|
||||
// Constructor for unbounded ops *with* transform/clip
|
||||
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const Matrix4& localTransform, const ClipBase* localClip);
|
||||
const Matrix4& localTransform, const ClipBase* localClip);
|
||||
|
||||
// Constructor for unbounded ops without transform/clip (namely shadows)
|
||||
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
|
||||
@@ -74,19 +75,15 @@ public:
|
||||
return outClip;
|
||||
}
|
||||
|
||||
const Rect& clipRect() const {
|
||||
return clipState->rect;
|
||||
}
|
||||
const Rect& clipRect() const { return clipState->rect; }
|
||||
|
||||
bool requiresClip() const {
|
||||
return clipSideFlags != OpClipSideFlags::None
|
||||
|| CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
|
||||
return clipSideFlags != OpClipSideFlags::None ||
|
||||
CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
|
||||
}
|
||||
|
||||
// returns the clip if it's needed to draw the operation, otherwise nullptr
|
||||
const ClipBase* getClipIfNeeded() const {
|
||||
return requiresClip() ? clipState : nullptr;
|
||||
}
|
||||
const ClipBase* getClipIfNeeded() const { return requiresClip() ? clipState : nullptr; }
|
||||
|
||||
Matrix4 transform;
|
||||
const ClipBase* clipState = nullptr;
|
||||
@@ -103,11 +100,11 @@ public:
|
||||
*/
|
||||
class BakedOpState {
|
||||
public:
|
||||
static BakedOpState* tryConstruct(LinearAllocator& allocator,
|
||||
Snapshot& snapshot, const RecordedOp& recordedOp);
|
||||
static BakedOpState* tryConstruct(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp);
|
||||
|
||||
static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator,
|
||||
Snapshot& snapshot, const RecordedOp& recordedOp);
|
||||
static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp);
|
||||
|
||||
enum class StrokeBehavior {
|
||||
// stroking is forced, regardless of style on paint (such as for lines)
|
||||
@@ -116,15 +113,16 @@ public:
|
||||
StyleDefined,
|
||||
};
|
||||
|
||||
static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
|
||||
Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
|
||||
bool expandForPathTexture);
|
||||
static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp,
|
||||
StrokeBehavior strokeBehavior,
|
||||
bool expandForPathTexture);
|
||||
|
||||
static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
|
||||
Snapshot& snapshot, const ShadowOp* shadowOpPtr);
|
||||
static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const ShadowOp* shadowOpPtr);
|
||||
|
||||
static BakedOpState* directConstruct(LinearAllocator& allocator,
|
||||
const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp);
|
||||
static BakedOpState* directConstruct(LinearAllocator& allocator, const ClipRect* clip,
|
||||
const Rect& dstRect, const RecordedOp& recordedOp);
|
||||
|
||||
// Set opaqueOverClippedBounds. If this method isn't called, the op is assumed translucent.
|
||||
void setupOpacity(const SkPaint* paint);
|
||||
@@ -140,8 +138,8 @@ public:
|
||||
private:
|
||||
friend class LinearAllocator;
|
||||
|
||||
BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
|
||||
const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture)
|
||||
BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp,
|
||||
bool expandForStroke, bool expandForPathTexture)
|
||||
: computedState(allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture)
|
||||
, alpha(snapshot.alpha)
|
||||
, roundRectClipState(snapshot.roundRectClipState)
|
||||
@@ -167,7 +165,7 @@ private:
|
||||
, op(&recordedOp) {}
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_BAKED_OP_STATE_H
|
||||
#endif // ANDROID_HWUI_BAKED_OP_STATE_H
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#include "GammaFontRenderer.h"
|
||||
#include "GlLayer.h"
|
||||
#include "Properties.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "ShadowTessellator.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#ifdef BUGREPORT_FONT_CACHE_USAGE
|
||||
#include "font/FontCacheHistoryTracker.h"
|
||||
#endif
|
||||
@@ -40,9 +40,9 @@ Caches* Caches::sInstance = nullptr;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if DEBUG_CACHE_FLUSH
|
||||
#define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#else
|
||||
#define FLUSH_LOGD(...)
|
||||
#define FLUSH_LOGD(...)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -98,8 +98,8 @@ void Caches::initConstraints() {
|
||||
|
||||
void Caches::initStaticProperties() {
|
||||
// OpenGL ES 3.0+ specific features
|
||||
gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects()
|
||||
&& property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
|
||||
gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects() &&
|
||||
property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
|
||||
}
|
||||
|
||||
void Caches::terminate() {
|
||||
@@ -143,10 +143,8 @@ void Caches::setProgram(Program* program) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32_t Caches::getOverdrawColor(uint32_t amount) const {
|
||||
static uint32_t sOverdrawColors[2][4] = {
|
||||
{ 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
|
||||
{ 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
|
||||
};
|
||||
static uint32_t sOverdrawColors[2][4] = {{0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000},
|
||||
{0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000}};
|
||||
if (amount < 1) amount = 1;
|
||||
if (amount > 4) amount = 4;
|
||||
|
||||
@@ -160,46 +158,44 @@ void Caches::dumpMemoryUsage() {
|
||||
ALOGD("%s", stringLog.string());
|
||||
}
|
||||
|
||||
void Caches::dumpMemoryUsage(String8 &log) {
|
||||
void Caches::dumpMemoryUsage(String8& log) {
|
||||
uint32_t total = 0;
|
||||
log.appendFormat("Current memory usage / total memory usage (bytes):\n");
|
||||
log.appendFormat(" TextureCache %8d / %8d\n",
|
||||
textureCache.getSize(), textureCache.getMaxSize());
|
||||
log.appendFormat(" TextureCache %8d / %8d\n", textureCache.getSize(),
|
||||
textureCache.getMaxSize());
|
||||
if (mRenderState) {
|
||||
int memused = 0;
|
||||
for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
|
||||
it != mRenderState->mActiveLayers.end(); it++) {
|
||||
it != mRenderState->mActiveLayers.end(); it++) {
|
||||
const Layer* layer = *it;
|
||||
LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL);
|
||||
const GlLayer* glLayer = static_cast<const GlLayer*>(layer);
|
||||
log.appendFormat(" GlLayer size %dx%d; texid=%u refs=%d\n",
|
||||
layer->getWidth(), layer->getHeight(),
|
||||
glLayer->getTextureId(),
|
||||
layer->getStrongCount());
|
||||
log.appendFormat(" GlLayer size %dx%d; texid=%u refs=%d\n", layer->getWidth(),
|
||||
layer->getHeight(), glLayer->getTextureId(), layer->getStrongCount());
|
||||
memused += layer->getWidth() * layer->getHeight() * 4;
|
||||
}
|
||||
log.appendFormat(" Layers total %8d (numLayers = %zu)\n",
|
||||
memused, mRenderState->mActiveLayers.size());
|
||||
log.appendFormat(" Layers total %8d (numLayers = %zu)\n", memused,
|
||||
mRenderState->mActiveLayers.size());
|
||||
total += memused;
|
||||
}
|
||||
log.appendFormat(" RenderBufferCache %8d / %8d\n",
|
||||
renderBufferCache.getSize(), renderBufferCache.getMaxSize());
|
||||
log.appendFormat(" GradientCache %8d / %8d\n",
|
||||
gradientCache.getSize(), gradientCache.getMaxSize());
|
||||
log.appendFormat(" PathCache %8d / %8d\n",
|
||||
pathCache.getSize(), pathCache.getMaxSize());
|
||||
log.appendFormat(" TessellationCache %8d / %8d\n",
|
||||
tessellationCache.getSize(), tessellationCache.getMaxSize());
|
||||
log.appendFormat(" RenderBufferCache %8d / %8d\n", renderBufferCache.getSize(),
|
||||
renderBufferCache.getMaxSize());
|
||||
log.appendFormat(" GradientCache %8d / %8d\n", gradientCache.getSize(),
|
||||
gradientCache.getMaxSize());
|
||||
log.appendFormat(" PathCache %8d / %8d\n", pathCache.getSize(),
|
||||
pathCache.getMaxSize());
|
||||
log.appendFormat(" TessellationCache %8d / %8d\n", tessellationCache.getSize(),
|
||||
tessellationCache.getMaxSize());
|
||||
log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
|
||||
dropShadowCache.getMaxSize());
|
||||
log.appendFormat(" PatchCache %8d / %8d\n",
|
||||
patchCache.getSize(), patchCache.getMaxSize());
|
||||
dropShadowCache.getMaxSize());
|
||||
log.appendFormat(" PatchCache %8d / %8d\n", patchCache.getSize(),
|
||||
patchCache.getMaxSize());
|
||||
|
||||
fontRenderer.dumpMemoryUsage(log);
|
||||
|
||||
log.appendFormat("Other:\n");
|
||||
log.appendFormat(" FboCache %8d / %8d\n",
|
||||
fboCache.getSize(), fboCache.getMaxSize());
|
||||
log.appendFormat(" FboCache %8d / %8d\n", fboCache.getSize(),
|
||||
fboCache.getMaxSize());
|
||||
|
||||
total += textureCache.getSize();
|
||||
total += renderBufferCache.getSize();
|
||||
@@ -238,13 +234,13 @@ void Caches::flush(FlushMode mode) {
|
||||
gradientCache.clear();
|
||||
fontRenderer.clear();
|
||||
fboCache.clear();
|
||||
// fall through
|
||||
// fall through
|
||||
case FlushMode::Moderate:
|
||||
fontRenderer.flush();
|
||||
textureCache.flush();
|
||||
pathCache.clear();
|
||||
tessellationCache.clear();
|
||||
// fall through
|
||||
// fall through
|
||||
case FlushMode::Layers:
|
||||
renderBufferCache.clear();
|
||||
break;
|
||||
@@ -274,5 +270,5 @@ TextureVertex* Caches::getRegionMesh() {
|
||||
// Temporary Properties
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -22,20 +22,20 @@
|
||||
#include "GammaFontRenderer.h"
|
||||
#include "GradientCache.h"
|
||||
#include "PatchCache.h"
|
||||
#include "ProgramCache.h"
|
||||
#include "PathCache.h"
|
||||
#include "ProgramCache.h"
|
||||
#include "RenderBufferCache.h"
|
||||
#include "renderstate/PixelBufferState.h"
|
||||
#include "renderstate/TextureState.h"
|
||||
#include "ResourceCache.h"
|
||||
#include "TessellationCache.h"
|
||||
#include "TextDropShadowCache.h"
|
||||
#include "TextureCache.h"
|
||||
#include "thread/TaskProcessor.h"
|
||||
#include "renderstate/PixelBufferState.h"
|
||||
#include "renderstate/TextureState.h"
|
||||
#include "thread/TaskManager.h"
|
||||
#include "thread/TaskProcessor.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <GLES3/gl3.h>
|
||||
|
||||
@@ -70,19 +70,14 @@ public:
|
||||
return *sInstance;
|
||||
}
|
||||
|
||||
static bool hasInstance() {
|
||||
return sInstance != nullptr;
|
||||
}
|
||||
static bool hasInstance() { return sInstance != nullptr; }
|
||||
|
||||
private:
|
||||
explicit Caches(RenderState& renderState);
|
||||
static Caches* sInstance;
|
||||
|
||||
public:
|
||||
enum class FlushMode {
|
||||
Layers = 0,
|
||||
Moderate,
|
||||
Full
|
||||
};
|
||||
enum class FlushMode { Layers = 0, Moderate, Full };
|
||||
|
||||
/**
|
||||
* Initialize caches.
|
||||
@@ -181,9 +176,9 @@ private:
|
||||
void initConstraints();
|
||||
void initStaticProperties();
|
||||
|
||||
static void eventMarkNull(GLsizei length, const GLchar* marker) { }
|
||||
static void startMarkNull(GLsizei length, const GLchar* marker) { }
|
||||
static void endMarkNull() { }
|
||||
static void eventMarkNull(GLsizei length, const GLchar* marker) {}
|
||||
static void startMarkNull(GLsizei length, const GLchar* marker) {}
|
||||
static void endMarkNull() {}
|
||||
|
||||
RenderState* mRenderState;
|
||||
|
||||
@@ -198,9 +193,9 @@ private:
|
||||
// TODO: move below to RenderState
|
||||
PixelBufferState* mPixelBufferState = nullptr;
|
||||
TextureState* mTextureState = nullptr;
|
||||
Program* mProgram = nullptr; // note: object owned by ProgramCache
|
||||
Program* mProgram = nullptr; // note: object owned by ProgramCache
|
||||
|
||||
}; // class Caches
|
||||
}; // class Caches
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace uirenderer {
|
||||
|
||||
class CanvasPropertyPrimitive : public VirtualLightRefBase {
|
||||
PREVENT_COPY_AND_ASSIGN(CanvasPropertyPrimitive);
|
||||
|
||||
public:
|
||||
explicit CanvasPropertyPrimitive(float initialValue) : value(initialValue) {}
|
||||
|
||||
@@ -35,6 +36,7 @@ public:
|
||||
|
||||
class CanvasPropertyPaint : public VirtualLightRefBase {
|
||||
PREVENT_COPY_AND_ASSIGN(CanvasPropertyPaint);
|
||||
|
||||
public:
|
||||
explicit CanvasPropertyPaint(const SkPaint& initialValue) : value(initialValue) {}
|
||||
|
||||
|
||||
@@ -21,14 +21,8 @@
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
|
||||
CanvasState::CanvasState(CanvasStateClient& renderer)
|
||||
: mWidth(-1)
|
||||
, mHeight(-1)
|
||||
, mSaveCount(1)
|
||||
, mCanvas(renderer)
|
||||
, mSnapshot(&mFirstSnapshot) {
|
||||
}
|
||||
: mWidth(-1), mHeight(-1), mSaveCount(1), mCanvas(renderer), mSnapshot(&mFirstSnapshot) {}
|
||||
|
||||
CanvasState::~CanvasState() {
|
||||
// First call freeSnapshot on all but mFirstSnapshot
|
||||
@@ -57,10 +51,9 @@ void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHe
|
||||
mSaveCount = 1;
|
||||
}
|
||||
|
||||
void CanvasState::initializeSaveStack(
|
||||
int viewportWidth, int viewportHeight,
|
||||
float clipLeft, float clipTop,
|
||||
float clipRight, float clipBottom, const Vector3& lightCenter) {
|
||||
void CanvasState::initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft,
|
||||
float clipTop, float clipRight, float clipBottom,
|
||||
const Vector3& lightCenter) {
|
||||
if (mWidth != viewportWidth || mHeight != viewportHeight) {
|
||||
mWidth = viewportWidth;
|
||||
mHeight = viewportHeight;
|
||||
@@ -92,7 +85,7 @@ void CanvasState::freeSnapshot(Snapshot* snapshot) {
|
||||
snapshot->~Snapshot();
|
||||
// Arbitrary number, just don't let this grown unbounded
|
||||
if (mSnapshotPoolCount > 10) {
|
||||
free((void*) snapshot);
|
||||
free((void*)snapshot);
|
||||
} else {
|
||||
snapshot->previous = mSnapshotPool;
|
||||
mSnapshotPool = snapshot;
|
||||
@@ -215,7 +208,7 @@ bool CanvasState::clipPath(const SkPath* path, SkClipOp op) {
|
||||
void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
|
||||
Rect bounds;
|
||||
float radius;
|
||||
if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
|
||||
if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
|
||||
|
||||
bool outlineIsRounded = MathUtils::isPositive(radius);
|
||||
if (!outlineIsRounded || currentTransform()->isSimple()) {
|
||||
@@ -241,10 +234,9 @@ void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline*
|
||||
* @param snapOut if set, the geometry will be treated as having an AA ramp.
|
||||
* See Rect::snapGeometryToPixelBoundaries()
|
||||
*/
|
||||
bool CanvasState::calculateQuickRejectForScissor(float left, float top,
|
||||
float right, float bottom,
|
||||
bool* clipRequired, bool* roundRectClipRequired,
|
||||
bool snapOut) const {
|
||||
bool CanvasState::calculateQuickRejectForScissor(float left, float top, float right, float bottom,
|
||||
bool* clipRequired, bool* roundRectClipRequired,
|
||||
bool snapOut) const {
|
||||
if (bottom <= top || right <= left) {
|
||||
return true;
|
||||
}
|
||||
@@ -265,21 +257,20 @@ bool CanvasState::calculateQuickRejectForScissor(float left, float top,
|
||||
|
||||
// round rect clip is required if RR clip exists, and geometry intersects its corners
|
||||
if (roundRectClipRequired) {
|
||||
*roundRectClipRequired = mSnapshot->roundRectClipState != nullptr
|
||||
&& mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
|
||||
*roundRectClipRequired = mSnapshot->roundRectClipState != nullptr &&
|
||||
mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CanvasState::quickRejectConservative(float left, float top,
|
||||
float right, float bottom) const {
|
||||
bool CanvasState::quickRejectConservative(float left, float top, float right, float bottom) const {
|
||||
if (bottom <= top || right <= left) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Rect r(left, top, right, bottom);
|
||||
currentTransform()->mapRect(r);
|
||||
r.roundOut(); // rounded out to be conservative
|
||||
r.roundOut(); // rounded out to be conservative
|
||||
|
||||
Rect clipRect(currentRenderTargetClip());
|
||||
clipRect.snapToPixelBoundaries();
|
||||
@@ -289,5 +280,5 @@ bool CanvasState::quickRejectConservative(float left, float top,
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace uirenderer {
|
||||
*/
|
||||
class CanvasStateClient {
|
||||
public:
|
||||
CanvasStateClient() { }
|
||||
virtual ~CanvasStateClient() { }
|
||||
CanvasStateClient() {}
|
||||
virtual ~CanvasStateClient() {}
|
||||
|
||||
/**
|
||||
* Callback allowing embedder to take actions in the middle of a
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
*/
|
||||
virtual GLuint getTargetFbo() const = 0;
|
||||
|
||||
}; // class CanvasStateClient
|
||||
}; // class CanvasStateClient
|
||||
|
||||
/**
|
||||
* Implements Canvas state methods on behalf of Renderers.
|
||||
@@ -86,13 +86,10 @@ public:
|
||||
* Initializes the first snapshot, computing the projection matrix,
|
||||
* and stores the dimensions of the render target.
|
||||
*/
|
||||
void initializeSaveStack(int viewportWidth, int viewportHeight,
|
||||
float clipLeft, float clipTop, float clipRight, float clipBottom,
|
||||
const Vector3& lightCenter);
|
||||
void initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft, float clipTop,
|
||||
float clipRight, float clipBottom, const Vector3& lightCenter);
|
||||
|
||||
bool hasRectToRectTransform() const {
|
||||
return CC_LIKELY(currentTransform()->rectToRect());
|
||||
}
|
||||
bool hasRectToRectTransform() const { return CC_LIKELY(currentTransform()->rectToRect()); }
|
||||
|
||||
// Save (layer)
|
||||
int getSaveCount() const { return mSaveCount; }
|
||||
@@ -112,9 +109,9 @@ public:
|
||||
void skew(float sx, float sy);
|
||||
|
||||
void setMatrix(const SkMatrix& matrix);
|
||||
void setMatrix(const Matrix4& matrix); // internal only convenience method
|
||||
void setMatrix(const Matrix4& matrix); // internal only convenience method
|
||||
void concatMatrix(const SkMatrix& matrix);
|
||||
void concatMatrix(const Matrix4& matrix); // internal only convenience method
|
||||
void concatMatrix(const Matrix4& matrix); // internal only convenience method
|
||||
|
||||
// Clip
|
||||
const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
|
||||
@@ -132,13 +129,11 @@ public:
|
||||
* outline.
|
||||
*/
|
||||
void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
|
||||
void setClippingRoundRect(LinearAllocator& allocator,
|
||||
const Rect& rect, float radius, bool highPriority = true) {
|
||||
void setClippingRoundRect(LinearAllocator& allocator, const Rect& rect, float radius,
|
||||
bool highPriority = true) {
|
||||
mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
|
||||
}
|
||||
void setProjectionPathMask(const SkPath* path) {
|
||||
mSnapshot->setProjectionPathMask(path);
|
||||
}
|
||||
void setProjectionPathMask(const SkPath* path) { mSnapshot->setProjectionPathMask(path); }
|
||||
|
||||
/**
|
||||
* Returns true if drawing in the rectangle (left, top, right, bottom)
|
||||
@@ -146,14 +141,19 @@ public:
|
||||
* perfect tests would return true.
|
||||
*/
|
||||
bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
|
||||
bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
|
||||
bool* clipRequired, bool* roundRectClipRequired,
|
||||
bool snapOut) const;
|
||||
|
||||
void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; }
|
||||
|
||||
inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
|
||||
inline const Rect& currentRenderTargetClip() const { return currentSnapshot()->getRenderTargetClip(); }
|
||||
inline const Rect& currentRenderTargetClip() const {
|
||||
return currentSnapshot()->getRenderTargetClip();
|
||||
}
|
||||
inline int currentFlags() const { return currentSnapshot()->flags; }
|
||||
const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
|
||||
const Vector3& currentLightCenter() const {
|
||||
return currentSnapshot()->getRelativeLightCenter();
|
||||
}
|
||||
int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
|
||||
int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
|
||||
int getWidth() const { return mWidth; }
|
||||
@@ -189,7 +189,7 @@ private:
|
||||
Snapshot* mSnapshotPool = nullptr;
|
||||
int mSnapshotPoolCount = 0;
|
||||
|
||||
}; // class CanvasState
|
||||
}; // class CanvasState
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -33,7 +33,7 @@ static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float
|
||||
Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
|
||||
const float kMinFloat = std::numeric_limits<float>::lowest();
|
||||
const float kMaxFloat = std::numeric_limits<float>::max();
|
||||
Rect transformedBounds = { kMaxFloat, kMaxFloat, kMinFloat, kMinFloat };
|
||||
Rect transformedBounds = {kMaxFloat, kMaxFloat, kMinFloat, kMinFloat};
|
||||
handlePoint(transformedBounds, transform, r.left, r.top);
|
||||
handlePoint(transformedBounds, transform, r.right, r.top);
|
||||
handlePoint(transformedBounds, transform, r.left, r.bottom);
|
||||
@@ -49,18 +49,12 @@ void ClipBase::dump() const {
|
||||
* TransformedRectangle
|
||||
*/
|
||||
|
||||
TransformedRectangle::TransformedRectangle() {
|
||||
}
|
||||
TransformedRectangle::TransformedRectangle() {}
|
||||
|
||||
TransformedRectangle::TransformedRectangle(const Rect& bounds,
|
||||
const Matrix4& transform)
|
||||
: mBounds(bounds)
|
||||
, mTransform(transform) {
|
||||
}
|
||||
|
||||
bool TransformedRectangle::canSimplyIntersectWith(
|
||||
const TransformedRectangle& other) const {
|
||||
TransformedRectangle::TransformedRectangle(const Rect& bounds, const Matrix4& transform)
|
||||
: mBounds(bounds), mTransform(transform) {}
|
||||
|
||||
bool TransformedRectangle::canSimplyIntersectWith(const TransformedRectangle& other) const {
|
||||
return mTransform == other.mTransform;
|
||||
}
|
||||
|
||||
@@ -76,9 +70,7 @@ bool TransformedRectangle::isEmpty() const {
|
||||
* RectangleList
|
||||
*/
|
||||
|
||||
RectangleList::RectangleList()
|
||||
: mTransformedRectanglesCount(0) {
|
||||
}
|
||||
RectangleList::RectangleList() : mTransformedRectanglesCount(0) {}
|
||||
|
||||
bool RectangleList::isEmpty() const {
|
||||
if (mTransformedRectanglesCount < 1) {
|
||||
@@ -110,8 +102,7 @@ void RectangleList::set(const Rect& bounds, const Matrix4& transform) {
|
||||
mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
|
||||
}
|
||||
|
||||
bool RectangleList::intersectWith(const Rect& bounds,
|
||||
const Matrix4& transform) {
|
||||
bool RectangleList::intersectWith(const Rect& bounds, const Matrix4& transform) {
|
||||
TransformedRectangle newRectangle(bounds, transform);
|
||||
|
||||
// Try to find a rectangle with a compatible transformation
|
||||
@@ -148,8 +139,7 @@ Rect RectangleList::calculateBounds() const {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
static SkPath pathFromTransformedRectangle(const Rect& bounds,
|
||||
const Matrix4& transform) {
|
||||
static SkPath pathFromTransformedRectangle(const Rect& bounds, const Matrix4& transform) {
|
||||
SkPath rectPath;
|
||||
SkPath rectPathTransformed;
|
||||
rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
|
||||
@@ -163,8 +153,8 @@ SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
|
||||
SkRegion rectangleListAsRegion;
|
||||
for (int index = 0; index < mTransformedRectanglesCount; index++) {
|
||||
const TransformedRectangle& tr(mTransformedRectangles[index]);
|
||||
SkPath rectPathTransformed = pathFromTransformedRectangle(
|
||||
tr.getBounds(), tr.getTransform());
|
||||
SkPath rectPathTransformed =
|
||||
pathFromTransformedRectangle(tr.getBounds(), tr.getTransform());
|
||||
if (index == 0) {
|
||||
rectangleListAsRegion.setPath(rectPathTransformed, clip);
|
||||
} else {
|
||||
@@ -186,9 +176,7 @@ void RectangleList::transform(const Matrix4& transform) {
|
||||
* ClipArea
|
||||
*/
|
||||
|
||||
ClipArea::ClipArea()
|
||||
: mMode(ClipMode::Rectangle) {
|
||||
}
|
||||
ClipArea::ClipArea() : mMode(ClipMode::Rectangle) {}
|
||||
|
||||
/*
|
||||
* Interface
|
||||
@@ -215,21 +203,20 @@ void ClipArea::setClip(float left, float top, float right, float bottom) {
|
||||
mClipRegion.setEmpty();
|
||||
}
|
||||
|
||||
void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
|
||||
SkRegion::Op op) {
|
||||
void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op) {
|
||||
if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
|
||||
if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
|
||||
onClipUpdated();
|
||||
switch (mMode) {
|
||||
case ClipMode::Rectangle:
|
||||
rectangleModeClipRectWithTransform(r, transform, op);
|
||||
break;
|
||||
case ClipMode::RectangleList:
|
||||
rectangleListModeClipRectWithTransform(r, transform, op);
|
||||
break;
|
||||
case ClipMode::Region:
|
||||
regionModeClipRectWithTransform(r, transform, op);
|
||||
break;
|
||||
case ClipMode::Rectangle:
|
||||
rectangleModeClipRectWithTransform(r, transform, op);
|
||||
break;
|
||||
case ClipMode::RectangleList:
|
||||
rectangleListModeClipRectWithTransform(r, transform, op);
|
||||
break;
|
||||
case ClipMode::Region:
|
||||
regionModeClipRectWithTransform(r, transform, op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,8 +229,7 @@ void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
|
||||
onClipRegionUpdated();
|
||||
}
|
||||
|
||||
void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
|
||||
SkRegion::Op op) {
|
||||
void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op) {
|
||||
if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
|
||||
if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
|
||||
onClipUpdated();
|
||||
@@ -269,9 +255,8 @@ void ClipArea::enterRectangleMode() {
|
||||
mMode = ClipMode::Rectangle;
|
||||
}
|
||||
|
||||
void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
|
||||
const mat4* transform, SkRegion::Op op) {
|
||||
|
||||
void ClipArea::rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform,
|
||||
SkRegion::Op op) {
|
||||
if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
|
||||
mClipRect = r;
|
||||
transform->mapRect(mClipRect);
|
||||
@@ -306,10 +291,9 @@ void ClipArea::enterRectangleListMode() {
|
||||
mRectangleList.set(mClipRect, Matrix4::identity());
|
||||
}
|
||||
|
||||
void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
|
||||
const mat4* transform, SkRegion::Op op) {
|
||||
if (op != SkRegion::kIntersect_Op
|
||||
|| !mRectangleList.intersectWith(r, *transform)) {
|
||||
void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
|
||||
SkRegion::Op op) {
|
||||
if (op != SkRegion::kIntersect_Op || !mRectangleList.intersectWith(r, *transform)) {
|
||||
enterRegionMode();
|
||||
regionModeClipRectWithTransform(r, transform, op);
|
||||
}
|
||||
@@ -332,8 +316,8 @@ void ClipArea::enterRegionMode() {
|
||||
}
|
||||
}
|
||||
|
||||
void ClipArea::regionModeClipRectWithTransform(const Rect& r,
|
||||
const mat4* transform, SkRegion::Op op) {
|
||||
void ClipArea::regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
|
||||
SkRegion::Op op) {
|
||||
SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
|
||||
SkRegion transformedRectRegion;
|
||||
regionFromPath(transformedRect, transformedRectRegion);
|
||||
@@ -365,24 +349,24 @@ const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
|
||||
}
|
||||
|
||||
static_assert(std::is_trivially_destructible<Rect>::value,
|
||||
"expect Rect to be trivially destructible");
|
||||
"expect Rect to be trivially destructible");
|
||||
static_assert(std::is_trivially_destructible<RectangleList>::value,
|
||||
"expect RectangleList to be trivially destructible");
|
||||
"expect RectangleList to be trivially destructible");
|
||||
|
||||
if (mLastSerialization == nullptr) {
|
||||
ClipBase* serialization = nullptr;
|
||||
switch (mMode) {
|
||||
case ClipMode::Rectangle:
|
||||
serialization = allocator.create<ClipRect>(mClipRect);
|
||||
break;
|
||||
case ClipMode::RectangleList:
|
||||
serialization = allocator.create<ClipRectList>(mRectangleList);
|
||||
serialization->rect = mRectangleList.calculateBounds();
|
||||
break;
|
||||
case ClipMode::Region:
|
||||
serialization = allocator.create<ClipRegion>(mClipRegion);
|
||||
serialization->rect.set(mClipRegion.getBounds());
|
||||
break;
|
||||
case ClipMode::Rectangle:
|
||||
serialization = allocator.create<ClipRect>(mClipRect);
|
||||
break;
|
||||
case ClipMode::RectangleList:
|
||||
serialization = allocator.create<ClipRectList>(mRectangleList);
|
||||
serialization->rect = mRectangleList.calculateBounds();
|
||||
break;
|
||||
case ClipMode::Region:
|
||||
serialization = allocator.create<ClipRegion>(mClipRegion);
|
||||
serialization->rect.set(mClipRegion.getBounds());
|
||||
break;
|
||||
}
|
||||
serialization->intersectWithRoot = mReplaceOpObserved;
|
||||
// TODO: this is only done for draw time, should eventually avoid for record time
|
||||
@@ -404,81 +388,79 @@ inline static const SkRegion& getRegion(const ClipBase* scb) {
|
||||
// For simplicity, doesn't account for rect merging
|
||||
static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
|
||||
int currentRectCount = clipArea.isRectangleList()
|
||||
? clipArea.getRectangleList().getTransformedRectanglesCount()
|
||||
: 1;
|
||||
? clipArea.getRectangleList().getTransformedRectanglesCount()
|
||||
: 1;
|
||||
int recordedRectCount = (scb->mode == ClipMode::RectangleList)
|
||||
? getRectList(scb).getTransformedRectanglesCount()
|
||||
: 1;
|
||||
? getRectList(scb).getTransformedRectanglesCount()
|
||||
: 1;
|
||||
return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
|
||||
}
|
||||
|
||||
static const ClipRect sEmptyClipRect(Rect(0, 0));
|
||||
|
||||
const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
|
||||
const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
|
||||
|
||||
const ClipBase* recordedClip,
|
||||
const Matrix4& recordedClipTransform) {
|
||||
// if no recordedClip passed, just serialize current state
|
||||
if (!recordedClip) return serializeClip(allocator);
|
||||
|
||||
// if either is empty, clip is empty
|
||||
if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect;
|
||||
if (CC_UNLIKELY(recordedClip->rect.isEmpty()) || mClipRect.isEmpty()) return &sEmptyClipRect;
|
||||
|
||||
if (!mLastResolutionResult
|
||||
|| recordedClip != mLastResolutionClip
|
||||
|| recordedClipTransform != mLastResolutionTransform) {
|
||||
if (!mLastResolutionResult || recordedClip != mLastResolutionClip ||
|
||||
recordedClipTransform != mLastResolutionTransform) {
|
||||
mLastResolutionClip = recordedClip;
|
||||
mLastResolutionTransform = recordedClipTransform;
|
||||
|
||||
if (CC_LIKELY(mMode == ClipMode::Rectangle
|
||||
&& recordedClip->mode == ClipMode::Rectangle
|
||||
&& recordedClipTransform.rectToRect())) {
|
||||
if (CC_LIKELY(mMode == ClipMode::Rectangle && recordedClip->mode == ClipMode::Rectangle &&
|
||||
recordedClipTransform.rectToRect())) {
|
||||
// common case - result is a single rectangle
|
||||
auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
|
||||
recordedClipTransform.mapRect(rectClip->rect);
|
||||
rectClip->rect.doIntersect(mClipRect);
|
||||
rectClip->rect.snapToPixelBoundaries();
|
||||
mLastResolutionResult = rectClip;
|
||||
} else if (CC_UNLIKELY(mMode == ClipMode::Region
|
||||
|| recordedClip->mode == ClipMode::Region
|
||||
|| cannotFitInRectangleList(*this, recordedClip))) {
|
||||
} else if (CC_UNLIKELY(mMode == ClipMode::Region ||
|
||||
recordedClip->mode == ClipMode::Region ||
|
||||
cannotFitInRectangleList(*this, recordedClip))) {
|
||||
// region case
|
||||
SkRegion other;
|
||||
switch (recordedClip->mode) {
|
||||
case ClipMode::Rectangle:
|
||||
if (CC_LIKELY(recordedClipTransform.rectToRect())) {
|
||||
// simple transform, skip creating SkPath
|
||||
Rect resultClip(recordedClip->rect);
|
||||
recordedClipTransform.mapRect(resultClip);
|
||||
other.setRect(resultClip.toSkIRect());
|
||||
} else {
|
||||
SkPath transformedRect = pathFromTransformedRectangle(recordedClip->rect,
|
||||
recordedClipTransform);
|
||||
other.setPath(transformedRect, createViewportRegion());
|
||||
case ClipMode::Rectangle:
|
||||
if (CC_LIKELY(recordedClipTransform.rectToRect())) {
|
||||
// simple transform, skip creating SkPath
|
||||
Rect resultClip(recordedClip->rect);
|
||||
recordedClipTransform.mapRect(resultClip);
|
||||
other.setRect(resultClip.toSkIRect());
|
||||
} else {
|
||||
SkPath transformedRect = pathFromTransformedRectangle(
|
||||
recordedClip->rect, recordedClipTransform);
|
||||
other.setPath(transformedRect, createViewportRegion());
|
||||
}
|
||||
break;
|
||||
case ClipMode::RectangleList: {
|
||||
RectangleList transformedList(getRectList(recordedClip));
|
||||
transformedList.transform(recordedClipTransform);
|
||||
other = transformedList.convertToRegion(createViewportRegion());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ClipMode::RectangleList: {
|
||||
RectangleList transformedList(getRectList(recordedClip));
|
||||
transformedList.transform(recordedClipTransform);
|
||||
other = transformedList.convertToRegion(createViewportRegion());
|
||||
break;
|
||||
}
|
||||
case ClipMode::Region:
|
||||
other = getRegion(recordedClip);
|
||||
applyTransformToRegion(recordedClipTransform, &other);
|
||||
case ClipMode::Region:
|
||||
other = getRegion(recordedClip);
|
||||
applyTransformToRegion(recordedClipTransform, &other);
|
||||
}
|
||||
|
||||
ClipRegion* regionClip = allocator.create<ClipRegion>();
|
||||
switch (mMode) {
|
||||
case ClipMode::Rectangle:
|
||||
regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
|
||||
break;
|
||||
case ClipMode::RectangleList:
|
||||
regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
|
||||
other, SkRegion::kIntersect_Op);
|
||||
break;
|
||||
case ClipMode::Region:
|
||||
regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
|
||||
break;
|
||||
case ClipMode::Rectangle:
|
||||
regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
|
||||
break;
|
||||
case ClipMode::RectangleList:
|
||||
regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
|
||||
other, SkRegion::kIntersect_Op);
|
||||
break;
|
||||
case ClipMode::Region:
|
||||
regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
|
||||
break;
|
||||
}
|
||||
// Don't need to snap, since region's in int bounds
|
||||
regionClip->rect.set(regionClip->region.getBounds());
|
||||
@@ -510,7 +492,7 @@ const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
|
||||
}
|
||||
|
||||
void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
|
||||
if (!clip) return; // nothing to do
|
||||
if (!clip) return; // nothing to do
|
||||
|
||||
if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
|
||||
clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
|
||||
|
||||
@@ -39,18 +39,14 @@ public:
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
const Rect& getBounds() const {
|
||||
return mBounds;
|
||||
}
|
||||
const Rect& getBounds() const { return mBounds; }
|
||||
|
||||
Rect transformedBounds() const {
|
||||
Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
|
||||
return transformedBounds;
|
||||
}
|
||||
|
||||
const Matrix4& getTransform() const {
|
||||
return mTransform;
|
||||
}
|
||||
const Matrix4& getTransform() const { return mTransform; }
|
||||
|
||||
void transform(const Matrix4& transform) {
|
||||
Matrix4 t;
|
||||
@@ -79,9 +75,7 @@ public:
|
||||
SkRegion convertToRegion(const SkRegion& clip) const;
|
||||
Rect calculateBounds() const;
|
||||
|
||||
enum {
|
||||
kMaxTransformedRectangles = 5
|
||||
};
|
||||
enum { kMaxTransformedRectangles = 5 };
|
||||
|
||||
private:
|
||||
int mTransformedRectanglesCount;
|
||||
@@ -97,11 +91,8 @@ enum class ClipMode {
|
||||
};
|
||||
|
||||
struct ClipBase {
|
||||
explicit ClipBase(ClipMode mode)
|
||||
: mode(mode) {}
|
||||
explicit ClipBase(const Rect& rect)
|
||||
: mode(ClipMode::Rectangle)
|
||||
, rect(rect) {}
|
||||
explicit ClipBase(ClipMode mode) : mode(mode) {}
|
||||
explicit ClipBase(const Rect& rect) : mode(ClipMode::Rectangle), rect(rect) {}
|
||||
const ClipMode mode;
|
||||
bool intersectWithRoot = false;
|
||||
// Bounds of the clipping area, used to define the scissor, and define which
|
||||
@@ -112,23 +103,18 @@ struct ClipBase {
|
||||
};
|
||||
|
||||
struct ClipRect : ClipBase {
|
||||
explicit ClipRect(const Rect& rect)
|
||||
: ClipBase(rect) {}
|
||||
explicit ClipRect(const Rect& rect) : ClipBase(rect) {}
|
||||
};
|
||||
|
||||
struct ClipRectList : ClipBase {
|
||||
explicit ClipRectList(const RectangleList& rectList)
|
||||
: ClipBase(ClipMode::RectangleList)
|
||||
, rectList(rectList) {}
|
||||
: ClipBase(ClipMode::RectangleList), rectList(rectList) {}
|
||||
RectangleList rectList;
|
||||
};
|
||||
|
||||
struct ClipRegion : ClipBase {
|
||||
explicit ClipRegion(const SkRegion& region)
|
||||
: ClipBase(ClipMode::Region)
|
||||
, region(region) {}
|
||||
ClipRegion()
|
||||
: ClipBase(ClipMode::Region) {}
|
||||
explicit ClipRegion(const SkRegion& region) : ClipBase(ClipMode::Region), region(region) {}
|
||||
ClipRegion() : ClipBase(ClipMode::Region) {}
|
||||
SkRegion region;
|
||||
};
|
||||
|
||||
@@ -138,44 +124,29 @@ public:
|
||||
|
||||
void setViewportDimensions(int width, int height);
|
||||
|
||||
bool isEmpty() const {
|
||||
return mClipRect.isEmpty();
|
||||
}
|
||||
bool isEmpty() const { return mClipRect.isEmpty(); }
|
||||
|
||||
void setEmpty();
|
||||
void setClip(float left, float top, float right, float bottom);
|
||||
void clipRectWithTransform(const Rect& r, const mat4* transform,
|
||||
SkRegion::Op op);
|
||||
void clipPathWithTransform(const SkPath& path, const mat4* transform,
|
||||
SkRegion::Op op);
|
||||
void clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
|
||||
void clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op);
|
||||
|
||||
const Rect& getClipRect() const {
|
||||
return mClipRect;
|
||||
}
|
||||
const Rect& getClipRect() const { return mClipRect; }
|
||||
|
||||
const SkRegion& getClipRegion() const {
|
||||
return mClipRegion;
|
||||
}
|
||||
const SkRegion& getClipRegion() const { return mClipRegion; }
|
||||
|
||||
const RectangleList& getRectangleList() const {
|
||||
return mRectangleList;
|
||||
}
|
||||
const RectangleList& getRectangleList() const { return mRectangleList; }
|
||||
|
||||
bool isRegion() const {
|
||||
return ClipMode::Region == mMode;
|
||||
}
|
||||
bool isRegion() const { return ClipMode::Region == mMode; }
|
||||
|
||||
bool isSimple() const {
|
||||
return mMode == ClipMode::Rectangle;
|
||||
}
|
||||
bool isSimple() const { return mMode == ClipMode::Rectangle; }
|
||||
|
||||
bool isRectangleList() const {
|
||||
return mMode == ClipMode::RectangleList;
|
||||
}
|
||||
bool isRectangleList() const { return mMode == ClipMode::RectangleList; }
|
||||
|
||||
WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator);
|
||||
WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
|
||||
const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
|
||||
WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
|
||||
LinearAllocator& allocator, const ClipBase* recordedClip,
|
||||
const Matrix4& recordedClipTransform);
|
||||
void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
|
||||
|
||||
static void applyTransformToRegion(const Matrix4& transform, SkRegion* region);
|
||||
@@ -185,14 +156,13 @@ private:
|
||||
void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
|
||||
|
||||
void enterRectangleListMode();
|
||||
void rectangleListModeClipRectWithTransform(const Rect& r,
|
||||
const mat4* transform, SkRegion::Op op);
|
||||
void rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
|
||||
SkRegion::Op op);
|
||||
|
||||
void enterRegionModeFromRectangleMode();
|
||||
void enterRegionModeFromRectangleListMode();
|
||||
void enterRegionMode();
|
||||
void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
|
||||
SkRegion::Op op);
|
||||
void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
|
||||
|
||||
void clipRegion(const SkRegion& region, SkRegion::Op op);
|
||||
void ensureClipRegion();
|
||||
@@ -205,9 +175,7 @@ private:
|
||||
mLastResolutionResult = nullptr;
|
||||
}
|
||||
|
||||
SkRegion createViewportRegion() {
|
||||
return SkRegion(mViewportBounds.toSkIRect());
|
||||
}
|
||||
SkRegion createViewportRegion() { return SkRegion(mViewportBounds.toSkIRect()); }
|
||||
|
||||
void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
|
||||
// TODO: this should not mask every path to the viewport - this makes it impossible to use
|
||||
|
||||
@@ -57,17 +57,18 @@ static void computeTransformImpl(const DirtyStack* currentFrame, Matrix4* outMat
|
||||
computeTransformImpl(currentFrame->prev, outMatrix);
|
||||
}
|
||||
switch (currentFrame->type) {
|
||||
case TransformRenderNode:
|
||||
currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix);
|
||||
break;
|
||||
case TransformMatrix4:
|
||||
outMatrix->multiply(*currentFrame->matrix4);
|
||||
break;
|
||||
case TransformNone:
|
||||
// nothing to be done
|
||||
break;
|
||||
default:
|
||||
LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d", currentFrame->type);
|
||||
case TransformRenderNode:
|
||||
currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix);
|
||||
break;
|
||||
case TransformMatrix4:
|
||||
outMatrix->multiply(*currentFrame->matrix4);
|
||||
break;
|
||||
case TransformNone:
|
||||
// nothing to be done
|
||||
break;
|
||||
default:
|
||||
LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d",
|
||||
currentFrame->type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,17 +105,17 @@ void DamageAccumulator::popTransform() {
|
||||
DirtyStack* dirtyFrame = mHead;
|
||||
mHead = mHead->prev;
|
||||
switch (dirtyFrame->type) {
|
||||
case TransformRenderNode:
|
||||
applyRenderNodeTransform(dirtyFrame);
|
||||
break;
|
||||
case TransformMatrix4:
|
||||
applyMatrix4Transform(dirtyFrame);
|
||||
break;
|
||||
case TransformNone:
|
||||
mHead->pendingDirty.join(dirtyFrame->pendingDirty);
|
||||
break;
|
||||
default:
|
||||
LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
|
||||
case TransformRenderNode:
|
||||
applyRenderNodeTransform(dirtyFrame);
|
||||
break;
|
||||
case TransformMatrix4:
|
||||
applyMatrix4Transform(dirtyFrame);
|
||||
break;
|
||||
case TransformNone:
|
||||
mHead->pendingDirty.join(dirtyFrame->pendingDirty);
|
||||
break;
|
||||
default:
|
||||
LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,8 +169,7 @@ static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
|
||||
if (frame) {
|
||||
while (frame->prev != frame) {
|
||||
frame = frame->prev;
|
||||
if (frame->type == TransformRenderNode
|
||||
&& frame->renderNode->hasProjectionReceiver()) {
|
||||
if (frame->type == TransformRenderNode && frame->renderNode->hasProjectionReceiver()) {
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,8 @@ void DamageAccumulator::peekAtDirty(SkRect* dest) const {
|
||||
}
|
||||
|
||||
void DamageAccumulator::finish(SkRect* totalDirty) {
|
||||
LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
|
||||
LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p",
|
||||
mHead->prev, mHead);
|
||||
// Root node never has a transform, so this is the fully mapped dirty rect
|
||||
*totalDirty = mHead->pendingDirty;
|
||||
totalDirty->roundOut(totalDirty);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
// Smaller than INT_MIN/INT_MAX because we offset these values
|
||||
// and thus don't want to be adding offsets to INT_MAX, that's bad
|
||||
#define DIRTY_MIN (-0x7ffffff-1)
|
||||
#define DIRTY_MIN (-0x7ffffff - 1)
|
||||
#define DIRTY_MAX (0x7ffffff)
|
||||
|
||||
namespace android {
|
||||
@@ -38,6 +38,7 @@ class Matrix4;
|
||||
|
||||
class DamageAccumulator {
|
||||
PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
|
||||
|
||||
public:
|
||||
DamageAccumulator();
|
||||
// mAllocator will clean everything up for us, no need for a dtor
|
||||
|
||||
@@ -102,9 +102,9 @@
|
||||
#define DEBUG_VECTOR_DRAWABLE 0
|
||||
|
||||
#if DEBUG_INIT
|
||||
#define INIT_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#define INIT_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#else
|
||||
#define INIT_LOGD(...)
|
||||
#define INIT_LOGD(...)
|
||||
#endif
|
||||
|
||||
#endif // ANDROID_HWUI_DEBUG_H
|
||||
#endif // ANDROID_HWUI_DEBUG_H
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
|
||||
Layer::Api layerApi)
|
||||
Layer::Api layerApi)
|
||||
: mRenderState(renderState)
|
||||
, mBlend(false)
|
||||
, mSurfaceTexture(nullptr)
|
||||
@@ -110,8 +110,8 @@ void DeferredLayerUpdater::apply() {
|
||||
|
||||
void DeferredLayerUpdater::doUpdateTexImage() {
|
||||
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
|
||||
"doUpdateTexImage non GL backend %x, GL %x, VK %x",
|
||||
mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
|
||||
"doUpdateTexImage non GL backend %x, GL %x, VK %x", mLayer->getApi(),
|
||||
Layer::Api::OpenGL, Layer::Api::Vulkan);
|
||||
if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
|
||||
float transform[16];
|
||||
|
||||
@@ -132,15 +132,15 @@ void DeferredLayerUpdater::doUpdateTexImage() {
|
||||
sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer();
|
||||
if (buffer != nullptr) {
|
||||
// force filtration if buffer size != layer size
|
||||
forceFilter = mWidth != static_cast<int>(buffer->getWidth())
|
||||
|| mHeight != static_cast<int>(buffer->getHeight());
|
||||
forceFilter = mWidth != static_cast<int>(buffer->getWidth()) ||
|
||||
mHeight != static_cast<int>(buffer->getHeight());
|
||||
}
|
||||
|
||||
#if DEBUG_RENDERER
|
||||
#if DEBUG_RENDERER
|
||||
if (dropCounter > 0) {
|
||||
RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
mSurfaceTexture->getTransformMatrix(transform);
|
||||
|
||||
updateLayer(forceFilter, transform);
|
||||
@@ -149,8 +149,8 @@ void DeferredLayerUpdater::doUpdateTexImage() {
|
||||
|
||||
void DeferredLayerUpdater::doUpdateVkTexImage() {
|
||||
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::Vulkan,
|
||||
"updateLayer non Vulkan backend %x, GL %x, VK %x",
|
||||
mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
|
||||
"updateLayer non Vulkan backend %x, GL %x, VK %x", mLayer->getApi(),
|
||||
Layer::Api::OpenGL, Layer::Api::Vulkan);
|
||||
|
||||
static const mat4 identityMatrix;
|
||||
updateLayer(false, identityMatrix.data);
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cutils/compiler.h>
|
||||
#include <gui/GLConsumer.h>
|
||||
#include <SkColorFilter.h>
|
||||
#include <SkMatrix.h>
|
||||
#include <cutils/compiler.h>
|
||||
#include <gui/GLConsumer.h>
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
@@ -41,10 +41,11 @@ public:
|
||||
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
|
||||
// and will not call incrementRef on it as a result.
|
||||
typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
|
||||
uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
|
||||
SkBlendMode mode, bool blend)> CreateLayerFn;
|
||||
ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState,
|
||||
CreateLayerFn createLayerFn, Layer::Api layerApi);
|
||||
uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
|
||||
SkBlendMode mode, bool blend)>
|
||||
CreateLayerFn;
|
||||
ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
|
||||
Layer::Api layerApi);
|
||||
|
||||
ANDROID_API ~DeferredLayerUpdater();
|
||||
|
||||
@@ -74,30 +75,24 @@ public:
|
||||
|
||||
GLenum target = texture->getCurrentTextureTarget();
|
||||
LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
|
||||
"set unsupported GLConsumer with target %x", target);
|
||||
"set unsupported GLConsumer with target %x", target);
|
||||
}
|
||||
}
|
||||
|
||||
ANDROID_API void updateTexImage() {
|
||||
mUpdateTexImage = true;
|
||||
}
|
||||
ANDROID_API void updateTexImage() { mUpdateTexImage = true; }
|
||||
|
||||
ANDROID_API void setTransform(const SkMatrix* matrix) {
|
||||
delete mTransform;
|
||||
mTransform = matrix ? new SkMatrix(*matrix) : nullptr;
|
||||
}
|
||||
|
||||
SkMatrix* getTransform() {
|
||||
return mTransform;
|
||||
}
|
||||
SkMatrix* getTransform() { return mTransform; }
|
||||
|
||||
ANDROID_API void setPaint(const SkPaint* paint);
|
||||
|
||||
void apply();
|
||||
|
||||
Layer* backingLayer() {
|
||||
return mLayer;
|
||||
}
|
||||
Layer* backingLayer() { return mLayer; }
|
||||
|
||||
void detachSurfaceTexture();
|
||||
|
||||
@@ -105,9 +100,7 @@ public:
|
||||
|
||||
void destroyLayer();
|
||||
|
||||
Layer::Api getBackingLayerApi() {
|
||||
return mLayerApi;
|
||||
}
|
||||
Layer::Api getBackingLayerApi() { return mLayerApi; }
|
||||
|
||||
private:
|
||||
RenderState& mRenderState;
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#include <gui/ISurfaceComposer.h>
|
||||
#include <gui/SurfaceComposerClient.h>
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
@@ -58,8 +58,7 @@ void DeviceInfo::load() {
|
||||
}
|
||||
|
||||
void DeviceInfo::loadDisplayInfo() {
|
||||
sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
|
||||
ISurfaceComposer::eDisplayIdMain));
|
||||
sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
|
||||
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
|
||||
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info, error %d", status);
|
||||
}
|
||||
|
||||
@@ -18,14 +18,15 @@
|
||||
|
||||
#include <ui/DisplayInfo.h>
|
||||
|
||||
#include "utils/Macros.h"
|
||||
#include "Extensions.h"
|
||||
#include "utils/Macros.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class DeviceInfo {
|
||||
PREVENT_COPY_AND_ASSIGN(DeviceInfo);
|
||||
|
||||
public:
|
||||
// returns nullptr if DeviceInfo is not initialized yet
|
||||
// Note this does not have a memory fence so it's up to the caller
|
||||
|
||||
@@ -44,8 +44,7 @@ DisplayList::DisplayList()
|
||||
, regions(stdAllocator)
|
||||
, referenceHolders(stdAllocator)
|
||||
, functors(stdAllocator)
|
||||
, vectorDrawables(stdAllocator) {
|
||||
}
|
||||
, vectorDrawables(stdAllocator) {}
|
||||
|
||||
DisplayList::~DisplayList() {
|
||||
cleanupResources();
|
||||
@@ -105,14 +104,16 @@ void DisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) {
|
||||
}
|
||||
}
|
||||
|
||||
bool DisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
|
||||
bool DisplayList::prepareListAndChildren(
|
||||
TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
|
||||
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
|
||||
info.prepareTextures = info.canvasContext.pinImages(bitmapResources);
|
||||
|
||||
for (auto&& op : children) {
|
||||
RenderNode* childNode = op->renderNode;
|
||||
info.damageAccumulator->pushTransform(&op->localMatrix);
|
||||
bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
|
||||
bool childFunctorsNeedLayer =
|
||||
functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
|
||||
childFn(childNode, observer, info, childFunctorsNeedLayer);
|
||||
info.damageAccumulator->popTransform();
|
||||
}
|
||||
@@ -140,5 +141,5 @@ void DisplayList::output(std::ostream& output, uint32_t level) {
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
|
||||
#include "Debug.h"
|
||||
#include "CanvasProperty.h"
|
||||
#include "Debug.h"
|
||||
#include "GlFunctorLifecycleListener.h"
|
||||
#include "Matrix.h"
|
||||
#include "RenderProperties.h"
|
||||
@@ -74,6 +74,7 @@ struct FunctorContainer {
|
||||
*/
|
||||
class DisplayList {
|
||||
friend class RecordingCanvas;
|
||||
|
||||
public:
|
||||
struct Chunk {
|
||||
// range of included ops in DisplayList::ops()
|
||||
@@ -106,14 +107,9 @@ public:
|
||||
|
||||
size_t addChild(NodeOpType* childOp);
|
||||
|
||||
void ref(VirtualLightRefBase* prop) { referenceHolders.push_back(prop); }
|
||||
|
||||
void ref(VirtualLightRefBase* prop) {
|
||||
referenceHolders.push_back(prop);
|
||||
}
|
||||
|
||||
size_t getUsedSize() {
|
||||
return allocator.usedSize();
|
||||
}
|
||||
size_t getUsedSize() { return allocator.usedSize(); }
|
||||
|
||||
virtual bool isEmpty() const { return ops.empty(); }
|
||||
virtual bool hasFunctor() const { return !functors.empty(); }
|
||||
@@ -125,7 +121,8 @@ public:
|
||||
|
||||
virtual void syncContents();
|
||||
virtual void updateChildren(std::function<void(RenderNode*)> updateFn);
|
||||
virtual bool prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
|
||||
virtual bool prepareListAndChildren(
|
||||
TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
|
||||
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn);
|
||||
|
||||
virtual void output(std::ostream& output, uint32_t level);
|
||||
@@ -148,12 +145,13 @@ private:
|
||||
LsaVector<const Res_png_9patch*> patchResources;
|
||||
LsaVector<std::unique_ptr<const SkPaint>> paints;
|
||||
LsaVector<std::unique_ptr<const SkRegion>> regions;
|
||||
LsaVector< sp<VirtualLightRefBase> > referenceHolders;
|
||||
LsaVector<sp<VirtualLightRefBase>> referenceHolders;
|
||||
|
||||
// List of functors
|
||||
LsaVector<FunctorContainer> functors;
|
||||
|
||||
// List of VectorDrawables that need to be notified of pushStaging. Note that this list gets nothing
|
||||
// List of VectorDrawables that need to be notified of pushStaging. Note that this list gets
|
||||
// nothing
|
||||
// but a callback during sync DisplayList, unlike the list of functors defined above, which
|
||||
// gets special treatment exclusive for webview.
|
||||
LsaVector<VectorDrawableRoot*> vectorDrawables;
|
||||
@@ -161,5 +159,5 @@ private:
|
||||
void cleanupResources();
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -32,13 +32,13 @@ namespace uirenderer {
|
||||
|
||||
Extensions::Extensions() {
|
||||
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
|
||||
//Extensions class is used only by OpenGL and SkiaGL pipelines
|
||||
//The code below will crash for SkiaVulkan, because OpenGL is not initialized
|
||||
//TODO: instantiate Extensions class only for OpenGL pipeline
|
||||
//TODO: remove the only usage of Extensions by SkiaGL in SkiaOpenGLReadback::copyImageInto
|
||||
// Extensions class is used only by OpenGL and SkiaGL pipelines
|
||||
// The code below will crash for SkiaVulkan, because OpenGL is not initialized
|
||||
// TODO: instantiate Extensions class only for OpenGL pipeline
|
||||
// TODO: remove the only usage of Extensions by SkiaGL in SkiaOpenGLReadback::copyImageInto
|
||||
return;
|
||||
}
|
||||
const char* version = (const char*) glGetString(GL_VERSION);
|
||||
const char* version = (const char*)glGetString(GL_VERSION);
|
||||
|
||||
// Section 6.1.5 of the OpenGL ES specification indicates the GL version
|
||||
// string strictly follows this format:
|
||||
@@ -58,7 +58,7 @@ Extensions::Extensions() {
|
||||
mVersionMinor = 0;
|
||||
}
|
||||
|
||||
auto extensions = StringUtils::split((const char*) glGetString(GL_EXTENSIONS));
|
||||
auto extensions = StringUtils::split((const char*)glGetString(GL_EXTENSIONS));
|
||||
mHasNPot = extensions.has("GL_OES_texture_npot");
|
||||
mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch");
|
||||
mHasDiscardFramebuffer = extensions.has("GL_EXT_discard_framebuffer");
|
||||
@@ -83,5 +83,5 @@ Extensions::Extensions() {
|
||||
#endif
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -63,9 +63,9 @@ private:
|
||||
|
||||
int mVersionMajor;
|
||||
int mVersionMinor;
|
||||
}; // class Extensions
|
||||
}; // class Extensions
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_EXTENSIONS_H
|
||||
#endif // ANDROID_HWUI_EXTENSIONS_H
|
||||
|
||||
@@ -27,8 +27,7 @@ namespace uirenderer {
|
||||
// Constructors/destructor
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FboCache::FboCache()
|
||||
: mMaxSize(0) {}
|
||||
FboCache::FboCache() : mMaxSize(0) {}
|
||||
|
||||
FboCache::~FboCache() {
|
||||
clear();
|
||||
@@ -79,5 +78,5 @@ bool FboCache::put(GLuint fbo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -71,9 +71,9 @@ public:
|
||||
private:
|
||||
SortedVector<GLuint> mCache;
|
||||
uint32_t mMaxSize;
|
||||
}; // class FboCache
|
||||
}; // class FboCache
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_FBO_CACHE_H
|
||||
#endif // ANDROID_HWUI_FBO_CACHE_H
|
||||
|
||||
@@ -33,8 +33,8 @@ struct FloatColor {
|
||||
void set(uint32_t color) {
|
||||
a = ((color >> 24) & 0xff) / 255.0f;
|
||||
r = a * EOCF(((color >> 16) & 0xff) / 255.0f);
|
||||
g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
|
||||
b = a * EOCF(((color ) & 0xff) / 255.0f);
|
||||
g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
|
||||
b = a * EOCF(((color)&0xff) / 255.0f);
|
||||
}
|
||||
|
||||
// "color" is a gamma-encoded sRGB color
|
||||
@@ -44,27 +44,18 @@ struct FloatColor {
|
||||
void setUnPreMultiplied(uint32_t color) {
|
||||
a = ((color >> 24) & 0xff) / 255.0f;
|
||||
r = EOCF(((color >> 16) & 0xff) / 255.0f);
|
||||
g = EOCF(((color >> 8) & 0xff) / 255.0f);
|
||||
b = EOCF(((color ) & 0xff) / 255.0f);
|
||||
g = EOCF(((color >> 8) & 0xff) / 255.0f);
|
||||
b = EOCF(((color)&0xff) / 255.0f);
|
||||
}
|
||||
|
||||
bool isNotBlack() {
|
||||
return a < 1.0f
|
||||
|| r > 0.0f
|
||||
|| g > 0.0f
|
||||
|| b > 0.0f;
|
||||
}
|
||||
bool isNotBlack() { return a < 1.0f || r > 0.0f || g > 0.0f || b > 0.0f; }
|
||||
|
||||
bool operator==(const FloatColor& other) const {
|
||||
return MathUtils::areEqual(r, other.r)
|
||||
&& MathUtils::areEqual(g, other.g)
|
||||
&& MathUtils::areEqual(b, other.b)
|
||||
&& MathUtils::areEqual(a, other.a);
|
||||
return MathUtils::areEqual(r, other.r) && MathUtils::areEqual(g, other.g) &&
|
||||
MathUtils::areEqual(b, other.b) && MathUtils::areEqual(a, other.a);
|
||||
}
|
||||
|
||||
bool operator!=(const FloatColor& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool operator!=(const FloatColor& other) const { return !(*this == other); }
|
||||
|
||||
float r;
|
||||
float g;
|
||||
|
||||
@@ -22,20 +22,20 @@
|
||||
#include "Caches.h"
|
||||
#include "Debug.h"
|
||||
#include "Extensions.h"
|
||||
#include "font/Font.h"
|
||||
#include "Glop.h"
|
||||
#include "GlopBuilder.h"
|
||||
#include "PixelBuffer.h"
|
||||
#include "Rect.h"
|
||||
#include "font/Font.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "utils/Blur.h"
|
||||
#include "utils/Timing.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <RenderScript.h>
|
||||
#include <SkGlyph.h>
|
||||
#include <SkUtils.h>
|
||||
#include <utils/Log.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
@@ -55,8 +55,8 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
|
||||
if (linearFiltering) {
|
||||
textureFillFlags |= TextureFillFlags::ForceFilter;
|
||||
}
|
||||
int transformFlags = pureTranslate
|
||||
? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
|
||||
int transformFlags =
|
||||
pureTranslate ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
|
||||
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
|
||||
bool gammaCorrection = true;
|
||||
#else
|
||||
@@ -93,7 +93,6 @@ FontRenderer::FontRenderer(const uint8_t* gammaTable)
|
||||
, mDrawn(false)
|
||||
, mInitialized(false)
|
||||
, mLinearFiltering(false) {
|
||||
|
||||
if (sLogFontRendererCreate) {
|
||||
INIT_LOGD("Creating FontRenderer");
|
||||
}
|
||||
@@ -118,10 +117,8 @@ FontRenderer::FontRenderer(const uint8_t* gammaTable)
|
||||
|
||||
if (sLogFontRendererCreate) {
|
||||
INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
|
||||
mSmallCacheWidth, mSmallCacheHeight,
|
||||
mLargeCacheWidth, mLargeCacheHeight >> 1,
|
||||
mLargeCacheWidth, mLargeCacheHeight >> 1,
|
||||
mLargeCacheWidth, mLargeCacheHeight);
|
||||
mSmallCacheWidth, mSmallCacheHeight, mLargeCacheWidth, mLargeCacheHeight >> 1,
|
||||
mLargeCacheWidth, mLargeCacheHeight >> 1, mLargeCacheWidth, mLargeCacheHeight);
|
||||
}
|
||||
|
||||
sLogFontRendererCreate = false;
|
||||
@@ -195,7 +192,8 @@ void FontRenderer::flushLargeCaches() {
|
||||
}
|
||||
|
||||
CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
|
||||
const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
|
||||
const SkGlyph& glyph, uint32_t* startX,
|
||||
uint32_t* startY) {
|
||||
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
|
||||
if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
|
||||
return cacheTextures[i];
|
||||
@@ -206,7 +204,7 @@ CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cac
|
||||
}
|
||||
|
||||
void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
|
||||
uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
|
||||
uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
|
||||
checkInit();
|
||||
|
||||
// If the glyph bitmap is empty let's assum the glyph is valid
|
||||
@@ -234,14 +232,14 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
|
||||
#if DEBUG_FONT_RENDERER
|
||||
ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
|
||||
#endif
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the glyph is too tall, don't cache it
|
||||
if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
|
||||
(*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
|
||||
ALOGE("Font size too large to fit in cache. width, height = %i, %i",
|
||||
(int) glyph.fWidth, (int) glyph.fHeight);
|
||||
(*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
|
||||
ALOGE("Font size too large to fit in cache. width, height = %i, %i", (int)glyph.fWidth,
|
||||
(int)glyph.fHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -285,14 +283,14 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
|
||||
}
|
||||
|
||||
uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
|
||||
uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
|
||||
uint8_t* bitmapBuffer = (uint8_t*)glyph.fImage;
|
||||
int srcStride = glyph.rowBytes();
|
||||
|
||||
// Copy the glyph image, taking the mask format into account
|
||||
switch (format) {
|
||||
case SkMask::kA8_Format: {
|
||||
uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
|
||||
- TEXTURE_BORDER_SIZE;
|
||||
uint32_t row =
|
||||
(startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
|
||||
// write leading border line
|
||||
memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
|
||||
// write glyph data
|
||||
@@ -337,9 +335,9 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
|
||||
memset(dstL, 0, rowSize + 2 * borderSize);
|
||||
// write glyph data
|
||||
while (dst < dstEnd) {
|
||||
memset(dstL += dstStride, 0, borderSize); // leading border column
|
||||
memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
|
||||
memset(dstR += dstStride, 0, borderSize); // trailing border column
|
||||
memset(dstL += dstStride, 0, borderSize); // leading border column
|
||||
memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
|
||||
memset(dstR += dstStride, 0, borderSize); // trailing border column
|
||||
}
|
||||
// write trailing border line
|
||||
memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
|
||||
@@ -347,9 +345,9 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
|
||||
}
|
||||
case SkMask::kBW_Format: {
|
||||
uint32_t cacheX = 0, cacheY = 0;
|
||||
uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
|
||||
- TEXTURE_BORDER_SIZE;
|
||||
static const uint8_t COLORS[2] = { 0, 255 };
|
||||
uint32_t row =
|
||||
(startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
|
||||
static const uint8_t COLORS[2] = {0, 255};
|
||||
// write leading border line
|
||||
memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
|
||||
// write glyph data
|
||||
@@ -388,7 +386,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
|
||||
}
|
||||
|
||||
CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
|
||||
bool allocate) {
|
||||
bool allocate) {
|
||||
CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
|
||||
|
||||
if (allocate) {
|
||||
@@ -405,18 +403,18 @@ void FontRenderer::initTextTexture() {
|
||||
clearCacheTextures(mRGBACacheTextures);
|
||||
|
||||
mUploadTexture = false;
|
||||
mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
|
||||
GL_ALPHA, true));
|
||||
mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
|
||||
GL_ALPHA, false));
|
||||
mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
|
||||
GL_ALPHA, false));
|
||||
mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
|
||||
GL_ALPHA, false));
|
||||
mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
|
||||
GL_RGBA, false));
|
||||
mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
|
||||
GL_RGBA, false));
|
||||
mACacheTextures.push_back(
|
||||
createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_ALPHA, true));
|
||||
mACacheTextures.push_back(
|
||||
createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false));
|
||||
mACacheTextures.push_back(
|
||||
createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false));
|
||||
mACacheTextures.push_back(
|
||||
createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, GL_ALPHA, false));
|
||||
mRGBACacheTextures.push_back(
|
||||
createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_RGBA, false));
|
||||
mRGBACacheTextures.push_back(
|
||||
createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_RGBA, false));
|
||||
mCurrentCacheTexture = mACacheTextures[0];
|
||||
}
|
||||
|
||||
@@ -432,7 +430,7 @@ void FontRenderer::checkInit() {
|
||||
}
|
||||
|
||||
void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
|
||||
bool& resetPixelStore, GLuint& lastTextureId) {
|
||||
bool& resetPixelStore, GLuint& lastTextureId) {
|
||||
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
|
||||
CacheTexture* cacheTexture = cacheTextures[i];
|
||||
if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
|
||||
@@ -500,24 +498,22 @@ void FontRenderer::issueDrawCommand() {
|
||||
issueDrawCommand(mRGBACacheTextures);
|
||||
}
|
||||
|
||||
void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
|
||||
float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4, CacheTexture* texture) {
|
||||
void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2,
|
||||
float u2, float v2, float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4,
|
||||
CacheTexture* texture) {
|
||||
if (texture != mCurrentCacheTexture) {
|
||||
// Now use the new texture id
|
||||
mCurrentCacheTexture = texture;
|
||||
}
|
||||
|
||||
mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
|
||||
x3, y3, u3, v3, x4, y4, u4, v4);
|
||||
mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4);
|
||||
}
|
||||
|
||||
void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
|
||||
float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4, CacheTexture* texture) {
|
||||
|
||||
if (mClip &&
|
||||
(x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
|
||||
void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2,
|
||||
float u2, float v2, float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4, CacheTexture* texture) {
|
||||
if (mClip && (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -535,10 +531,10 @@ void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
|
||||
}
|
||||
}
|
||||
|
||||
void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
|
||||
float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4, CacheTexture* texture) {
|
||||
|
||||
void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2,
|
||||
float u2, float v2, float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4,
|
||||
CacheTexture* texture) {
|
||||
appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
|
||||
|
||||
if (mBounds) {
|
||||
@@ -557,8 +553,9 @@ void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
|
||||
mCurrentFont = Font::create(this, paint, matrix);
|
||||
}
|
||||
|
||||
FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
|
||||
int numGlyphs, float radius, const float* positions) {
|
||||
FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t* glyphs,
|
||||
int numGlyphs, float radius,
|
||||
const float* positions) {
|
||||
checkInit();
|
||||
|
||||
DropShadow image;
|
||||
@@ -580,8 +577,8 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
|
||||
mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
|
||||
|
||||
uint32_t intRadius = Blur::convertRadiusToInt(radius);
|
||||
uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
|
||||
uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
|
||||
uint32_t paddedWidth = (uint32_t)(bounds.right - bounds.left) + 2 * intRadius;
|
||||
uint32_t paddedHeight = (uint32_t)(bounds.top - bounds.bottom) + 2 * intRadius;
|
||||
|
||||
uint32_t maxSize = Caches::getInstance().maxTextureSize;
|
||||
if (paddedWidth > maxSize || paddedHeight > maxSize) {
|
||||
@@ -593,7 +590,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
|
||||
paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
|
||||
}
|
||||
int size = paddedWidth * paddedHeight;
|
||||
uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
|
||||
uint8_t* dataBuffer = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
|
||||
|
||||
memset(dataBuffer, 0, size);
|
||||
|
||||
@@ -604,8 +601,8 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
|
||||
// text has non-whitespace, so draw and blur to create the shadow
|
||||
// NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
|
||||
// TODO: don't draw pure whitespace in the first place, and avoid needing this check
|
||||
mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
|
||||
Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
|
||||
mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY, Font::BITMAP, dataBuffer,
|
||||
paddedWidth, paddedHeight, nullptr, positions);
|
||||
|
||||
// Unbind any PBO we might have used
|
||||
Caches::getInstance().pixelBufferState().unbind();
|
||||
@@ -639,7 +636,7 @@ void FontRenderer::finishRender() {
|
||||
}
|
||||
|
||||
void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
|
||||
const SkMatrix& matrix) {
|
||||
const SkMatrix& matrix) {
|
||||
Font* font = Font::create(this, paint, matrix);
|
||||
font->precache(paint, glyphs, numGlyphs);
|
||||
}
|
||||
@@ -649,8 +646,8 @@ void FontRenderer::endPrecaching() {
|
||||
}
|
||||
|
||||
bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
|
||||
int numGlyphs, int x, int y, const float* positions,
|
||||
Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
|
||||
int numGlyphs, int x, int y, const float* positions, Rect* bounds,
|
||||
TextDrawFunctor* functor, bool forceFinish) {
|
||||
if (!mCurrentFont) {
|
||||
ALOGE("No font set");
|
||||
return false;
|
||||
@@ -667,8 +664,8 @@ bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const g
|
||||
}
|
||||
|
||||
bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
|
||||
int numGlyphs, const SkPath* path, float hOffset, float vOffset,
|
||||
Rect* bounds, TextDrawFunctor* functor) {
|
||||
int numGlyphs, const SkPath* path, float hOffset, float vOffset,
|
||||
Rect* bounds, TextDrawFunctor* functor) {
|
||||
if (!mCurrentFont) {
|
||||
ALOGE("No font set");
|
||||
return false;
|
||||
@@ -684,7 +681,7 @@ bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, cons
|
||||
void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
|
||||
uint32_t intRadius = Blur::convertRadiusToInt(radius);
|
||||
if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
|
||||
uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
|
||||
uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
|
||||
|
||||
if (mRs == nullptr) {
|
||||
mRs = new RSC::RS();
|
||||
@@ -700,14 +697,12 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo
|
||||
}
|
||||
if (mRs != nullptr) {
|
||||
RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
|
||||
RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
|
||||
RS_ALLOCATION_MIPMAP_NONE,
|
||||
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
|
||||
*image);
|
||||
RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
|
||||
RS_ALLOCATION_MIPMAP_NONE,
|
||||
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
|
||||
outImage);
|
||||
RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(
|
||||
mRs, t, RS_ALLOCATION_MIPMAP_NONE,
|
||||
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, *image);
|
||||
RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(
|
||||
mRs, t, RS_ALLOCATION_MIPMAP_NONE,
|
||||
RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, outImage);
|
||||
|
||||
mRsScript->setRadius(radius);
|
||||
mRsScript->setInput(ain);
|
||||
@@ -768,7 +763,7 @@ const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum fo
|
||||
}
|
||||
|
||||
static void dumpTextures(String8& log, const char* tag,
|
||||
const std::vector<CacheTexture*>& cacheTextures) {
|
||||
const std::vector<CacheTexture*>& cacheTextures) {
|
||||
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
|
||||
CacheTexture* cacheTexture = cacheTextures[i];
|
||||
if (cacheTexture && cacheTexture->getPixelBuffer()) {
|
||||
@@ -803,5 +798,5 @@ uint32_t FontRenderer::getSize() const {
|
||||
return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "font/FontUtil.h"
|
||||
#include "font/CacheTexture.h"
|
||||
#include "font/CachedGlyphInfo.h"
|
||||
#include "font/Font.h"
|
||||
#include "font/FontUtil.h"
|
||||
#ifdef BUGREPORT_FONT_CACHE_USAGE
|
||||
#include "font/FontCacheHistoryTracker.h"
|
||||
#endif
|
||||
@@ -36,10 +36,10 @@
|
||||
|
||||
#include "RenderScript.h"
|
||||
namespace RSC {
|
||||
class Element;
|
||||
class RS;
|
||||
class ScriptIntrinsicBlur;
|
||||
class sp;
|
||||
class Element;
|
||||
class RS;
|
||||
class ScriptIntrinsicBlur;
|
||||
class sp;
|
||||
}
|
||||
|
||||
namespace android {
|
||||
@@ -51,22 +51,18 @@ struct ClipBase;
|
||||
|
||||
class TextDrawFunctor {
|
||||
public:
|
||||
TextDrawFunctor(
|
||||
BakedOpRenderer* renderer,
|
||||
const BakedOpState* bakedState,
|
||||
const ClipBase* clip,
|
||||
float x, float y, bool pureTranslate,
|
||||
int alpha, SkBlendMode mode, const SkPaint* paint)
|
||||
: renderer(renderer)
|
||||
, bakedState(bakedState)
|
||||
, clip(clip)
|
||||
, x(x)
|
||||
, y(y)
|
||||
, pureTranslate(pureTranslate)
|
||||
, alpha(alpha)
|
||||
, mode(mode)
|
||||
, paint(paint) {
|
||||
}
|
||||
TextDrawFunctor(BakedOpRenderer* renderer, const BakedOpState* bakedState, const ClipBase* clip,
|
||||
float x, float y, bool pureTranslate, int alpha, SkBlendMode mode,
|
||||
const SkPaint* paint)
|
||||
: renderer(renderer)
|
||||
, bakedState(bakedState)
|
||||
, clip(clip)
|
||||
, x(x)
|
||||
, y(y)
|
||||
, pureTranslate(pureTranslate)
|
||||
, alpha(alpha)
|
||||
, mode(mode)
|
||||
, paint(paint) {}
|
||||
|
||||
void draw(CacheTexture& texture, bool linearFiltering);
|
||||
|
||||
@@ -91,16 +87,17 @@ public:
|
||||
|
||||
void setFont(const SkPaint* paint, const SkMatrix& matrix);
|
||||
|
||||
void precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, const SkMatrix& matrix);
|
||||
void precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
|
||||
const SkMatrix& matrix);
|
||||
void endPrecaching();
|
||||
|
||||
bool renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
|
||||
int numGlyphs, int x, int y, const float* positions,
|
||||
Rect* outBounds, TextDrawFunctor* functor, bool forceFinish = true);
|
||||
bool renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs, int numGlyphs,
|
||||
int x, int y, const float* positions, Rect* outBounds,
|
||||
TextDrawFunctor* functor, bool forceFinish = true);
|
||||
|
||||
bool renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
|
||||
int numGlyphs, const SkPath* path,
|
||||
float hOffset, float vOffset, Rect* outBounds, TextDrawFunctor* functor);
|
||||
int numGlyphs, const SkPath* path, float hOffset, float vOffset,
|
||||
Rect* outBounds, TextDrawFunctor* functor);
|
||||
|
||||
struct DropShadow {
|
||||
uint32_t width;
|
||||
@@ -112,12 +109,10 @@ public:
|
||||
|
||||
// After renderDropShadow returns, the called owns the memory in DropShadow.image
|
||||
// and is responsible for releasing it when it's done with it
|
||||
DropShadow renderDropShadow(const SkPaint* paint, const glyph_t *glyphs, int numGlyphs,
|
||||
float radius, const float* positions);
|
||||
DropShadow renderDropShadow(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
|
||||
float radius, const float* positions);
|
||||
|
||||
void setTextureFiltering(bool linearFiltering) {
|
||||
mLinearFiltering = linearFiltering;
|
||||
}
|
||||
void setTextureFiltering(bool linearFiltering) { mLinearFiltering = linearFiltering; }
|
||||
|
||||
uint32_t getSize() const;
|
||||
void dumpMemoryUsage(String8& log) const;
|
||||
@@ -135,10 +130,10 @@ private:
|
||||
void deallocateTextureMemory(CacheTexture* cacheTexture);
|
||||
void initTextTexture();
|
||||
CacheTexture* createCacheTexture(int width, int height, GLenum format, bool allocate);
|
||||
void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
|
||||
uint32_t *retOriginX, uint32_t *retOriginY, bool precaching);
|
||||
CacheTexture* cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures, const SkGlyph& glyph,
|
||||
uint32_t* startX, uint32_t* startY);
|
||||
void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, uint32_t* retOriginX,
|
||||
uint32_t* retOriginY, bool precaching);
|
||||
CacheTexture* cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
|
||||
const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);
|
||||
|
||||
void flushAllAndInvalidate();
|
||||
|
||||
@@ -148,24 +143,19 @@ private:
|
||||
|
||||
void issueDrawCommand(std::vector<CacheTexture*>& cacheTextures);
|
||||
void issueDrawCommand();
|
||||
void appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
|
||||
float x2, float y2, float u2, float v2,
|
||||
float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4, CacheTexture* texture);
|
||||
void appendMeshQuad(float x1, float y1, float u1, float v1,
|
||||
float x2, float y2, float u2, float v2,
|
||||
float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4, CacheTexture* texture);
|
||||
void appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
|
||||
float x2, float y2, float u2, float v2,
|
||||
float x3, float y3, float u3, float v3,
|
||||
float x4, float y4, float u4, float v4, CacheTexture* texture);
|
||||
void appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
|
||||
float v2, float x3, float y3, float u3, float v3, float x4, float y4,
|
||||
float u4, float v4, CacheTexture* texture);
|
||||
void appendMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
|
||||
float v2, float x3, float y3, float u3, float v3, float x4, float y4,
|
||||
float u4, float v4, CacheTexture* texture);
|
||||
void appendRotatedMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
|
||||
float v2, float x3, float y3, float u3, float v3, float x4, float y4,
|
||||
float u4, float v4, CacheTexture* texture);
|
||||
|
||||
void checkTextureUpdate();
|
||||
|
||||
void setTextureDirty() {
|
||||
mUploadTexture = true;
|
||||
}
|
||||
void setTextureDirty() { mUploadTexture = true; }
|
||||
|
||||
const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const;
|
||||
uint32_t getCacheSize(GLenum format) const;
|
||||
@@ -205,14 +195,14 @@ private:
|
||||
RSC::sp<RSC::ScriptIntrinsicBlur> mRsScript;
|
||||
|
||||
static void computeGaussianWeights(float* weights, int32_t radius);
|
||||
static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
|
||||
int32_t width, int32_t height);
|
||||
static void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
|
||||
int32_t width, int32_t height);
|
||||
static void horizontalBlur(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
|
||||
int32_t width, int32_t height);
|
||||
static void verticalBlur(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
|
||||
int32_t width, int32_t height);
|
||||
|
||||
// the input image handle may have its pointer replaced (to avoid copies)
|
||||
void blurImage(uint8_t** image, int32_t width, int32_t height, float radius);
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include "LayerUpdateQueue.h"
|
||||
#include "RenderNode.h"
|
||||
#include "VectorDrawable.h"
|
||||
#include "renderstate/OffscreenBufferPool.h"
|
||||
#include "hwui/Canvas.h"
|
||||
#include "renderstate/OffscreenBufferPool.h"
|
||||
#include "utils/FatVector.h"
|
||||
#include "utils/PaintUtils.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
@@ -32,9 +32,8 @@
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
FrameBuilder::FrameBuilder(const SkRect& clip,
|
||||
uint32_t viewportWidth, uint32_t viewportHeight,
|
||||
const LightGeometry& lightGeometry, Caches& caches)
|
||||
FrameBuilder::FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
|
||||
const LightGeometry& lightGeometry, Caches& caches)
|
||||
: mStdAllocator(mAllocator)
|
||||
, mLayerBuilders(mStdAllocator)
|
||||
, mLayerStack(mStdAllocator)
|
||||
@@ -42,18 +41,16 @@ FrameBuilder::FrameBuilder(const SkRect& clip,
|
||||
, mCaches(caches)
|
||||
, mLightRadius(lightGeometry.radius)
|
||||
, mDrawFbo0(true) {
|
||||
|
||||
// Prepare to defer Fbo0
|
||||
auto fbo0 = mAllocator.create<LayerBuilder>(viewportWidth, viewportHeight, Rect(clip));
|
||||
mLayerBuilders.push_back(fbo0);
|
||||
mLayerStack.push_back(0);
|
||||
mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
|
||||
clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
|
||||
lightGeometry.center);
|
||||
mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, clip.fLeft, clip.fTop,
|
||||
clip.fRight, clip.fBottom, lightGeometry.center);
|
||||
}
|
||||
|
||||
FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers,
|
||||
const LightGeometry& lightGeometry, Caches& caches)
|
||||
FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const LightGeometry& lightGeometry,
|
||||
Caches& caches)
|
||||
: mStdAllocator(mAllocator)
|
||||
, mLayerBuilders(mStdAllocator)
|
||||
, mLayerStack(mStdAllocator)
|
||||
@@ -67,9 +64,7 @@ FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers,
|
||||
auto fbo0 = mAllocator.create<LayerBuilder>(1, 1, Rect(1, 1));
|
||||
mLayerBuilders.push_back(fbo0);
|
||||
mLayerStack.push_back(0);
|
||||
mCanvasState.initializeSaveStack(1, 1,
|
||||
0, 0, 1, 1,
|
||||
lightGeometry.center);
|
||||
mCanvasState.initializeSaveStack(1, 1, 0, 0, 1, 1, lightGeometry.center);
|
||||
|
||||
deferLayers(layers);
|
||||
}
|
||||
@@ -84,8 +79,8 @@ void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) {
|
||||
// as not to lose info on what portion is damaged
|
||||
OffscreenBuffer* layer = layerNode->getLayer();
|
||||
if (CC_LIKELY(layer)) {
|
||||
ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u",
|
||||
layerNode->getName(), layerNode->getWidth(), layerNode->getHeight());
|
||||
ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u", layerNode->getName(),
|
||||
layerNode->getWidth(), layerNode->getHeight());
|
||||
|
||||
Rect layerDamage = layers.entries()[i].damage;
|
||||
// TODO: ensure layer damage can't be larger than layer
|
||||
@@ -96,8 +91,8 @@ void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) {
|
||||
Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
|
||||
layer->inverseTransformInWindow.mapPoint3d(lightCenter);
|
||||
|
||||
saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
|
||||
layerDamage, lightCenter, nullptr, layerNode);
|
||||
saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0, layerDamage,
|
||||
lightCenter, nullptr, layerNode);
|
||||
|
||||
if (layerNode->getDisplayList()) {
|
||||
deferNodeOps(*layerNode);
|
||||
@@ -121,19 +116,18 @@ void FrameBuilder::deferRenderNode(float tx, float ty, Rect clipRect, RenderNode
|
||||
mCanvasState.save(SaveFlags::MatrixClip);
|
||||
mCanvasState.translate(tx, ty);
|
||||
mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
|
||||
SkClipOp::kIntersect);
|
||||
SkClipOp::kIntersect);
|
||||
deferNodePropsAndOps(renderNode);
|
||||
mCanvasState.restore();
|
||||
}
|
||||
|
||||
static Rect nodeBounds(RenderNode& node) {
|
||||
auto& props = node.properties();
|
||||
return Rect(props.getLeft(), props.getTop(),
|
||||
props.getRight(), props.getBottom());
|
||||
return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom());
|
||||
}
|
||||
|
||||
void FrameBuilder::deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes,
|
||||
const Rect& contentDrawBounds) {
|
||||
void FrameBuilder::deferRenderNodeScene(const std::vector<sp<RenderNode> >& nodes,
|
||||
const Rect& contentDrawBounds) {
|
||||
if (nodes.size() < 1) return;
|
||||
if (nodes.size() == 1) {
|
||||
if (!nodes[0]->nothingToDraw()) {
|
||||
@@ -170,14 +164,16 @@ void FrameBuilder::deferRenderNodeScene(const std::vector< sp<RenderNode> >& nod
|
||||
// the backdrop, so this isn't necessary.
|
||||
if (content.right < backdrop.right) {
|
||||
// draw backdrop to right side of content
|
||||
deferRenderNode(0, 0, Rect(content.right, backdrop.top,
|
||||
backdrop.right, backdrop.bottom), *nodes[0]);
|
||||
deferRenderNode(0, 0,
|
||||
Rect(content.right, backdrop.top, backdrop.right, backdrop.bottom),
|
||||
*nodes[0]);
|
||||
}
|
||||
if (content.bottom < backdrop.bottom) {
|
||||
// draw backdrop to bottom of content
|
||||
// Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
|
||||
deferRenderNode(0, 0, Rect(content.left, content.bottom,
|
||||
content.right, backdrop.bottom), *nodes[0]);
|
||||
deferRenderNode(0, 0,
|
||||
Rect(content.left, content.bottom, content.right, backdrop.bottom),
|
||||
*nodes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,11 +206,9 @@ void FrameBuilder::onSnapshotRestored(const Snapshot& removed, const Snapshot& r
|
||||
void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
|
||||
const RenderProperties& properties = node.properties();
|
||||
const Outline& outline = properties.getOutline();
|
||||
if (properties.getAlpha() <= 0
|
||||
|| (outline.getShouldClip() && outline.isEmpty())
|
||||
|| properties.getScaleX() == 0
|
||||
|| properties.getScaleY() == 0) {
|
||||
return; // rejected
|
||||
if (properties.getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty()) ||
|
||||
properties.getScaleX() == 0 || properties.getScaleY() == 0) {
|
||||
return; // rejected
|
||||
}
|
||||
|
||||
if (properties.getLeft() != 0 || properties.getTop() != 0) {
|
||||
@@ -236,12 +230,12 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
|
||||
const int width = properties.getWidth();
|
||||
const int height = properties.getHeight();
|
||||
|
||||
Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
|
||||
Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
|
||||
const bool isLayer = properties.effectiveLayerType() != LayerType::None;
|
||||
int clipFlags = properties.getClippingFlags();
|
||||
if (properties.getAlpha() < 1) {
|
||||
if (isLayer) {
|
||||
clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
|
||||
clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
|
||||
}
|
||||
if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
|
||||
// simply scale rendering content's alpha
|
||||
@@ -251,7 +245,7 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
|
||||
saveLayerBounds.set(0, 0, width, height);
|
||||
if (clipFlags) {
|
||||
properties.getClippingRectForFlags(clipFlags, &saveLayerBounds);
|
||||
clipFlags = 0; // all clipping done by savelayer
|
||||
clipFlags = 0; // all clipping done by savelayer
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,21 +259,21 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
|
||||
Rect clipRect;
|
||||
properties.getClippingRectForFlags(clipFlags, &clipRect);
|
||||
mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
|
||||
SkClipOp::kIntersect);
|
||||
SkClipOp::kIntersect);
|
||||
}
|
||||
|
||||
if (properties.getRevealClip().willClip()) {
|
||||
Rect bounds;
|
||||
properties.getRevealClip().getBounds(&bounds);
|
||||
mCanvasState.setClippingRoundRect(mAllocator,
|
||||
bounds, properties.getRevealClip().getRadius());
|
||||
mCanvasState.setClippingRoundRect(mAllocator, bounds,
|
||||
properties.getRevealClip().getRadius());
|
||||
} else if (properties.getOutline().willClip()) {
|
||||
mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline()));
|
||||
}
|
||||
|
||||
bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty()
|
||||
|| (properties.getClipToBounds()
|
||||
&& mCanvasState.quickRejectConservative(0, 0, width, height));
|
||||
bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty() ||
|
||||
(properties.getClipToBounds() &&
|
||||
mCanvasState.quickRejectConservative(0, 0, width, height));
|
||||
if (!quickRejected) {
|
||||
// not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
|
||||
if (node.getLayer()) {
|
||||
@@ -296,9 +290,8 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
|
||||
SkPaint saveLayerPaint;
|
||||
saveLayerPaint.setAlpha(properties.getAlpha());
|
||||
deferBeginLayerOp(*mAllocator.create_trivial<BeginLayerOp>(
|
||||
saveLayerBounds,
|
||||
Matrix4::identity(),
|
||||
nullptr, // no record-time clip - need only respect defer-time one
|
||||
saveLayerBounds, Matrix4::identity(),
|
||||
nullptr, // no record-time clip - need only respect defer-time one
|
||||
&saveLayerPaint));
|
||||
deferNodeOps(node);
|
||||
deferEndLayerOp(*mAllocator.create_trivial<EndLayerOp>());
|
||||
@@ -311,8 +304,8 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
|
||||
typedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair;
|
||||
|
||||
template <typename V>
|
||||
static void buildZSortedChildList(V* zTranslatedNodes,
|
||||
const DisplayList& displayList, const DisplayList::Chunk& chunk) {
|
||||
static void buildZSortedChildList(V* zTranslatedNodes, const DisplayList& displayList,
|
||||
const DisplayList::Chunk& chunk) {
|
||||
if (chunk.beginChildIndex == chunk.endChildIndex) return;
|
||||
|
||||
for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
|
||||
@@ -343,11 +336,10 @@ static size_t findNonNegativeIndex(const V& zTranslatedNodes) {
|
||||
|
||||
template <typename V>
|
||||
void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode,
|
||||
const V& zTranslatedNodes) {
|
||||
const V& zTranslatedNodes) {
|
||||
const int size = zTranslatedNodes.size();
|
||||
if (size == 0
|
||||
|| (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
|
||||
|| (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
|
||||
if (size == 0 || (mode == ChildrenSelectMode::Negative && zTranslatedNodes[0].key > 0.0f) ||
|
||||
(mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
|
||||
// no 3d children to draw
|
||||
return;
|
||||
}
|
||||
@@ -364,11 +356,11 @@ void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMo
|
||||
if (mode == ChildrenSelectMode::Negative) {
|
||||
drawIndex = 0;
|
||||
endIndex = nonNegativeIndex;
|
||||
shadowIndex = endIndex; // draw no shadows
|
||||
shadowIndex = endIndex; // draw no shadows
|
||||
} else {
|
||||
drawIndex = nonNegativeIndex;
|
||||
endIndex = size;
|
||||
shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
|
||||
shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
|
||||
}
|
||||
|
||||
float lastCasterZ = 0.0f;
|
||||
@@ -381,7 +373,7 @@ void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMo
|
||||
if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) {
|
||||
deferShadow(reorderClip, *casterNodeOp);
|
||||
|
||||
lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
|
||||
lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
|
||||
shadowIndex++;
|
||||
continue;
|
||||
}
|
||||
@@ -397,11 +389,9 @@ void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp&
|
||||
auto& node = *casterNodeOp.renderNode;
|
||||
auto& properties = node.properties();
|
||||
|
||||
if (properties.getAlpha() <= 0.0f
|
||||
|| properties.getOutline().getAlpha() <= 0.0f
|
||||
|| !properties.getOutline().getPath()
|
||||
|| properties.getScaleX() == 0
|
||||
|| properties.getScaleY() == 0) {
|
||||
if (properties.getAlpha() <= 0.0f || properties.getOutline().getAlpha() <= 0.0f ||
|
||||
!properties.getOutline().getPath() || properties.getScaleX() == 0 ||
|
||||
properties.getScaleY() == 0) {
|
||||
// no shadow to draw
|
||||
return;
|
||||
}
|
||||
@@ -432,8 +422,8 @@ void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp&
|
||||
Rect clipBounds;
|
||||
properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
|
||||
SkPath clipBoundsPath;
|
||||
clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
|
||||
clipBounds.right, clipBounds.bottom);
|
||||
clipBoundsPath.addRect(clipBounds.left, clipBounds.top, clipBounds.right,
|
||||
clipBounds.bottom);
|
||||
|
||||
Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
|
||||
casterPath = frameAllocatedPath;
|
||||
@@ -442,7 +432,7 @@ void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp&
|
||||
// apply reorder clip to shadow, so it respects clip at beginning of reorderable chunk
|
||||
int restoreTo = mCanvasState.save(SaveFlags::MatrixClip);
|
||||
mCanvasState.writableSnapshot()->applyClip(reorderClip,
|
||||
*mCanvasState.currentSnapshot()->transform);
|
||||
*mCanvasState.currentSnapshot()->transform);
|
||||
if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
|
||||
Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
|
||||
Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
|
||||
@@ -450,13 +440,9 @@ void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp&
|
||||
node.applyViewPropertyTransforms(shadowMatrixZ, true);
|
||||
|
||||
sp<TessellationCache::ShadowTask> task = mCaches.tessellationCache.getShadowTask(
|
||||
mCanvasState.currentTransform(),
|
||||
mCanvasState.getLocalClipBounds(),
|
||||
casterAlpha >= 1.0f,
|
||||
casterPath,
|
||||
&shadowMatrixXY, &shadowMatrixZ,
|
||||
mCanvasState.currentSnapshot()->getRelativeLightCenter(),
|
||||
mLightRadius);
|
||||
mCanvasState.currentTransform(), mCanvasState.getLocalClipBounds(),
|
||||
casterAlpha >= 1.0f, casterPath, &shadowMatrixXY, &shadowMatrixZ,
|
||||
mCanvasState.currentSnapshot()->getRelativeLightCenter(), mLightRadius);
|
||||
ShadowOp* shadowOp = mAllocator.create<ShadowOp>(task, casterAlpha);
|
||||
BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
|
||||
mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
|
||||
@@ -471,15 +457,13 @@ void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
|
||||
int count = mCanvasState.save(SaveFlags::MatrixClip);
|
||||
const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
|
||||
|
||||
SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
|
||||
SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
|
||||
if (projectionReceiverOutline) {
|
||||
// transform the mask for this projector into render target space
|
||||
// TODO: consider combining both transforms by stashing transform instead of applying
|
||||
SkMatrix skCurrentTransform;
|
||||
mCanvasState.currentTransform()->copyTo(skCurrentTransform);
|
||||
projectionReceiverOutline->transform(
|
||||
skCurrentTransform,
|
||||
&transformedMaskPath);
|
||||
projectionReceiverOutline->transform(skCurrentTransform, &transformedMaskPath);
|
||||
mCanvasState.setProjectionPathMask(&transformedMaskPath);
|
||||
}
|
||||
|
||||
@@ -509,10 +493,12 @@ void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
|
||||
* This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas.
|
||||
* E.g. a BitmapOp op then would be dispatched to FrameBuilder::onBitmapOp(const BitmapOp&)
|
||||
*/
|
||||
#define OP_RECEIVER(Type) \
|
||||
[](FrameBuilder& frameBuilder, const RecordedOp& op) { frameBuilder.defer##Type(static_cast<const Type&>(op)); },
|
||||
#define OP_RECEIVER(Type) \
|
||||
[](FrameBuilder& frameBuilder, const RecordedOp& op) { \
|
||||
frameBuilder.defer##Type(static_cast<const Type&>(op)); \
|
||||
},
|
||||
void FrameBuilder::deferNodeOps(const RenderNode& renderNode) {
|
||||
typedef void (*OpDispatcher) (FrameBuilder& frameBuilder, const RecordedOp& op);
|
||||
typedef void (*OpDispatcher)(FrameBuilder & frameBuilder, const RecordedOp& op);
|
||||
static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER);
|
||||
|
||||
// can't be null, since DL=null node rejection happens before deferNodePropsAndOps
|
||||
@@ -526,9 +512,9 @@ void FrameBuilder::deferNodeOps(const RenderNode& renderNode) {
|
||||
const RecordedOp* op = displayList.getOps()[opIndex];
|
||||
receivers[op->opId](*this, *op);
|
||||
|
||||
if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty()
|
||||
&& displayList.projectionReceiveIndex >= 0
|
||||
&& static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) {
|
||||
if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() &&
|
||||
displayList.projectionReceiveIndex >= 0 &&
|
||||
static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) {
|
||||
deferProjectedChildren(renderNode);
|
||||
}
|
||||
}
|
||||
@@ -542,7 +528,7 @@ void FrameBuilder::deferRenderNodeOpImpl(const RenderNodeOp& op) {
|
||||
|
||||
// apply state from RecordedOp (clip first, since op's clip is transformed by current matrix)
|
||||
mCanvasState.writableSnapshot()->applyClip(op.localClip,
|
||||
*mCanvasState.currentSnapshot()->transform);
|
||||
*mCanvasState.currentSnapshot()->transform);
|
||||
mCanvasState.concatMatrix(op.localMatrix);
|
||||
|
||||
// then apply state from node properties, and defer ops
|
||||
@@ -562,12 +548,12 @@ void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) {
|
||||
* for paint's style on the bounds being computed.
|
||||
*/
|
||||
BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
|
||||
BakedOpState::StrokeBehavior strokeBehavior, bool expandForPathTexture) {
|
||||
BakedOpState::StrokeBehavior strokeBehavior,
|
||||
bool expandForPathTexture) {
|
||||
// Note: here we account for stroke when baking the op
|
||||
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
|
||||
mAllocator, *mCanvasState.writableSnapshot(), op,
|
||||
strokeBehavior, expandForPathTexture);
|
||||
if (!bakedState) return nullptr; // quick rejected
|
||||
mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior, expandForPathTexture);
|
||||
if (!bakedState) return nullptr; // quick rejected
|
||||
|
||||
if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) {
|
||||
bakedState->setupOpacity(op.paint);
|
||||
@@ -586,8 +572,8 @@ BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t ba
|
||||
static batchid_t tessBatchId(const RecordedOp& op) {
|
||||
const SkPaint& paint = *(op.paint);
|
||||
return paint.getPathEffect()
|
||||
? OpBatchType::AlphaMaskTexture
|
||||
: (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
|
||||
? OpBatchType::AlphaMaskTexture
|
||||
: (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
|
||||
}
|
||||
|
||||
void FrameBuilder::deferArcOp(const ArcOp& op) {
|
||||
@@ -598,13 +584,13 @@ void FrameBuilder::deferArcOp(const ArcOp& op) {
|
||||
}
|
||||
|
||||
static bool hasMergeableClip(const BakedOpState& state) {
|
||||
return !state.computedState.clipState
|
||||
|| state.computedState.clipState->mode == ClipMode::Rectangle;
|
||||
return !state.computedState.clipState ||
|
||||
state.computedState.clipState->mode == ClipMode::Rectangle;
|
||||
}
|
||||
|
||||
void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
|
||||
BakedOpState* bakedState = tryBakeOpState(op);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
|
||||
if (op.bitmap->isOpaque()) {
|
||||
bakedState->setupOpacity(op.paint);
|
||||
@@ -613,11 +599,10 @@ void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
|
||||
// Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
|
||||
// Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
|
||||
// MergingDrawBatch::canMergeWith()
|
||||
if (bakedState->computedState.transform.isSimple()
|
||||
&& bakedState->computedState.transform.positiveScale()
|
||||
&& PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
|
||||
&& op.bitmap->colorType() != kAlpha_8_SkColorType
|
||||
&& hasMergeableClip(*bakedState)) {
|
||||
if (bakedState->computedState.transform.isSimple() &&
|
||||
bakedState->computedState.transform.positiveScale() &&
|
||||
PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
|
||||
op.bitmap->colorType() != kAlpha_8_SkColorType && hasMergeableClip(*bakedState)) {
|
||||
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
|
||||
currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId);
|
||||
} else {
|
||||
@@ -627,24 +612,21 @@ void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
|
||||
|
||||
void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
|
||||
BakedOpState* bakedState = tryBakeOpState(op);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
|
||||
}
|
||||
|
||||
void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) {
|
||||
BakedOpState* bakedState = tryBakeOpState(op);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
|
||||
}
|
||||
|
||||
void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) {
|
||||
Bitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty();
|
||||
SkPaint* paint = op.vectorDrawable->getPaint();
|
||||
const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds,
|
||||
op.localMatrix,
|
||||
op.localClip,
|
||||
paint,
|
||||
&bitmap,
|
||||
const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(
|
||||
op.unmappedBounds, op.localMatrix, op.localClip, paint, &bitmap,
|
||||
Rect(bitmap.width(), bitmap.height()));
|
||||
deferBitmapRectOp(*resolvedOp);
|
||||
}
|
||||
@@ -656,23 +638,20 @@ void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) {
|
||||
float y = *(op.y);
|
||||
float radius = *(op.radius);
|
||||
Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
|
||||
const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(
|
||||
unmappedBounds,
|
||||
op.localMatrix,
|
||||
op.localClip,
|
||||
op.paint);
|
||||
const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(unmappedBounds, op.localMatrix,
|
||||
op.localClip, op.paint);
|
||||
deferOvalOp(*resolvedOp);
|
||||
}
|
||||
|
||||
void FrameBuilder::deferColorOp(const ColorOp& op) {
|
||||
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
|
||||
}
|
||||
|
||||
void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
|
||||
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
|
||||
}
|
||||
|
||||
@@ -687,11 +666,11 @@ void FrameBuilder::deferOvalOp(const OvalOp& op) {
|
||||
|
||||
void FrameBuilder::deferPatchOp(const PatchOp& op) {
|
||||
BakedOpState* bakedState = tryBakeOpState(op);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
|
||||
if (bakedState->computedState.transform.isPureTranslate()
|
||||
&& PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
|
||||
&& hasMergeableClip(*bakedState)) {
|
||||
if (bakedState->computedState.transform.isPureTranslate() &&
|
||||
PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
|
||||
hasMergeableClip(*bakedState)) {
|
||||
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
|
||||
|
||||
// Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together
|
||||
@@ -723,7 +702,8 @@ void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) {
|
||||
if (CC_LIKELY(state && !op.paint->getPathEffect())) {
|
||||
// TODO: consider storing tessellation task in BakedOpState
|
||||
mCaches.tessellationCache.precacheRoundRect(state->computedState.transform, *(op.paint),
|
||||
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
|
||||
op.unmappedBounds.getWidth(),
|
||||
op.unmappedBounds.getHeight(), op.rx, op.ry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,16 +711,14 @@ void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
|
||||
// allocate a temporary round rect op (with mAllocator, so it persists until render), so the
|
||||
// renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
|
||||
const RoundRectOp* resolvedOp = mAllocator.create_trivial<RoundRectOp>(
|
||||
Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
|
||||
op.localMatrix,
|
||||
op.localClip,
|
||||
Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), op.localMatrix, op.localClip,
|
||||
op.paint, *op.rx, *op.ry);
|
||||
deferRoundRectOp(*resolvedOp);
|
||||
}
|
||||
|
||||
void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) {
|
||||
BakedOpState* bakedState = tryBakeOpState(op);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
|
||||
}
|
||||
|
||||
@@ -753,12 +731,12 @@ void FrameBuilder::deferTextOp(const TextOp& op) {
|
||||
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
|
||||
mAllocator, *mCanvasState.writableSnapshot(), op,
|
||||
BakedOpState::StrokeBehavior::StyleDefined, false);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
|
||||
batchid_t batchId = textBatchId(*(op.paint));
|
||||
if (bakedState->computedState.transform.isPureTranslate()
|
||||
&& PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
|
||||
&& hasMergeableClip(*bakedState)) {
|
||||
if (bakedState->computedState.transform.isPureTranslate() &&
|
||||
PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
|
||||
hasMergeableClip(*bakedState)) {
|
||||
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor());
|
||||
currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId);
|
||||
} else {
|
||||
@@ -773,19 +751,19 @@ void FrameBuilder::deferTextOp(const TextOp& op) {
|
||||
// Partial transform case, see BakedOpDispatcher::renderTextOp
|
||||
float sx, sy;
|
||||
totalTransform.decomposeScale(sx, sy);
|
||||
fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::MakeScale(
|
||||
roundf(std::max(1.0f, sx)),
|
||||
roundf(std::max(1.0f, sy))));
|
||||
fontRenderer.precache(
|
||||
op.paint, op.glyphs, op.glyphCount,
|
||||
SkMatrix::MakeScale(roundf(std::max(1.0f, sx)), roundf(std::max(1.0f, sy))));
|
||||
}
|
||||
}
|
||||
|
||||
void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
|
||||
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
|
||||
|
||||
mCaches.fontRenderer.getFontRenderer().precache(
|
||||
op.paint, op.glyphs, op.glyphCount, SkMatrix::I());
|
||||
mCaches.fontRenderer.getFontRenderer().precache(op.paint, op.glyphs, op.glyphCount,
|
||||
SkMatrix::I());
|
||||
}
|
||||
|
||||
void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
|
||||
@@ -802,28 +780,27 @@ void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
|
||||
}
|
||||
BakedOpState* bakedState = tryBakeOpState(*textureLayerOp);
|
||||
|
||||
if (!bakedState) return; // quick rejected
|
||||
if (!bakedState) return; // quick rejected
|
||||
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
|
||||
}
|
||||
|
||||
void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
|
||||
float contentTranslateX, float contentTranslateY,
|
||||
const Rect& repaintRect,
|
||||
const Vector3& lightCenter,
|
||||
const BeginLayerOp* beginLayerOp, RenderNode* renderNode) {
|
||||
void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX,
|
||||
float contentTranslateY, const Rect& repaintRect,
|
||||
const Vector3& lightCenter, const BeginLayerOp* beginLayerOp,
|
||||
RenderNode* renderNode) {
|
||||
mCanvasState.save(SaveFlags::MatrixClip);
|
||||
mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
|
||||
mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
|
||||
mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter);
|
||||
mCanvasState.writableSnapshot()->transform->loadTranslate(
|
||||
contentTranslateX, contentTranslateY, 0);
|
||||
mCanvasState.writableSnapshot()->setClip(
|
||||
repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom);
|
||||
mCanvasState.writableSnapshot()->transform->loadTranslate(contentTranslateX, contentTranslateY,
|
||||
0);
|
||||
mCanvasState.writableSnapshot()->setClip(repaintRect.left, repaintRect.top, repaintRect.right,
|
||||
repaintRect.bottom);
|
||||
|
||||
// create a new layer repaint, and push its index on the stack
|
||||
mLayerStack.push_back(mLayerBuilders.size());
|
||||
auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight,
|
||||
repaintRect, beginLayerOp, renderNode);
|
||||
auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight, repaintRect,
|
||||
beginLayerOp, renderNode);
|
||||
mLayerBuilders.push_back(newFbo);
|
||||
}
|
||||
|
||||
@@ -836,8 +813,8 @@ void FrameBuilder::restoreForLayer() {
|
||||
// TODO: defer time rejection (when bounds become empty) + tests
|
||||
// Option - just skip layers with no bounds at playback + defer?
|
||||
void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) {
|
||||
uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
|
||||
uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
|
||||
uint32_t layerWidth = (uint32_t)op.unmappedBounds.getWidth();
|
||||
uint32_t layerHeight = (uint32_t)op.unmappedBounds.getHeight();
|
||||
|
||||
auto previous = mCanvasState.currentSnapshot();
|
||||
Vector3 lightCenter = previous->getRelativeLightCenter();
|
||||
@@ -873,11 +850,8 @@ void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) {
|
||||
float contentTranslateX = -saveLayerBounds.left;
|
||||
float contentTranslateY = -saveLayerBounds.top;
|
||||
|
||||
saveForLayer(layerWidth, layerHeight,
|
||||
contentTranslateX, contentTranslateY,
|
||||
Rect(layerWidth, layerHeight),
|
||||
lightCenter,
|
||||
&op, nullptr);
|
||||
saveForLayer(layerWidth, layerHeight, contentTranslateX, contentTranslateY,
|
||||
Rect(layerWidth, layerHeight), lightCenter, &op, nullptr);
|
||||
}
|
||||
|
||||
void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
|
||||
@@ -890,8 +864,8 @@ void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
|
||||
// to translate the drawLayer by how much the contents was translated
|
||||
// TODO: Unify this with beginLayerOp so we don't have to calculate this
|
||||
// twice
|
||||
uint32_t layerWidth = (uint32_t) beginLayerOp.unmappedBounds.getWidth();
|
||||
uint32_t layerHeight = (uint32_t) beginLayerOp.unmappedBounds.getHeight();
|
||||
uint32_t layerWidth = (uint32_t)beginLayerOp.unmappedBounds.getWidth();
|
||||
uint32_t layerHeight = (uint32_t)beginLayerOp.unmappedBounds.getHeight();
|
||||
|
||||
auto previous = mCanvasState.currentSnapshot();
|
||||
Vector3 lightCenter = previous->getRelativeLightCenter();
|
||||
@@ -900,8 +874,7 @@ void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
|
||||
// parent content transform * canvas transform * bounds offset
|
||||
Matrix4 contentTransform(*(previous->transform));
|
||||
contentTransform.multiply(beginLayerOp.localMatrix);
|
||||
contentTransform.translate(beginLayerOp.unmappedBounds.left,
|
||||
beginLayerOp.unmappedBounds.top);
|
||||
contentTransform.translate(beginLayerOp.unmappedBounds.left, beginLayerOp.unmappedBounds.top);
|
||||
|
||||
Matrix4 inverseContentTransform;
|
||||
inverseContentTransform.loadInverse(contentTransform);
|
||||
@@ -927,10 +900,7 @@ void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
|
||||
// record the draw operation into the previous layer's list of draw commands
|
||||
// uses state from the associated beginLayerOp, since it has all the state needed for drawing
|
||||
LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(
|
||||
beginLayerOp.unmappedBounds,
|
||||
localMatrix,
|
||||
beginLayerOp.localClip,
|
||||
beginLayerOp.paint,
|
||||
beginLayerOp.unmappedBounds, localMatrix, beginLayerOp.localClip, beginLayerOp.paint,
|
||||
&(mLayerBuilders[finishedLayerIndex]->offscreenBuffer));
|
||||
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
|
||||
|
||||
@@ -959,15 +929,16 @@ void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) {
|
||||
// Unclipped layer rejected - push a null op, so next EndUnclippedLayerOp is ignored
|
||||
currentLayer().activeUnclippedSaveLayers.push_back(nullptr);
|
||||
} else {
|
||||
// Allocate a holding position for the layer object (copyTo will produce, copyFrom will consume)
|
||||
// Allocate a holding position for the layer object (copyTo will produce, copyFrom will
|
||||
// consume)
|
||||
OffscreenBuffer** layerHandle = mAllocator.create<OffscreenBuffer*>(nullptr);
|
||||
|
||||
/**
|
||||
* First, defer an operation to copy out the content from the rendertarget into a layer.
|
||||
*/
|
||||
auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
|
||||
BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
|
||||
&(currentLayer().repaintClip), dstRect, *copyToOp);
|
||||
BakedOpState* bakedState = BakedOpState::directConstruct(
|
||||
mAllocator, &(currentLayer().repaintClip), dstRect, *copyToOp);
|
||||
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
|
||||
|
||||
/**
|
||||
@@ -981,8 +952,8 @@ void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) {
|
||||
* a balanced EndUnclippedLayerOp is seen
|
||||
*/
|
||||
auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
|
||||
bakedState = BakedOpState::directConstruct(mAllocator,
|
||||
&(currentLayer().repaintClip), dstRect, *copyFromOp);
|
||||
bakedState = BakedOpState::directConstruct(mAllocator, &(currentLayer().repaintClip),
|
||||
dstRect, *copyFromOp);
|
||||
currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
|
||||
}
|
||||
}
|
||||
@@ -1001,5 +972,5 @@ void FrameBuilder::finishDefer() {
|
||||
mCaches.fontRenderer.endPrecaching();
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
#include "RecordedOp.h"
|
||||
#include "utils/GLUtils.h"
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct SkRect;
|
||||
|
||||
@@ -60,12 +60,11 @@ public:
|
||||
float radius;
|
||||
};
|
||||
|
||||
FrameBuilder(const SkRect& clip,
|
||||
uint32_t viewportWidth, uint32_t viewportHeight,
|
||||
const LightGeometry& lightGeometry, Caches& caches);
|
||||
FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
|
||||
const LightGeometry& lightGeometry, Caches& caches);
|
||||
|
||||
FrameBuilder(const LayerUpdateQueue& layerUpdateQueue,
|
||||
const LightGeometry& lightGeometry, Caches& caches);
|
||||
FrameBuilder(const LayerUpdateQueue& layerUpdateQueue, const LightGeometry& lightGeometry,
|
||||
Caches& caches);
|
||||
|
||||
void deferLayers(const LayerUpdateQueue& layers);
|
||||
|
||||
@@ -73,8 +72,8 @@ public:
|
||||
|
||||
void deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode);
|
||||
|
||||
void deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes,
|
||||
const Rect& contentDrawBounds);
|
||||
void deferRenderNodeScene(const std::vector<sp<RenderNode> >& nodes,
|
||||
const Rect& contentDrawBounds);
|
||||
|
||||
virtual ~FrameBuilder() {}
|
||||
|
||||
@@ -88,32 +87,32 @@ public:
|
||||
void replayBakedOps(Renderer& renderer) {
|
||||
std::vector<OffscreenBuffer*> temporaryLayers;
|
||||
finishDefer();
|
||||
/**
|
||||
* Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
|
||||
* dispatch the op via a method on a static dispatcher when the op is replayed.
|
||||
*
|
||||
* For example a BitmapOp would resolve, via the lambda lookup, to calling:
|
||||
*
|
||||
* StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
|
||||
*/
|
||||
#define X(Type) \
|
||||
[](void* renderer, const BakedOpState& state) { \
|
||||
StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), \
|
||||
static_cast<const Type&>(*(state.op)), state); \
|
||||
},
|
||||
/**
|
||||
* Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
|
||||
* dispatch the op via a method on a static dispatcher when the op is replayed.
|
||||
*
|
||||
* For example a BitmapOp would resolve, via the lambda lookup, to calling:
|
||||
*
|
||||
* StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
|
||||
*/
|
||||
#define X(Type) \
|
||||
[](void* renderer, const BakedOpState& state) { \
|
||||
StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), \
|
||||
static_cast<const Type&>(*(state.op)), state); \
|
||||
},
|
||||
static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
|
||||
#undef X
|
||||
#undef X
|
||||
|
||||
/**
|
||||
* Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
|
||||
* static dispatcher when the group of merged ops is replayed.
|
||||
*/
|
||||
#define X(Type) \
|
||||
[](void* renderer, const MergedBakedOpList& opList) { \
|
||||
StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
|
||||
},
|
||||
/**
|
||||
* Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
|
||||
* static dispatcher when the group of merged ops is replayed.
|
||||
*/
|
||||
#define X(Type) \
|
||||
[](void* renderer, const MergedBakedOpList& opList) { \
|
||||
StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
|
||||
},
|
||||
static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X);
|
||||
#undef X
|
||||
#undef X
|
||||
|
||||
// Relay through layers in reverse order, since layers
|
||||
// later in the list will be drawn by earlier ones
|
||||
@@ -168,15 +167,10 @@ public:
|
||||
|
||||
private:
|
||||
void finishDefer();
|
||||
enum class ChildrenSelectMode {
|
||||
Negative,
|
||||
Positive
|
||||
};
|
||||
void saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
|
||||
float contentTranslateX, float contentTranslateY,
|
||||
const Rect& repaintRect,
|
||||
const Vector3& lightCenter,
|
||||
const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
|
||||
enum class ChildrenSelectMode { Negative, Positive };
|
||||
void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX,
|
||||
float contentTranslateY, const Rect& repaintRect, const Vector3& lightCenter,
|
||||
const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
|
||||
void restoreForLayer();
|
||||
|
||||
LayerBuilder& currentLayer() { return *(mLayerBuilders[mLayerStack.back()]); }
|
||||
@@ -185,16 +179,16 @@ private:
|
||||
return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
|
||||
}
|
||||
BakedOpState* tryBakeUnboundedOpState(const RecordedOp& recordedOp) {
|
||||
return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
|
||||
return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(),
|
||||
recordedOp);
|
||||
}
|
||||
|
||||
|
||||
// should always be surrounded by a save/restore pair, and not called if DisplayList is null
|
||||
void deferNodePropsAndOps(RenderNode& node);
|
||||
|
||||
template <typename V>
|
||||
void defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode,
|
||||
const V& zTranslatedNodes);
|
||||
const V& zTranslatedNodes);
|
||||
|
||||
void deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterOp);
|
||||
|
||||
@@ -206,20 +200,19 @@ private:
|
||||
|
||||
void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
|
||||
|
||||
SkPath* createFrameAllocatedPath() {
|
||||
return mAllocator.create<SkPath>();
|
||||
}
|
||||
SkPath* createFrameAllocatedPath() { return mAllocator.create<SkPath>(); }
|
||||
|
||||
BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
|
||||
BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined,
|
||||
bool expandForPathTexture = false);
|
||||
BakedOpState::StrokeBehavior strokeBehavior =
|
||||
BakedOpState::StrokeBehavior::StyleDefined,
|
||||
bool expandForPathTexture = false);
|
||||
|
||||
/**
|
||||
* Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
|
||||
*
|
||||
* These private methods are called from within deferImpl to defer each individual op
|
||||
* type differently.
|
||||
*/
|
||||
/**
|
||||
* Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
|
||||
*
|
||||
* These private methods are called from within deferImpl to defer each individual op
|
||||
* type differently.
|
||||
*/
|
||||
#define X(Type) void defer##Type(const Type& op);
|
||||
MAP_DEFERRABLE_OPS(X)
|
||||
#undef X
|
||||
@@ -254,5 +247,5 @@ private:
|
||||
const bool mDrawFbo0;
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -21,30 +21,30 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
const std::string FrameInfoNames[] = {
|
||||
"Flags",
|
||||
"IntendedVsync",
|
||||
"Vsync",
|
||||
"OldestInputEvent",
|
||||
"NewestInputEvent",
|
||||
"HandleInputStart",
|
||||
"AnimationStart",
|
||||
"PerformTraversalsStart",
|
||||
"DrawStart",
|
||||
"SyncQueued",
|
||||
"SyncStart",
|
||||
"IssueDrawCommandsStart",
|
||||
"SwapBuffers",
|
||||
"FrameCompleted",
|
||||
"DequeueBufferDuration",
|
||||
"QueueBufferDuration",
|
||||
"Flags",
|
||||
"IntendedVsync",
|
||||
"Vsync",
|
||||
"OldestInputEvent",
|
||||
"NewestInputEvent",
|
||||
"HandleInputStart",
|
||||
"AnimationStart",
|
||||
"PerformTraversalsStart",
|
||||
"DrawStart",
|
||||
"SyncQueued",
|
||||
"SyncStart",
|
||||
"IssueDrawCommandsStart",
|
||||
"SwapBuffers",
|
||||
"FrameCompleted",
|
||||
"DequeueBufferDuration",
|
||||
"QueueBufferDuration",
|
||||
};
|
||||
|
||||
static_assert((sizeof(FrameInfoNames)/sizeof(FrameInfoNames[0]))
|
||||
== static_cast<int>(FrameInfoIndex::NumIndexes),
|
||||
"size mismatch: FrameInfoNames doesn't match the enum!");
|
||||
static_assert((sizeof(FrameInfoNames) / sizeof(FrameInfoNames[0])) ==
|
||||
static_cast<int>(FrameInfoIndex::NumIndexes),
|
||||
"size mismatch: FrameInfoNames doesn't match the enum!");
|
||||
|
||||
static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 16,
|
||||
"Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
|
||||
"Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
|
||||
|
||||
void FrameInfo::importUiThreadInfo(int64_t* info) {
|
||||
memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
|
||||
|
||||
@@ -59,12 +59,12 @@ enum class FrameInfoIndex {
|
||||
extern const std::string FrameInfoNames[];
|
||||
|
||||
namespace FrameInfoFlags {
|
||||
enum {
|
||||
WindowLayoutChanged = 1 << 0,
|
||||
RTAnimation = 1 << 1,
|
||||
SurfaceCanvas = 1 << 2,
|
||||
SkippedFrame = 1 << 3,
|
||||
};
|
||||
enum {
|
||||
WindowLayoutChanged = 1 << 0,
|
||||
RTAnimation = 1 << 1,
|
||||
SurfaceCanvas = 1 << 2,
|
||||
SkippedFrame = 1 << 3,
|
||||
};
|
||||
};
|
||||
|
||||
class ANDROID_API UiFrameInfoBuilder {
|
||||
@@ -91,9 +91,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
inline int64_t& set(FrameInfoIndex index) {
|
||||
return mBuffer[static_cast<int>(index)];
|
||||
}
|
||||
inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; }
|
||||
|
||||
int64_t* mBuffer;
|
||||
};
|
||||
@@ -102,33 +100,23 @@ class FrameInfo {
|
||||
public:
|
||||
void importUiThreadInfo(int64_t* info);
|
||||
|
||||
void markSyncStart() {
|
||||
set(FrameInfoIndex::SyncStart) = systemTime(CLOCK_MONOTONIC);
|
||||
}
|
||||
void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(CLOCK_MONOTONIC); }
|
||||
|
||||
void markIssueDrawCommandsStart() {
|
||||
set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(CLOCK_MONOTONIC);
|
||||
}
|
||||
|
||||
void markSwapBuffers() {
|
||||
set(FrameInfoIndex::SwapBuffers) = systemTime(CLOCK_MONOTONIC);
|
||||
}
|
||||
void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(CLOCK_MONOTONIC); }
|
||||
|
||||
void markFrameCompleted() {
|
||||
set(FrameInfoIndex::FrameCompleted) = systemTime(CLOCK_MONOTONIC);
|
||||
}
|
||||
void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(CLOCK_MONOTONIC); }
|
||||
|
||||
void addFlag(int frameInfoFlag) {
|
||||
set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
|
||||
}
|
||||
|
||||
const int64_t* data() const {
|
||||
return mFrameInfo;
|
||||
}
|
||||
const int64_t* data() const { return mFrameInfo; }
|
||||
|
||||
inline int64_t operator[](FrameInfoIndex index) const {
|
||||
return get(index);
|
||||
}
|
||||
inline int64_t operator[](FrameInfoIndex index) const { return get(index); }
|
||||
|
||||
inline int64_t operator[](int index) const {
|
||||
if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0;
|
||||
@@ -140,12 +128,10 @@ public:
|
||||
int64_t starttime = get(start);
|
||||
int64_t gap = endtime - starttime;
|
||||
gap = starttime > 0 ? gap : 0;
|
||||
if (end > FrameInfoIndex::SyncQueued &&
|
||||
start < FrameInfoIndex::SyncQueued) {
|
||||
if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) {
|
||||
// Need to subtract out the time spent in a stalled state
|
||||
// as this will be captured by the previous frame's info
|
||||
int64_t offset = get(FrameInfoIndex::SyncStart)
|
||||
- get(FrameInfoIndex::SyncQueued);
|
||||
int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued);
|
||||
if (offset > 0) {
|
||||
gap -= offset;
|
||||
}
|
||||
@@ -157,9 +143,7 @@ public:
|
||||
return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
|
||||
}
|
||||
|
||||
inline int64_t& set(FrameInfoIndex index) {
|
||||
return mFrameInfo[static_cast<int>(index)];
|
||||
}
|
||||
inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
|
||||
|
||||
inline int64_t get(FrameInfoIndex index) const {
|
||||
if (index == FrameInfoIndex::NumIndexes) return 0;
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
#include <cutils/compiler.h>
|
||||
#include <array>
|
||||
|
||||
#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return
|
||||
#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
|
||||
#define RETURN_IF_PROFILING_DISABLED() \
|
||||
if (CC_LIKELY(mType == ProfileType::None)) return
|
||||
#define RETURN_IF_DISABLED() \
|
||||
if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
|
||||
|
||||
#define PROFILE_DRAW_WIDTH 3
|
||||
#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
|
||||
@@ -48,22 +50,22 @@ struct BarSegment {
|
||||
SkColor color;
|
||||
};
|
||||
|
||||
static const std::array<BarSegment,7> Bar {{
|
||||
{ FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700 },
|
||||
{ FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, Color::Green_700 },
|
||||
{ FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700 },
|
||||
{ FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500 },
|
||||
{ FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300 },
|
||||
{ FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
|
||||
{ FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
|
||||
static const std::array<BarSegment, 7> Bar{{
|
||||
{FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700},
|
||||
{FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart,
|
||||
Color::Green_700},
|
||||
{FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700},
|
||||
{FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500},
|
||||
{FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300},
|
||||
{FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
|
||||
{FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
|
||||
}};
|
||||
|
||||
static int dpToPx(int dp, float density) {
|
||||
return (int) (dp * density + 0.5f);
|
||||
return (int)(dp * density + 0.5f);
|
||||
}
|
||||
|
||||
FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source)
|
||||
: mFrameSource(source) {
|
||||
FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) {
|
||||
setDensity(1);
|
||||
}
|
||||
|
||||
@@ -97,8 +99,8 @@ void FrameInfoVisualizer::draw(IProfileRenderer& renderer) {
|
||||
if (mFlashToggle) {
|
||||
SkPaint paint;
|
||||
paint.setColor(0x7fff0000);
|
||||
renderer.drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
|
||||
mDirtyRegion.fRight, mDirtyRegion.fBottom, paint);
|
||||
renderer.drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop, mDirtyRegion.fRight,
|
||||
mDirtyRegion.fBottom, paint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +171,8 @@ void FrameInfoVisualizer::initializeRects(const int baseline, const int width) {
|
||||
|
||||
void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
|
||||
int fast_i = (mNumFastRects - 1) * 4;
|
||||
int janky_i = (mNumJankyRects - 1) * 4;;
|
||||
int janky_i = (mNumJankyRects - 1) * 4;
|
||||
;
|
||||
for (size_t fi = 0; fi < mFrameSource.size(); fi++) {
|
||||
if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
|
||||
continue;
|
||||
@@ -210,11 +213,8 @@ void FrameInfoVisualizer::drawThreshold(IProfileRenderer& renderer) {
|
||||
SkPaint paint;
|
||||
paint.setColor(THRESHOLD_COLOR);
|
||||
float yLocation = renderer.getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
|
||||
renderer.drawRect(0.0f,
|
||||
yLocation - mThresholdStroke/2,
|
||||
renderer.getViewportWidth(),
|
||||
yLocation + mThresholdStroke/2,
|
||||
paint);
|
||||
renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(),
|
||||
yLocation + mThresholdStroke / 2, paint);
|
||||
}
|
||||
|
||||
bool FrameInfoVisualizer::consumeProperties() {
|
||||
@@ -245,7 +245,7 @@ void FrameInfoVisualizer::dumpData(int fd) {
|
||||
// last call to dumpData(). In other words if there's a dumpData(), draw frame,
|
||||
// dumpData(), the last dumpData() should only log 1 frame.
|
||||
|
||||
FILE *file = fdopen(fd, "a");
|
||||
FILE* file = fdopen(fd, "a");
|
||||
fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
|
||||
|
||||
for (size_t i = 0; i < mFrameSource.size(); i++) {
|
||||
|
||||
@@ -26,5 +26,5 @@ public:
|
||||
virtual void notify(const int64_t* buffer);
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include "FrameInfo.h"
|
||||
#include "FrameMetricsObserver.h"
|
||||
@@ -32,9 +32,7 @@ class FrameMetricsReporter {
|
||||
public:
|
||||
FrameMetricsReporter() {}
|
||||
|
||||
void addObserver(FrameMetricsObserver* observer) {
|
||||
mObservers.push_back(observer);
|
||||
}
|
||||
void addObserver(FrameMetricsObserver* observer) { mObservers.push_back(observer); }
|
||||
|
||||
bool removeObserver(FrameMetricsObserver* observer) {
|
||||
for (size_t i = 0; i < mObservers.size(); i++) {
|
||||
@@ -46,9 +44,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasObservers() {
|
||||
return mObservers.size() > 0;
|
||||
}
|
||||
bool hasObservers() { return mObservers.size() > 0; }
|
||||
|
||||
void reportFrameMetrics(const int64_t* stats) {
|
||||
for (size_t i = 0; i < mObservers.size(); i++) {
|
||||
@@ -57,9 +53,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector< sp<FrameMetricsObserver> > mObservers;
|
||||
std::vector<sp<FrameMetricsObserver> > mObservers;
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Debug.h"
|
||||
#include "GammaFontRenderer.h"
|
||||
#include "Debug.h"
|
||||
#include "Properties.h"
|
||||
|
||||
namespace android {
|
||||
@@ -39,5 +39,5 @@ void GammaFontRenderer::endPrecaching() {
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -26,9 +26,7 @@ class GammaFontRenderer {
|
||||
public:
|
||||
GammaFontRenderer();
|
||||
|
||||
void clear() {
|
||||
mRenderer.reset(nullptr);
|
||||
}
|
||||
void clear() { mRenderer.reset(nullptr); }
|
||||
|
||||
void flush() {
|
||||
if (mRenderer) {
|
||||
@@ -55,9 +53,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getSize() const {
|
||||
return mRenderer ? mRenderer->getSize() : 0;
|
||||
}
|
||||
uint32_t getSize() const { return mRenderer ? mRenderer->getSize() : 0; }
|
||||
|
||||
void endPrecaching();
|
||||
|
||||
@@ -68,7 +64,7 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H
|
||||
#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H
|
||||
|
||||
@@ -28,5 +28,5 @@ public:
|
||||
virtual void onGlFunctorReleased(Functor* functor) = 0;
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -23,17 +23,16 @@
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#define ATRACE_LAYER_WORK(label) \
|
||||
ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
|
||||
label, \
|
||||
(renderNode.get() != NULL) ? renderNode->getName() : "", \
|
||||
getWidth(), getHeight())
|
||||
#define ATRACE_LAYER_WORK(label) \
|
||||
ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", label, \
|
||||
(renderNode.get() != NULL) ? renderNode->getName() : "", getWidth(), \
|
||||
getHeight())
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
|
||||
SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
|
||||
SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
|
||||
: Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
|
||||
, caches(Caches::getInstance())
|
||||
, texture(caches) {
|
||||
@@ -73,5 +72,5 @@ void GlLayer::generateTexture() {
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -35,42 +35,26 @@ public:
|
||||
SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
|
||||
virtual ~GlLayer();
|
||||
|
||||
uint32_t getWidth() const override {
|
||||
return texture.mWidth;
|
||||
}
|
||||
uint32_t getWidth() const override { return texture.mWidth; }
|
||||
|
||||
uint32_t getHeight() const override {
|
||||
return texture.mHeight;
|
||||
}
|
||||
uint32_t getHeight() const override { return texture.mHeight; }
|
||||
|
||||
void setSize(uint32_t width, uint32_t height) override {
|
||||
texture.updateLayout(width, height, texture.internalFormat(), texture.format(),
|
||||
texture.target());
|
||||
texture.target());
|
||||
}
|
||||
|
||||
void setBlend(bool blend) override {
|
||||
texture.blend = blend;
|
||||
}
|
||||
void setBlend(bool blend) override { texture.blend = blend; }
|
||||
|
||||
bool isBlend() const override {
|
||||
return texture.blend;
|
||||
}
|
||||
bool isBlend() const override { return texture.blend; }
|
||||
|
||||
inline GLuint getTextureId() const {
|
||||
return texture.id();
|
||||
}
|
||||
inline GLuint getTextureId() const { return texture.id(); }
|
||||
|
||||
inline Texture& getTexture() {
|
||||
return texture;
|
||||
}
|
||||
inline Texture& getTexture() { return texture; }
|
||||
|
||||
inline GLenum getRenderTarget() const {
|
||||
return texture.target();
|
||||
}
|
||||
inline GLenum getRenderTarget() const { return texture.target(); }
|
||||
|
||||
inline bool isRenderable() const {
|
||||
return texture.target() != GL_NONE;
|
||||
}
|
||||
inline bool isRenderable() const { return texture.target() != GL_NONE; }
|
||||
|
||||
void setRenderTarget(GLenum renderTarget);
|
||||
|
||||
@@ -89,7 +73,7 @@ private:
|
||||
* The texture backing this layer.
|
||||
*/
|
||||
Texture texture;
|
||||
}; // struct GlLayer
|
||||
}; // struct GlLayer
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -41,34 +41,34 @@ class Texture;
|
||||
*/
|
||||
|
||||
namespace VertexAttribFlags {
|
||||
enum {
|
||||
// Mesh is pure x,y vertex pairs
|
||||
None = 0,
|
||||
// Mesh has texture coordinates embedded. Note that texture can exist without this flag
|
||||
// being set, if coordinates passed to sampler are determined another way.
|
||||
TextureCoord = 1 << 0,
|
||||
// Mesh has color embedded (to export to varying)
|
||||
Color = 1 << 1,
|
||||
// Mesh has alpha embedded (to export to varying)
|
||||
Alpha = 1 << 2,
|
||||
};
|
||||
enum {
|
||||
// Mesh is pure x,y vertex pairs
|
||||
None = 0,
|
||||
// Mesh has texture coordinates embedded. Note that texture can exist without this flag
|
||||
// being set, if coordinates passed to sampler are determined another way.
|
||||
TextureCoord = 1 << 0,
|
||||
// Mesh has color embedded (to export to varying)
|
||||
Color = 1 << 1,
|
||||
// Mesh has alpha embedded (to export to varying)
|
||||
Alpha = 1 << 2,
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Enumerates transform features
|
||||
*/
|
||||
namespace TransformFlags {
|
||||
enum {
|
||||
None = 0,
|
||||
enum {
|
||||
None = 0,
|
||||
|
||||
// offset the eventual drawing matrix by a tiny amount to
|
||||
// disambiguate sampling patterns with non-AA rendering
|
||||
OffsetByFudgeFactor = 1 << 0,
|
||||
// offset the eventual drawing matrix by a tiny amount to
|
||||
// disambiguate sampling patterns with non-AA rendering
|
||||
OffsetByFudgeFactor = 1 << 0,
|
||||
|
||||
// Canvas transform isn't applied to the mesh at draw time,
|
||||
// since it's already built in.
|
||||
MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
|
||||
};
|
||||
// Canvas transform isn't applied to the mesh at draw time,
|
||||
// since it's already built in.
|
||||
MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -86,10 +86,11 @@ namespace TransformFlags {
|
||||
*/
|
||||
struct Glop {
|
||||
PREVENT_COPY_AND_ASSIGN(Glop);
|
||||
|
||||
public:
|
||||
Glop() { }
|
||||
Glop() {}
|
||||
struct Mesh {
|
||||
GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
|
||||
GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
|
||||
|
||||
// buffer object and void* are mutually exclusive.
|
||||
// Only GL_UNSIGNED_SHORT supported.
|
||||
@@ -110,7 +111,7 @@ public:
|
||||
} vertices;
|
||||
|
||||
int elementCount;
|
||||
int vertexCount; // only used for meshes (for glDrawRangeElements)
|
||||
int vertexCount; // only used for meshes (for glDrawRangeElements)
|
||||
TextureVertex mappedVertices[4];
|
||||
} mesh;
|
||||
|
||||
@@ -148,10 +149,11 @@ public:
|
||||
Matrix4 canvas;
|
||||
int transformFlags;
|
||||
|
||||
const Matrix4& meshTransform() const {
|
||||
return (transformFlags & TransformFlags::MeshIgnoresCanvasTransform)
|
||||
? Matrix4::identity() : canvas;
|
||||
}
|
||||
const Matrix4& meshTransform() const {
|
||||
return (transformFlags & TransformFlags::MeshIgnoresCanvasTransform)
|
||||
? Matrix4::identity()
|
||||
: canvas;
|
||||
}
|
||||
} transform;
|
||||
|
||||
const RoundRectClipState* roundRectClipState = nullptr;
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
#include "Matrix.h"
|
||||
#include "Patch.h"
|
||||
#include "PathCache.h"
|
||||
#include "renderstate/MeshState.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "SkiaShader.h"
|
||||
#include "Texture.h"
|
||||
#include "utils/PaintUtils.h"
|
||||
#include "VertexBuffer.h"
|
||||
#include "renderstate/MeshState.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "utils/PaintUtils.h"
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
#include <SkPaint.h>
|
||||
@@ -36,13 +36,13 @@
|
||||
|
||||
#if DEBUG_GLOP_BUILDER
|
||||
|
||||
#define TRIGGER_STAGE(stageFlag) \
|
||||
LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
|
||||
#define TRIGGER_STAGE(stageFlag) \
|
||||
LOG_ALWAYS_FATAL_IF((stageFlag)&mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
|
||||
mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
|
||||
|
||||
#define REQUIRE_STAGES(requiredFlags) \
|
||||
#define REQUIRE_STAGES(requiredFlags) \
|
||||
LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
|
||||
"not prepared for current stage")
|
||||
"not prepared for current stage")
|
||||
|
||||
#else
|
||||
|
||||
@@ -62,10 +62,7 @@ static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {
|
||||
}
|
||||
|
||||
GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
|
||||
: mRenderState(renderState)
|
||||
, mCaches(caches)
|
||||
, mShader(nullptr)
|
||||
, mOutGlop(outGlop) {
|
||||
: mRenderState(renderState), mCaches(caches), mShader(nullptr), mOutGlop(outGlop) {
|
||||
mStageFlags = kInitialStage;
|
||||
}
|
||||
|
||||
@@ -77,12 +74,10 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementC
|
||||
TRIGGER_STAGE(kMeshStage);
|
||||
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
|
||||
mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
|
||||
mOutGlop->mesh.vertices = {
|
||||
vbo,
|
||||
VertexAttribFlags::TextureCoord,
|
||||
nullptr, (const void*) kMeshTextureOffset, nullptr,
|
||||
kTextureVertexStride };
|
||||
mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
|
||||
mOutGlop->mesh.vertices = {vbo, VertexAttribFlags::TextureCoord,
|
||||
nullptr, (const void*)kMeshTextureOffset,
|
||||
nullptr, kTextureVertexStride};
|
||||
mOutGlop->mesh.elementCount = elementCount;
|
||||
return *this;
|
||||
}
|
||||
@@ -91,12 +86,13 @@ GlopBuilder& GlopBuilder::setMeshUnitQuad() {
|
||||
TRIGGER_STAGE(kMeshStage);
|
||||
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
|
||||
mOutGlop->mesh.indices = { 0, nullptr };
|
||||
mOutGlop->mesh.vertices = {
|
||||
mRenderState.meshState().getUnitQuadVBO(),
|
||||
VertexAttribFlags::None,
|
||||
nullptr, nullptr, nullptr,
|
||||
kTextureVertexStride };
|
||||
mOutGlop->mesh.indices = {0, nullptr};
|
||||
mOutGlop->mesh.vertices = {mRenderState.meshState().getUnitQuadVBO(),
|
||||
VertexAttribFlags::None,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
kTextureVertexStride};
|
||||
mOutGlop->mesh.elementCount = 4;
|
||||
return *this;
|
||||
}
|
||||
@@ -110,12 +106,13 @@ GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
|
||||
TRIGGER_STAGE(kMeshStage);
|
||||
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
|
||||
mOutGlop->mesh.indices = { 0, nullptr };
|
||||
mOutGlop->mesh.vertices = {
|
||||
mRenderState.meshState().getUnitQuadVBO(),
|
||||
VertexAttribFlags::TextureCoord,
|
||||
nullptr, (const void*) kMeshTextureOffset, nullptr,
|
||||
kTextureVertexStride };
|
||||
mOutGlop->mesh.indices = {0, nullptr};
|
||||
mOutGlop->mesh.vertices = {mRenderState.meshState().getUnitQuadVBO(),
|
||||
VertexAttribFlags::TextureCoord,
|
||||
nullptr,
|
||||
(const void*)kMeshTextureOffset,
|
||||
nullptr,
|
||||
kTextureVertexStride};
|
||||
mOutGlop->mesh.elementCount = 4;
|
||||
return *this;
|
||||
}
|
||||
@@ -130,12 +127,13 @@ GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect u
|
||||
|
||||
const TextureVertex* textureVertex = mOutGlop->mesh.mappedVertices;
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
|
||||
mOutGlop->mesh.indices = { 0, nullptr };
|
||||
mOutGlop->mesh.vertices = {
|
||||
0,
|
||||
VertexAttribFlags::TextureCoord,
|
||||
&textureVertex[0].x, &textureVertex[0].u, nullptr,
|
||||
kTextureVertexStride };
|
||||
mOutGlop->mesh.indices = {0, nullptr};
|
||||
mOutGlop->mesh.vertices = {0,
|
||||
VertexAttribFlags::TextureCoord,
|
||||
&textureVertex[0].x,
|
||||
&textureVertex[0].u,
|
||||
nullptr,
|
||||
kTextureVertexStride};
|
||||
mOutGlop->mesh.elementCount = 4;
|
||||
return *this;
|
||||
}
|
||||
@@ -144,12 +142,9 @@ GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount)
|
||||
TRIGGER_STAGE(kMeshStage);
|
||||
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
|
||||
mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
|
||||
mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
|
||||
mOutGlop->mesh.vertices = {
|
||||
0,
|
||||
VertexAttribFlags::None,
|
||||
vertexData, nullptr, nullptr,
|
||||
kVertexStride };
|
||||
0, VertexAttribFlags::None, vertexData, nullptr, nullptr, kVertexStride};
|
||||
mOutGlop->mesh.elementCount = 6 * quadCount;
|
||||
return *this;
|
||||
}
|
||||
@@ -158,26 +153,29 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData,
|
||||
TRIGGER_STAGE(kMeshStage);
|
||||
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
|
||||
mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
|
||||
mOutGlop->mesh.vertices = {
|
||||
0,
|
||||
VertexAttribFlags::TextureCoord,
|
||||
&vertexData[0].x, &vertexData[0].u, nullptr,
|
||||
kTextureVertexStride };
|
||||
mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
|
||||
mOutGlop->mesh.vertices = {0,
|
||||
VertexAttribFlags::TextureCoord,
|
||||
&vertexData[0].x,
|
||||
&vertexData[0].u,
|
||||
nullptr,
|
||||
kTextureVertexStride};
|
||||
mOutGlop->mesh.elementCount = elementCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) {
|
||||
GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData,
|
||||
int elementCount) {
|
||||
TRIGGER_STAGE(kMeshStage);
|
||||
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
|
||||
mOutGlop->mesh.indices = { 0, nullptr };
|
||||
mOutGlop->mesh.vertices = {
|
||||
0,
|
||||
VertexAttribFlags::TextureCoord | VertexAttribFlags::Color,
|
||||
&vertexData[0].x, &vertexData[0].u, &vertexData[0].r,
|
||||
kColorTextureVertexStride };
|
||||
mOutGlop->mesh.indices = {0, nullptr};
|
||||
mOutGlop->mesh.vertices = {0,
|
||||
VertexAttribFlags::TextureCoord | VertexAttribFlags::Color,
|
||||
&vertexData[0].x,
|
||||
&vertexData[0].u,
|
||||
&vertexData[0].r,
|
||||
kColorTextureVertexStride};
|
||||
mOutGlop->mesh.elementCount = elementCount;
|
||||
return *this;
|
||||
}
|
||||
@@ -191,15 +189,16 @@ GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer)
|
||||
bool indices = flags & VertexBuffer::kIndices;
|
||||
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
|
||||
mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() };
|
||||
mOutGlop->mesh.vertices = {
|
||||
0,
|
||||
alphaVertex ? VertexAttribFlags::Alpha : VertexAttribFlags::None,
|
||||
vertexBuffer.getBuffer(), nullptr, nullptr,
|
||||
alphaVertex ? kAlphaVertexStride : kVertexStride };
|
||||
mOutGlop->mesh.elementCount = indices
|
||||
? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
|
||||
mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements()
|
||||
mOutGlop->mesh.indices = {0, vertexBuffer.getIndices()};
|
||||
mOutGlop->mesh.vertices = {0,
|
||||
alphaVertex ? VertexAttribFlags::Alpha : VertexAttribFlags::None,
|
||||
vertexBuffer.getBuffer(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
alphaVertex ? kAlphaVertexStride : kVertexStride};
|
||||
mOutGlop->mesh.elementCount =
|
||||
indices ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
|
||||
mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements()
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -207,12 +206,13 @@ GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) {
|
||||
TRIGGER_STAGE(kMeshStage);
|
||||
|
||||
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
|
||||
mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
|
||||
mOutGlop->mesh.vertices = {
|
||||
mCaches.patchCache.getMeshBuffer(),
|
||||
VertexAttribFlags::TextureCoord,
|
||||
(void*)patch.positionOffset, (void*)patch.textureOffset, nullptr,
|
||||
kTextureVertexStride };
|
||||
mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
|
||||
mOutGlop->mesh.vertices = {mCaches.patchCache.getMeshBuffer(),
|
||||
VertexAttribFlags::TextureCoord,
|
||||
(void*)patch.positionOffset,
|
||||
(void*)patch.textureOffset,
|
||||
nullptr,
|
||||
kTextureVertexStride};
|
||||
mOutGlop->mesh.elementCount = patch.indexCount;
|
||||
return *this;
|
||||
}
|
||||
@@ -221,9 +221,9 @@ GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) {
|
||||
// Fill
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GlopBuilder::setFill(int color, float alphaScale,
|
||||
SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
|
||||
const SkShader* shader, const SkColorFilter* colorFilter) {
|
||||
void GlopBuilder::setFill(int color, float alphaScale, SkBlendMode mode,
|
||||
Blend::ModeOrderSwap modeUsage, const SkShader* shader,
|
||||
const SkColorFilter* colorFilter) {
|
||||
if (mode != SkBlendMode::kClear) {
|
||||
if (!shader) {
|
||||
FloatColor c;
|
||||
@@ -235,23 +235,20 @@ void GlopBuilder::setFill(int color, float alphaScale,
|
||||
mOutGlop->fill.color = c;
|
||||
} else {
|
||||
float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
|
||||
mOutGlop->fill.color = { 1, 1, 1, alpha };
|
||||
mOutGlop->fill.color = {1, 1, 1, alpha};
|
||||
}
|
||||
} else {
|
||||
mOutGlop->fill.color = { 0, 0, 0, 1 };
|
||||
mOutGlop->fill.color = {0, 0, 0, 1};
|
||||
}
|
||||
|
||||
mOutGlop->blend = { GL_ZERO, GL_ZERO };
|
||||
if (mOutGlop->fill.color.a < 1.0f
|
||||
|| (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
|
||||
|| (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
|
||||
|| mOutGlop->roundRectClipState
|
||||
|| PaintUtils::isBlendedShader(shader)
|
||||
|| PaintUtils::isBlendedColorFilter(colorFilter)
|
||||
|| mode != SkBlendMode::kSrcOver) {
|
||||
mOutGlop->blend = {GL_ZERO, GL_ZERO};
|
||||
if (mOutGlop->fill.color.a < 1.0f ||
|
||||
(mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) ||
|
||||
(mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend) ||
|
||||
mOutGlop->roundRectClipState || PaintUtils::isBlendedShader(shader) ||
|
||||
PaintUtils::isBlendedColorFilter(colorFilter) || mode != SkBlendMode::kSrcOver) {
|
||||
if (CC_LIKELY(mode <= SkBlendMode::kScreen)) {
|
||||
Blend::getFactors(mode, modeUsage,
|
||||
&mOutGlop->blend.src, &mOutGlop->blend.dst);
|
||||
Blend::getFactors(mode, modeUsage, &mOutGlop->blend.src, &mOutGlop->blend.dst);
|
||||
} else {
|
||||
// These blend modes are not supported by OpenGL directly and have
|
||||
// to be implemented using shaders. Since the shader will perform
|
||||
@@ -264,23 +261,25 @@ void GlopBuilder::setFill(int color, float alphaScale,
|
||||
// blending in shader, don't enable
|
||||
} else {
|
||||
// unsupported
|
||||
Blend::getFactors(SkBlendMode::kSrcOver, modeUsage,
|
||||
&mOutGlop->blend.src, &mOutGlop->blend.dst);
|
||||
Blend::getFactors(SkBlendMode::kSrcOver, modeUsage, &mOutGlop->blend.src,
|
||||
&mOutGlop->blend.dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
mShader = shader; // shader resolved in ::build()
|
||||
mShader = shader; // shader resolved in ::build()
|
||||
|
||||
if (colorFilter) {
|
||||
SkColor color;
|
||||
SkBlendMode bmode;
|
||||
SkScalar srcColorMatrix[20];
|
||||
if (colorFilter->asColorMode(&color, &bmode)) {
|
||||
mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend;
|
||||
mOutGlop->fill.filterMode = mDescription.colorOp =
|
||||
ProgramDescription::ColorFilterMode::Blend;
|
||||
mDescription.colorMode = bmode;
|
||||
mOutGlop->fill.filter.color.set(color);
|
||||
} else if (colorFilter->asColorMatrix(srcColorMatrix)) {
|
||||
mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Matrix;
|
||||
mOutGlop->fill.filterMode = mDescription.colorOp =
|
||||
ProgramDescription::ColorFilterMode::Matrix;
|
||||
|
||||
float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
|
||||
memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
|
||||
@@ -291,10 +290,10 @@ void GlopBuilder::setFill(int color, float alphaScale,
|
||||
// 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 = mOutGlop->fill.filter.matrix.vector;
|
||||
colorVector[0] = EOCF(srcColorMatrix[4] / 255.0f);
|
||||
colorVector[1] = EOCF(srcColorMatrix[9] / 255.0f);
|
||||
colorVector[0] = EOCF(srcColorMatrix[4] / 255.0f);
|
||||
colorVector[1] = EOCF(srcColorMatrix[9] / 255.0f);
|
||||
colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
|
||||
colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
|
||||
colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
|
||||
} else {
|
||||
ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName());
|
||||
LOG_ALWAYS_FATAL("unsupported ColorFilter");
|
||||
@@ -304,14 +303,15 @@ void GlopBuilder::setFill(int color, float alphaScale,
|
||||
}
|
||||
}
|
||||
|
||||
GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
|
||||
const int textureFillFlags, const SkPaint* paint, float alphaScale) {
|
||||
GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, const int textureFillFlags,
|
||||
const SkPaint* paint, float alphaScale) {
|
||||
TRIGGER_STAGE(kFillStage);
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
GLenum filter = (textureFillFlags & TextureFillFlags::ForceFilter)
|
||||
? GL_LINEAR : PaintUtils::getFilter(paint);
|
||||
mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, nullptr };
|
||||
? GL_LINEAR
|
||||
: PaintUtils::getFilter(paint);
|
||||
mOutGlop->fill.texture = {&texture, filter, GL_CLAMP_TO_EDGE, nullptr};
|
||||
|
||||
if (paint) {
|
||||
int color = paint->getColor();
|
||||
@@ -322,20 +322,17 @@ GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
|
||||
color |= 0x00FFFFFF;
|
||||
shader = nullptr;
|
||||
}
|
||||
setFill(color, alphaScale,
|
||||
paint->getBlendMode(), Blend::ModeOrderSwap::NoSwap,
|
||||
shader, paint->getColorFilter());
|
||||
setFill(color, alphaScale, paint->getBlendMode(), Blend::ModeOrderSwap::NoSwap, shader,
|
||||
paint->getColorFilter());
|
||||
} else {
|
||||
mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
|
||||
mOutGlop->fill.color = {alphaScale, alphaScale, alphaScale, alphaScale};
|
||||
|
||||
if (alphaScale < 1.0f
|
||||
|| (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
|
||||
|| texture.blend
|
||||
|| mOutGlop->roundRectClipState) {
|
||||
if (alphaScale < 1.0f || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) ||
|
||||
texture.blend || mOutGlop->roundRectClipState) {
|
||||
Blend::getFactors(SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap,
|
||||
&mOutGlop->blend.src, &mOutGlop->blend.dst);
|
||||
&mOutGlop->blend.src, &mOutGlop->blend.dst);
|
||||
} else {
|
||||
mOutGlop->blend = { GL_ZERO, GL_ZERO };
|
||||
mOutGlop->blend = {GL_ZERO, GL_ZERO};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,32 +350,28 @@ GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale, b
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
if (CC_LIKELY(!shadowInterp)) {
|
||||
mOutGlop->fill.texture = {
|
||||
nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
|
||||
mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
|
||||
} else {
|
||||
mOutGlop->fill.texture = {
|
||||
mCaches.textureState().getShadowLutTexture(),
|
||||
GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
|
||||
mOutGlop->fill.texture = {mCaches.textureState().getShadowLutTexture(), GL_INVALID_ENUM,
|
||||
GL_INVALID_ENUM, nullptr};
|
||||
}
|
||||
|
||||
setFill(paint.getColor(), alphaScale,
|
||||
paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
|
||||
setFill(paint.getColor(), alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
|
||||
paint.getShader(), paint.getColorFilter());
|
||||
mDescription.useShadowAlphaInterp = shadowInterp;
|
||||
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
|
||||
const SkPaint& paint, float alphaScale) {
|
||||
GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint,
|
||||
float alphaScale) {
|
||||
TRIGGER_STAGE(kFillStage);
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
//specify invalid filter/clamp, since these are always static for PathTextures
|
||||
mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
|
||||
// specify invalid filter/clamp, since these are always static for PathTextures
|
||||
mOutGlop->fill.texture = {&texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
|
||||
|
||||
setFill(paint.getColor(), alphaScale,
|
||||
paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
|
||||
setFill(paint.getColor(), alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
|
||||
paint.getShader(), paint.getColorFilter());
|
||||
|
||||
mDescription.hasAlpha8Texture = true;
|
||||
@@ -387,12 +380,12 @@ GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
|
||||
}
|
||||
|
||||
GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
|
||||
const SkPaint& paint, float alphaScale) {
|
||||
const SkPaint& paint, float alphaScale) {
|
||||
TRIGGER_STAGE(kFillStage);
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
//specify invalid filter/clamp, since these are always static for ShadowTextures
|
||||
mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
|
||||
// specify invalid filter/clamp, since these are always static for ShadowTextures
|
||||
mOutGlop->fill.texture = {&texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
|
||||
|
||||
const int ALPHA_BITMASK = SK_ColorBLACK;
|
||||
const int COLOR_BITMASK = ~ALPHA_BITMASK;
|
||||
@@ -401,8 +394,7 @@ GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int
|
||||
shadowColor &= paint.getColor() | COLOR_BITMASK;
|
||||
}
|
||||
|
||||
setFill(shadowColor, alphaScale,
|
||||
paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
|
||||
setFill(shadowColor, alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
|
||||
paint.getShader(), paint.getColorFilter());
|
||||
|
||||
mDescription.hasAlpha8Texture = true;
|
||||
@@ -414,9 +406,9 @@ GlopBuilder& GlopBuilder::setFillBlack() {
|
||||
TRIGGER_STAGE(kFillStage);
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
|
||||
setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap,
|
||||
nullptr, nullptr);
|
||||
mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
|
||||
setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap, nullptr,
|
||||
nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -424,18 +416,19 @@ GlopBuilder& GlopBuilder::setFillClear() {
|
||||
TRIGGER_STAGE(kFillStage);
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
|
||||
setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kClear, Blend::ModeOrderSwap::NoSwap,
|
||||
nullptr, nullptr);
|
||||
mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
|
||||
setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kClear, Blend::ModeOrderSwap::NoSwap, nullptr,
|
||||
nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
|
||||
float alpha, SkBlendMode mode, Blend::ModeOrderSwap modeUsage) {
|
||||
float alpha, SkBlendMode mode,
|
||||
Blend::ModeOrderSwap modeUsage) {
|
||||
TRIGGER_STAGE(kFillStage);
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
|
||||
mOutGlop->fill.texture = {&texture, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr};
|
||||
|
||||
setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter);
|
||||
|
||||
@@ -447,11 +440,11 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) {
|
||||
TRIGGER_STAGE(kFillStage);
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
mOutGlop->fill.texture = { &(layer.getTexture()),
|
||||
GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
|
||||
mOutGlop->fill.texture = {&(layer.getTexture()), GL_LINEAR, GL_CLAMP_TO_EDGE,
|
||||
&layer.getTexTransform()};
|
||||
|
||||
setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap,
|
||||
nullptr, layer.getColorFilter());
|
||||
setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap, nullptr,
|
||||
layer.getColorFilter());
|
||||
|
||||
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
|
||||
mDescription.hasTextureTransform = true;
|
||||
@@ -459,15 +452,14 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) {
|
||||
}
|
||||
|
||||
GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
|
||||
bool requiresFilter) {
|
||||
bool requiresFilter) {
|
||||
TRIGGER_STAGE(kFillStage);
|
||||
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
|
||||
|
||||
GLenum filter = requiresFilter ? GL_LINEAR : GL_NEAREST;
|
||||
mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, &textureTransform };
|
||||
mOutGlop->fill.texture = {&texture, filter, GL_CLAMP_TO_EDGE, &textureTransform};
|
||||
|
||||
setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap,
|
||||
nullptr, nullptr);
|
||||
setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap, nullptr, nullptr);
|
||||
|
||||
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
|
||||
mDescription.hasTextureTransform = true;
|
||||
@@ -518,8 +510,8 @@ GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination)
|
||||
const float translateX = meshTransform.getTranslateX();
|
||||
const float translateY = meshTransform.getTranslateY();
|
||||
|
||||
left = (int) floorf(left + translateX + 0.5f) - translateX;
|
||||
top = (int) floorf(top + translateY + 0.5f) - translateY;
|
||||
left = (int)floorf(left + translateX + 0.5f) - translateX;
|
||||
top = (int)floorf(top + translateY + 0.5f) - translateY;
|
||||
mOutGlop->fill.texture.filter = GL_NEAREST;
|
||||
}
|
||||
|
||||
@@ -535,7 +527,8 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, c
|
||||
return *this;
|
||||
}
|
||||
|
||||
GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) {
|
||||
GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY,
|
||||
const Rect source) {
|
||||
TRIGGER_STAGE(kModelViewStage);
|
||||
REQUIRE_STAGES(kTransformStage | kFillStage);
|
||||
|
||||
@@ -545,8 +538,8 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offset
|
||||
const float translateX = meshTransform.getTranslateX();
|
||||
const float translateY = meshTransform.getTranslateY();
|
||||
|
||||
offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
|
||||
offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
|
||||
offsetX = (int)floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
|
||||
offsetY = (int)floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
|
||||
mOutGlop->fill.texture.filter = GL_NEAREST;
|
||||
}
|
||||
|
||||
@@ -572,27 +565,25 @@ GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundR
|
||||
|
||||
void verify(const ProgramDescription& description, const Glop& glop) {
|
||||
if (glop.fill.texture.texture != nullptr) {
|
||||
LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture)
|
||||
|| (!description.hasTexture
|
||||
&& !description.hasExternalTexture
|
||||
&& !description.useShadowAlphaInterp)
|
||||
|| ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0
|
||||
&& !description.useShadowAlphaInterp)),
|
||||
"Texture %p, hT%d, hET %d, attribFlags %x",
|
||||
glop.fill.texture.texture,
|
||||
LOG_ALWAYS_FATAL_IF(
|
||||
((description.hasTexture && description.hasExternalTexture) ||
|
||||
(!description.hasTexture && !description.hasExternalTexture &&
|
||||
!description.useShadowAlphaInterp) ||
|
||||
((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0 &&
|
||||
!description.useShadowAlphaInterp)),
|
||||
"Texture %p, hT%d, hET %d, attribFlags %x", glop.fill.texture.texture,
|
||||
description.hasTexture, description.hasExternalTexture,
|
||||
glop.mesh.vertices.attribFlags);
|
||||
} else {
|
||||
LOG_ALWAYS_FATAL_IF((description.hasTexture
|
||||
|| description.hasExternalTexture
|
||||
|| ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)),
|
||||
"No texture, hT%d, hET %d, attribFlags %x",
|
||||
description.hasTexture, description.hasExternalTexture,
|
||||
glop.mesh.vertices.attribFlags);
|
||||
LOG_ALWAYS_FATAL_IF(
|
||||
(description.hasTexture || description.hasExternalTexture ||
|
||||
((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)),
|
||||
"No texture, hT%d, hET %d, attribFlags %x", description.hasTexture,
|
||||
description.hasExternalTexture, glop.mesh.vertices.attribFlags);
|
||||
}
|
||||
|
||||
if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
|
||||
&& glop.mesh.vertices.bufferObject) {
|
||||
if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha) &&
|
||||
glop.mesh.vertices.bufferObject) {
|
||||
LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible");
|
||||
}
|
||||
|
||||
@@ -621,9 +612,10 @@ void GlopBuilder::build() {
|
||||
|
||||
// Enable debug highlight when what we're about to draw is tested against
|
||||
// the stencil buffer and if stencil highlight debugging is on
|
||||
mDescription.hasDebugHighlight = !Properties::debugOverdraw
|
||||
&& Properties::debugStencilClip == StencilClipDebug::ShowHighlight
|
||||
&& mRenderState.stencil().isTestEnabled();
|
||||
mDescription.hasDebugHighlight =
|
||||
!Properties::debugOverdraw &&
|
||||
Properties::debugStencilClip == StencilClipDebug::ShowHighlight &&
|
||||
mRenderState.stencil().isTestEnabled();
|
||||
|
||||
// serialize shader info into ShaderData
|
||||
GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
|
||||
@@ -640,15 +632,13 @@ void GlopBuilder::build() {
|
||||
} else {
|
||||
shaderMatrix = mOutGlop->transform.modelView;
|
||||
}
|
||||
SkiaShader::store(mCaches, *mShader, shaderMatrix,
|
||||
&textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
|
||||
SkiaShader::store(mCaches, *mShader, shaderMatrix, &textureUnit, &mDescription,
|
||||
&(mOutGlop->fill.skiaShaderData));
|
||||
}
|
||||
|
||||
// duplicates ProgramCache's definition of color uniform presence
|
||||
const bool singleColor = !mDescription.hasTexture
|
||||
&& !mDescription.hasExternalTexture
|
||||
&& !mDescription.hasGradient
|
||||
&& !mDescription.hasBitmap;
|
||||
const bool singleColor = !mDescription.hasTexture && !mDescription.hasExternalTexture &&
|
||||
!mDescription.hasGradient && !mDescription.hasBitmap;
|
||||
mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
|
||||
|
||||
verify(mDescription, *mOutGlop);
|
||||
@@ -661,31 +651,31 @@ void GlopBuilder::dump(const Glop& glop) {
|
||||
ALOGD("Glop Mesh");
|
||||
const Glop::Mesh& mesh = glop.mesh;
|
||||
ALOGD(" primitive mode: %d", mesh.primitiveMode);
|
||||
ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject, mesh.indices.indices);
|
||||
ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject,
|
||||
mesh.indices.indices);
|
||||
|
||||
const Glop::Mesh::Vertices& vertices = glop.mesh.vertices;
|
||||
ALOGD(" vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d",
|
||||
vertices.bufferObject, vertices.attribFlags,
|
||||
vertices.position, vertices.texCoord, vertices.color, vertices.stride);
|
||||
vertices.bufferObject, vertices.attribFlags, vertices.position, vertices.texCoord,
|
||||
vertices.color, vertices.stride);
|
||||
ALOGD(" element count: %d", mesh.elementCount);
|
||||
|
||||
ALOGD("Glop Fill");
|
||||
const Glop::Fill& fill = glop.fill;
|
||||
ALOGD(" program %p", fill.program);
|
||||
if (fill.texture.texture) {
|
||||
ALOGD(" texture %p, target %d, filter %d, clamp %d",
|
||||
fill.texture.texture, fill.texture.texture->target(),
|
||||
fill.texture.filter, fill.texture.clamp);
|
||||
ALOGD(" texture %p, target %d, filter %d, clamp %d", fill.texture.texture,
|
||||
fill.texture.texture->target(), fill.texture.filter, fill.texture.clamp);
|
||||
if (fill.texture.textureTransform) {
|
||||
fill.texture.textureTransform->dump("texture transform");
|
||||
}
|
||||
}
|
||||
ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f",
|
||||
fill.color.a, fill.color.r, fill.color.g, fill.color.b);
|
||||
ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None,
|
||||
" filterMode %d", (int)fill.filterMode);
|
||||
ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f", fill.color.a, fill.color.r,
|
||||
fill.color.g, fill.color.b);
|
||||
ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None, " filterMode %d",
|
||||
(int)fill.filterMode);
|
||||
ALOGD_IF(fill.skiaShaderData.skiaShaderType, " shader type %d",
|
||||
fill.skiaShaderData.skiaShaderType);
|
||||
fill.skiaShaderData.skiaShaderType);
|
||||
|
||||
ALOGD("Glop transform");
|
||||
glop.transform.modelView.dump(" model view");
|
||||
|
||||
@@ -39,15 +39,16 @@ struct PathTexture;
|
||||
struct ShadowTexture;
|
||||
|
||||
namespace TextureFillFlags {
|
||||
enum {
|
||||
None = 0,
|
||||
IsAlphaMaskTexture = 1 << 0,
|
||||
ForceFilter = 1 << 1,
|
||||
};
|
||||
enum {
|
||||
None = 0,
|
||||
IsAlphaMaskTexture = 1 << 0,
|
||||
ForceFilter = 1 << 1,
|
||||
};
|
||||
}
|
||||
|
||||
class GlopBuilder {
|
||||
PREVENT_COPY_AND_ASSIGN(GlopBuilder);
|
||||
|
||||
public:
|
||||
GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
|
||||
|
||||
@@ -57,26 +58,29 @@ public:
|
||||
GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs);
|
||||
GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer);
|
||||
GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount);
|
||||
GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); // TODO: use indexed quads
|
||||
GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount
|
||||
GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData,
|
||||
int elementCount); // TODO: use indexed quads
|
||||
GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData,
|
||||
int elementCount); // TODO: take quadCount
|
||||
GlopBuilder& setMeshPatchQuads(const Patch& patch);
|
||||
|
||||
GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale, bool shadowInterp = false); // TODO: avoid boolean with default
|
||||
GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale,
|
||||
bool shadowInterp = false); // TODO: avoid boolean with default
|
||||
GlopBuilder& setFillTexturePaint(Texture& texture, const int textureFillFlags,
|
||||
const SkPaint* paint, float alphaScale);
|
||||
GlopBuilder& setFillPathTexturePaint(PathTexture& texture,
|
||||
const SkPaint& paint, float alphaScale);
|
||||
const SkPaint* paint, float alphaScale);
|
||||
GlopBuilder& setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint,
|
||||
float alphaScale);
|
||||
GlopBuilder& setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
|
||||
const SkPaint& paint, float alphaScale);
|
||||
const SkPaint& paint, float alphaScale);
|
||||
GlopBuilder& setFillBlack();
|
||||
GlopBuilder& setFillClear();
|
||||
GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
|
||||
float alpha, SkBlendMode mode, Blend::ModeOrderSwap modeUsage);
|
||||
GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter, float alpha,
|
||||
SkBlendMode mode, Blend::ModeOrderSwap modeUsage);
|
||||
GlopBuilder& setFillTextureLayer(GlLayer& layer, float alpha);
|
||||
// TODO: setFillLayer normally forces its own wrap & filter mode,
|
||||
// which isn't always correct.
|
||||
GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
|
||||
bool requiresFilter);
|
||||
bool requiresFilter);
|
||||
|
||||
GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags);
|
||||
|
||||
@@ -91,8 +95,8 @@ public:
|
||||
}
|
||||
GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
|
||||
GlopBuilder& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source);
|
||||
GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap,
|
||||
float offsetX, float offsetY, const Rect& source) {
|
||||
GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap, float offsetX, float offsetY,
|
||||
const Rect& source) {
|
||||
if (snap) {
|
||||
return setModelViewOffsetRectSnap(offsetX, offsetY, source);
|
||||
} else {
|
||||
@@ -111,10 +115,10 @@ public:
|
||||
void build();
|
||||
|
||||
static void dump(const Glop& glop);
|
||||
|
||||
private:
|
||||
void setFill(int color, float alphaScale,
|
||||
SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
|
||||
const SkShader* shader, const SkColorFilter* colorFilter);
|
||||
void setFill(int color, float alphaScale, SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
|
||||
const SkShader* shader, const SkColorFilter* colorFilter);
|
||||
|
||||
enum StageFlags {
|
||||
kInitialStage = 0,
|
||||
@@ -123,7 +127,8 @@ private:
|
||||
kModelViewStage = 1 << 2,
|
||||
kFillStage = 1 << 3,
|
||||
kRoundRectClipStage = 1 << 4,
|
||||
kAllStages = kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
|
||||
kAllStages =
|
||||
kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
|
||||
} mStageFlags;
|
||||
|
||||
ProgramDescription mDescription;
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utils/StringUtils.h"
|
||||
#include "Texture.h"
|
||||
#include "utils/StringUtils.h"
|
||||
|
||||
#include <cutils/compiler.h>
|
||||
#include <GpuMemoryTracker.h>
|
||||
#include <cutils/compiler.h>
|
||||
#include <utils/Trace.h>
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
@@ -33,9 +33,7 @@ pthread_t gGpuThread = 0;
|
||||
#define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
|
||||
|
||||
const char* TYPE_NAMES[] = {
|
||||
"Texture",
|
||||
"OffscreenBuffer",
|
||||
"Layer",
|
||||
"Texture", "OffscreenBuffer", "Layer",
|
||||
};
|
||||
|
||||
struct TypeStats {
|
||||
@@ -55,21 +53,22 @@ void GpuMemoryTracker::notifySizeChanged(int newSize) {
|
||||
void GpuMemoryTracker::startTrackingObject() {
|
||||
auto result = gObjectSet.insert(this);
|
||||
LOG_ALWAYS_FATAL_IF(!result.second,
|
||||
"startTrackingObject() on %p failed, already being tracked!", this);
|
||||
"startTrackingObject() on %p failed, already being tracked!", this);
|
||||
gObjectStats[static_cast<int>(mType)].count++;
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::stopTrackingObject() {
|
||||
size_t removed = gObjectSet.erase(this);
|
||||
LOG_ALWAYS_FATAL_IF(removed != 1,
|
||||
"stopTrackingObject removed %zd, is %p not being tracked?",
|
||||
removed, this);
|
||||
LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?",
|
||||
removed, this);
|
||||
gObjectStats[static_cast<int>(mType)].count--;
|
||||
}
|
||||
|
||||
void GpuMemoryTracker::onGpuContextCreated() {
|
||||
LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a gpu thread? "
|
||||
"current = %lu, gpu thread = %lu", pthread_self(), gGpuThread);
|
||||
LOG_ALWAYS_FATAL_IF(gGpuThread != 0,
|
||||
"We already have a gpu thread? "
|
||||
"current = %lu, gpu thread = %lu",
|
||||
pthread_self(), gGpuThread);
|
||||
gGpuThread = pthread_self();
|
||||
}
|
||||
|
||||
@@ -124,8 +123,8 @@ void GpuMemoryTracker::onFrameCompleted() {
|
||||
if (obj->objectType() == GpuObjectType::Texture) {
|
||||
const Texture* texture = static_cast<Texture*>(obj);
|
||||
if (texture->cleanup) {
|
||||
ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u",
|
||||
texture->id(), texture->width(), texture->height());
|
||||
ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", texture->id(),
|
||||
texture->width(), texture->height());
|
||||
freeList.push_back(texture);
|
||||
}
|
||||
}
|
||||
@@ -136,5 +135,5 @@ void GpuMemoryTracker::onFrameCompleted() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android;
|
||||
} // namespace uirenderer
|
||||
} // namespace android;
|
||||
|
||||
@@ -25,11 +25,11 @@ namespace uirenderer {
|
||||
|
||||
extern pthread_t gGpuThread;
|
||||
|
||||
#define ASSERT_GPU_THREAD() LOG_ALWAYS_FATAL_IF( \
|
||||
!pthread_equal(gGpuThread, pthread_self()), \
|
||||
"Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
|
||||
"!= gpu thread %lu", this, static_cast<int>(mType), mSize, \
|
||||
pthread_self(), gGpuThread)
|
||||
#define ASSERT_GPU_THREAD() \
|
||||
LOG_ALWAYS_FATAL_IF(!pthread_equal(gGpuThread, pthread_self()), \
|
||||
"Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
|
||||
"!= gpu thread %lu", \
|
||||
this, static_cast<int>(mType), mSize, pthread_self(), gGpuThread)
|
||||
|
||||
enum class GpuObjectType {
|
||||
Texture = 0,
|
||||
@@ -73,5 +73,5 @@ private:
|
||||
GpuObjectType mType;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android;
|
||||
} // namespace uirenderer
|
||||
} // namespace android;
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
#include "Caches.h"
|
||||
#include "Debug.h"
|
||||
#include "DeviceInfo.h"
|
||||
#include "GradientCache.h"
|
||||
#include "Properties.h"
|
||||
#include "DeviceInfo.h"
|
||||
|
||||
#include <cutils/properties.h>
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace uirenderer {
|
||||
// Functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static inline T min(T a, T b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
@@ -122,8 +122,7 @@ void GradientCache::clear() {
|
||||
mCache.clear();
|
||||
}
|
||||
|
||||
void GradientCache::getGradientInfo(const uint32_t* colors, const int count,
|
||||
GradientInfo& info) {
|
||||
void GradientCache::getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info) {
|
||||
uint32_t width = 256 * (count - 1);
|
||||
|
||||
// If the npot extension is not supported we cannot use non-clamp
|
||||
@@ -145,9 +144,8 @@ void GradientCache::getGradientInfo(const uint32_t* colors, const int count,
|
||||
info.hasAlpha = hasAlpha;
|
||||
}
|
||||
|
||||
Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
|
||||
uint32_t* colors, float* positions, int count) {
|
||||
|
||||
Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors,
|
||||
float* positions, int count) {
|
||||
GradientInfo info;
|
||||
getGradientInfo(colors, count, info);
|
||||
|
||||
@@ -159,18 +157,19 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
|
||||
const uint32_t size = info.width * 2 * bytesPerPixel();
|
||||
while (getSize() + size > mMaxSize) {
|
||||
LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
|
||||
"Ran out of things to remove from the cache? getSize() = %" PRIu32
|
||||
", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32,
|
||||
getSize(), size, mMaxSize, info.width);
|
||||
"Ran out of things to remove from the cache? getSize() = %" PRIu32
|
||||
", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32,
|
||||
getSize(), size, mMaxSize, info.width);
|
||||
}
|
||||
|
||||
generateTexture(colors, positions, info.width, 2, texture);
|
||||
|
||||
mSize += size;
|
||||
LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(),
|
||||
"size != texture->objectSize(), size %" PRIu32 ", objectSize %d"
|
||||
" width = %" PRIu32 " bytesPerPixel() = %zu",
|
||||
size, texture->objectSize(), info.width, bytesPerPixel());
|
||||
"size != texture->objectSize(), size %" PRIu32
|
||||
", objectSize %d"
|
||||
" width = %" PRIu32 " bytesPerPixel() = %zu",
|
||||
size, texture->objectSize(), info.width, bytesPerPixel());
|
||||
mCache.put(gradient, texture);
|
||||
|
||||
return texture;
|
||||
@@ -186,8 +185,8 @@ size_t GradientCache::sourceBytesPerPixel() const {
|
||||
return 4 * (mUseFloatTexture ? sizeof(float) : sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end,
|
||||
float amount, uint8_t*& dst) const {
|
||||
void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end, float amount,
|
||||
uint8_t*& dst) const {
|
||||
float oppAmount = 1.0f - amount;
|
||||
float a = start.a * oppAmount + end.a * amount;
|
||||
*dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f);
|
||||
@@ -196,11 +195,11 @@ void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end,
|
||||
*dst++ = uint8_t(a * 255.0f);
|
||||
}
|
||||
|
||||
void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
|
||||
float amount, uint8_t*& dst) const {
|
||||
void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, float amount,
|
||||
uint8_t*& dst) const {
|
||||
float oppAmount = 1.0f - amount;
|
||||
float a = start.a * oppAmount + end.a * amount;
|
||||
float* d = (float*) dst;
|
||||
float* d = (float*)dst;
|
||||
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
|
||||
// We want to stay linear
|
||||
*d++ = (start.r * oppAmount + end.r * amount);
|
||||
@@ -215,8 +214,8 @@ void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
|
||||
dst += 4 * sizeof(float);
|
||||
}
|
||||
|
||||
void GradientCache::generateTexture(uint32_t* colors, float* positions,
|
||||
const uint32_t width, const uint32_t height, Texture* texture) {
|
||||
void GradientCache::generateTexture(uint32_t* colors, float* positions, const uint32_t width,
|
||||
const uint32_t height, Texture* texture) {
|
||||
const GLsizei rowBytes = width * sourceBytesPerPixel();
|
||||
uint8_t pixels[rowBytes * height];
|
||||
|
||||
@@ -269,5 +268,5 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions,
|
||||
texture->setWrap(GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -60,13 +60,9 @@ struct GradientCacheEntry {
|
||||
|
||||
static int compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs);
|
||||
|
||||
bool operator==(const GradientCacheEntry& other) const {
|
||||
return compare(*this, other) == 0;
|
||||
}
|
||||
bool operator==(const GradientCacheEntry& other) const { return compare(*this, other) == 0; }
|
||||
|
||||
bool operator!=(const GradientCacheEntry& other) const {
|
||||
return compare(*this, other) != 0;
|
||||
}
|
||||
bool operator!=(const GradientCacheEntry& other) const { return compare(*this, other) != 0; }
|
||||
|
||||
std::unique_ptr<uint32_t[]> colors;
|
||||
std::unique_ptr<float[]> positions;
|
||||
@@ -82,7 +78,7 @@ private:
|
||||
memcpy(this->positions.get(), positions, count * sizeof(float));
|
||||
}
|
||||
|
||||
}; // GradientCacheEntry
|
||||
}; // GradientCacheEntry
|
||||
|
||||
// Caching support
|
||||
|
||||
@@ -103,7 +99,7 @@ inline hash_t hash_type(const GradientCacheEntry& entry) {
|
||||
* Any texture added to the cache causing the cache to grow beyond the maximum
|
||||
* allowed size will also cause the oldest texture to be kicked out.
|
||||
*/
|
||||
class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
|
||||
class GradientCache : public OnEntryRemoved<GradientCacheEntry, Texture*> {
|
||||
public:
|
||||
explicit GradientCache(const Extensions& extensions);
|
||||
~GradientCache();
|
||||
@@ -138,11 +134,11 @@ private:
|
||||
* Adds a new linear gradient to the cache. The generated texture is
|
||||
* returned.
|
||||
*/
|
||||
Texture* addLinearGradient(GradientCacheEntry& gradient,
|
||||
uint32_t* colors, float* positions, int count);
|
||||
Texture* addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors, float* positions,
|
||||
int count);
|
||||
|
||||
void generateTexture(uint32_t* colors, float* positions,
|
||||
const uint32_t width, const uint32_t height, Texture* texture);
|
||||
void generateTexture(uint32_t* colors, float* positions, const uint32_t width,
|
||||
const uint32_t height, Texture* texture);
|
||||
|
||||
struct GradientInfo {
|
||||
uint32_t width;
|
||||
@@ -155,12 +151,12 @@ private:
|
||||
size_t sourceBytesPerPixel() const;
|
||||
|
||||
typedef void (GradientCache::*ChannelMixer)(const FloatColor& start, const FloatColor& end,
|
||||
float amount, uint8_t*& dst) const;
|
||||
float amount, uint8_t*& dst) const;
|
||||
|
||||
void mixBytes(const FloatColor& start, const FloatColor& end,
|
||||
float amount, uint8_t*& dst) const;
|
||||
void mixFloats(const FloatColor& start, const FloatColor& end,
|
||||
float amount, uint8_t*& dst) const;
|
||||
void mixBytes(const FloatColor& start, const FloatColor& end, float amount,
|
||||
uint8_t*& dst) const;
|
||||
void mixFloats(const FloatColor& start, const FloatColor& end, float amount,
|
||||
uint8_t*& dst) const;
|
||||
|
||||
LruCache<GradientCacheEntry, Texture*> mCache;
|
||||
|
||||
@@ -173,9 +169,9 @@ private:
|
||||
bool mHasLinearBlending;
|
||||
|
||||
mutable Mutex mLock;
|
||||
}; // class GradientCache
|
||||
}; // class GradientCache
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_GRADIENT_CACHE_H
|
||||
#endif // ANDROID_HWUI_GRADIENT_CACHE_H
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace uirenderer {
|
||||
class IProfileRenderer {
|
||||
public:
|
||||
virtual void drawRect(float left, float top, float right, float bottom,
|
||||
const SkPaint& paint) = 0;
|
||||
const SkPaint& paint) = 0;
|
||||
virtual void drawRects(const float* rects, int count, const SkPaint& paint) = 0;
|
||||
virtual uint32_t getViewportWidth() = 0;
|
||||
virtual uint32_t getViewportHeight() = 0;
|
||||
|
||||
@@ -25,11 +25,11 @@ namespace uirenderer {
|
||||
Image::Image(sp<GraphicBuffer> buffer) {
|
||||
// Create the EGLImage object that maps the GraphicBuffer
|
||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
|
||||
EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
|
||||
EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
|
||||
EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
|
||||
|
||||
mImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
|
||||
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
|
||||
mImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
|
||||
attrs);
|
||||
|
||||
if (mImage == EGL_NO_IMAGE_KHR) {
|
||||
ALOGW("Error creating image (%#x)", eglGetError());
|
||||
@@ -57,5 +57,5 @@ Image::~Image() {
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -45,23 +45,19 @@ public:
|
||||
* Returns the name of the GL texture that can be used to sample
|
||||
* from this image.
|
||||
*/
|
||||
GLuint getTexture() const {
|
||||
return mTexture;
|
||||
}
|
||||
GLuint getTexture() const { return mTexture; }
|
||||
|
||||
/**
|
||||
* Returns the name of the EGL image represented by this object.
|
||||
*/
|
||||
EGLImageKHR getImage() const {
|
||||
return mImage;
|
||||
}
|
||||
EGLImageKHR getImage() const { return mImage; }
|
||||
|
||||
private:
|
||||
GLuint mTexture;
|
||||
EGLImageKHR mImage;
|
||||
}; // class Image
|
||||
}; // class Image
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_IMAGE_H
|
||||
#endif // ANDROID_HWUI_IMAGE_H
|
||||
|
||||
@@ -54,8 +54,10 @@ static float o(float t, float s) {
|
||||
}
|
||||
|
||||
float AnticipateOvershootInterpolator::interpolate(float t) {
|
||||
if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
|
||||
else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
|
||||
if (t < 0.5f)
|
||||
return 0.5f * a(t * 2.0f, mTension);
|
||||
else
|
||||
return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
|
||||
}
|
||||
|
||||
static float bounce(float t) {
|
||||
@@ -64,10 +66,14 @@ static float bounce(float t) {
|
||||
|
||||
float BounceInterpolator::interpolate(float t) {
|
||||
t *= 1.1226f;
|
||||
if (t < 0.3535f) return bounce(t);
|
||||
else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
|
||||
else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
|
||||
else return bounce(t - 1.0435f) + 0.95f;
|
||||
if (t < 0.3535f)
|
||||
return bounce(t);
|
||||
else if (t < 0.7408f)
|
||||
return bounce(t - 0.54719f) + 0.7f;
|
||||
else if (t < 0.9644f)
|
||||
return bounce(t - 0.8526f) + 0.9f;
|
||||
else
|
||||
return bounce(t - 1.0435f) + 0.95f;
|
||||
}
|
||||
|
||||
float CycleInterpolator::interpolate(float input) {
|
||||
@@ -119,16 +125,11 @@ float PathInterpolator::interpolate(float t) {
|
||||
float startY = mY[startIndex];
|
||||
float endY = mY[endIndex];
|
||||
return startY + (fraction * (endY - startY));
|
||||
|
||||
}
|
||||
|
||||
LUTInterpolator::LUTInterpolator(float* values, size_t size)
|
||||
: mValues(values)
|
||||
, mSize(size) {
|
||||
}
|
||||
LUTInterpolator::LUTInterpolator(float* values, size_t size) : mValues(values), mSize(size) {}
|
||||
|
||||
LUTInterpolator::~LUTInterpolator() {
|
||||
}
|
||||
LUTInterpolator::~LUTInterpolator() {}
|
||||
|
||||
float LUTInterpolator::interpolate(float input) {
|
||||
// lut position should only be at the end of the table when input is 1f.
|
||||
@@ -140,10 +141,12 @@ float LUTInterpolator::interpolate(float input) {
|
||||
float ipart, weight;
|
||||
weight = modff(lutpos, &ipart);
|
||||
|
||||
int i1 = (int) ipart;
|
||||
int i2 = std::min(i1 + 1, (int) mSize - 1);
|
||||
int i1 = (int)ipart;
|
||||
int i2 = std::min(i1 + 1, (int)mSize - 1);
|
||||
|
||||
LOG_ALWAYS_FATAL_IF(i1 < 0 || i2 < 0, "negatives in interpolation!"
|
||||
LOG_ALWAYS_FATAL_IF(
|
||||
i1 < 0 || i2 < 0,
|
||||
"negatives in interpolation!"
|
||||
" i1=%d, i2=%d, input=%f, lutpos=%f, size=%zu, values=%p, ipart=%f, weight=%f",
|
||||
i1, i2, input, lutpos, mSize, mValues.get(), ipart, weight);
|
||||
|
||||
@@ -153,6 +156,5 @@ float LUTInterpolator::interpolate(float input) {
|
||||
return MathUtils::lerp(v1, v2, weight);
|
||||
}
|
||||
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
@@ -44,8 +44,9 @@ public:
|
||||
|
||||
class ANDROID_API AccelerateInterpolator : public Interpolator {
|
||||
public:
|
||||
explicit AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor*2) {}
|
||||
explicit AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor * 2) {}
|
||||
virtual float interpolate(float input) override;
|
||||
|
||||
private:
|
||||
const float mFactor;
|
||||
const float mDoubleFactor;
|
||||
@@ -55,6 +56,7 @@ class ANDROID_API AnticipateInterpolator : public Interpolator {
|
||||
public:
|
||||
explicit AnticipateInterpolator(float tension) : mTension(tension) {}
|
||||
virtual float interpolate(float input) override;
|
||||
|
||||
private:
|
||||
const float mTension;
|
||||
};
|
||||
@@ -63,6 +65,7 @@ class ANDROID_API AnticipateOvershootInterpolator : public Interpolator {
|
||||
public:
|
||||
explicit AnticipateOvershootInterpolator(float tension) : mTension(tension) {}
|
||||
virtual float interpolate(float input) override;
|
||||
|
||||
private:
|
||||
const float mTension;
|
||||
};
|
||||
@@ -76,6 +79,7 @@ class ANDROID_API CycleInterpolator : public Interpolator {
|
||||
public:
|
||||
explicit CycleInterpolator(float cycles) : mCycles(cycles) {}
|
||||
virtual float interpolate(float input) override;
|
||||
|
||||
private:
|
||||
const float mCycles;
|
||||
};
|
||||
@@ -84,6 +88,7 @@ class ANDROID_API DecelerateInterpolator : public Interpolator {
|
||||
public:
|
||||
explicit DecelerateInterpolator(float factor) : mFactor(factor) {}
|
||||
virtual float interpolate(float input) override;
|
||||
|
||||
private:
|
||||
const float mFactor;
|
||||
};
|
||||
@@ -97,15 +102,16 @@ class ANDROID_API OvershootInterpolator : public Interpolator {
|
||||
public:
|
||||
explicit OvershootInterpolator(float tension) : mTension(tension) {}
|
||||
virtual float interpolate(float input) override;
|
||||
|
||||
private:
|
||||
const float mTension;
|
||||
};
|
||||
|
||||
class ANDROID_API PathInterpolator : public Interpolator {
|
||||
public:
|
||||
explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y)
|
||||
: mX (x), mY(y) {}
|
||||
explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y) : mX(x), mY(y) {}
|
||||
virtual float interpolate(float input) override;
|
||||
|
||||
private:
|
||||
std::vector<float> mX;
|
||||
std::vector<float> mY;
|
||||
|
||||
@@ -106,25 +106,23 @@ void JankTracker::setFrameInterval(nsecs_t frameInterval) {
|
||||
mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval);
|
||||
mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval);
|
||||
mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval);
|
||||
|
||||
}
|
||||
|
||||
void JankTracker::finishFrame(const FrameInfo& frame) {
|
||||
// Fast-path for jank-free frames
|
||||
int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted);
|
||||
if (mDequeueTimeForgiveness
|
||||
&& frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
|
||||
nsecs_t expectedDequeueDuration =
|
||||
mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync]
|
||||
- frame[FrameInfoIndex::IssueDrawCommandsStart];
|
||||
if (mDequeueTimeForgiveness && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
|
||||
nsecs_t expectedDequeueDuration = mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync] -
|
||||
frame[FrameInfoIndex::IssueDrawCommandsStart];
|
||||
if (expectedDequeueDuration > 0) {
|
||||
// Forgive only up to the expected amount, but not more than
|
||||
// the actual time spent blocked.
|
||||
nsecs_t forgiveAmount = std::min(expectedDequeueDuration,
|
||||
frame[FrameInfoIndex::DequeueBufferDuration]);
|
||||
nsecs_t forgiveAmount =
|
||||
std::min(expectedDequeueDuration, frame[FrameInfoIndex::DequeueBufferDuration]);
|
||||
LOG_ALWAYS_FATAL_IF(forgiveAmount >= totalDuration,
|
||||
"Impossible dequeue duration! dequeue duration reported %" PRId64
|
||||
", total duration %" PRId64, forgiveAmount, totalDuration);
|
||||
"Impossible dequeue duration! dequeue duration reported %" PRId64
|
||||
", total duration %" PRId64,
|
||||
forgiveAmount, totalDuration);
|
||||
totalDuration -= forgiveAmount;
|
||||
}
|
||||
}
|
||||
@@ -148,13 +146,14 @@ void JankTracker::finishFrame(const FrameInfo& frame) {
|
||||
for (int i = 0; i < NUM_BUCKETS; i++) {
|
||||
int64_t delta = frame.duration(COMPARISONS[i].start, COMPARISONS[i].end);
|
||||
if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
|
||||
mData->reportJankType((JankType) i);
|
||||
(*mGlobalData)->reportJankType((JankType) i);
|
||||
mData->reportJankType((JankType)i);
|
||||
(*mGlobalData)->reportJankType((JankType)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JankTracker::dumpData(int fd, const ProfileDataDescription* description, const ProfileData* data) {
|
||||
void JankTracker::dumpData(int fd, const ProfileDataDescription* description,
|
||||
const ProfileData* data) {
|
||||
if (description) {
|
||||
switch (description->type) {
|
||||
case JankTrackerType::Generic:
|
||||
@@ -199,9 +198,8 @@ void JankTracker::reset() {
|
||||
mFrames.clear();
|
||||
mData->reset();
|
||||
(*mGlobalData)->reset();
|
||||
sFrameStart = Properties::filterOutTestOverhead
|
||||
? FrameInfoIndex::HandleInputStart
|
||||
: FrameInfoIndex::IntendedVsync;
|
||||
sFrameStart = Properties::filterOutTestOverhead ? FrameInfoIndex::HandleInputStart
|
||||
: FrameInfoIndex::IntendedVsync;
|
||||
}
|
||||
|
||||
} /* namespace uirenderer */
|
||||
|
||||
@@ -70,7 +70,8 @@ public:
|
||||
private:
|
||||
void setFrameInterval(nsecs_t frameIntervalNanos);
|
||||
|
||||
static void dumpData(int fd, const ProfileDataDescription* description, const ProfileData* data);
|
||||
static void dumpData(int fd, const ProfileDataDescription* description,
|
||||
const ProfileData* data);
|
||||
|
||||
std::array<int64_t, NUM_BUCKETS> mThresholds;
|
||||
int64_t mFrameInterval;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
|
||||
SkBlendMode mode)
|
||||
SkBlendMode mode)
|
||||
: GpuMemoryTracker(GpuObjectType::Layer)
|
||||
, mRenderState(renderState)
|
||||
, mApi(api)
|
||||
@@ -52,5 +52,5 @@ void Layer::postDecStrong() {
|
||||
mRenderState.postDecStrong(this);
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <GpuMemoryTracker.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include <SkPaint.h>
|
||||
#include <SkBlendMode.h>
|
||||
#include <SkPaint.h>
|
||||
|
||||
#include "Matrix.h"
|
||||
|
||||
@@ -43,9 +43,7 @@ public:
|
||||
Vulkan = 1,
|
||||
};
|
||||
|
||||
Api getApi() const {
|
||||
return mApi;
|
||||
}
|
||||
Api getApi() const { return mApi; }
|
||||
|
||||
~Layer();
|
||||
|
||||
@@ -59,44 +57,28 @@ public:
|
||||
|
||||
virtual bool isBlend() const = 0;
|
||||
|
||||
inline void setForceFilter(bool forceFilter) {
|
||||
this->forceFilter = forceFilter;
|
||||
}
|
||||
inline void setForceFilter(bool forceFilter) { this->forceFilter = forceFilter; }
|
||||
|
||||
inline bool getForceFilter() const {
|
||||
return forceFilter;
|
||||
}
|
||||
inline bool getForceFilter() const { return forceFilter; }
|
||||
|
||||
inline void setAlpha(int alpha) {
|
||||
this->alpha = alpha;
|
||||
}
|
||||
inline void setAlpha(int alpha) { this->alpha = alpha; }
|
||||
|
||||
inline void setAlpha(int alpha, SkBlendMode mode) {
|
||||
this->alpha = alpha;
|
||||
this->mode = mode;
|
||||
}
|
||||
|
||||
inline int getAlpha() const {
|
||||
return alpha;
|
||||
}
|
||||
inline int getAlpha() const { return alpha; }
|
||||
|
||||
inline SkBlendMode getMode() const {
|
||||
return mode;
|
||||
}
|
||||
inline SkBlendMode getMode() const { return mode; }
|
||||
|
||||
inline SkColorFilter* getColorFilter() const {
|
||||
return colorFilter;
|
||||
}
|
||||
inline SkColorFilter* getColorFilter() const { return colorFilter; }
|
||||
|
||||
void setColorFilter(SkColorFilter* filter);
|
||||
|
||||
inline mat4& getTexTransform() {
|
||||
return texTransform;
|
||||
}
|
||||
inline mat4& getTexTransform() { return texTransform; }
|
||||
|
||||
inline mat4& getTransform() {
|
||||
return transform;
|
||||
}
|
||||
inline mat4& getTransform() { return transform; }
|
||||
|
||||
/**
|
||||
* Posts a decStrong call to the appropriate thread.
|
||||
@@ -106,7 +88,7 @@ public:
|
||||
|
||||
protected:
|
||||
Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
|
||||
SkBlendMode mode);
|
||||
SkBlendMode mode);
|
||||
|
||||
RenderState& mRenderState;
|
||||
|
||||
@@ -143,7 +125,7 @@ private:
|
||||
*/
|
||||
mat4 transform;
|
||||
|
||||
}; // struct Layer
|
||||
}; // struct Layer
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -29,8 +29,7 @@ namespace uirenderer {
|
||||
class BatchBase {
|
||||
public:
|
||||
BatchBase(batchid_t batchId, BakedOpState* op, bool merging)
|
||||
: mBatchId(batchId)
|
||||
, mMerging(merging) {
|
||||
: mBatchId(batchId), mMerging(merging) {
|
||||
mBounds = op->computedState.clippedBounds;
|
||||
mOps.push_back(op);
|
||||
}
|
||||
@@ -52,9 +51,10 @@ public:
|
||||
const std::vector<BakedOpState*>& getOps() const { return mOps; }
|
||||
|
||||
void dump() const {
|
||||
ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING,
|
||||
this, mBatchId, mMerging, (int) mOps.size(), RECT_ARGS(mBounds));
|
||||
ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING, this, mBatchId,
|
||||
mMerging, (int)mOps.size(), RECT_ARGS(mBounds));
|
||||
}
|
||||
|
||||
protected:
|
||||
batchid_t mBatchId;
|
||||
Rect mBounds;
|
||||
@@ -64,9 +64,7 @@ protected:
|
||||
|
||||
class OpBatch : public BatchBase {
|
||||
public:
|
||||
OpBatch(batchid_t batchId, BakedOpState* op)
|
||||
: BatchBase(batchId, op, false) {
|
||||
}
|
||||
OpBatch(batchid_t batchId, BakedOpState* op) : BatchBase(batchId, op, false) {}
|
||||
|
||||
void batchOp(BakedOpState* op) {
|
||||
mBounds.unionWith(op->computedState.clippedBounds);
|
||||
@@ -77,16 +75,14 @@ public:
|
||||
class MergingOpBatch : public BatchBase {
|
||||
public:
|
||||
MergingOpBatch(batchid_t batchId, BakedOpState* op)
|
||||
: BatchBase(batchId, op, true)
|
||||
, mClipSideFlags(op->computedState.clipSideFlags) {
|
||||
}
|
||||
: BatchBase(batchId, op, true), mClipSideFlags(op->computedState.clipSideFlags) {}
|
||||
|
||||
/*
|
||||
* Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds
|
||||
* and clip side flags. Positive bounds delta means new bounds fit in old.
|
||||
*/
|
||||
static inline bool checkSide(const int currentFlags, const int newFlags, const int side,
|
||||
float boundsDelta) {
|
||||
float boundsDelta) {
|
||||
bool currentClipExists = currentFlags & side;
|
||||
bool newClipExists = newFlags & side;
|
||||
|
||||
@@ -100,16 +96,14 @@ public:
|
||||
}
|
||||
|
||||
static bool paintIsDefault(const SkPaint& paint) {
|
||||
return paint.getAlpha() == 255
|
||||
&& paint.getColorFilter() == nullptr
|
||||
&& paint.getShader() == nullptr;
|
||||
return paint.getAlpha() == 255 && paint.getColorFilter() == nullptr &&
|
||||
paint.getShader() == nullptr;
|
||||
}
|
||||
|
||||
static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) {
|
||||
// Note: don't check color, since all currently mergeable ops can merge across colors
|
||||
return a.getAlpha() == b.getAlpha()
|
||||
&& a.getColorFilter() == b.getColorFilter()
|
||||
&& a.getShader() == b.getShader();
|
||||
return a.getAlpha() == b.getAlpha() && a.getColorFilter() == b.getColorFilter() &&
|
||||
a.getShader() == b.getShader();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -123,8 +117,8 @@ public:
|
||||
* dropped, so we make simplifying qualifications on the ops that can merge, per op type.
|
||||
*/
|
||||
bool canMergeWith(BakedOpState* op) const {
|
||||
bool isTextBatch = getBatchId() == OpBatchType::Text
|
||||
|| getBatchId() == OpBatchType::ColorText;
|
||||
bool isTextBatch =
|
||||
getBatchId() == OpBatchType::Text || getBatchId() == OpBatchType::ColorText;
|
||||
|
||||
// Overlapping other operations is only allowed for text without shadow. For other ops,
|
||||
// multiDraw isn't guaranteed to overdraw correctly
|
||||
@@ -142,8 +136,9 @@ public:
|
||||
if (lhs->roundRectClipState != rhs->roundRectClipState) return false;
|
||||
|
||||
// Local masks prevent merge, since they're potentially in different coordinate spaces
|
||||
if (lhs->computedState.localProjectionPathMask
|
||||
|| rhs->computedState.localProjectionPathMask) return false;
|
||||
if (lhs->computedState.localProjectionPathMask ||
|
||||
rhs->computedState.localProjectionPathMask)
|
||||
return false;
|
||||
|
||||
/* Clipping compatibility check
|
||||
*
|
||||
@@ -155,15 +150,18 @@ public:
|
||||
if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) {
|
||||
const Rect& opBounds = op->computedState.clippedBounds;
|
||||
float boundsDelta = mBounds.left - opBounds.left;
|
||||
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false;
|
||||
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta))
|
||||
return false;
|
||||
boundsDelta = mBounds.top - opBounds.top;
|
||||
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false;
|
||||
|
||||
// right and bottom delta calculation reversed to account for direction
|
||||
boundsDelta = opBounds.right - mBounds.right;
|
||||
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false;
|
||||
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta))
|
||||
return false;
|
||||
boundsDelta = opBounds.bottom - mBounds.bottom;
|
||||
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false;
|
||||
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta))
|
||||
return false;
|
||||
}
|
||||
|
||||
const SkPaint* newPaint = op->op->paint;
|
||||
@@ -197,8 +195,8 @@ private:
|
||||
int mClipSideFlags;
|
||||
};
|
||||
|
||||
LayerBuilder::LayerBuilder(uint32_t width, uint32_t height,
|
||||
const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
|
||||
LayerBuilder::LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect,
|
||||
const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
|
||||
: width(width)
|
||||
, height(height)
|
||||
, repaintRect(repaintRect)
|
||||
@@ -210,7 +208,7 @@ LayerBuilder::LayerBuilder(uint32_t width, uint32_t height,
|
||||
// iterate back toward target to see if anything drawn since should overlap the new op
|
||||
// if no target, merging ops still iterate to find similar batch to insert after
|
||||
void LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds,
|
||||
BatchBase** targetBatch, size_t* insertBatchIndex) const {
|
||||
BatchBase** targetBatch, size_t* insertBatchIndex) const {
|
||||
for (int i = mBatches.size() - 1; i >= 0; i--) {
|
||||
BatchBase* overBatch = mBatches[i];
|
||||
|
||||
@@ -219,7 +217,7 @@ void LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds,
|
||||
// TODO: also consider shader shared between batch types
|
||||
if (batchId == overBatch->getBatchId()) {
|
||||
*insertBatchIndex = i + 1;
|
||||
if (!*targetBatch) break; // found insert position, quit
|
||||
if (!*targetBatch) break; // found insert position, quit
|
||||
}
|
||||
|
||||
if (overBatch->intersects(clippedBounds)) {
|
||||
@@ -242,10 +240,10 @@ void LayerBuilder::onDeferOp(LinearAllocator& allocator, const BakedOpState* bak
|
||||
// and issue them together in one draw.
|
||||
flushLayerClears(allocator);
|
||||
|
||||
if (CC_UNLIKELY(activeUnclippedSaveLayers.empty()
|
||||
&& bakedState->computedState.opaqueOverClippedBounds
|
||||
&& bakedState->computedState.clippedBounds.contains(repaintRect)
|
||||
&& !Properties::debugOverdraw)) {
|
||||
if (CC_UNLIKELY(activeUnclippedSaveLayers.empty() &&
|
||||
bakedState->computedState.opaqueOverClippedBounds &&
|
||||
bakedState->computedState.clippedBounds.contains(repaintRect) &&
|
||||
!Properties::debugOverdraw)) {
|
||||
// discard all deferred drawing ops, since new one will occlude them
|
||||
clear();
|
||||
}
|
||||
@@ -258,7 +256,7 @@ void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
|
||||
// put the verts in the frame allocator, since
|
||||
// 1) SimpleRectsOps needs verts, not rects
|
||||
// 2) even if mClearRects stored verts, std::vectors will move their contents
|
||||
Vertex* const verts = (Vertex*) allocator.create_trivial_array<Vertex>(vertCount);
|
||||
Vertex* const verts = (Vertex*)allocator.create_trivial_array<Vertex>(vertCount);
|
||||
|
||||
Vertex* currentVert = verts;
|
||||
Rect bounds = mClearRects[0];
|
||||
@@ -269,35 +267,34 @@ void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
|
||||
Vertex::set(currentVert++, rect.left, rect.bottom);
|
||||
Vertex::set(currentVert++, rect.right, rect.bottom);
|
||||
}
|
||||
mClearRects.clear(); // discard rects before drawing so this method isn't reentrant
|
||||
mClearRects.clear(); // discard rects before drawing so this method isn't reentrant
|
||||
|
||||
// One or more unclipped saveLayers have been enqueued, with deferred clears.
|
||||
// Flush all of these clears with a single draw
|
||||
SkPaint* paint = allocator.create<SkPaint>();
|
||||
paint->setBlendMode(SkBlendMode::kClear);
|
||||
SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(bounds,
|
||||
Matrix4::identity(), nullptr, paint,
|
||||
verts, vertCount);
|
||||
BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
|
||||
&repaintClip, bounds, *op);
|
||||
SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(
|
||||
bounds, Matrix4::identity(), nullptr, paint, verts, vertCount);
|
||||
BakedOpState* bakedState =
|
||||
BakedOpState::directConstruct(allocator, &repaintClip, bounds, *op);
|
||||
deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices);
|
||||
}
|
||||
}
|
||||
|
||||
void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
|
||||
BakedOpState* op, batchid_t batchId) {
|
||||
void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op,
|
||||
batchid_t batchId) {
|
||||
onDeferOp(allocator, op);
|
||||
OpBatch* targetBatch = mBatchLookup[batchId];
|
||||
|
||||
size_t insertBatchIndex = mBatches.size();
|
||||
if (targetBatch) {
|
||||
locateInsertIndex(batchId, op->computedState.clippedBounds,
|
||||
(BatchBase**)(&targetBatch), &insertBatchIndex);
|
||||
locateInsertIndex(batchId, op->computedState.clippedBounds, (BatchBase**)(&targetBatch),
|
||||
&insertBatchIndex);
|
||||
}
|
||||
|
||||
if (targetBatch) {
|
||||
targetBatch->batchOp(op);
|
||||
} else {
|
||||
} else {
|
||||
// new non-merging batch
|
||||
targetBatch = allocator.create<OpBatch>(batchId, op);
|
||||
mBatchLookup[batchId] = targetBatch;
|
||||
@@ -305,8 +302,8 @@ void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
|
||||
}
|
||||
}
|
||||
|
||||
void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
|
||||
BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
|
||||
void LayerBuilder::deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId,
|
||||
mergeid_t mergeId) {
|
||||
onDeferOp(allocator, op);
|
||||
MergingOpBatch* targetBatch = nullptr;
|
||||
|
||||
@@ -320,12 +317,12 @@ void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
|
||||
}
|
||||
|
||||
size_t insertBatchIndex = mBatches.size();
|
||||
locateInsertIndex(batchId, op->computedState.clippedBounds,
|
||||
(BatchBase**)(&targetBatch), &insertBatchIndex);
|
||||
locateInsertIndex(batchId, op->computedState.clippedBounds, (BatchBase**)(&targetBatch),
|
||||
&insertBatchIndex);
|
||||
|
||||
if (targetBatch) {
|
||||
targetBatch->mergeOp(op);
|
||||
} else {
|
||||
} else {
|
||||
// new merging batch
|
||||
targetBatch = allocator.create<MergingOpBatch>(batchId, op);
|
||||
mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
|
||||
@@ -334,11 +331,11 @@ void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
|
||||
}
|
||||
}
|
||||
|
||||
void LayerBuilder::replayBakedOpsImpl(void* arg,
|
||||
BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const {
|
||||
void LayerBuilder::replayBakedOpsImpl(void* arg, BakedOpReceiver* unmergedReceivers,
|
||||
MergedOpReceiver* mergedReceivers) const {
|
||||
if (renderNode) {
|
||||
ATRACE_FORMAT_BEGIN("Issue HW Layer DisplayList %s %ux%u",
|
||||
renderNode->getName(), width, height);
|
||||
ATRACE_FORMAT_BEGIN("Issue HW Layer DisplayList %s %ux%u", renderNode->getName(), width,
|
||||
height);
|
||||
} else {
|
||||
ATRACE_BEGIN("flush drawing commands");
|
||||
}
|
||||
@@ -348,12 +345,9 @@ void LayerBuilder::replayBakedOpsImpl(void* arg,
|
||||
if (size > 1 && batch->isMerging()) {
|
||||
int opId = batch->getOps()[0]->op->opId;
|
||||
const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch);
|
||||
MergedBakedOpList data = {
|
||||
batch->getOps().data(),
|
||||
size,
|
||||
mergingBatch->getClipSideFlags(),
|
||||
mergingBatch->getClipRect()
|
||||
};
|
||||
MergedBakedOpList data = {batch->getOps().data(), size,
|
||||
mergingBatch->getClipSideFlags(),
|
||||
mergingBatch->getClipRect()};
|
||||
mergedReceivers[opId](arg, data);
|
||||
} else {
|
||||
for (const BakedOpState* op : batch->getOps()) {
|
||||
@@ -373,13 +367,12 @@ void LayerBuilder::clear() {
|
||||
}
|
||||
|
||||
void LayerBuilder::dump() const {
|
||||
ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)",
|
||||
this, width, height, offscreenBuffer, beginLayerOp,
|
||||
renderNode, renderNode ? renderNode->getName() : "-");
|
||||
ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)", this, width, height,
|
||||
offscreenBuffer, beginLayerOp, renderNode, renderNode ? renderNode->getName() : "-");
|
||||
for (const BatchBase* batch : mBatches) {
|
||||
batch->dump();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include "Rect.h"
|
||||
#include "utils/Macros.h"
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct SkRect;
|
||||
|
||||
@@ -42,22 +42,22 @@ typedef int batchid_t;
|
||||
typedef const void* mergeid_t;
|
||||
|
||||
namespace OpBatchType {
|
||||
enum {
|
||||
Bitmap,
|
||||
MergedPatch,
|
||||
AlphaVertices,
|
||||
Vertices,
|
||||
AlphaMaskTexture,
|
||||
Text,
|
||||
ColorText,
|
||||
Shadow,
|
||||
TextureLayer,
|
||||
Functor,
|
||||
CopyToLayer,
|
||||
CopyFromLayer,
|
||||
enum {
|
||||
Bitmap,
|
||||
MergedPatch,
|
||||
AlphaVertices,
|
||||
Vertices,
|
||||
AlphaMaskTexture,
|
||||
Text,
|
||||
ColorText,
|
||||
Shadow,
|
||||
TextureLayer,
|
||||
Functor,
|
||||
CopyToLayer,
|
||||
CopyFromLayer,
|
||||
|
||||
Count // must be last
|
||||
};
|
||||
Count // must be last
|
||||
};
|
||||
}
|
||||
|
||||
typedef void (*BakedOpReceiver)(void*, const BakedOpState&);
|
||||
@@ -68,37 +68,36 @@ typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList);
|
||||
* for a single FBO/layer.
|
||||
*/
|
||||
class LayerBuilder {
|
||||
// Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip
|
||||
PREVENT_COPY_AND_ASSIGN(LayerBuilder);
|
||||
// Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip
|
||||
PREVENT_COPY_AND_ASSIGN(LayerBuilder);
|
||||
|
||||
public:
|
||||
// Create LayerBuilder for Fbo0
|
||||
LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect)
|
||||
: LayerBuilder(width, height, repaintRect, nullptr, nullptr) {};
|
||||
: LayerBuilder(width, height, repaintRect, nullptr, nullptr){};
|
||||
|
||||
// Create LayerBuilder for an offscreen layer, where beginLayerOp is present for a
|
||||
// saveLayer, renderNode is present for a HW layer.
|
||||
LayerBuilder(uint32_t width, uint32_t height,
|
||||
const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
|
||||
LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect,
|
||||
const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
|
||||
|
||||
// iterate back toward target to see if anything drawn since should overlap the new op
|
||||
// if no target, merging ops still iterate to find similar batch to insert after
|
||||
void locateInsertIndex(int batchId, const Rect& clippedBounds,
|
||||
BatchBase** targetBatch, size_t* insertBatchIndex) const;
|
||||
void locateInsertIndex(int batchId, const Rect& clippedBounds, BatchBase** targetBatch,
|
||||
size_t* insertBatchIndex) const;
|
||||
|
||||
void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId);
|
||||
|
||||
// insertion point of a new batch, will hopefully be immediately after similar batch
|
||||
// (generally, should be similar shader)
|
||||
void deferMergeableOp(LinearAllocator& allocator,
|
||||
BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
|
||||
void deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId,
|
||||
mergeid_t mergeId);
|
||||
|
||||
void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const;
|
||||
|
||||
void deferLayerClear(const Rect& dstRect);
|
||||
|
||||
bool empty() const {
|
||||
return mBatches.empty();
|
||||
}
|
||||
bool empty() const { return mBatches.empty(); }
|
||||
|
||||
void clear();
|
||||
|
||||
@@ -114,6 +113,7 @@ public:
|
||||
|
||||
// list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps
|
||||
std::vector<BakedOpState*> activeUnclippedSaveLayers;
|
||||
|
||||
private:
|
||||
void onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState);
|
||||
void flushLayerClears(LinearAllocator& allocator);
|
||||
@@ -128,10 +128,10 @@ private:
|
||||
std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count];
|
||||
|
||||
// Maps batch ids to the most recent *non-merging* batch of that id
|
||||
OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr };
|
||||
OpBatch* mBatchLookup[OpBatchType::Count] = {nullptr};
|
||||
|
||||
std::vector<Rect> mClearRects;
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -39,5 +39,5 @@ void LayerUpdateQueue::enqueueLayerWithDamage(RenderNode* renderNode, Rect damag
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
#ifndef ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
|
||||
#define ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
|
||||
|
||||
#include <utils/StrongPointer.h>
|
||||
#include "Rect.h"
|
||||
#include "utils/Macros.h"
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
@@ -31,11 +31,11 @@ class RenderNode;
|
||||
|
||||
class LayerUpdateQueue {
|
||||
PREVENT_COPY_AND_ASSIGN(LayerUpdateQueue);
|
||||
|
||||
public:
|
||||
struct Entry {
|
||||
Entry(RenderNode* renderNode, const Rect& damage)
|
||||
: renderNode(renderNode)
|
||||
, damage(damage) {}
|
||||
: renderNode(renderNode), damage(damage) {}
|
||||
sp<RenderNode> renderNode;
|
||||
Rect damage;
|
||||
};
|
||||
@@ -44,11 +44,12 @@ public:
|
||||
void enqueueLayerWithDamage(RenderNode* renderNode, Rect dirty);
|
||||
void clear();
|
||||
const std::vector<Entry>& entries() const { return mEntries; }
|
||||
|
||||
private:
|
||||
std::vector<Entry> mEntries;
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
|
||||
#endif // ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
|
||||
|
||||
@@ -43,24 +43,24 @@ const Matrix4& Matrix4::identity() {
|
||||
}
|
||||
|
||||
void Matrix4::loadIdentity() {
|
||||
data[kScaleX] = 1.0f;
|
||||
data[kSkewY] = 0.0f;
|
||||
data[2] = 0.0f;
|
||||
data[kScaleX] = 1.0f;
|
||||
data[kSkewY] = 0.0f;
|
||||
data[2] = 0.0f;
|
||||
data[kPerspective0] = 0.0f;
|
||||
|
||||
data[kSkewX] = 0.0f;
|
||||
data[kScaleY] = 1.0f;
|
||||
data[6] = 0.0f;
|
||||
data[kSkewX] = 0.0f;
|
||||
data[kScaleY] = 1.0f;
|
||||
data[6] = 0.0f;
|
||||
data[kPerspective1] = 0.0f;
|
||||
|
||||
data[8] = 0.0f;
|
||||
data[9] = 0.0f;
|
||||
data[kScaleZ] = 1.0f;
|
||||
data[11] = 0.0f;
|
||||
data[8] = 0.0f;
|
||||
data[9] = 0.0f;
|
||||
data[kScaleZ] = 1.0f;
|
||||
data[11] = 0.0f;
|
||||
|
||||
data[kTranslateX] = 0.0f;
|
||||
data[kTranslateY] = 0.0f;
|
||||
data[kTranslateZ] = 0.0f;
|
||||
data[kTranslateX] = 0.0f;
|
||||
data[kTranslateY] = 0.0f;
|
||||
data[kTranslateZ] = 0.0f;
|
||||
data[kPerspective2] = 1.0f;
|
||||
|
||||
mType = kTypeIdentity | kTypeRectToRect;
|
||||
@@ -75,7 +75,7 @@ uint8_t Matrix4::getType() const {
|
||||
mType = kTypeIdentity;
|
||||
|
||||
if (data[kPerspective0] != 0.0f || data[kPerspective1] != 0.0f ||
|
||||
data[kPerspective2] != 1.0f) {
|
||||
data[kPerspective2] != 1.0f) {
|
||||
mType |= kTypePerspective;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ uint8_t Matrix4::getType() const {
|
||||
// it doesn't preserve rectangles.
|
||||
if (!(mType & kTypePerspective)) {
|
||||
if ((isZero(m00) && isZero(m11) && !isZero(m01) && !isZero(m10)) ||
|
||||
(isZero(m01) && isZero(m10) && !isZero(m00) && !isZero(m11))) {
|
||||
(isZero(m01) && isZero(m10) && !isZero(m00) && !isZero(m11))) {
|
||||
mType |= kTypeRectToRect;
|
||||
}
|
||||
}
|
||||
@@ -155,17 +155,17 @@ void Matrix4::load(const float* v) {
|
||||
void Matrix4::load(const SkMatrix& v) {
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
data[kScaleX] = v[SkMatrix::kMScaleX];
|
||||
data[kSkewX] = v[SkMatrix::kMSkewX];
|
||||
data[kScaleX] = v[SkMatrix::kMScaleX];
|
||||
data[kSkewX] = v[SkMatrix::kMSkewX];
|
||||
data[kTranslateX] = v[SkMatrix::kMTransX];
|
||||
|
||||
data[kSkewY] = v[SkMatrix::kMSkewY];
|
||||
data[kScaleY] = v[SkMatrix::kMScaleY];
|
||||
data[kSkewY] = v[SkMatrix::kMSkewY];
|
||||
data[kScaleY] = v[SkMatrix::kMScaleY];
|
||||
data[kTranslateY] = v[SkMatrix::kMTransY];
|
||||
|
||||
data[kPerspective0] = v[SkMatrix::kMPersp0];
|
||||
data[kPerspective1] = v[SkMatrix::kMPersp1];
|
||||
data[kPerspective2] = v[SkMatrix::kMPersp2];
|
||||
data[kPerspective0] = v[SkMatrix::kMPersp0];
|
||||
data[kPerspective1] = v[SkMatrix::kMPersp1];
|
||||
data[kPerspective2] = v[SkMatrix::kMPersp2];
|
||||
|
||||
data[kScaleZ] = 1.0f;
|
||||
|
||||
@@ -183,10 +183,10 @@ void Matrix4::copyTo(SkMatrix& v) const {
|
||||
v.reset();
|
||||
|
||||
v.set(SkMatrix::kMScaleX, data[kScaleX]);
|
||||
v.set(SkMatrix::kMSkewX, data[kSkewX]);
|
||||
v.set(SkMatrix::kMSkewX, data[kSkewX]);
|
||||
v.set(SkMatrix::kMTransX, data[kTranslateX]);
|
||||
|
||||
v.set(SkMatrix::kMSkewY, data[kSkewY]);
|
||||
v.set(SkMatrix::kMSkewY, data[kSkewY]);
|
||||
v.set(SkMatrix::kMScaleY, data[kScaleY]);
|
||||
v.set(SkMatrix::kMTransY, data[kTranslateY]);
|
||||
|
||||
@@ -201,13 +201,13 @@ void Matrix4::loadInverse(const Matrix4& v) {
|
||||
// Reset the matrix
|
||||
// Unnamed fields are never written to except by
|
||||
// loadIdentity(), they don't need to be reset
|
||||
data[kScaleX] = 1.0f;
|
||||
data[kSkewX] = 0.0f;
|
||||
data[kScaleX] = 1.0f;
|
||||
data[kSkewX] = 0.0f;
|
||||
|
||||
data[kScaleY] = 1.0f;
|
||||
data[kSkewY] = 0.0f;
|
||||
data[kScaleY] = 1.0f;
|
||||
data[kSkewY] = 0.0f;
|
||||
|
||||
data[kScaleZ] = 1.0f;
|
||||
data[kScaleZ] = 1.0f;
|
||||
|
||||
data[kPerspective0] = 0.0f;
|
||||
data[kPerspective1] = 0.0f;
|
||||
@@ -215,43 +215,48 @@ void Matrix4::loadInverse(const Matrix4& v) {
|
||||
|
||||
// No need to deal with kTranslateZ because isPureTranslate()
|
||||
// only returns true when the kTranslateZ component is 0
|
||||
data[kTranslateX] = -v.data[kTranslateX];
|
||||
data[kTranslateY] = -v.data[kTranslateY];
|
||||
data[kTranslateZ] = 0.0f;
|
||||
data[kTranslateX] = -v.data[kTranslateX];
|
||||
data[kTranslateY] = -v.data[kTranslateY];
|
||||
data[kTranslateZ] = 0.0f;
|
||||
|
||||
// A "pure translate" matrix can be identity or translation
|
||||
mType = v.getType();
|
||||
return;
|
||||
}
|
||||
|
||||
double scale = 1.0 /
|
||||
(v.data[kScaleX] * ((double) v.data[kScaleY] * v.data[kPerspective2] -
|
||||
(double) v.data[kTranslateY] * v.data[kPerspective1]) +
|
||||
v.data[kSkewX] * ((double) v.data[kTranslateY] * v.data[kPerspective0] -
|
||||
(double) v.data[kSkewY] * v.data[kPerspective2]) +
|
||||
v.data[kTranslateX] * ((double) v.data[kSkewY] * v.data[kPerspective1] -
|
||||
(double) v.data[kScaleY] * v.data[kPerspective0]));
|
||||
double scale = 1.0 / (v.data[kScaleX] * ((double)v.data[kScaleY] * v.data[kPerspective2] -
|
||||
(double)v.data[kTranslateY] * v.data[kPerspective1]) +
|
||||
v.data[kSkewX] * ((double)v.data[kTranslateY] * v.data[kPerspective0] -
|
||||
(double)v.data[kSkewY] * v.data[kPerspective2]) +
|
||||
v.data[kTranslateX] * ((double)v.data[kSkewY] * v.data[kPerspective1] -
|
||||
(double)v.data[kScaleY] * v.data[kPerspective0]));
|
||||
|
||||
data[kScaleX] = (v.data[kScaleY] * v.data[kPerspective2] -
|
||||
v.data[kTranslateY] * v.data[kPerspective1]) * scale;
|
||||
data[kSkewX] = (v.data[kTranslateX] * v.data[kPerspective1] -
|
||||
v.data[kSkewX] * v.data[kPerspective2]) * scale;
|
||||
data[kTranslateX] = (v.data[kSkewX] * v.data[kTranslateY] -
|
||||
v.data[kTranslateX] * v.data[kScaleY]) * scale;
|
||||
v.data[kTranslateY] * v.data[kPerspective1]) *
|
||||
scale;
|
||||
data[kSkewX] =
|
||||
(v.data[kTranslateX] * v.data[kPerspective1] - v.data[kSkewX] * v.data[kPerspective2]) *
|
||||
scale;
|
||||
data[kTranslateX] =
|
||||
(v.data[kSkewX] * v.data[kTranslateY] - v.data[kTranslateX] * v.data[kScaleY]) * scale;
|
||||
|
||||
data[kSkewY] = (v.data[kTranslateY] * v.data[kPerspective0] -
|
||||
v.data[kSkewY] * v.data[kPerspective2]) * scale;
|
||||
data[kSkewY] =
|
||||
(v.data[kTranslateY] * v.data[kPerspective0] - v.data[kSkewY] * v.data[kPerspective2]) *
|
||||
scale;
|
||||
data[kScaleY] = (v.data[kScaleX] * v.data[kPerspective2] -
|
||||
v.data[kTranslateX] * v.data[kPerspective0]) * scale;
|
||||
data[kTranslateY] = (v.data[kTranslateX] * v.data[kSkewY] -
|
||||
v.data[kScaleX] * v.data[kTranslateY]) * scale;
|
||||
v.data[kTranslateX] * v.data[kPerspective0]) *
|
||||
scale;
|
||||
data[kTranslateY] =
|
||||
(v.data[kTranslateX] * v.data[kSkewY] - v.data[kScaleX] * v.data[kTranslateY]) * scale;
|
||||
|
||||
data[kPerspective0] = (v.data[kSkewY] * v.data[kPerspective1] -
|
||||
v.data[kScaleY] * v.data[kPerspective0]) * scale;
|
||||
data[kPerspective1] = (v.data[kSkewX] * v.data[kPerspective0] -
|
||||
v.data[kScaleX] * v.data[kPerspective1]) * scale;
|
||||
data[kPerspective2] = (v.data[kScaleX] * v.data[kScaleY] -
|
||||
v.data[kSkewX] * v.data[kSkewY]) * scale;
|
||||
data[kPerspective0] =
|
||||
(v.data[kSkewY] * v.data[kPerspective1] - v.data[kScaleY] * v.data[kPerspective0]) *
|
||||
scale;
|
||||
data[kPerspective1] =
|
||||
(v.data[kSkewX] * v.data[kPerspective0] - v.data[kScaleX] * v.data[kPerspective1]) *
|
||||
scale;
|
||||
data[kPerspective2] =
|
||||
(v.data[kScaleX] * v.data[kScaleY] - v.data[kSkewX] * v.data[kSkewY]) * scale;
|
||||
|
||||
mType = kTypeUnknown;
|
||||
}
|
||||
@@ -298,13 +303,13 @@ void Matrix4::loadScale(float sx, float sy, float sz) {
|
||||
void Matrix4::loadSkew(float sx, float sy) {
|
||||
loadIdentity();
|
||||
|
||||
data[kScaleX] = 1.0f;
|
||||
data[kSkewX] = sx;
|
||||
data[kTranslateX] = 0.0f;
|
||||
data[kScaleX] = 1.0f;
|
||||
data[kSkewX] = sx;
|
||||
data[kTranslateX] = 0.0f;
|
||||
|
||||
data[kSkewY] = sy;
|
||||
data[kScaleY] = 1.0f;
|
||||
data[kTranslateY] = 0.0f;
|
||||
data[kSkewY] = sy;
|
||||
data[kScaleY] = 1.0f;
|
||||
data[kTranslateY] = 0.0f;
|
||||
|
||||
data[kPerspective0] = 0.0f;
|
||||
data[kPerspective1] = 0.0f;
|
||||
@@ -320,23 +325,23 @@ void Matrix4::loadRotate(float angle) {
|
||||
|
||||
loadIdentity();
|
||||
|
||||
data[kScaleX] = c;
|
||||
data[kSkewX] = -s;
|
||||
data[kScaleX] = c;
|
||||
data[kSkewX] = -s;
|
||||
|
||||
data[kSkewY] = s;
|
||||
data[kScaleY] = c;
|
||||
data[kSkewY] = s;
|
||||
data[kScaleY] = c;
|
||||
|
||||
mType = kTypeUnknown;
|
||||
}
|
||||
|
||||
void Matrix4::loadRotate(float angle, float x, float y, float z) {
|
||||
data[kPerspective0] = 0.0f;
|
||||
data[kPerspective1] = 0.0f;
|
||||
data[11] = 0.0f;
|
||||
data[kTranslateX] = 0.0f;
|
||||
data[kTranslateY] = 0.0f;
|
||||
data[kTranslateZ] = 0.0f;
|
||||
data[kPerspective2] = 1.0f;
|
||||
data[kPerspective0] = 0.0f;
|
||||
data[kPerspective1] = 0.0f;
|
||||
data[11] = 0.0f;
|
||||
data[kTranslateX] = 0.0f;
|
||||
data[kTranslateY] = 0.0f;
|
||||
data[kTranslateZ] = 0.0f;
|
||||
data[kPerspective2] = 1.0f;
|
||||
|
||||
angle *= float(M_PI / 180.0f);
|
||||
float c = cosf(angle);
|
||||
@@ -356,27 +361,27 @@ void Matrix4::loadRotate(float angle, float x, float y, float z) {
|
||||
const float ys = y * s;
|
||||
const float zs = z * s;
|
||||
|
||||
data[kScaleX] = x * x * nc + c;
|
||||
data[kSkewX] = xy * nc - zs;
|
||||
data[8] = zx * nc + ys;
|
||||
data[kSkewY] = xy * nc + zs;
|
||||
data[kScaleY] = y * y * nc + c;
|
||||
data[9] = yz * nc - xs;
|
||||
data[2] = zx * nc - ys;
|
||||
data[6] = yz * nc + xs;
|
||||
data[kScaleZ] = z * z * nc + c;
|
||||
data[kScaleX] = x * x * nc + c;
|
||||
data[kSkewX] = xy * nc - zs;
|
||||
data[8] = zx * nc + ys;
|
||||
data[kSkewY] = xy * nc + zs;
|
||||
data[kScaleY] = y * y * nc + c;
|
||||
data[9] = yz * nc - xs;
|
||||
data[2] = zx * nc - ys;
|
||||
data[6] = yz * nc + xs;
|
||||
data[kScaleZ] = z * z * nc + c;
|
||||
|
||||
mType = kTypeUnknown;
|
||||
}
|
||||
|
||||
void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) {
|
||||
for (int i = 0 ; i < 4 ; i++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float z = 0;
|
||||
float w = 0;
|
||||
|
||||
for (int j = 0 ; j < 4 ; j++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
const float e = v.get(i, j);
|
||||
x += u.get(j, 0) * e;
|
||||
y += u.get(j, 1) * e;
|
||||
@@ -412,7 +417,7 @@ float Matrix4::mapZ(const Vector3& orig) const {
|
||||
}
|
||||
|
||||
void Matrix4::mapPoint3d(Vector3& vec) const {
|
||||
//TODO: optimize simple case
|
||||
// TODO: optimize simple case
|
||||
const Vector3 orig(vec);
|
||||
vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX];
|
||||
vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY];
|
||||
@@ -469,16 +474,11 @@ void Matrix4::mapRect(Rect& r) const {
|
||||
return;
|
||||
}
|
||||
|
||||
float vertices[] = {
|
||||
r.left, r.top,
|
||||
r.right, r.top,
|
||||
r.right, r.bottom,
|
||||
r.left, r.bottom
|
||||
};
|
||||
float vertices[] = {r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom};
|
||||
|
||||
float x, y, z;
|
||||
|
||||
for (int i = 0; i < 8; i+= 2) {
|
||||
for (int i = 0; i < 8; i += 2) {
|
||||
float px = vertices[i];
|
||||
float py = vertices[i + 1];
|
||||
|
||||
@@ -498,10 +498,14 @@ void Matrix4::mapRect(Rect& r) const {
|
||||
x = vertices[i];
|
||||
y = vertices[i + 1];
|
||||
|
||||
if (x < r.left) r.left = x;
|
||||
else if (x > r.right) r.right = x;
|
||||
if (y < r.top) r.top = y;
|
||||
else if (y > r.bottom) r.bottom = y;
|
||||
if (x < r.left)
|
||||
r.left = x;
|
||||
else if (x > r.right)
|
||||
r.right = x;
|
||||
if (y < r.top)
|
||||
r.top = y;
|
||||
else if (y > r.bottom)
|
||||
r.bottom = y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,5 +526,5 @@ void Matrix4::dump(const char* label) const {
|
||||
ALOGD("]");
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -18,27 +18,26 @@
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
#include <SkMatrix.h>
|
||||
#include <cutils/compiler.h>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <SkMatrix.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
#define SK_MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
|
||||
#define SK_MATRIX_ARGS(m) \
|
||||
(m)->get(0), (m)->get(1), (m)->get(2), \
|
||||
(m)->get(3), (m)->get(4), (m)->get(5), \
|
||||
(m)->get(6), (m)->get(7), (m)->get(8)
|
||||
#define SK_MATRIX_ARGS(m) \
|
||||
(m)->get(0), (m)->get(1), (m)->get(2), (m)->get(3), (m)->get(4), (m)->get(5), (m)->get(6), \
|
||||
(m)->get(7), (m)->get(8)
|
||||
|
||||
#define MATRIX_4_STRING "[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
|
||||
#define MATRIX_4_STRING \
|
||||
"[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
|
||||
" [%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]"
|
||||
#define MATRIX_4_ARGS(m) \
|
||||
(m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], \
|
||||
(m)->data[1], (m)->data[5], (m)->data[9], (m)->data[13], \
|
||||
(m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
|
||||
(m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15] \
|
||||
#define MATRIX_4_ARGS(m) \
|
||||
(m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], (m)->data[1], (m)->data[5], \
|
||||
(m)->data[9], (m)->data[13], (m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
|
||||
(m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15]
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Classes
|
||||
@@ -77,21 +76,15 @@ public:
|
||||
|
||||
static const int sGeometryMask = 0xf;
|
||||
|
||||
Matrix4() {
|
||||
loadIdentity();
|
||||
}
|
||||
Matrix4() { loadIdentity(); }
|
||||
|
||||
explicit Matrix4(const float* v) {
|
||||
load(v);
|
||||
}
|
||||
explicit Matrix4(const float* v) { load(v); }
|
||||
|
||||
Matrix4(const SkMatrix& v) { // NOLINT, implicit
|
||||
load(v);
|
||||
}
|
||||
|
||||
float operator[](int index) const {
|
||||
return data[index];
|
||||
}
|
||||
float operator[](int index) const { return data[index]; }
|
||||
|
||||
float& operator[](int index) {
|
||||
mType = kTypeUnknown;
|
||||
@@ -107,9 +100,7 @@ public:
|
||||
return !memcmp(&a.data[0], &b.data[0], 16 * sizeof(float));
|
||||
}
|
||||
|
||||
friend bool operator!=(const Matrix4& a, const Matrix4& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
friend bool operator!=(const Matrix4& a, const Matrix4& b) { return !(a == b); }
|
||||
|
||||
void loadIdentity();
|
||||
|
||||
@@ -126,9 +117,7 @@ public:
|
||||
void loadMultiply(const Matrix4& u, const Matrix4& v);
|
||||
|
||||
void loadOrtho(float left, float right, float bottom, float top, float near, float far);
|
||||
void loadOrtho(int width, int height) {
|
||||
loadOrtho(0, width, height, 0, -1, 1);
|
||||
}
|
||||
void loadOrtho(int width, int height) { loadOrtho(0, width, height, 0, -1, 1); }
|
||||
|
||||
uint8_t getType() const;
|
||||
|
||||
@@ -208,8 +197,8 @@ public:
|
||||
|
||||
float mapZ(const Vector3& orig) const;
|
||||
void mapPoint3d(Vector3& vec) const;
|
||||
void mapPoint(float& x, float& y) const; // 2d only
|
||||
void mapRect(Rect& r) const; // 2d only
|
||||
void mapPoint(float& x, float& y) const; // 2d only
|
||||
void mapRect(Rect& r) const; // 2d only
|
||||
|
||||
float getTranslateX() const;
|
||||
float getTranslateY() const;
|
||||
@@ -241,17 +230,13 @@ public:
|
||||
private:
|
||||
mutable uint8_t mType;
|
||||
|
||||
inline float get(int i, int j) const {
|
||||
return data[i * 4 + j];
|
||||
}
|
||||
inline float get(int i, int j) const { return data[i * 4 + j]; }
|
||||
|
||||
inline void set(int i, int j, float v) {
|
||||
data[i * 4 + j] = v;
|
||||
}
|
||||
inline void set(int i, int j, float v) { data[i * 4 + j] = v; }
|
||||
|
||||
uint8_t getGeometryType() const;
|
||||
|
||||
}; // class Matrix4
|
||||
}; // class Matrix4
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Types
|
||||
@@ -259,6 +244,5 @@ private:
|
||||
|
||||
typedef Matrix4 mat4;
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace android {
|
||||
namespace NinePatchUtils {
|
||||
|
||||
static inline void SetLatticeDivs(SkCanvas::Lattice* lattice, const Res_png_9patch& chunk,
|
||||
int width, int height) {
|
||||
int width, int height) {
|
||||
lattice->fXCount = chunk.numXDivs;
|
||||
lattice->fYCount = chunk.numYDivs;
|
||||
lattice->fXDivs = chunk.getXDivs();
|
||||
@@ -54,7 +54,7 @@ static inline int NumDistinctRects(const SkCanvas::Lattice& lattice) {
|
||||
}
|
||||
|
||||
static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, SkCanvas::Lattice::Flags* flags,
|
||||
int numFlags, const Res_png_9patch& chunk) {
|
||||
int numFlags, const Res_png_9patch& chunk) {
|
||||
lattice->fFlags = flags;
|
||||
sk_bzero(flags, numFlags * sizeof(SkCanvas::Lattice::Flags));
|
||||
|
||||
@@ -92,5 +92,5 @@ static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, SkCanvas::Lattice
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace NinePatchUtils
|
||||
}; // namespace android
|
||||
}; // namespace NinePatchUtils
|
||||
}; // namespace android
|
||||
|
||||
@@ -34,14 +34,13 @@ void OpDumper::dump(const RecordedOp& op, std::ostream& output, int level) {
|
||||
op.localMatrix.mapRect(localBounds);
|
||||
output << sOpNameLut[op.opId] << " " << localBounds;
|
||||
|
||||
if (op.localClip
|
||||
&& (!op.localClip->rect.contains(localBounds) || op.localClip->intersectWithRoot)) {
|
||||
output << std::fixed << std::setprecision(0)
|
||||
<< " clip=" << op.localClip->rect
|
||||
<< " mode=" << (int)op.localClip->mode;
|
||||
if (op.localClip &&
|
||||
(!op.localClip->rect.contains(localBounds) || op.localClip->intersectWithRoot)) {
|
||||
output << std::fixed << std::setprecision(0) << " clip=" << op.localClip->rect
|
||||
<< " mode=" << (int)op.localClip->mode;
|
||||
|
||||
if (op.localClip->intersectWithRoot) {
|
||||
output << " iwr";
|
||||
output << " iwr";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,5 +49,5 @@ const char* OpDumper::opName(const RecordedOp& op) {
|
||||
return sOpNameLut[op.opId];
|
||||
}
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -29,5 +29,5 @@ public:
|
||||
static const char* opName(const RecordedOp& op);
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -17,30 +17,29 @@
|
||||
#include "OpenGLReadback.h"
|
||||
|
||||
#include "Caches.h"
|
||||
#include "Image.h"
|
||||
#include "GlopBuilder.h"
|
||||
#include "GlLayer.h"
|
||||
#include "GlopBuilder.h"
|
||||
#include "Image.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "renderthread/EglManager.h"
|
||||
#include "utils/GLUtils.h"
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
#include <gui/Surface.h>
|
||||
#include <ui/Fence.h>
|
||||
#include <ui/GraphicBuffer.h>
|
||||
#include <gui/Surface.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
|
||||
SkBitmap* bitmap) {
|
||||
SkBitmap* bitmap) {
|
||||
ATRACE_CALL();
|
||||
// Setup the source
|
||||
sp<GraphicBuffer> sourceBuffer;
|
||||
sp<Fence> sourceFence;
|
||||
Matrix4 texTransform;
|
||||
status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence,
|
||||
texTransform.data);
|
||||
status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
|
||||
texTransform.invalidateType();
|
||||
if (err != NO_ERROR) {
|
||||
ALOGW("Failed to get last queued buffer, error = %d", err);
|
||||
@@ -64,7 +63,8 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
|
||||
}
|
||||
|
||||
CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
|
||||
Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) {
|
||||
Matrix4& texTransform, const Rect& srcRect,
|
||||
SkBitmap* bitmap) {
|
||||
mRenderThread.eglManager().initialize();
|
||||
// TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
|
||||
// GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
|
||||
@@ -72,11 +72,11 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
|
||||
|
||||
// Create the EGLImage object that maps the GraphicBuffer
|
||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
EGLClientBuffer clientBuffer = (EGLClientBuffer) graphicBuffer->getNativeBuffer();
|
||||
EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
|
||||
EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
|
||||
EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
|
||||
|
||||
EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
|
||||
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
|
||||
EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
|
||||
clientBuffer, attrs);
|
||||
|
||||
if (sourceImage == EGL_NO_IMAGE_KHR) {
|
||||
ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
|
||||
@@ -85,8 +85,8 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
|
||||
|
||||
uint32_t width = graphicBuffer->getWidth();
|
||||
uint32_t height = graphicBuffer->getHeight();
|
||||
CopyResult copyResult = copyImageInto(sourceImage, texTransform, width, height,
|
||||
srcRect, bitmap);
|
||||
CopyResult copyResult =
|
||||
copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap);
|
||||
|
||||
// All we're flushing & finishing is the deletion of the texture since
|
||||
// copyImageInto already did a major flush & finish as an implicit
|
||||
@@ -105,10 +105,7 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, S
|
||||
}
|
||||
|
||||
static float sFlipVInit[16] = {
|
||||
1, 0, 0, 0,
|
||||
0, -1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 1, 0, 1,
|
||||
1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
};
|
||||
|
||||
static const Matrix4 sFlipV(sFlipVInit);
|
||||
@@ -116,20 +113,19 @@ static const Matrix4 sFlipV(sFlipVInit);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
|
||||
Texture& sourceTexture, const Matrix4& texTransform, const Rect& srcRect,
|
||||
SkBitmap* bitmap) {
|
||||
inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, Texture& sourceTexture,
|
||||
const Matrix4& texTransform, const Rect& srcRect,
|
||||
SkBitmap* bitmap) {
|
||||
int destWidth = bitmap->width();
|
||||
int destHeight = bitmap->height();
|
||||
if (destWidth > caches.maxTextureSize
|
||||
|| destHeight > caches.maxTextureSize) {
|
||||
ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d",
|
||||
destWidth, destHeight, caches.maxTextureSize);
|
||||
if (destWidth > caches.maxTextureSize || destHeight > caches.maxTextureSize) {
|
||||
ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", destWidth,
|
||||
destHeight, caches.maxTextureSize);
|
||||
return CopyResult::DestinationInvalid;
|
||||
}
|
||||
|
||||
if (bitmap->colorType() == kRGBA_F16_SkColorType &&
|
||||
!caches.extensions().hasRenderableFloatTextures()) {
|
||||
!caches.extensions().hasRenderableFloatTextures()) {
|
||||
ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
|
||||
return CopyResult::DestinationInvalid;
|
||||
}
|
||||
@@ -189,10 +185,8 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight,
|
||||
0, format, type, nullptr);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, texture, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight, 0, format, type, nullptr);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||||
|
||||
{
|
||||
bool requiresFilter;
|
||||
@@ -209,15 +203,15 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
|
||||
// GLES coordinates.
|
||||
croppedTexTransform.multiply(sFlipV);
|
||||
croppedTexTransform.translate(srcRect.left / sourceTexture.width(),
|
||||
srcRect.top / sourceTexture.height(), 0);
|
||||
srcRect.top / sourceTexture.height(), 0);
|
||||
croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),
|
||||
srcRect.getHeight() / sourceTexture.height(), 1);
|
||||
srcRect.getHeight() / sourceTexture.height(), 1);
|
||||
croppedTexTransform.multiply(sFlipV);
|
||||
requiresFilter = srcRect.getWidth() != (float) destWidth
|
||||
|| srcRect.getHeight() != (float) destHeight;
|
||||
requiresFilter = srcRect.getWidth() != (float)destWidth ||
|
||||
srcRect.getHeight() != (float)destHeight;
|
||||
} else {
|
||||
requiresFilter = sourceTexture.width() != (uint32_t) destWidth
|
||||
|| sourceTexture.height() != (uint32_t) destHeight;
|
||||
requiresFilter = sourceTexture.width() != (uint32_t)destWidth ||
|
||||
sourceTexture.height() != (uint32_t)destHeight;
|
||||
}
|
||||
Glop glop;
|
||||
GlopBuilder(renderState, caches, &glop)
|
||||
@@ -232,8 +226,7 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
|
||||
renderState.render(glop, ortho, false);
|
||||
|
||||
// TODO: We should convert to linear space when the target is RGBA16F
|
||||
glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
|
||||
type, bitmap->getPixels());
|
||||
glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels());
|
||||
bitmap->notifyPixelsChanged();
|
||||
}
|
||||
|
||||
@@ -246,10 +239,9 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
|
||||
return CopyResult::Success;
|
||||
}
|
||||
|
||||
CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage,
|
||||
const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect,
|
||||
SkBitmap* bitmap) {
|
||||
|
||||
CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
|
||||
int imgWidth, int imgHeight, const Rect& srcRect,
|
||||
SkBitmap* bitmap) {
|
||||
// If this is a 90 or 270 degree rotation we need to swap width/height
|
||||
// This is a fuzzy way of checking that.
|
||||
if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
|
||||
@@ -271,26 +263,25 @@ CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage,
|
||||
|
||||
Texture sourceTexture(caches);
|
||||
sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */,
|
||||
GL_TEXTURE_EXTERNAL_OES);
|
||||
GL_TEXTURE_EXTERNAL_OES);
|
||||
|
||||
CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(),
|
||||
sourceTexture, imgTransform, srcRect, bitmap);
|
||||
CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), sourceTexture,
|
||||
imgTransform, srcRect, bitmap);
|
||||
sourceTexture.deleteTexture();
|
||||
return copyResult;
|
||||
}
|
||||
|
||||
bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread,
|
||||
GlLayer& layer, SkBitmap* bitmap) {
|
||||
bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
|
||||
SkBitmap* bitmap) {
|
||||
if (!layer.isRenderable()) {
|
||||
// layer has never been updated by DeferredLayerUpdater, abort copy
|
||||
return false;
|
||||
}
|
||||
|
||||
return CopyResult::Success == copyTextureInto(Caches::getInstance(),
|
||||
renderThread.renderState(), layer.getTexture(), layer.getTexTransform(),
|
||||
Rect(), bitmap);
|
||||
return CopyResult::Success == copyTextureInto(Caches::getInstance(), renderThread.renderState(),
|
||||
layer.getTexture(), layer.getTexTransform(),
|
||||
Rect(), bitmap);
|
||||
}
|
||||
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -30,19 +30,21 @@ class GlLayer;
|
||||
class OpenGLReadback : public Readback {
|
||||
public:
|
||||
virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
|
||||
SkBitmap* bitmap) override;
|
||||
SkBitmap* bitmap) override;
|
||||
virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
|
||||
SkBitmap* bitmap) override;
|
||||
SkBitmap* bitmap) override;
|
||||
|
||||
protected:
|
||||
explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
|
||||
virtual ~OpenGLReadback() {}
|
||||
|
||||
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
|
||||
int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0;
|
||||
int imgWidth, int imgHeight, const Rect& srcRect,
|
||||
SkBitmap* bitmap) = 0;
|
||||
|
||||
private:
|
||||
CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
|
||||
const Rect& srcRect, SkBitmap* bitmap);
|
||||
const Rect& srcRect, SkBitmap* bitmap);
|
||||
};
|
||||
|
||||
class OpenGLReadbackImpl : public OpenGLReadback {
|
||||
@@ -53,12 +55,13 @@ public:
|
||||
* Copies the layer's contents into the provided bitmap.
|
||||
*/
|
||||
static bool copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
|
||||
SkBitmap* bitmap);
|
||||
SkBitmap* bitmap);
|
||||
|
||||
protected:
|
||||
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
|
||||
int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override;
|
||||
int imgWidth, int imgHeight, const Rect& srcRect,
|
||||
SkBitmap* bitmap) override;
|
||||
};
|
||||
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
|
||||
@@ -26,27 +26,14 @@ namespace uirenderer {
|
||||
|
||||
class Outline {
|
||||
public:
|
||||
enum class Type {
|
||||
None = 0,
|
||||
Empty = 1,
|
||||
ConvexPath = 2,
|
||||
RoundRect = 3
|
||||
};
|
||||
enum class Type { None = 0, Empty = 1, ConvexPath = 2, RoundRect = 3 };
|
||||
|
||||
Outline()
|
||||
: mShouldClip(false)
|
||||
, mType(Type::None)
|
||||
, mRadius(0)
|
||||
, mAlpha(0.0f) {}
|
||||
Outline() : mShouldClip(false), mType(Type::None), mRadius(0), mAlpha(0.0f) {}
|
||||
|
||||
void setRoundRect(int left, int top, int right, int bottom, float radius, float alpha) {
|
||||
mAlpha = alpha;
|
||||
if (mType == Type::RoundRect
|
||||
&& left == mBounds.left
|
||||
&& right == mBounds.right
|
||||
&& top == mBounds.top
|
||||
&& bottom == mBounds.bottom
|
||||
&& radius == mRadius) {
|
||||
if (mType == Type::RoundRect && left == mBounds.left && right == mBounds.right &&
|
||||
top == mBounds.top && bottom == mBounds.bottom && radius == mRadius) {
|
||||
// nothing to change, don't do any work
|
||||
return;
|
||||
}
|
||||
@@ -58,8 +45,7 @@ public:
|
||||
// update mPath to reflect new outline
|
||||
mPath.reset();
|
||||
if (MathUtils::isPositive(radius)) {
|
||||
mPath.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom),
|
||||
radius, radius);
|
||||
mPath.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom), radius, radius);
|
||||
} else {
|
||||
mPath.addRect(left, top, right, bottom);
|
||||
}
|
||||
@@ -88,21 +74,13 @@ public:
|
||||
mAlpha = 0.0f;
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
return mType == Type::Empty;
|
||||
}
|
||||
bool isEmpty() const { return mType == Type::Empty; }
|
||||
|
||||
float getAlpha() const {
|
||||
return mAlpha;
|
||||
}
|
||||
float getAlpha() const { return mAlpha; }
|
||||
|
||||
void setShouldClip(bool clip) {
|
||||
mShouldClip = clip;
|
||||
}
|
||||
void setShouldClip(bool clip) { mShouldClip = clip; }
|
||||
|
||||
bool getShouldClip() const {
|
||||
return mShouldClip;
|
||||
}
|
||||
bool getShouldClip() const { return mShouldClip; }
|
||||
|
||||
bool willClip() const {
|
||||
// only round rect outlines can be used for clipping
|
||||
@@ -129,17 +107,11 @@ public:
|
||||
return &mPath;
|
||||
}
|
||||
|
||||
Type getType() const {
|
||||
return mType;
|
||||
}
|
||||
Type getType() const { return mType; }
|
||||
|
||||
const Rect& getBounds() const {
|
||||
return mBounds;
|
||||
}
|
||||
const Rect& getBounds() const { return mBounds; }
|
||||
|
||||
float getRadius() const {
|
||||
return mRadius;
|
||||
}
|
||||
float getRadius() const { return mRadius; }
|
||||
|
||||
private:
|
||||
bool mShouldClip;
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include "UvMapper.h"
|
||||
#include "utils/MathUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utils/Log.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
@@ -35,10 +35,9 @@ uint32_t Patch::getSize() const {
|
||||
return verticesCount * sizeof(TextureVertex);
|
||||
}
|
||||
|
||||
Patch::Patch(const float bitmapWidth, const float bitmapHeight,
|
||||
float width, float height, const UvMapper& mapper, const Res_png_9patch* patch)
|
||||
Patch::Patch(const float bitmapWidth, const float bitmapHeight, float width, float height,
|
||||
const UvMapper& mapper, const Res_png_9patch* patch)
|
||||
: mColors(patch->getColors()) {
|
||||
|
||||
int8_t emptyQuads = 0;
|
||||
const int8_t numColors = patch->numColors;
|
||||
if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
|
||||
@@ -121,8 +120,8 @@ Patch::Patch(const float bitmapWidth, const float bitmapHeight,
|
||||
v1 += vOffset / bitmapHeight;
|
||||
|
||||
if (stepY > 0.0f) {
|
||||
generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX,
|
||||
width, bitmapWidth, quadCount);
|
||||
generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX, width,
|
||||
bitmapWidth, quadCount);
|
||||
}
|
||||
|
||||
y1 = y2;
|
||||
@@ -133,8 +132,8 @@ Patch::Patch(const float bitmapWidth, const float bitmapHeight,
|
||||
|
||||
if (previousStepY != bitmapHeight) {
|
||||
y2 = height;
|
||||
generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX,
|
||||
width, bitmapWidth, quadCount);
|
||||
generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX, width, bitmapWidth,
|
||||
quadCount);
|
||||
}
|
||||
|
||||
if (verticesCount != maxVertices) {
|
||||
@@ -144,9 +143,9 @@ Patch::Patch(const float bitmapWidth, const float bitmapHeight,
|
||||
}
|
||||
}
|
||||
|
||||
void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
|
||||
float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
|
||||
float width, float bitmapWidth, uint32_t& quadCount) {
|
||||
void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, float y1,
|
||||
float y2, float v1, float v2, float stretchX, float rescaleX, float width,
|
||||
float bitmapWidth, uint32_t& quadCount) {
|
||||
float previousStepX = 0.0f;
|
||||
|
||||
float x1 = 0.0f;
|
||||
@@ -184,8 +183,8 @@ void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& v
|
||||
}
|
||||
}
|
||||
|
||||
void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
|
||||
float u1, float v1, float u2, float v2, uint32_t& quadCount) {
|
||||
void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1,
|
||||
float v1, float u2, float v2, uint32_t& quadCount) {
|
||||
const uint32_t oldQuadCount = quadCount;
|
||||
quadCount++;
|
||||
|
||||
@@ -226,5 +225,5 @@ void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, f
|
||||
#endif
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -39,9 +39,8 @@ struct TextureVertex;
|
||||
|
||||
class Patch {
|
||||
public:
|
||||
Patch(const float bitmapWidth, const float bitmapHeight,
|
||||
float width, float height,
|
||||
const UvMapper& mapper, const Res_png_9patch* patch);
|
||||
Patch(const float bitmapWidth, const float bitmapHeight, float width, float height,
|
||||
const UvMapper& mapper, const Res_png_9patch* patch);
|
||||
|
||||
/**
|
||||
* Returns the size of this patch's mesh in bytes.
|
||||
@@ -58,17 +57,17 @@ public:
|
||||
GLintptr textureOffset = 0;
|
||||
|
||||
private:
|
||||
void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
|
||||
float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
|
||||
float width, float bitmapWidth, uint32_t& quadCount);
|
||||
void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
|
||||
float u1, float v1, float u2, float v2, uint32_t& quadCount);
|
||||
void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, float y1,
|
||||
float y2, float v1, float v2, float stretchX, float rescaleX, float width,
|
||||
float bitmapWidth, uint32_t& quadCount);
|
||||
void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1,
|
||||
float v1, float u2, float v2, uint32_t& quadCount);
|
||||
|
||||
const uint32_t* mColors;
|
||||
UvMapper mUvMapper;
|
||||
}; // struct Patch
|
||||
}; // struct Patch
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_PATCH_H
|
||||
#endif // ANDROID_HWUI_PATCH_H
|
||||
|
||||
@@ -56,7 +56,7 @@ hash_t PatchCache::PatchDescription::hash() const {
|
||||
}
|
||||
|
||||
int PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs,
|
||||
const PatchCache::PatchDescription& rhs) {
|
||||
const PatchCache::PatchDescription& rhs) {
|
||||
return memcmp(&lhs, &rhs, sizeof(PatchDescription));
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ void PatchCache::removeDeferred(Res_png_9patch* patch) {
|
||||
void PatchCache::clearGarbage() {
|
||||
Vector<patch_pair_t> patchesToRemove;
|
||||
|
||||
{ // scope for the mutex
|
||||
{ // scope for the mutex
|
||||
Mutex::Autolock _l(mLock);
|
||||
size_t count = mGarbage.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
@@ -123,7 +123,7 @@ void PatchCache::clearGarbage() {
|
||||
remove(patchesToRemove, patch);
|
||||
// A Res_png_9patch is actually an array of byte that's larger
|
||||
// than sizeof(Res_png_9patch). It must be freed as an array.
|
||||
delete[] (int8_t*) patch;
|
||||
delete[](int8_t*) patch;
|
||||
}
|
||||
mGarbage.clear();
|
||||
}
|
||||
@@ -153,8 +153,8 @@ void PatchCache::clearGarbage() {
|
||||
}
|
||||
|
||||
void PatchCache::createVertexBuffer() {
|
||||
mRenderState.meshState().genOrUpdateMeshBuffer(&mMeshBuffer,
|
||||
mMaxSize, nullptr, GL_DYNAMIC_DRAW);
|
||||
mRenderState.meshState().genOrUpdateMeshBuffer(&mMeshBuffer, mMaxSize, nullptr,
|
||||
GL_DYNAMIC_DRAW);
|
||||
mSize = 0;
|
||||
mFreeBlocks = new BufferBlock(0, mMaxSize);
|
||||
}
|
||||
@@ -198,11 +198,11 @@ void PatchCache::setupMesh(Patch* newMesh) {
|
||||
}
|
||||
|
||||
// Copy the 9patch mesh in the VBO
|
||||
newMesh->positionOffset = (GLintptr) (block->offset);
|
||||
newMesh->positionOffset = (GLintptr)(block->offset);
|
||||
newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset;
|
||||
|
||||
mRenderState.meshState().updateMeshBufferSubData(mMeshBuffer, newMesh->positionOffset, size,
|
||||
newMesh->vertices.get());
|
||||
newMesh->vertices.get());
|
||||
|
||||
// Remove the block since we've used it entirely
|
||||
if (block->size == size) {
|
||||
@@ -223,15 +223,15 @@ void PatchCache::setupMesh(Patch* newMesh) {
|
||||
|
||||
static const UvMapper sIdentity;
|
||||
|
||||
const Patch* PatchCache::get( const uint32_t bitmapWidth, const uint32_t bitmapHeight,
|
||||
const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
|
||||
|
||||
const Patch* PatchCache::get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
|
||||
const float pixelWidth, const float pixelHeight,
|
||||
const Res_png_9patch* patch) {
|
||||
const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch);
|
||||
const Patch* mesh = mCache.get(description);
|
||||
|
||||
if (!mesh) {
|
||||
Patch* newMesh = new Patch(bitmapWidth, bitmapHeight,
|
||||
pixelWidth, pixelHeight, sIdentity, patch);
|
||||
Patch* newMesh =
|
||||
new Patch(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, sIdentity, patch);
|
||||
|
||||
if (newMesh->vertices) {
|
||||
setupMesh(newMesh);
|
||||
@@ -260,5 +260,5 @@ void PatchCache::dumpFreeBlocks(const char* prefix) {
|
||||
}
|
||||
#endif
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -36,9 +36,9 @@ class Patch;
|
||||
|
||||
// Debug
|
||||
#if DEBUG_PATCHES
|
||||
#define PATCH_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#define PATCH_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#else
|
||||
#define PATCH_LOGD(...)
|
||||
#define PATCH_LOGD(...)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -54,20 +54,14 @@ public:
|
||||
~PatchCache();
|
||||
|
||||
const Patch* get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
|
||||
const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch);
|
||||
const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch);
|
||||
void clear();
|
||||
|
||||
uint32_t getSize() const {
|
||||
return mSize;
|
||||
}
|
||||
uint32_t getSize() const { return mSize; }
|
||||
|
||||
uint32_t getMaxSize() const {
|
||||
return mMaxSize;
|
||||
}
|
||||
uint32_t getMaxSize() const { return mMaxSize; }
|
||||
|
||||
GLuint getMeshBuffer() const {
|
||||
return mMeshBuffer;
|
||||
}
|
||||
GLuint getMeshBuffer() const { return mMeshBuffer; }
|
||||
|
||||
/**
|
||||
* Removes the entries associated with the specified 9-patch. This is meant
|
||||
@@ -81,18 +75,23 @@ public:
|
||||
*/
|
||||
void clearGarbage();
|
||||
|
||||
|
||||
private:
|
||||
struct PatchDescription {
|
||||
PatchDescription(): mPatch(nullptr), mBitmapWidth(0), mBitmapHeight(0),
|
||||
mPixelWidth(0), mPixelHeight(0) {
|
||||
}
|
||||
PatchDescription()
|
||||
: mPatch(nullptr)
|
||||
, mBitmapWidth(0)
|
||||
, mBitmapHeight(0)
|
||||
, mPixelWidth(0)
|
||||
, mPixelHeight(0) {}
|
||||
|
||||
PatchDescription(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
|
||||
const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch):
|
||||
mPatch(patch), mBitmapWidth(bitmapWidth), mBitmapHeight(bitmapHeight),
|
||||
mPixelWidth(pixelWidth), mPixelHeight(pixelHeight) {
|
||||
}
|
||||
const float pixelWidth, const float pixelHeight,
|
||||
const Res_png_9patch* patch)
|
||||
: mPatch(patch)
|
||||
, mBitmapWidth(bitmapWidth)
|
||||
, mBitmapHeight(bitmapHeight)
|
||||
, mPixelWidth(pixelWidth)
|
||||
, mPixelHeight(pixelHeight) {}
|
||||
|
||||
hash_t hash() const;
|
||||
|
||||
@@ -100,27 +99,20 @@ private:
|
||||
|
||||
static int compare(const PatchDescription& lhs, const PatchDescription& rhs);
|
||||
|
||||
bool operator==(const PatchDescription& other) const {
|
||||
return compare(*this, other) == 0;
|
||||
}
|
||||
bool operator==(const PatchDescription& other) const { return compare(*this, other) == 0; }
|
||||
|
||||
bool operator!=(const PatchDescription& other) const {
|
||||
return compare(*this, other) != 0;
|
||||
}
|
||||
bool operator!=(const PatchDescription& other) const { return compare(*this, other) != 0; }
|
||||
|
||||
friend inline int strictly_order_type(const PatchDescription& lhs,
|
||||
const PatchDescription& rhs) {
|
||||
const PatchDescription& rhs) {
|
||||
return PatchDescription::compare(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
friend inline int compare_type(const PatchDescription& lhs,
|
||||
const PatchDescription& rhs) {
|
||||
friend inline int compare_type(const PatchDescription& lhs, const PatchDescription& rhs) {
|
||||
return PatchDescription::compare(lhs, rhs);
|
||||
}
|
||||
|
||||
friend inline hash_t hash_type(const PatchDescription& entry) {
|
||||
return entry.hash();
|
||||
}
|
||||
friend inline hash_t hash_type(const PatchDescription& entry) { return entry.hash(); }
|
||||
|
||||
private:
|
||||
const Res_png_9patch* mPatch;
|
||||
@@ -129,7 +121,7 @@ private:
|
||||
float mPixelWidth;
|
||||
float mPixelHeight;
|
||||
|
||||
}; // struct PatchDescription
|
||||
}; // struct PatchDescription
|
||||
|
||||
/**
|
||||
* A buffer block represents an empty range in the mesh buffer
|
||||
@@ -139,14 +131,13 @@ private:
|
||||
* to track available regions of memory in the VBO.
|
||||
*/
|
||||
struct BufferBlock {
|
||||
BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(nullptr) {
|
||||
}
|
||||
BufferBlock(uint32_t offset, uint32_t size) : offset(offset), size(size), next(nullptr) {}
|
||||
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
|
||||
BufferBlock* next;
|
||||
}; // struct BufferBlock
|
||||
}; // struct BufferBlock
|
||||
|
||||
typedef Pair<const PatchDescription*, Patch*> patch_pair_t;
|
||||
|
||||
@@ -174,7 +165,7 @@ private:
|
||||
// Garbage tracking, required to handle GC events on the VM side
|
||||
Vector<Res_png_9patch*> mGarbage;
|
||||
mutable Mutex mLock;
|
||||
}; // class PatchCache
|
||||
}; // class PatchCache
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -46,13 +46,14 @@ static bool compareWidthHeight(const T& lhs, const T& rhs) {
|
||||
}
|
||||
|
||||
static bool compareRoundRects(const PathDescription::Shape::RoundRect& lhs,
|
||||
const PathDescription::Shape::RoundRect& rhs) {
|
||||
const PathDescription::Shape::RoundRect& rhs) {
|
||||
return compareWidthHeight(lhs, rhs) && lhs.mRx == rhs.mRx && lhs.mRy == rhs.mRy;
|
||||
}
|
||||
|
||||
static bool compareArcs(const PathDescription::Shape::Arc& lhs, const PathDescription::Shape::Arc& rhs) {
|
||||
static bool compareArcs(const PathDescription::Shape::Arc& lhs,
|
||||
const PathDescription::Shape::Arc& rhs) {
|
||||
return compareWidthHeight(lhs, rhs) && lhs.mStartAngle == rhs.mStartAngle &&
|
||||
lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter;
|
||||
lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -91,7 +92,7 @@ hash_t PathDescription::hash() const {
|
||||
hash = JenkinsHashMix(hash, android::hash_type(miter));
|
||||
hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
|
||||
hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
|
||||
hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
|
||||
hash = JenkinsHashMixBytes(hash, (uint8_t*)&shape, sizeof(Shape));
|
||||
return JenkinsHashWhiten(hash);
|
||||
}
|
||||
|
||||
@@ -126,7 +127,7 @@ bool PathDescription::operator==(const PathDescription& rhs) const {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void computePathBounds(const SkPath* path, const SkPaint* paint, PathTexture* texture,
|
||||
uint32_t& width, uint32_t& height) {
|
||||
uint32_t& width, uint32_t& height) {
|
||||
const SkRect& bounds = path->getBounds();
|
||||
const float pathWidth = std::max(bounds.width(), 1.0f);
|
||||
const float pathHeight = std::max(bounds.height(), 1.0f);
|
||||
@@ -134,7 +135,7 @@ static void computePathBounds(const SkPath* path, const SkPaint* paint, PathText
|
||||
texture->left = floorf(bounds.fLeft);
|
||||
texture->top = floorf(bounds.fTop);
|
||||
|
||||
texture->offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
|
||||
texture->offset = (int)floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
|
||||
|
||||
width = uint32_t(pathWidth + texture->offset * 2.0 + 0.5);
|
||||
height = uint32_t(pathHeight + texture->offset * 2.0 + 0.5);
|
||||
@@ -152,12 +153,12 @@ static void initPaint(SkPaint& paint) {
|
||||
}
|
||||
|
||||
static sk_sp<Bitmap> drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture,
|
||||
uint32_t maxTextureSize) {
|
||||
uint32_t maxTextureSize) {
|
||||
uint32_t width, height;
|
||||
computePathBounds(path, paint, texture, width, height);
|
||||
if (width > maxTextureSize || height > maxTextureSize) {
|
||||
ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
|
||||
width, height, maxTextureSize, maxTextureSize);
|
||||
ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", width, height,
|
||||
maxTextureSize, maxTextureSize);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -230,13 +231,13 @@ void PathCache::removeTexture(PathTexture* texture) {
|
||||
// to the cache and the size wasn't increased
|
||||
if (size > mSize) {
|
||||
ALOGE("Removing path texture of size %d will leave "
|
||||
"the cache in an inconsistent state", size);
|
||||
"the cache in an inconsistent state",
|
||||
size);
|
||||
}
|
||||
mSize -= size;
|
||||
}
|
||||
|
||||
PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
|
||||
texture->id, size, mSize);
|
||||
PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d", texture->id, size, mSize);
|
||||
if (mDebugEnabled) {
|
||||
ALOGD("Shape deleted, size = %d", size);
|
||||
}
|
||||
@@ -258,14 +259,16 @@ void PathCache::purgeCache(uint32_t width, uint32_t height) {
|
||||
|
||||
void PathCache::trim() {
|
||||
while (mSize > mMaxSize || mCache.size() > PATH_CACHE_COUNT_LIMIT) {
|
||||
LOG_ALWAYS_FATAL_IF(!mCache.size(), "Inconsistent mSize! Ran out of items to remove!"
|
||||
" mSize = %u, mMaxSize = %u", mSize, mMaxSize);
|
||||
LOG_ALWAYS_FATAL_IF(!mCache.size(),
|
||||
"Inconsistent mSize! Ran out of items to remove!"
|
||||
" mSize = %u, mMaxSize = %u",
|
||||
mSize, mMaxSize);
|
||||
mCache.removeOldest();
|
||||
}
|
||||
}
|
||||
|
||||
PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
|
||||
const SkPaint* paint) {
|
||||
PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath* path,
|
||||
const SkPaint* paint) {
|
||||
ATRACE_NAME("Generate Path Texture");
|
||||
|
||||
PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
|
||||
@@ -280,8 +283,8 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p
|
||||
return texture;
|
||||
}
|
||||
|
||||
void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap,
|
||||
PathTexture* texture, bool addToCache) {
|
||||
void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap, PathTexture* texture,
|
||||
bool addToCache) {
|
||||
generateTexture(bitmap, texture);
|
||||
|
||||
// Note here that we upload to a texture even if it's bigger than mMaxSize.
|
||||
@@ -289,8 +292,7 @@ void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap,
|
||||
// immediately on trim, or on any other Path entering the cache.
|
||||
uint32_t size = texture->width() * texture->height();
|
||||
mSize += size;
|
||||
PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
|
||||
texture->id, size, mSize);
|
||||
PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d", texture->id, size, mSize);
|
||||
if (mDebugEnabled) {
|
||||
ALOGD("Shape created, size = %d", size);
|
||||
}
|
||||
@@ -313,9 +315,8 @@ void PathCache::generateTexture(Bitmap& bitmap, Texture* texture) {
|
||||
// Path precaching
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PathCache::PathProcessor::PathProcessor(Caches& caches):
|
||||
TaskProcessor<sk_sp<Bitmap> >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
|
||||
}
|
||||
PathCache::PathProcessor::PathProcessor(Caches& caches)
|
||||
: TaskProcessor<sk_sp<Bitmap> >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {}
|
||||
|
||||
void PathCache::PathProcessor::onProcess(const sp<Task<sk_sp<Bitmap> > >& task) {
|
||||
PathTask* t = static_cast<PathTask*>(task.get());
|
||||
@@ -336,7 +337,7 @@ void PathCache::removeDeferred(const SkPath* path) {
|
||||
void PathCache::clearGarbage() {
|
||||
Vector<PathDescription> pathsToRemove;
|
||||
|
||||
{ // scope for the mutex
|
||||
{ // scope for the mutex
|
||||
Mutex::Autolock l(mLock);
|
||||
for (const uint32_t generationID : mGarbage) {
|
||||
LruCache<PathDescription, PathTexture*>::Iterator iter(mCache);
|
||||
@@ -433,8 +434,8 @@ void PathCache::precache(const SkPath* path, const SkPaint* paint) {
|
||||
// Rounded rects
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PathTexture* PathCache::getRoundRect(float width, float height,
|
||||
float rx, float ry, const SkPaint* paint) {
|
||||
PathTexture* PathCache::getRoundRect(float width, float height, float rx, float ry,
|
||||
const SkPaint* paint) {
|
||||
PathDescription entry(ShapeType::RoundRect, paint);
|
||||
entry.shape.roundRect.mWidth = width;
|
||||
entry.shape.roundRect.mHeight = height;
|
||||
@@ -525,8 +526,8 @@ PathTexture* PathCache::getRect(float width, float height, const SkPaint* paint)
|
||||
// Arcs
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PathTexture* PathCache::getArc(float width, float height,
|
||||
float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
|
||||
PathTexture* PathCache::getArc(float width, float height, float startAngle, float sweepAngle,
|
||||
bool useCenter, const SkPaint* paint) {
|
||||
PathDescription entry(ShapeType::Arc, paint);
|
||||
entry.shape.arc.mWidth = width;
|
||||
entry.shape.arc.mHeight = height;
|
||||
@@ -554,5 +555,5 @@ PathTexture* PathCache::getArc(float width, float height,
|
||||
return texture;
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -47,9 +47,9 @@ class Caches;
|
||||
|
||||
// Debug
|
||||
#if DEBUG_PATHS
|
||||
#define PATH_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#define PATH_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#else
|
||||
#define PATH_LOGD(...)
|
||||
#define PATH_LOGD(...)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -57,11 +57,10 @@ class Caches;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct PathTexture;
|
||||
class PathTask: public Task<sk_sp<Bitmap>> {
|
||||
class PathTask : public Task<sk_sp<Bitmap>> {
|
||||
public:
|
||||
PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture):
|
||||
path(*path), paint(*paint), texture(texture) {
|
||||
}
|
||||
PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture)
|
||||
: path(*path), paint(*paint), texture(texture) {}
|
||||
|
||||
// copied, since input path not guaranteed to survive for duration of task
|
||||
const SkPath path;
|
||||
@@ -74,15 +73,10 @@ public:
|
||||
/**
|
||||
* Alpha texture used to represent a path.
|
||||
*/
|
||||
struct PathTexture: public Texture {
|
||||
PathTexture(Caches& caches, int generation)
|
||||
: Texture(caches) {
|
||||
this->generation = generation;
|
||||
}
|
||||
struct PathTexture : public Texture {
|
||||
PathTexture(Caches& caches, int generation) : Texture(caches) { this->generation = generation; }
|
||||
|
||||
~PathTexture() {
|
||||
clearTask();
|
||||
}
|
||||
~PathTexture() { clearTask(); }
|
||||
|
||||
/**
|
||||
* Left coordinate of the path bounds.
|
||||
@@ -97,13 +91,9 @@ struct PathTexture: public Texture {
|
||||
*/
|
||||
float offset = 0;
|
||||
|
||||
sp<PathTask> task() const {
|
||||
return mTask;
|
||||
}
|
||||
sp<PathTask> task() const { return mTask; }
|
||||
|
||||
void setTask(const sp<PathTask>& task) {
|
||||
mTask = task;
|
||||
}
|
||||
void setTask(const sp<PathTask>& task) { mTask = task; }
|
||||
|
||||
void clearTask() {
|
||||
if (mTask != nullptr) {
|
||||
@@ -113,17 +103,9 @@ struct PathTexture: public Texture {
|
||||
|
||||
private:
|
||||
sp<PathTask> mTask;
|
||||
}; // struct PathTexture
|
||||
}; // struct PathTexture
|
||||
|
||||
enum class ShapeType {
|
||||
None,
|
||||
Rect,
|
||||
RoundRect,
|
||||
Circle,
|
||||
Oval,
|
||||
Arc,
|
||||
Path
|
||||
};
|
||||
enum class ShapeType { None, Rect, RoundRect, Circle, Oval, Arc, Path };
|
||||
|
||||
struct PathDescription {
|
||||
HASHABLE_TYPE(PathDescription);
|
||||
@@ -173,7 +155,7 @@ struct PathDescription {
|
||||
* Any texture added to the cache causing the cache to grow beyond the maximum
|
||||
* allowed size will also cause the oldest texture to be kicked out.
|
||||
*/
|
||||
class PathCache: public OnEntryRemoved<PathDescription, PathTexture*> {
|
||||
class PathCache : public OnEntryRemoved<PathDescription, PathTexture*> {
|
||||
public:
|
||||
PathCache();
|
||||
~PathCache();
|
||||
@@ -203,9 +185,9 @@ public:
|
||||
PathTexture* getOval(float width, float height, const SkPaint* paint);
|
||||
PathTexture* getRect(float width, float height, const SkPaint* paint);
|
||||
PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
|
||||
bool useCenter, const SkPaint* paint);
|
||||
bool useCenter, const SkPaint* paint);
|
||||
PathTexture* get(const SkPath* path, const SkPaint* paint);
|
||||
void remove(const SkPath* path, const SkPaint* paint);
|
||||
void remove(const SkPath* path, const SkPaint* paint);
|
||||
|
||||
/**
|
||||
* Removes the specified path. This is meant to be called from threads
|
||||
@@ -234,19 +216,16 @@ public:
|
||||
void precache(const SkPath* path, const SkPaint* paint);
|
||||
|
||||
private:
|
||||
PathTexture* addTexture(const PathDescription& entry,
|
||||
const SkPath *path, const SkPaint* paint);
|
||||
PathTexture* addTexture(const PathDescription& entry, const SkPath* path, const SkPaint* paint);
|
||||
|
||||
/**
|
||||
* Generates the texture from a bitmap into the specified texture structure.
|
||||
*/
|
||||
void generateTexture(Bitmap& bitmap, Texture* texture);
|
||||
void generateTexture(const PathDescription& entry, Bitmap& bitmap, PathTexture* texture,
|
||||
bool addToCache = true);
|
||||
bool addToCache = true);
|
||||
|
||||
PathTexture* get(const PathDescription& entry) {
|
||||
return mCache.get(entry);
|
||||
}
|
||||
PathTexture* get(const PathDescription& entry) { return mCache.get(entry); }
|
||||
|
||||
/**
|
||||
* Ensures there is enough space in the cache for a texture of the specified
|
||||
@@ -258,13 +237,12 @@ private:
|
||||
|
||||
void init();
|
||||
|
||||
|
||||
class PathProcessor: public TaskProcessor<sk_sp<Bitmap> > {
|
||||
class PathProcessor : public TaskProcessor<sk_sp<Bitmap>> {
|
||||
public:
|
||||
explicit PathProcessor(Caches& caches);
|
||||
~PathProcessor() { }
|
||||
~PathProcessor() {}
|
||||
|
||||
virtual void onProcess(const sp<Task<sk_sp<Bitmap> > >& task) override;
|
||||
virtual void onProcess(const sp<Task<sk_sp<Bitmap>>>& task) override;
|
||||
|
||||
private:
|
||||
uint32_t mMaxTextureSize;
|
||||
@@ -281,9 +259,9 @@ private:
|
||||
|
||||
std::vector<uint32_t> mGarbage;
|
||||
mutable Mutex mLock;
|
||||
}; // class PathCache
|
||||
}; // class PathCache
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_PATH_CACHE_H
|
||||
#endif // ANDROID_HWUI_PATH_CACHE_H
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
#include "jni.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <utils/Log.h>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -36,8 +36,8 @@ static size_t nextStart(const char* s, size_t length, size_t startIndex) {
|
||||
// used for floating point numbers' scientific notation.
|
||||
// Therefore, when searching for next command, we should ignore 'e'
|
||||
// and 'E'.
|
||||
if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
|
||||
&& c != 'e' && c != 'E') {
|
||||
if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0)) && c != 'e' &&
|
||||
c != 'E') {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
@@ -52,7 +52,8 @@ static size_t nextStart(const char* s, size_t length, size_t startIndex) {
|
||||
* @param result the result of the extraction, including the position of the
|
||||
* the starting position of next number, whether it is ending with a '-'.
|
||||
*/
|
||||
static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s, int start, int end) {
|
||||
static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s, int start,
|
||||
int end) {
|
||||
// Now looking for ' ', ',', '.' or '-' from the start.
|
||||
int currentIndex = start;
|
||||
bool foundSeparator = false;
|
||||
@@ -64,30 +65,30 @@ static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s
|
||||
isExponential = false;
|
||||
char currentChar = s[currentIndex];
|
||||
switch (currentChar) {
|
||||
case ' ':
|
||||
case ',':
|
||||
foundSeparator = true;
|
||||
break;
|
||||
case '-':
|
||||
// The negative sign following a 'e' or 'E' is not a separator.
|
||||
if (currentIndex != start && !isPrevExponential) {
|
||||
case ' ':
|
||||
case ',':
|
||||
foundSeparator = true;
|
||||
*outEndWithNegOrDot = true;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
if (!secondDot) {
|
||||
secondDot = true;
|
||||
} else {
|
||||
// This is the second dot, and it is considered as a separator.
|
||||
foundSeparator = true;
|
||||
*outEndWithNegOrDot = true;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
isExponential = true;
|
||||
break;
|
||||
break;
|
||||
case '-':
|
||||
// The negative sign following a 'e' or 'E' is not a separator.
|
||||
if (currentIndex != start && !isPrevExponential) {
|
||||
foundSeparator = true;
|
||||
*outEndWithNegOrDot = true;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
if (!secondDot) {
|
||||
secondDot = true;
|
||||
} else {
|
||||
// This is the second dot, and it is considered as a separator.
|
||||
foundSeparator = true;
|
||||
*outEndWithNegOrDot = true;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
isExponential = true;
|
||||
break;
|
||||
}
|
||||
if (foundSeparator) {
|
||||
break;
|
||||
@@ -98,7 +99,8 @@ static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s
|
||||
*outEndPosition = currentIndex;
|
||||
}
|
||||
|
||||
static float parseFloat(PathParser::ParseResult* result, const char* startPtr, size_t expectedLength) {
|
||||
static float parseFloat(PathParser::ParseResult* result, const char* startPtr,
|
||||
size_t expectedLength) {
|
||||
char* endPtr = NULL;
|
||||
float currentValue = strtof(startPtr, &endPtr);
|
||||
if ((currentValue == HUGE_VALF || currentValue == -HUGE_VALF) && errno == ERANGE) {
|
||||
@@ -122,8 +124,7 @@ static float parseFloat(PathParser::ParseResult* result, const char* startPtr, s
|
||||
* @return true on success
|
||||
*/
|
||||
static void getFloats(std::vector<float>* outPoints, PathParser::ParseResult* result,
|
||||
const char* pathStr, int start, int end) {
|
||||
|
||||
const char* pathStr, int start, int end) {
|
||||
if (pathStr[start] == 'z' || pathStr[start] == 'Z') {
|
||||
return;
|
||||
}
|
||||
@@ -138,8 +139,7 @@ static void getFloats(std::vector<float>* outPoints, PathParser::ParseResult* re
|
||||
extract(&endPosition, &endWithNegOrDot, pathStr, startPosition, end);
|
||||
|
||||
if (startPosition < endPosition) {
|
||||
float currentValue = parseFloat(result, &pathStr[startPosition],
|
||||
end - startPosition);
|
||||
float currentValue = parseFloat(result, &pathStr[startPosition], end - startPosition);
|
||||
if (result->failureOccurred) {
|
||||
return;
|
||||
}
|
||||
@@ -158,12 +158,12 @@ static void getFloats(std::vector<float>* outPoints, PathParser::ParseResult* re
|
||||
|
||||
bool PathParser::isVerbValid(char verb) {
|
||||
verb = tolower(verb);
|
||||
return verb == 'a' || verb == 'c' || verb == 'h' || verb == 'l' || verb == 'm' || verb == 'q'
|
||||
|| verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
|
||||
return verb == 'a' || verb == 'c' || verb == 'h' || verb == 'l' || verb == 'm' || verb == 'q' ||
|
||||
verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
|
||||
}
|
||||
|
||||
void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
|
||||
const char* pathStr, size_t strLen) {
|
||||
const char* pathStr, size_t strLen) {
|
||||
if (pathStr == NULL) {
|
||||
result->failureOccurred = true;
|
||||
result->failureMessage = "Path string cannot be NULL.";
|
||||
@@ -188,8 +188,8 @@ void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
|
||||
getFloats(&points, result, pathStr, start, end);
|
||||
if (!isVerbValid(pathStr[start])) {
|
||||
result->failureOccurred = true;
|
||||
result->failureMessage = "Invalid pathData. Failure occurred at position "
|
||||
+ std::to_string(start) + " of path: " + pathStr;
|
||||
result->failureMessage = "Invalid pathData. Failure occurred at position " +
|
||||
std::to_string(start) + " of path: " + pathStr;
|
||||
}
|
||||
// If either verb or points is not valid, return immediately.
|
||||
if (result->failureOccurred) {
|
||||
@@ -205,8 +205,8 @@ void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
|
||||
if ((end - start) == 1 && start < strLen) {
|
||||
if (!isVerbValid(pathStr[start])) {
|
||||
result->failureOccurred = true;
|
||||
result->failureMessage = "Invalid pathData. Failure occurred at position "
|
||||
+ std::to_string(start) + " of path: " + pathStr;
|
||||
result->failureMessage = "Invalid pathData. Failure occurred at position " +
|
||||
std::to_string(start) + " of path: " + pathStr;
|
||||
return;
|
||||
}
|
||||
data->verbs.push_back(pathStr[start]);
|
||||
@@ -235,7 +235,8 @@ void PathParser::dump(const PathData& data) {
|
||||
ALOGD("points are : %s", os.str().c_str());
|
||||
}
|
||||
|
||||
void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
|
||||
void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr,
|
||||
size_t strLen) {
|
||||
PathData pathData;
|
||||
getPathDataFromAsciiString(&pathData, result, pathStr, strLen);
|
||||
if (result->failureOccurred) {
|
||||
@@ -252,5 +253,5 @@ void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result,
|
||||
return;
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; //namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -20,16 +20,15 @@
|
||||
#include "VectorDrawable.h"
|
||||
#include "utils/VectorDrawableUtils.h"
|
||||
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include <cutils/compiler.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
|
||||
class PathParser {
|
||||
public:
|
||||
struct ANDROID_API ParseResult {
|
||||
@@ -40,13 +39,13 @@ public:
|
||||
* Parse the string literal and create a Skia Path. Return true on success.
|
||||
*/
|
||||
ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
|
||||
const char* pathStr, size_t strLength);
|
||||
const char* pathStr, size_t strLength);
|
||||
ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
|
||||
const char* pathStr, size_t strLength);
|
||||
const char* pathStr, size_t strLength);
|
||||
static void dump(const PathData& data);
|
||||
static bool isVerbValid(char verb);
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
#endif //ANDROID_HWUI_PATHPARSER_H
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
#endif // ANDROID_HWUI_PATHPARSER_H
|
||||
|
||||
@@ -18,13 +18,12 @@
|
||||
#define VERTEX_DEBUG 0
|
||||
|
||||
#if VERTEX_DEBUG
|
||||
#define DEBUG_DUMP_ALPHA_BUFFER() \
|
||||
for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
|
||||
ALOGD("point %d at %f %f, alpha %f", \
|
||||
i, buffer[i].x, buffer[i].y, buffer[i].alpha); \
|
||||
#define DEBUG_DUMP_ALPHA_BUFFER() \
|
||||
for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
|
||||
ALOGD("point %d at %f %f, alpha %f", i, buffer[i].x, buffer[i].y, buffer[i].alpha); \
|
||||
}
|
||||
#define DEBUG_DUMP_BUFFER() \
|
||||
for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
|
||||
#define DEBUG_DUMP_BUFFER() \
|
||||
for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
|
||||
ALOGD("point %d at %f %f", i, buffer[i].x, buffer[i].y); \
|
||||
}
|
||||
#else
|
||||
@@ -41,13 +40,13 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <SkPath.h>
|
||||
#include <SkGeometry.h> // WARNING: Internal Skia Header
|
||||
#include <SkPaint.h>
|
||||
#include <SkPath.h>
|
||||
#include <SkPoint.h>
|
||||
#include <SkGeometry.h> // WARNING: Internal Skia Header
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
@@ -64,8 +63,8 @@ namespace uirenderer {
|
||||
/**
|
||||
* Extracts the x and y scale from the transform as positive values, and clamps them
|
||||
*/
|
||||
void PathTessellator::extractTessellationScales(const Matrix4& transform,
|
||||
float* scaleX, float* scaleY) {
|
||||
void PathTessellator::extractTessellationScales(const Matrix4& transform, float* scaleX,
|
||||
float* scaleY) {
|
||||
if (CC_LIKELY(transform.isPureTranslate())) {
|
||||
*scaleX = 1.0f;
|
||||
*scaleY = 1.0f;
|
||||
@@ -98,9 +97,12 @@ inline static Vector2 totalOffsetFromNormals(const Vector2& normalA, const Vecto
|
||||
*/
|
||||
struct PaintInfo {
|
||||
public:
|
||||
PaintInfo(const SkPaint* paint, const mat4& transform) :
|
||||
style(paint->getStyle()), cap(paint->getStrokeCap()), isAA(paint->isAntiAlias()),
|
||||
halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
|
||||
PaintInfo(const SkPaint* paint, const mat4& transform)
|
||||
: style(paint->getStyle())
|
||||
, cap(paint->getStrokeCap())
|
||||
, isAA(paint->isAntiAlias())
|
||||
, halfStrokeWidth(paint->getStrokeWidth() * 0.5f)
|
||||
, maxAlpha(1.0f) {
|
||||
// compute inverse scales
|
||||
if (CC_LIKELY(transform.isPureTranslate())) {
|
||||
inverseScaleX = 1.0f;
|
||||
@@ -113,7 +115,7 @@ public:
|
||||
}
|
||||
|
||||
if (isAA && halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
|
||||
2 * halfStrokeWidth < inverseScaleX) {
|
||||
2 * halfStrokeWidth < inverseScaleX) {
|
||||
// AA, with non-hairline stroke, width < 1 pixel. Scale alpha and treat as hairline.
|
||||
maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
|
||||
halfStrokeWidth = 0.0f;
|
||||
@@ -171,17 +173,17 @@ public:
|
||||
if (halfStrokeWidth == 0) {
|
||||
// hairline, outset by (0.5f + fudge factor) in post-scaling space
|
||||
bounds->outset(fabs(inverseScaleX) * (0.5f + Vertex::GeometryFudgeFactor()),
|
||||
fabs(inverseScaleY) * (0.5f + Vertex::GeometryFudgeFactor()));
|
||||
fabs(inverseScaleY) * (0.5f + Vertex::GeometryFudgeFactor()));
|
||||
} else {
|
||||
// non hairline, outset by half stroke width pre-scaled, and fudge factor post scaled
|
||||
bounds->outset(halfStrokeWidth + fabs(inverseScaleX) * Vertex::GeometryFudgeFactor(),
|
||||
halfStrokeWidth + fabs(inverseScaleY) * Vertex::GeometryFudgeFactor());
|
||||
halfStrokeWidth + fabs(inverseScaleY) * Vertex::GeometryFudgeFactor());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void getFillVerticesFromPerimeter(const std::vector<Vertex>& perimeter,
|
||||
VertexBuffer& vertexBuffer) {
|
||||
VertexBuffer& vertexBuffer) {
|
||||
Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size());
|
||||
|
||||
int currentIndex = 0;
|
||||
@@ -206,7 +208,8 @@ void getFillVerticesFromPerimeter(const std::vector<Vertex>& perimeter,
|
||||
* (for a total of perimeter.size() * 2 + 2 vertices)
|
||||
*/
|
||||
void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo,
|
||||
const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
|
||||
const std::vector<Vertex>& perimeter,
|
||||
VertexBuffer& vertexBuffer) {
|
||||
Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size() * 2 + 2);
|
||||
|
||||
int currentIndex = 0;
|
||||
@@ -222,13 +225,11 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo,
|
||||
Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
|
||||
paintInfo.scaleOffsetForStrokeWidth(totalOffset);
|
||||
|
||||
Vertex::set(&buffer[currentIndex++],
|
||||
current->x + totalOffset.x,
|
||||
current->y + totalOffset.y);
|
||||
Vertex::set(&buffer[currentIndex++], current->x + totalOffset.x,
|
||||
current->y + totalOffset.y);
|
||||
|
||||
Vertex::set(&buffer[currentIndex++],
|
||||
current->x - totalOffset.x,
|
||||
current->y - totalOffset.y);
|
||||
Vertex::set(&buffer[currentIndex++], current->x - totalOffset.x,
|
||||
current->y - totalOffset.y);
|
||||
|
||||
current = next;
|
||||
lastNormal = nextNormal;
|
||||
@@ -242,7 +243,8 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo,
|
||||
}
|
||||
|
||||
static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center,
|
||||
const Vector2& normal, Vertex* buffer, int& currentIndex, bool begin) {
|
||||
const Vector2& normal, Vertex* buffer, int& currentIndex,
|
||||
bool begin) {
|
||||
Vector2 strokeOffset = normal;
|
||||
paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
|
||||
|
||||
@@ -264,7 +266,8 @@ static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& cente
|
||||
* 2 - can zig-zag across 'extra' vertices at either end, to create round caps
|
||||
*/
|
||||
void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
|
||||
const std::vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
|
||||
const std::vector<Vertex>& vertices,
|
||||
VertexBuffer& vertexBuffer) {
|
||||
const int extra = paintInfo.capExtraDivisions();
|
||||
const int allocSize = (vertices.size() + extra) * 2;
|
||||
Vertex* buffer = vertexBuffer.alloc<Vertex>(allocSize);
|
||||
@@ -272,12 +275,9 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
|
||||
const int lastIndex = vertices.size() - 1;
|
||||
if (extra > 0) {
|
||||
// tessellate both round caps
|
||||
float beginTheta = atan2(
|
||||
- (vertices[0].x - vertices[1].x),
|
||||
vertices[0].y - vertices[1].y);
|
||||
float endTheta = atan2(
|
||||
- (vertices[lastIndex].x - vertices[lastIndex - 1].x),
|
||||
vertices[lastIndex].y - vertices[lastIndex - 1].y);
|
||||
float beginTheta = atan2(-(vertices[0].x - vertices[1].x), vertices[0].y - vertices[1].y);
|
||||
float endTheta = atan2(-(vertices[lastIndex].x - vertices[lastIndex - 1].x),
|
||||
vertices[lastIndex].y - vertices[lastIndex - 1].y);
|
||||
const float dTheta = PI / (extra + 1);
|
||||
|
||||
int capOffset;
|
||||
@@ -291,16 +291,15 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
|
||||
beginTheta += dTheta;
|
||||
Vector2 beginRadialOffset = {cosf(beginTheta), sinf(beginTheta)};
|
||||
paintInfo.scaleOffsetForStrokeWidth(beginRadialOffset);
|
||||
Vertex::set(&buffer[capOffset],
|
||||
vertices[0].x + beginRadialOffset.x,
|
||||
vertices[0].y + beginRadialOffset.y);
|
||||
Vertex::set(&buffer[capOffset], vertices[0].x + beginRadialOffset.x,
|
||||
vertices[0].y + beginRadialOffset.y);
|
||||
|
||||
endTheta += dTheta;
|
||||
Vector2 endRadialOffset = {cosf(endTheta), sinf(endTheta)};
|
||||
paintInfo.scaleOffsetForStrokeWidth(endRadialOffset);
|
||||
Vertex::set(&buffer[allocSize - 1 - capOffset],
|
||||
vertices[lastIndex].x + endRadialOffset.x,
|
||||
vertices[lastIndex].y + endRadialOffset.y);
|
||||
vertices[lastIndex].x + endRadialOffset.x,
|
||||
vertices[lastIndex].y + endRadialOffset.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +316,7 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
|
||||
Vector2 nextNormal = {next->y - current->y, current->x - next->x};
|
||||
nextNormal.normalize();
|
||||
|
||||
Vector2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal);
|
||||
Vector2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal);
|
||||
paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
|
||||
|
||||
Vector2 center = {current->x, current->y};
|
||||
@@ -344,8 +343,8 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
|
||||
* 3 - zig zag back and forth inside the shape to fill it (using perimeter.size() vertices)
|
||||
*/
|
||||
void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo,
|
||||
const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer,
|
||||
float maxAlpha = 1.0f) {
|
||||
const std::vector<Vertex>& perimeter,
|
||||
VertexBuffer& vertexBuffer, float maxAlpha = 1.0f) {
|
||||
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(perimeter.size() * 3 + 2);
|
||||
|
||||
// generate alpha points - fill Alpha vertex gaps in between each point with
|
||||
@@ -362,16 +361,13 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo,
|
||||
|
||||
// AA point offset from original point is that point's normal, such that each side is offset
|
||||
// by .5 pixels
|
||||
Vector2 totalOffset = paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
|
||||
Vector2 totalOffset =
|
||||
paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
|
||||
|
||||
AlphaVertex::set(&buffer[currentIndex++],
|
||||
current->x + totalOffset.x,
|
||||
current->y + totalOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[currentIndex++],
|
||||
current->x - totalOffset.x,
|
||||
current->y - totalOffset.y,
|
||||
maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentIndex++], current->x + totalOffset.x,
|
||||
current->y + totalOffset.y, 0.0f);
|
||||
AlphaVertex::set(&buffer[currentIndex++], current->x - totalOffset.x,
|
||||
current->y - totalOffset.y, maxAlpha);
|
||||
|
||||
current = next;
|
||||
lastNormal = nextNormal;
|
||||
@@ -404,12 +400,11 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo,
|
||||
* getStrokeVerticesFromUnclosedVerticesAA() below.
|
||||
*/
|
||||
inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vertex>& vertices,
|
||||
AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) {
|
||||
AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) {
|
||||
const int extra = paintInfo.capExtraDivisions();
|
||||
const int extraOffset = (extra + 1) / 2;
|
||||
const int capIndex = isFirst
|
||||
? 2 * offset + 6 + 2 * (extra + extraOffset)
|
||||
: offset + 2 + 2 * extraOffset;
|
||||
const int capIndex =
|
||||
isFirst ? 2 * offset + 6 + 2 * (extra + extraOffset) : offset + 2 + 2 * extraOffset;
|
||||
if (isFirst) normal *= -1;
|
||||
|
||||
// TODO: this normal should be scaled by radialScale if extra != 0, see totalOffsetFromNormals()
|
||||
@@ -437,26 +432,18 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vert
|
||||
referencePoint += rotated;
|
||||
}
|
||||
|
||||
AlphaVertex::set(&buffer[capIndex + 0],
|
||||
referencePoint.x + outerOffset.x + capAAOffset.x,
|
||||
referencePoint.y + outerOffset.y + capAAOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[capIndex + 1],
|
||||
referencePoint.x + innerOffset.x - capAAOffset.x,
|
||||
referencePoint.y + innerOffset.y - capAAOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[capIndex + 0], referencePoint.x + outerOffset.x + capAAOffset.x,
|
||||
referencePoint.y + outerOffset.y + capAAOffset.y, 0.0f);
|
||||
AlphaVertex::set(&buffer[capIndex + 1], referencePoint.x + innerOffset.x - capAAOffset.x,
|
||||
referencePoint.y + innerOffset.y - capAAOffset.y, paintInfo.maxAlpha);
|
||||
|
||||
bool isRound = paintInfo.cap == SkPaint::kRound_Cap;
|
||||
|
||||
const int postCapIndex = (isRound && isFirst) ? (2 * extraOffset - 2) : capIndex + (2 * extra);
|
||||
AlphaVertex::set(&buffer[postCapIndex + 2],
|
||||
referencePoint.x - outerOffset.x + capAAOffset.x,
|
||||
referencePoint.y - outerOffset.y + capAAOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[postCapIndex + 3],
|
||||
referencePoint.x - innerOffset.x - capAAOffset.x,
|
||||
referencePoint.y - innerOffset.y - capAAOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[postCapIndex + 2], referencePoint.x - outerOffset.x + capAAOffset.x,
|
||||
referencePoint.y - outerOffset.y + capAAOffset.y, 0.0f);
|
||||
AlphaVertex::set(&buffer[postCapIndex + 3], referencePoint.x - innerOffset.x - capAAOffset.x,
|
||||
referencePoint.y - innerOffset.y - capAAOffset.y, paintInfo.maxAlpha);
|
||||
|
||||
if (isRound) {
|
||||
const float dTheta = PI / (extra + 1);
|
||||
@@ -475,20 +462,18 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vert
|
||||
AAOffset = paintInfo.deriveAAOffset(radialOffset);
|
||||
paintInfo.scaleOffsetForStrokeWidth(radialOffset);
|
||||
AlphaVertex::set(&buffer[capPerimIndex++],
|
||||
referencePoint.x + radialOffset.x + AAOffset.x,
|
||||
referencePoint.y + radialOffset.y + AAOffset.y,
|
||||
0.0f);
|
||||
referencePoint.x + radialOffset.x + AAOffset.x,
|
||||
referencePoint.y + radialOffset.y + AAOffset.y, 0.0f);
|
||||
AlphaVertex::set(&buffer[capPerimIndex++],
|
||||
referencePoint.x + radialOffset.x - AAOffset.x,
|
||||
referencePoint.y + radialOffset.y - AAOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
referencePoint.x + radialOffset.x - AAOffset.x,
|
||||
referencePoint.y + radialOffset.y - AAOffset.y, paintInfo.maxAlpha);
|
||||
|
||||
if (isFirst && i == extra - extraOffset) {
|
||||
//copy most recent two points to first two points
|
||||
// copy most recent two points to first two points
|
||||
buffer[0] = buffer[capPerimIndex - 2];
|
||||
buffer[1] = buffer[capPerimIndex - 1];
|
||||
|
||||
capPerimIndex = 2; // start writing the rest of the round cap at index 2
|
||||
capPerimIndex = 2; // start writing the rest of the round cap at index 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,7 +498,7 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vert
|
||||
if (isFirst) {
|
||||
buffer[0] = buffer[postCapIndex + 2];
|
||||
buffer[1] = buffer[postCapIndex + 3];
|
||||
buffer[postCapIndex + 4] = buffer[1]; // degenerate tris (the only two!)
|
||||
buffer[postCapIndex + 4] = buffer[1]; // degenerate tris (the only two!)
|
||||
buffer[postCapIndex + 5] = buffer[postCapIndex + 1];
|
||||
} else {
|
||||
buffer[6 * vertices.size()] = buffer[postCapIndex + 1];
|
||||
@@ -574,8 +559,8 @@ or, for rounded caps:
|
||||
= 2 + 6 * pts + 6 * roundDivs
|
||||
*/
|
||||
void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo,
|
||||
const std::vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
|
||||
|
||||
const std::vector<Vertex>& vertices,
|
||||
VertexBuffer& vertexBuffer) {
|
||||
const int extra = paintInfo.capExtraDivisions();
|
||||
const int allocSize = 6 * vertices.size() + 2 + 6 * extra;
|
||||
|
||||
@@ -609,32 +594,20 @@ void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo,
|
||||
Vector2 outerOffset = innerOffset + AAOffset;
|
||||
innerOffset -= AAOffset;
|
||||
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++],
|
||||
current->x + outerOffset.x,
|
||||
current->y + outerOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++],
|
||||
current->x + innerOffset.x,
|
||||
current->y + innerOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + outerOffset.x,
|
||||
current->y + outerOffset.y, 0.0f);
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + innerOffset.x,
|
||||
current->y + innerOffset.y, paintInfo.maxAlpha);
|
||||
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++],
|
||||
current->x + innerOffset.x,
|
||||
current->y + innerOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++],
|
||||
current->x - innerOffset.x,
|
||||
current->y - innerOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++], current->x + innerOffset.x,
|
||||
current->y + innerOffset.y, paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++], current->x - innerOffset.x,
|
||||
current->y - innerOffset.y, paintInfo.maxAlpha);
|
||||
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex--],
|
||||
current->x - innerOffset.x,
|
||||
current->y - innerOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex--],
|
||||
current->x - outerOffset.x,
|
||||
current->y - outerOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex--], current->x - innerOffset.x,
|
||||
current->y - innerOffset.y, paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex--], current->x - outerOffset.x,
|
||||
current->y - outerOffset.y, 0.0f);
|
||||
|
||||
current = next;
|
||||
lastNormal = nextNormal;
|
||||
@@ -646,9 +619,9 @@ void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo,
|
||||
DEBUG_DUMP_ALPHA_BUFFER();
|
||||
}
|
||||
|
||||
|
||||
void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo,
|
||||
const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
|
||||
const std::vector<Vertex>& perimeter,
|
||||
VertexBuffer& vertexBuffer) {
|
||||
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8);
|
||||
|
||||
int offset = 2 * perimeter.size() + 3;
|
||||
@@ -673,32 +646,20 @@ void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo,
|
||||
Vector2 outerOffset = innerOffset + AAOffset;
|
||||
innerOffset -= AAOffset;
|
||||
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++],
|
||||
current->x + outerOffset.x,
|
||||
current->y + outerOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++],
|
||||
current->x + innerOffset.x,
|
||||
current->y + innerOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + outerOffset.x,
|
||||
current->y + outerOffset.y, 0.0f);
|
||||
AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + innerOffset.x,
|
||||
current->y + innerOffset.y, paintInfo.maxAlpha);
|
||||
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++],
|
||||
current->x + innerOffset.x,
|
||||
current->y + innerOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++],
|
||||
current->x - innerOffset.x,
|
||||
current->y - innerOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++], current->x + innerOffset.x,
|
||||
current->y + innerOffset.y, paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentStrokeIndex++], current->x - innerOffset.x,
|
||||
current->y - innerOffset.y, paintInfo.maxAlpha);
|
||||
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex++],
|
||||
current->x - innerOffset.x,
|
||||
current->y - innerOffset.y,
|
||||
paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex++],
|
||||
current->x - outerOffset.x,
|
||||
current->y - outerOffset.y,
|
||||
0.0f);
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex++], current->x - innerOffset.x,
|
||||
current->y - innerOffset.y, paintInfo.maxAlpha);
|
||||
AlphaVertex::set(&buffer[currentAAInnerIndex++], current->x - outerOffset.x,
|
||||
current->y - outerOffset.y, 0.0f);
|
||||
|
||||
current = next;
|
||||
lastNormal = nextNormal;
|
||||
@@ -720,8 +681,8 @@ void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo,
|
||||
DEBUG_DUMP_ALPHA_BUFFER();
|
||||
}
|
||||
|
||||
void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
|
||||
const mat4& transform, VertexBuffer& vertexBuffer) {
|
||||
void PathTessellator::tessellatePath(const SkPath& path, const SkPaint* paint,
|
||||
const mat4& transform, VertexBuffer& vertexBuffer) {
|
||||
ATRACE_CALL();
|
||||
|
||||
const PaintInfo paintInfo(paint, transform);
|
||||
@@ -742,9 +703,9 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
|
||||
// force close if we're filling the path, since fill path expects closed perimeter.
|
||||
bool forceClose = paintInfo.style != SkPaint::kStroke_Style;
|
||||
PathApproximationInfo approximationInfo(threshInvScaleX, threshInvScaleY,
|
||||
OUTLINE_REFINE_THRESHOLD);
|
||||
bool wasClosed = approximatePathOutlineVertices(path, forceClose,
|
||||
approximationInfo, tempVertices);
|
||||
OUTLINE_REFINE_THRESHOLD);
|
||||
bool wasClosed =
|
||||
approximatePathOutlineVertices(path, forceClose, approximationInfo, tempVertices);
|
||||
|
||||
if (!tempVertices.size()) {
|
||||
// path was empty, return without allocating vertex buffer
|
||||
@@ -753,8 +714,7 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
|
||||
|
||||
#if VERTEX_DEBUG
|
||||
for (unsigned int i = 0; i < tempVertices.size(); i++) {
|
||||
ALOGD("orig path: point at %f %f",
|
||||
tempVertices[i].x, tempVertices[i].y);
|
||||
ALOGD("orig path: point at %f %f", tempVertices[i].x, tempVertices[i].y);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -790,8 +750,8 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
|
||||
const float* points, int count, Rect& bounds) {
|
||||
static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer, const float* points,
|
||||
int count, Rect& bounds) {
|
||||
bounds.set(points[0], points[1], points[0], points[1]);
|
||||
|
||||
int numPoints = count / 2;
|
||||
@@ -806,7 +766,7 @@ static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
|
||||
}
|
||||
|
||||
void PathTessellator::tessellatePoints(const float* points, int count, const SkPaint* paint,
|
||||
const mat4& transform, VertexBuffer& vertexBuffer) {
|
||||
const mat4& transform, VertexBuffer& vertexBuffer) {
|
||||
const PaintInfo paintInfo(paint, transform);
|
||||
|
||||
// determine point shape
|
||||
@@ -823,7 +783,7 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP
|
||||
// calculate outline
|
||||
std::vector<Vertex> outlineVertices;
|
||||
PathApproximationInfo approximationInfo(paintInfo.inverseScaleX, paintInfo.inverseScaleY,
|
||||
OUTLINE_REFINE_THRESHOLD);
|
||||
OUTLINE_REFINE_THRESHOLD);
|
||||
approximatePathOutlineVertices(path, true, approximationInfo, outlineVertices);
|
||||
|
||||
if (!outlineVertices.size()) return;
|
||||
@@ -847,7 +807,7 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP
|
||||
}
|
||||
|
||||
void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
|
||||
const mat4& transform, VertexBuffer& vertexBuffer) {
|
||||
const mat4& transform, VertexBuffer& vertexBuffer) {
|
||||
ATRACE_CALL();
|
||||
const PaintInfo paintInfo(paint, transform);
|
||||
|
||||
@@ -900,7 +860,7 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float threshold,
|
||||
std::vector<Vertex>& outputVertices) {
|
||||
std::vector<Vertex>& outputVertices) {
|
||||
PathApproximationInfo approximationInfo(1.0f, 1.0f, threshold);
|
||||
return approximatePathOutlineVertices(path, true, approximationInfo, outputVertices);
|
||||
}
|
||||
@@ -932,6 +892,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool initialized = false;
|
||||
double lastX = 0;
|
||||
@@ -940,7 +901,8 @@ private:
|
||||
};
|
||||
|
||||
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose,
|
||||
const PathApproximationInfo& approximationInfo, std::vector<Vertex>& outputVertices) {
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex>& outputVertices) {
|
||||
ATRACE_CALL();
|
||||
|
||||
// TODO: to support joins other than sharp miter, join vertices should be labelled in the
|
||||
@@ -950,7 +912,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
|
||||
SkPath::Verb v;
|
||||
ClockwiseEnforcer clockwiseEnforcer;
|
||||
while (SkPath::kDone_Verb != (v = iter.next(pts))) {
|
||||
switch (v) {
|
||||
switch (v) {
|
||||
case SkPath::kMove_Verb:
|
||||
outputVertices.push_back(Vertex{pts[0].x(), pts[0].y()});
|
||||
ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
|
||||
@@ -967,22 +929,17 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
ALOGV("kQuad_Verb");
|
||||
recursiveQuadraticBezierVertices(
|
||||
pts[0].x(), pts[0].y(),
|
||||
pts[2].x(), pts[2].y(),
|
||||
pts[1].x(), pts[1].y(),
|
||||
approximationInfo, outputVertices);
|
||||
recursiveQuadraticBezierVertices(pts[0].x(), pts[0].y(), pts[2].x(), pts[2].y(),
|
||||
pts[1].x(), pts[1].y(), approximationInfo,
|
||||
outputVertices);
|
||||
clockwiseEnforcer.addPoint(pts[1]);
|
||||
clockwiseEnforcer.addPoint(pts[2]);
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
ALOGV("kCubic_Verb");
|
||||
recursiveCubicBezierVertices(
|
||||
pts[0].x(), pts[0].y(),
|
||||
pts[1].x(), pts[1].y(),
|
||||
pts[3].x(), pts[3].y(),
|
||||
pts[2].x(), pts[2].y(),
|
||||
approximationInfo, outputVertices);
|
||||
recursiveCubicBezierVertices(pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y(),
|
||||
pts[3].x(), pts[3].y(), pts[2].x(), pts[2].y(),
|
||||
approximationInfo, outputVertices);
|
||||
clockwiseEnforcer.addPoint(pts[1]);
|
||||
clockwiseEnforcer.addPoint(pts[2]);
|
||||
clockwiseEnforcer.addPoint(pts[3]);
|
||||
@@ -990,37 +947,33 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
|
||||
case SkPath::kConic_Verb: {
|
||||
ALOGV("kConic_Verb");
|
||||
SkAutoConicToQuads converter;
|
||||
const SkPoint* quads = converter.computeQuads(pts, iter.conicWeight(),
|
||||
approximationInfo.thresholdForConicQuads);
|
||||
const SkPoint* quads = converter.computeQuads(
|
||||
pts, iter.conicWeight(), approximationInfo.thresholdForConicQuads);
|
||||
for (int i = 0; i < converter.countQuads(); ++i) {
|
||||
const int offset = 2 * i;
|
||||
recursiveQuadraticBezierVertices(
|
||||
quads[offset].x(), quads[offset].y(),
|
||||
quads[offset+2].x(), quads[offset+2].y(),
|
||||
quads[offset+1].x(), quads[offset+1].y(),
|
||||
approximationInfo, outputVertices);
|
||||
recursiveQuadraticBezierVertices(quads[offset].x(), quads[offset].y(),
|
||||
quads[offset + 2].x(), quads[offset + 2].y(),
|
||||
quads[offset + 1].x(), quads[offset + 1].y(),
|
||||
approximationInfo, outputVertices);
|
||||
}
|
||||
clockwiseEnforcer.addPoint(pts[1]);
|
||||
clockwiseEnforcer.addPoint(pts[2]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
static_assert(SkPath::kMove_Verb == 0
|
||||
&& SkPath::kLine_Verb == 1
|
||||
&& SkPath::kQuad_Verb == 2
|
||||
&& SkPath::kConic_Verb == 3
|
||||
&& SkPath::kCubic_Verb == 4
|
||||
&& SkPath::kClose_Verb == 5
|
||||
&& SkPath::kDone_Verb == 6,
|
||||
"Path enum changed, new types may have been added");
|
||||
static_assert(SkPath::kMove_Verb == 0 && SkPath::kLine_Verb == 1 &&
|
||||
SkPath::kQuad_Verb == 2 && SkPath::kConic_Verb == 3 &&
|
||||
SkPath::kCubic_Verb == 4 && SkPath::kClose_Verb == 5 &&
|
||||
SkPath::kDone_Verb == 6,
|
||||
"Path enum changed, new types may have been added");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool wasClosed = false;
|
||||
int size = outputVertices.size();
|
||||
if (size >= 2 && outputVertices[0].x == outputVertices[size - 1].x &&
|
||||
outputVertices[0].y == outputVertices[size - 1].y) {
|
||||
outputVertices[0].y == outputVertices[size - 1].y) {
|
||||
outputVertices.pop_back();
|
||||
wasClosed = true;
|
||||
}
|
||||
@@ -1045,19 +998,17 @@ static inline float getThreshold(const PathApproximationInfo& info, float dx, fl
|
||||
return info.thresholdSquared * scale;
|
||||
}
|
||||
|
||||
void PathTessellator::recursiveCubicBezierVertices(
|
||||
float p1x, float p1y, float c1x, float c1y,
|
||||
float p2x, float p2y, float c2x, float c2y,
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex>& outputVertices, int depth) {
|
||||
void PathTessellator::recursiveCubicBezierVertices(float p1x, float p1y, float c1x, float c1y,
|
||||
float p2x, float p2y, float c2x, float c2y,
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex>& outputVertices, int depth) {
|
||||
float dx = p2x - p1x;
|
||||
float dy = p2y - p1y;
|
||||
float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
|
||||
float d2 = fabs((c2x - p2x) * dy - (c2y - p2y) * dx);
|
||||
float d = d1 + d2;
|
||||
|
||||
if (depth >= MAX_DEPTH
|
||||
|| d * d <= getThreshold(approximationInfo, dx, dy)) {
|
||||
if (depth >= MAX_DEPTH || d * d <= getThreshold(approximationInfo, dx, dy)) {
|
||||
// below thresh, draw line by adding endpoint
|
||||
outputVertices.push_back(Vertex{p2x, p2y});
|
||||
} else {
|
||||
@@ -1078,30 +1029,23 @@ void PathTessellator::recursiveCubicBezierVertices(
|
||||
float mx = (p1c1c2x + p2c1c2x) * 0.5f;
|
||||
float my = (p1c1c2y + p2c1c2y) * 0.5f;
|
||||
|
||||
recursiveCubicBezierVertices(
|
||||
p1x, p1y, p1c1x, p1c1y,
|
||||
mx, my, p1c1c2x, p1c1c2y,
|
||||
approximationInfo, outputVertices, depth + 1);
|
||||
recursiveCubicBezierVertices(
|
||||
mx, my, p2c1c2x, p2c1c2y,
|
||||
p2x, p2y, p2c2x, p2c2y,
|
||||
approximationInfo, outputVertices, depth + 1);
|
||||
recursiveCubicBezierVertices(p1x, p1y, p1c1x, p1c1y, mx, my, p1c1c2x, p1c1c2y,
|
||||
approximationInfo, outputVertices, depth + 1);
|
||||
recursiveCubicBezierVertices(mx, my, p2c1c2x, p2c1c2y, p2x, p2y, p2c2x, p2c2y,
|
||||
approximationInfo, outputVertices, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PathTessellator::recursiveQuadraticBezierVertices(
|
||||
float ax, float ay,
|
||||
float bx, float by,
|
||||
float cx, float cy,
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex>& outputVertices, int depth) {
|
||||
float ax, float ay, float bx, float by, float cx, float cy,
|
||||
const PathApproximationInfo& approximationInfo, std::vector<Vertex>& outputVertices,
|
||||
int depth) {
|
||||
float dx = bx - ax;
|
||||
float dy = by - ay;
|
||||
// d is the cross product of vector (B-A) and (C-B).
|
||||
float d = (cx - bx) * dy - (cy - by) * dx;
|
||||
|
||||
if (depth >= MAX_DEPTH
|
||||
|| d * d <= getThreshold(approximationInfo, dx, dy)) {
|
||||
if (depth >= MAX_DEPTH || d * d <= getThreshold(approximationInfo, dx, dy)) {
|
||||
// below thresh, draw line by adding endpoint
|
||||
outputVertices.push_back(Vertex{bx, by});
|
||||
} else {
|
||||
@@ -1114,12 +1058,12 @@ void PathTessellator::recursiveQuadraticBezierVertices(
|
||||
float mx = (acx + bcx) * 0.5f;
|
||||
float my = (acy + bcy) * 0.5f;
|
||||
|
||||
recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
|
||||
approximationInfo, outputVertices, depth + 1);
|
||||
recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
|
||||
approximationInfo, outputVertices, depth + 1);
|
||||
recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy, approximationInfo,
|
||||
outputVertices, depth + 1);
|
||||
recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy, approximationInfo,
|
||||
outputVertices, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -39,11 +39,10 @@ namespace uirenderer {
|
||||
*/
|
||||
struct PathApproximationInfo {
|
||||
PathApproximationInfo(float invScaleX, float invScaleY, float pixelThreshold)
|
||||
: thresholdSquared(pixelThreshold * pixelThreshold)
|
||||
, sqrInvScaleX(invScaleX * invScaleX)
|
||||
, sqrInvScaleY(invScaleY * invScaleY)
|
||||
, thresholdForConicQuads(pixelThreshold * std::min(invScaleX, invScaleY) / 2.0f) {
|
||||
};
|
||||
: thresholdSquared(pixelThreshold * pixelThreshold)
|
||||
, sqrInvScaleX(invScaleX * invScaleX)
|
||||
, sqrInvScaleY(invScaleY * invScaleY)
|
||||
, thresholdForConicQuads(pixelThreshold * std::min(invScaleX, invScaleY) / 2.0f){};
|
||||
|
||||
const float thresholdSquared;
|
||||
const float sqrInvScaleX;
|
||||
@@ -64,7 +63,8 @@ public:
|
||||
static void extractTessellationScales(const Matrix4& transform, float* scaleX, float* scaleY);
|
||||
|
||||
/**
|
||||
* Populates a VertexBuffer with a tessellated approximation of the input convex path, as a single
|
||||
* Populates a VertexBuffer with a tessellated approximation of the input convex path, as a
|
||||
* single
|
||||
* triangle strip. Note: joins are not currently supported.
|
||||
*
|
||||
* @param path The path to be approximated
|
||||
@@ -74,8 +74,8 @@ public:
|
||||
* vertex approximation, and correct AA ramp offsetting.
|
||||
* @param vertexBuffer The output buffer
|
||||
*/
|
||||
static void tessellatePath(const SkPath& path, const SkPaint* paint,
|
||||
const mat4& transform, VertexBuffer& vertexBuffer);
|
||||
static void tessellatePath(const SkPath& path, const SkPaint* paint, const mat4& transform,
|
||||
VertexBuffer& vertexBuffer);
|
||||
|
||||
/**
|
||||
* Populates a VertexBuffer with a tessellated approximation of points as a single triangle
|
||||
@@ -84,12 +84,13 @@ public:
|
||||
* @param points The center vertices of the points to be drawn
|
||||
* @param count The number of floats making up the point vertices
|
||||
* @param paint The paint the points will be drawn with indicating AA, stroke width & cap
|
||||
* @param transform The transform the points will be drawn with, used to drive stretch-aware path
|
||||
* @param transform The transform the points will be drawn with, used to drive stretch-aware
|
||||
* path
|
||||
* vertex approximation, and correct AA ramp offsetting
|
||||
* @param vertexBuffer The output buffer
|
||||
*/
|
||||
static void tessellatePoints(const float* points, int count, const SkPaint* paint,
|
||||
const mat4& transform, VertexBuffer& vertexBuffer);
|
||||
const mat4& transform, VertexBuffer& vertexBuffer);
|
||||
|
||||
/**
|
||||
* Populates a VertexBuffer with a tessellated approximation of lines as a single triangle
|
||||
@@ -98,12 +99,13 @@ public:
|
||||
* @param points Pairs of endpoints defining the lines to be drawn
|
||||
* @param count The number of floats making up the line vertices
|
||||
* @param paint The paint the lines will be drawn with indicating AA, stroke width & cap
|
||||
* @param transform The transform the points will be drawn with, used to drive stretch-aware path
|
||||
* @param transform The transform the points will be drawn with, used to drive stretch-aware
|
||||
* path
|
||||
* vertex approximation, and correct AA ramp offsetting
|
||||
* @param vertexBuffer The output buffer
|
||||
*/
|
||||
static void tessellateLines(const float* points, int count, const SkPaint* paint,
|
||||
const mat4& transform, VertexBuffer& vertexBuffer);
|
||||
const mat4& transform, VertexBuffer& vertexBuffer);
|
||||
|
||||
/**
|
||||
* Approximates a convex outline into a clockwise Vector of 2d vertices.
|
||||
@@ -112,38 +114,35 @@ public:
|
||||
* @param threshold The threshold of acceptable error (in pixels) when approximating
|
||||
* @param outputVertices An empty Vector which will be populated with the output
|
||||
*/
|
||||
static bool approximatePathOutlineVertices(const SkPath &path, float threshold,
|
||||
std::vector<Vertex> &outputVertices);
|
||||
static bool approximatePathOutlineVertices(const SkPath& path, float threshold,
|
||||
std::vector<Vertex>& outputVertices);
|
||||
|
||||
private:
|
||||
static bool approximatePathOutlineVertices(const SkPath &path, bool forceClose,
|
||||
const PathApproximationInfo& approximationInfo, std::vector<Vertex> &outputVertices);
|
||||
static bool approximatePathOutlineVertices(const SkPath& path, bool forceClose,
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex>& outputVertices);
|
||||
|
||||
/*
|
||||
endpoints a & b,
|
||||
control c
|
||||
*/
|
||||
static void recursiveQuadraticBezierVertices(
|
||||
float ax, float ay,
|
||||
float bx, float by,
|
||||
float cx, float cy,
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex> &outputVertices, int depth = 0);
|
||||
/*
|
||||
endpoints a & b,
|
||||
control c
|
||||
*/
|
||||
static void recursiveQuadraticBezierVertices(float ax, float ay, float bx, float by, float cx,
|
||||
float cy,
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex>& outputVertices,
|
||||
int depth = 0);
|
||||
|
||||
/*
|
||||
endpoints p1, p2
|
||||
control c1, c2
|
||||
*/
|
||||
static void recursiveCubicBezierVertices(
|
||||
float p1x, float p1y,
|
||||
float c1x, float c1y,
|
||||
float p2x, float p2y,
|
||||
float c2x, float c2y,
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex> &outputVertices, int depth = 0);
|
||||
/*
|
||||
endpoints p1, p2
|
||||
control c1, c2
|
||||
*/
|
||||
static void recursiveCubicBezierVertices(float p1x, float p1y, float c1x, float c1y, float p2x,
|
||||
float p2y, float c2x, float c2y,
|
||||
const PathApproximationInfo& approximationInfo,
|
||||
std::vector<Vertex>& outputVertices, int depth = 0);
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_PATH_TESSELLATOR_H
|
||||
#endif // ANDROID_HWUI_PATH_TESSELLATOR_H
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace uirenderer {
|
||||
// CPU pixel buffer
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CpuPixelBuffer: public PixelBuffer {
|
||||
class CpuPixelBuffer : public PixelBuffer {
|
||||
public:
|
||||
CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
|
||||
|
||||
@@ -48,8 +48,7 @@ private:
|
||||
|
||||
CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
|
||||
: PixelBuffer(format, width, height)
|
||||
, mBuffer(new uint8_t[width * height * formatSize(format)]) {
|
||||
}
|
||||
, mBuffer(new uint8_t[width * height * formatSize(format)]) {}
|
||||
|
||||
uint8_t* CpuPixelBuffer::map(AccessMode mode) {
|
||||
if (mAccessMode == kAccessMode_None) {
|
||||
@@ -63,15 +62,15 @@ void CpuPixelBuffer::unmap() {
|
||||
}
|
||||
|
||||
void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
|
||||
mFormat, GL_UNSIGNED_BYTE, &mBuffer[offset]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE,
|
||||
&mBuffer[offset]);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GPU pixel buffer
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GpuPixelBuffer: public PixelBuffer {
|
||||
class GpuPixelBuffer : public PixelBuffer {
|
||||
public:
|
||||
GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
|
||||
~GpuPixelBuffer();
|
||||
@@ -89,11 +88,10 @@ private:
|
||||
Caches& mCaches;
|
||||
};
|
||||
|
||||
GpuPixelBuffer::GpuPixelBuffer(GLenum format,
|
||||
uint32_t width, uint32_t height)
|
||||
GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
|
||||
: PixelBuffer(format, width, height)
|
||||
, mMappedPointer(nullptr)
|
||||
, mCaches(Caches::getInstance()){
|
||||
, mCaches(Caches::getInstance()) {
|
||||
glGenBuffers(1, &mBuffer);
|
||||
|
||||
mCaches.pixelBufferState().bind(mBuffer);
|
||||
@@ -108,7 +106,7 @@ GpuPixelBuffer::~GpuPixelBuffer() {
|
||||
uint8_t* GpuPixelBuffer::map(AccessMode mode) {
|
||||
if (mAccessMode == kAccessMode_None) {
|
||||
mCaches.pixelBufferState().bind(mBuffer);
|
||||
mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
|
||||
mMappedPointer = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
|
||||
if (CC_UNLIKELY(!mMappedPointer)) {
|
||||
GLUtils::dumpGLErrors();
|
||||
LOG_ALWAYS_FATAL("Failed to map PBO");
|
||||
@@ -138,8 +136,8 @@ void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t hei
|
||||
// If the buffer is not mapped, unmap() will not bind it
|
||||
mCaches.pixelBufferState().bind(mBuffer);
|
||||
unmap();
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
|
||||
GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE,
|
||||
reinterpret_cast<void*>(offset));
|
||||
mCaches.pixelBufferState().unbind();
|
||||
}
|
||||
|
||||
@@ -147,13 +145,12 @@ void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t hei
|
||||
// Factory
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PixelBuffer* PixelBuffer::create(GLenum format,
|
||||
uint32_t width, uint32_t height, BufferType type) {
|
||||
PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
|
||||
if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
|
||||
return new GpuPixelBuffer(format, width, height);
|
||||
}
|
||||
return new CpuPixelBuffer(format, width, height);
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -45,10 +45,7 @@ namespace uirenderer {
|
||||
*/
|
||||
class PixelBuffer {
|
||||
public:
|
||||
enum BufferType {
|
||||
kBufferType_Auto,
|
||||
kBufferType_CPU
|
||||
};
|
||||
enum BufferType { kBufferType_Auto, kBufferType_CPU };
|
||||
|
||||
enum AccessMode {
|
||||
kAccessMode_None = 0,
|
||||
@@ -66,17 +63,14 @@ public:
|
||||
* a CPU or GPU buffer.
|
||||
*/
|
||||
static PixelBuffer* create(GLenum format, uint32_t width, uint32_t height,
|
||||
BufferType type = kBufferType_Auto);
|
||||
BufferType type = kBufferType_Auto);
|
||||
|
||||
virtual ~PixelBuffer() {
|
||||
}
|
||||
virtual ~PixelBuffer() {}
|
||||
|
||||
/**
|
||||
* Returns the format of this render buffer.
|
||||
*/
|
||||
GLenum getFormat() const {
|
||||
return mFormat;
|
||||
}
|
||||
GLenum getFormat() const { return mFormat; }
|
||||
|
||||
/**
|
||||
* Maps this before with the specified access mode. This method
|
||||
@@ -95,9 +89,7 @@ public:
|
||||
* Returns the current access mode for this buffer. If the buffer
|
||||
* is not mapped, this method returns kAccessMode_None.
|
||||
*/
|
||||
AccessMode getAccessMode() const {
|
||||
return mAccessMode;
|
||||
}
|
||||
AccessMode getAccessMode() const { return mAccessMode; }
|
||||
|
||||
/**
|
||||
* Upload the specified rectangle of this pixel buffer as a
|
||||
@@ -121,23 +113,17 @@ public:
|
||||
/**
|
||||
* Returns the width of the render buffer in pixels.
|
||||
*/
|
||||
uint32_t getWidth() const {
|
||||
return mWidth;
|
||||
}
|
||||
uint32_t getWidth() const { return mWidth; }
|
||||
|
||||
/**
|
||||
* Returns the height of the render buffer in pixels.
|
||||
*/
|
||||
uint32_t getHeight() const {
|
||||
return mHeight;
|
||||
}
|
||||
uint32_t getHeight() const { return mHeight; }
|
||||
|
||||
/**
|
||||
* Returns the size of this pixel buffer in bytes.
|
||||
*/
|
||||
uint32_t getSize() const {
|
||||
return mWidth * mHeight * formatSize(mFormat);
|
||||
}
|
||||
uint32_t getSize() const { return mWidth * mHeight * formatSize(mFormat); }
|
||||
|
||||
/**
|
||||
* Returns the offset of a pixel in this pixel buffer, in bytes.
|
||||
@@ -178,7 +164,7 @@ public:
|
||||
return 3;
|
||||
}
|
||||
|
||||
ALOGE("unsupported format: %d",format);
|
||||
ALOGE("unsupported format: %d", format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -187,9 +173,8 @@ protected:
|
||||
* Creates a new render buffer in the specified format and dimensions.
|
||||
* The format must be GL_ALPHA or GL_RGBA.
|
||||
*/
|
||||
PixelBuffer(GLenum format, uint32_t width, uint32_t height):
|
||||
mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {
|
||||
}
|
||||
PixelBuffer(GLenum format, uint32_t width, uint32_t height)
|
||||
: mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {}
|
||||
|
||||
/**
|
||||
* Unmaps this buffer, if needed. After the buffer is unmapped,
|
||||
@@ -205,9 +190,9 @@ protected:
|
||||
|
||||
AccessMode mAccessMode;
|
||||
|
||||
}; // class PixelBuffer
|
||||
}; // class PixelBuffer
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_PIXEL_BUFFER_H
|
||||
#endif // ANDROID_HWUI_PIXEL_BUFFER_H
|
||||
|
||||
@@ -22,11 +22,8 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
static const char* JANK_TYPE_NAMES[] = {
|
||||
"Missed Vsync",
|
||||
"High input latency",
|
||||
"Slow UI thread",
|
||||
"Slow bitmap uploads",
|
||||
"Slow issue draw commands",
|
||||
"Missed Vsync", "High input latency", "Slow UI thread",
|
||||
"Slow bitmap uploads", "Slow issue draw commands",
|
||||
};
|
||||
|
||||
// The bucketing algorithm controls so to speak
|
||||
@@ -54,10 +51,8 @@ static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime) {
|
||||
// index = threshold + (amountAboveThreshold / 2)
|
||||
// However if index is <= this will do nothing. It will underflow, do
|
||||
// a right shift by 0 (no-op), then overflow back to the original value
|
||||
index = ((index - kBucket4msIntervals) >> (index > kBucket4msIntervals))
|
||||
+ kBucket4msIntervals;
|
||||
index = ((index - kBucket2msIntervals) >> (index > kBucket2msIntervals))
|
||||
+ kBucket2msIntervals;
|
||||
index = ((index - kBucket4msIntervals) >> (index > kBucket4msIntervals)) + kBucket4msIntervals;
|
||||
index = ((index - kBucket2msIntervals) >> (index > kBucket2msIntervals)) + kBucket2msIntervals;
|
||||
// If index was < minThreshold at the start of all this it's going to
|
||||
// be a pretty garbage value right now. However, mask is 0 so we'll end
|
||||
// up with the desired result of 0.
|
||||
@@ -101,8 +96,7 @@ void ProfileData::mergeWith(const ProfileData& other) {
|
||||
mJankFrameCount += other.mJankFrameCount;
|
||||
mTotalFrameCount >>= divider;
|
||||
mTotalFrameCount += other.mTotalFrameCount;
|
||||
if (mStatStartTime > other.mStatStartTime
|
||||
|| mStatStartTime == 0) {
|
||||
if (mStatStartTime > other.mStatStartTime || mStatStartTime == 0) {
|
||||
mStatStartTime = other.mStatStartTime;
|
||||
}
|
||||
}
|
||||
@@ -111,7 +105,7 @@ void ProfileData::dump(int fd) const {
|
||||
dprintf(fd, "\nStats since: %" PRIu64 "ns", mStatStartTime);
|
||||
dprintf(fd, "\nTotal frames rendered: %u", mTotalFrameCount);
|
||||
dprintf(fd, "\nJanky frames: %u (%.2f%%)", mJankFrameCount,
|
||||
(float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
|
||||
(float)mJankFrameCount / (float)mTotalFrameCount * 100.0f);
|
||||
dprintf(fd, "\n50th percentile: %ums", findPercentile(50));
|
||||
dprintf(fd, "\n90th percentile: %ums", findPercentile(90));
|
||||
dprintf(fd, "\n95th percentile: %ums", findPercentile(95));
|
||||
|
||||
@@ -70,8 +70,8 @@ public:
|
||||
void histogramForEach(const std::function<void(HistogramEntry)>& callback) const;
|
||||
|
||||
constexpr static int HistogramSize() {
|
||||
return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value
|
||||
+ std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value;
|
||||
return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value +
|
||||
std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value;
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
// Open our guts up to unit tests
|
||||
friend class MockProfileData;
|
||||
|
||||
std::array <uint32_t, NUM_BUCKETS> mJankTypeCounts;
|
||||
std::array<uint32_t, NUM_BUCKETS> mJankTypeCounts;
|
||||
// See comments on kBucket* constants for what this holds
|
||||
std::array<uint32_t, 57> mFrameCounts;
|
||||
// Holds a histogram of frame times in 50ms increments from 150ms to 5s
|
||||
@@ -106,4 +106,3 @@ public:
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <log/log.h>
|
||||
#include <cutils/ashmem.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
@@ -52,21 +52,20 @@ void ProfileDataContainer::switchStorageToAshmem(int ashmemfd) {
|
||||
int regionSize = ashmem_get_size_region(ashmemfd);
|
||||
if (regionSize < 0) {
|
||||
int err = errno;
|
||||
ALOGW("Failed to get ashmem region size from fd %d, err %d %s", ashmemfd, err, strerror(err));
|
||||
ALOGW("Failed to get ashmem region size from fd %d, err %d %s", ashmemfd, err,
|
||||
strerror(err));
|
||||
return;
|
||||
}
|
||||
if (regionSize < static_cast<int>(sizeof(ProfileData))) {
|
||||
ALOGW("Ashmem region is too small! Received %d, required %u",
|
||||
regionSize, static_cast<unsigned int>(sizeof(ProfileData)));
|
||||
ALOGW("Ashmem region is too small! Received %d, required %u", regionSize,
|
||||
static_cast<unsigned int>(sizeof(ProfileData)));
|
||||
return;
|
||||
}
|
||||
ProfileData* newData = reinterpret_cast<ProfileData*>(
|
||||
mmap(NULL, sizeof(ProfileData), PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, ashmemfd, 0));
|
||||
mmap(NULL, sizeof(ProfileData), PROT_READ | PROT_WRITE, MAP_SHARED, ashmemfd, 0));
|
||||
if (newData == MAP_FAILED) {
|
||||
int err = errno;
|
||||
ALOGW("Failed to move profile data to ashmem fd %d, error = %d",
|
||||
ashmemfd, err);
|
||||
ALOGW("Failed to move profile data to ashmem fd %d, error = %d", ashmemfd, err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace uirenderer {
|
||||
|
||||
class ProfileDataContainer {
|
||||
PREVENT_COPY_AND_ASSIGN(ProfileDataContainer);
|
||||
|
||||
public:
|
||||
explicit ProfileDataContainer() {}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
void ProfileRenderer::drawRect(float left, float top, float right, float bottom,
|
||||
const SkPaint& paint) {
|
||||
const SkPaint& paint) {
|
||||
mRenderer.drawRect(left, top, right, bottom, &paint);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,7 @@ namespace uirenderer {
|
||||
|
||||
class ProfileRenderer : public IProfileRenderer {
|
||||
public:
|
||||
ProfileRenderer(BakedOpRenderer& renderer)
|
||||
: mRenderer(renderer) {
|
||||
}
|
||||
ProfileRenderer(BakedOpRenderer& renderer) : mRenderer(renderer) {}
|
||||
|
||||
void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
|
||||
void drawRects(const float* rects, int count, const SkPaint& paint) override;
|
||||
|
||||
@@ -151,7 +151,7 @@ GLuint Program::buildShader(const char* source, GLenum type) {
|
||||
}
|
||||
|
||||
void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
|
||||
const mat4& transformMatrix, bool offset) {
|
||||
const mat4& transformMatrix, bool offset) {
|
||||
if (projectionMatrix != mProjection || offset != mOffset) {
|
||||
if (CC_LIKELY(!offset)) {
|
||||
glUniformMatrix4fv(projection, 1, GL_FALSE, &projectionMatrix.data[0]);
|
||||
@@ -195,5 +195,5 @@ void Program::remove() {
|
||||
mUse = false;
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -39,25 +39,25 @@ namespace uirenderer {
|
||||
|
||||
// Debug
|
||||
#if DEBUG_PROGRAMS
|
||||
#define PROGRAM_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#define PROGRAM_LOGD(...) ALOGD(__VA_ARGS__)
|
||||
#else
|
||||
#define PROGRAM_LOGD(...)
|
||||
#define PROGRAM_LOGD(...)
|
||||
#endif
|
||||
|
||||
#define COLOR_COMPONENT_THRESHOLD 1.0f
|
||||
#define COLOR_COMPONENT_INV_THRESHOLD 0.0f
|
||||
|
||||
#define PROGRAM_KEY_TEXTURE 0x01
|
||||
#define PROGRAM_KEY_A8_TEXTURE 0x02
|
||||
#define PROGRAM_KEY_BITMAP 0x04
|
||||
#define PROGRAM_KEY_GRADIENT 0x08
|
||||
#define PROGRAM_KEY_BITMAP_FIRST 0x10
|
||||
#define PROGRAM_KEY_COLOR_MATRIX 0x20
|
||||
#define PROGRAM_KEY_COLOR_BLEND 0x40
|
||||
#define PROGRAM_KEY_BITMAP_NPOT 0x80
|
||||
#define PROGRAM_KEY_BITMAP_EXTERNAL 0x100
|
||||
#define PROGRAM_KEY_TEXTURE 0x01
|
||||
#define PROGRAM_KEY_A8_TEXTURE 0x02
|
||||
#define PROGRAM_KEY_BITMAP 0x04
|
||||
#define PROGRAM_KEY_GRADIENT 0x08
|
||||
#define PROGRAM_KEY_BITMAP_FIRST 0x10
|
||||
#define PROGRAM_KEY_COLOR_MATRIX 0x20
|
||||
#define PROGRAM_KEY_COLOR_BLEND 0x40
|
||||
#define PROGRAM_KEY_BITMAP_NPOT 0x80
|
||||
#define PROGRAM_KEY_BITMAP_EXTERNAL 0x100
|
||||
|
||||
#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
|
||||
#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
|
||||
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
|
||||
|
||||
#define PROGRAM_KEY_SWAP_SRC_DST_SHIFT 13
|
||||
@@ -71,7 +71,7 @@ namespace uirenderer {
|
||||
#define PROGRAM_BITMAP_WRAPS_SHIFT 9
|
||||
#define PROGRAM_BITMAP_WRAPT_SHIFT 11
|
||||
|
||||
#define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type
|
||||
#define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type
|
||||
#define PROGRAM_MODULATE_SHIFT 35
|
||||
|
||||
#define PROGRAM_HAS_VERTEX_ALPHA_SHIFT 36
|
||||
@@ -91,7 +91,7 @@ namespace uirenderer {
|
||||
#define PROGRAM_HAS_LINEAR_TEXTURE 45
|
||||
|
||||
#define PROGRAM_HAS_COLOR_SPACE_CONVERSION 46
|
||||
#define PROGRAM_TRANSFER_FUNCTION 47 // 2 bits for transfer function
|
||||
#define PROGRAM_TRANSFER_FUNCTION 47 // 2 bits for transfer function
|
||||
#define PROGRAM_HAS_TRANSLUCENT_CONVERSION 49
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -110,21 +110,11 @@ typedef uint64_t programid;
|
||||
* A ProgramDescription must be used in conjunction with a ProgramCache.
|
||||
*/
|
||||
struct ProgramDescription {
|
||||
enum class ColorFilterMode : int8_t {
|
||||
None = 0,
|
||||
Matrix,
|
||||
Blend
|
||||
};
|
||||
enum class ColorFilterMode : int8_t { None = 0, Matrix, Blend };
|
||||
|
||||
enum Gradient : int8_t {
|
||||
kGradientLinear = 0,
|
||||
kGradientCircular,
|
||||
kGradientSweep
|
||||
};
|
||||
enum Gradient : int8_t { kGradientLinear = 0, kGradientCircular, kGradientSweep };
|
||||
|
||||
ProgramDescription() {
|
||||
reset();
|
||||
}
|
||||
ProgramDescription() { reset(); }
|
||||
|
||||
// Texturing
|
||||
bool hasTexture;
|
||||
@@ -243,7 +233,7 @@ struct ProgramDescription {
|
||||
*/
|
||||
bool setAlpha8ColorModulate(const float r, const float g, const float b, const float a) {
|
||||
modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
|
||||
g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
|
||||
g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
|
||||
return modulate;
|
||||
}
|
||||
|
||||
@@ -277,12 +267,12 @@ struct ProgramDescription {
|
||||
break;
|
||||
case ColorFilterMode::Blend:
|
||||
key |= PROGRAM_KEY_COLOR_BLEND;
|
||||
key |= ((int) colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
|
||||
key |= ((int)colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
|
||||
break;
|
||||
case ColorFilterMode::None:
|
||||
break;
|
||||
}
|
||||
key |= ((int) framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
|
||||
key |= ((int)framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
|
||||
key |= programid(swapSrcDst) << PROGRAM_KEY_SWAP_SRC_DST_SHIFT;
|
||||
key |= programid(modulate) << PROGRAM_MODULATE_SHIFT;
|
||||
key |= programid(hasVertexAlpha) << PROGRAM_HAS_VERTEX_ALPHA_SHIFT;
|
||||
@@ -307,8 +297,7 @@ struct ProgramDescription {
|
||||
void log(const char* message) const {
|
||||
#if DEBUG_PROGRAMS
|
||||
programid k = key();
|
||||
PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
|
||||
uint32_t(k & 0xffffffff));
|
||||
PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32), uint32_t(k & 0xffffffff));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -325,7 +314,7 @@ private:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}; // struct ProgramDescription
|
||||
}; // struct ProgramDescription
|
||||
|
||||
/**
|
||||
* A program holds a vertex and a fragment shader. It offers several utility
|
||||
@@ -333,10 +322,7 @@ private:
|
||||
*/
|
||||
class Program {
|
||||
public:
|
||||
enum ShaderBindings {
|
||||
kBindingPosition,
|
||||
kBindingTexCoords
|
||||
};
|
||||
enum ShaderBindings { kBindingPosition, kBindingTexCoords };
|
||||
|
||||
/**
|
||||
* Creates a new program with the specified vertex and fragment
|
||||
@@ -370,23 +356,19 @@ public:
|
||||
* Indicates whether this program is currently in use with
|
||||
* the GL context.
|
||||
*/
|
||||
inline bool isInUse() const {
|
||||
return mUse;
|
||||
}
|
||||
inline bool isInUse() const { return mUse; }
|
||||
|
||||
/**
|
||||
* Indicates whether this program was correctly compiled and linked.
|
||||
*/
|
||||
inline bool isInitialized() const {
|
||||
return mInitialized;
|
||||
}
|
||||
inline bool isInitialized() const { return mInitialized; }
|
||||
|
||||
/**
|
||||
* Binds the program with the specified projection, modelView and
|
||||
* transform matrices.
|
||||
*/
|
||||
void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
|
||||
const mat4& transformMatrix, bool offset = false);
|
||||
void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, const mat4& transformMatrix,
|
||||
bool offset = false);
|
||||
|
||||
/**
|
||||
* Sets the color associated with this shader.
|
||||
@@ -456,9 +438,9 @@ private:
|
||||
|
||||
mat4 mProjection;
|
||||
bool mOffset;
|
||||
}; // class Program
|
||||
}; // class Program
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_PROGRAM_H
|
||||
#endif // ANDROID_HWUI_PROGRAM_H
|
||||
|
||||
@@ -41,19 +41,14 @@ namespace uirenderer {
|
||||
const char* gVS_Header_Start =
|
||||
"#version 100\n"
|
||||
"attribute vec4 position;\n";
|
||||
const char* gVS_Header_Attributes_TexCoords =
|
||||
"attribute vec2 texCoords;\n";
|
||||
const char* gVS_Header_Attributes_Colors =
|
||||
"attribute vec4 colors;\n";
|
||||
const char* gVS_Header_Attributes_VertexAlphaParameters =
|
||||
"attribute float vtxAlpha;\n";
|
||||
const char* gVS_Header_Uniforms_TextureTransform =
|
||||
"uniform mat4 mainTextureTransform;\n";
|
||||
const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n";
|
||||
const char* gVS_Header_Attributes_Colors = "attribute vec4 colors;\n";
|
||||
const char* gVS_Header_Attributes_VertexAlphaParameters = "attribute float vtxAlpha;\n";
|
||||
const char* gVS_Header_Uniforms_TextureTransform = "uniform mat4 mainTextureTransform;\n";
|
||||
const char* gVS_Header_Uniforms =
|
||||
"uniform mat4 projection;\n" \
|
||||
"uniform mat4 projection;\n"
|
||||
"uniform mat4 transform;\n";
|
||||
const char* gVS_Header_Uniforms_HasGradient =
|
||||
"uniform mat4 screenSpace;\n";
|
||||
const char* gVS_Header_Uniforms_HasGradient = "uniform mat4 screenSpace;\n";
|
||||
const char* gVS_Header_Uniforms_HasBitmap =
|
||||
"uniform mat4 textureTransform;\n"
|
||||
"uniform mediump vec2 textureDimension;\n";
|
||||
@@ -61,35 +56,24 @@ const char* gVS_Header_Uniforms_HasRoundRectClip =
|
||||
"uniform mat4 roundRectInvTransform;\n"
|
||||
"uniform mediump vec4 roundRectInnerRectLTWH;\n"
|
||||
"uniform mediump float roundRectRadius;\n";
|
||||
const char* gVS_Header_Varyings_HasTexture =
|
||||
"varying vec2 outTexCoords;\n";
|
||||
const char* gVS_Header_Varyings_HasColors =
|
||||
"varying vec4 outColors;\n";
|
||||
const char* gVS_Header_Varyings_HasVertexAlpha =
|
||||
"varying float alpha;\n";
|
||||
const char* gVS_Header_Varyings_HasBitmap =
|
||||
"varying highp vec2 outBitmapTexCoords;\n";
|
||||
const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n";
|
||||
const char* gVS_Header_Varyings_HasColors = "varying vec4 outColors;\n";
|
||||
const char* gVS_Header_Varyings_HasVertexAlpha = "varying float alpha;\n";
|
||||
const char* gVS_Header_Varyings_HasBitmap = "varying highp vec2 outBitmapTexCoords;\n";
|
||||
const char* gVS_Header_Varyings_HasGradient[6] = {
|
||||
// Linear
|
||||
"varying highp vec2 linear;\n",
|
||||
"varying float linear;\n",
|
||||
"varying highp vec2 linear;\n", "varying float linear;\n",
|
||||
|
||||
// Circular
|
||||
"varying highp vec2 circular;\n",
|
||||
"varying highp vec2 circular;\n",
|
||||
"varying highp vec2 circular;\n", "varying highp vec2 circular;\n",
|
||||
|
||||
// Sweep
|
||||
"varying highp vec2 sweep;\n",
|
||||
"varying highp vec2 sweep;\n",
|
||||
"varying highp vec2 sweep;\n", "varying highp vec2 sweep;\n",
|
||||
};
|
||||
const char* gVS_Header_Varyings_HasRoundRectClip =
|
||||
"varying mediump vec2 roundRectPos;\n";
|
||||
const char* gVS_Main =
|
||||
"\nvoid main(void) {\n";
|
||||
const char* gVS_Main_OutTexCoords =
|
||||
" outTexCoords = texCoords;\n";
|
||||
const char* gVS_Main_OutColors =
|
||||
" outColors = colors;\n";
|
||||
const char* gVS_Header_Varyings_HasRoundRectClip = "varying mediump vec2 roundRectPos;\n";
|
||||
const char* gVS_Main = "\nvoid main(void) {\n";
|
||||
const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n";
|
||||
const char* gVS_Main_OutColors = " outColors = colors;\n";
|
||||
const char* gVS_Main_OutTransformedTexCoords =
|
||||
" outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
|
||||
const char* gVS_Main_OutGradient[6] = {
|
||||
@@ -102,53 +86,42 @@ const char* gVS_Main_OutGradient[6] = {
|
||||
" circular = (screenSpace * position).xy;\n",
|
||||
|
||||
// Sweep
|
||||
" sweep = (screenSpace * position).xy;\n",
|
||||
" sweep = (screenSpace * position).xy;\n"
|
||||
};
|
||||
" sweep = (screenSpace * position).xy;\n", " sweep = (screenSpace * position).xy;\n"};
|
||||
const char* gVS_Main_OutBitmapTexCoords =
|
||||
" outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
|
||||
const char* gVS_Main_Position =
|
||||
" vec4 transformedPosition = projection * transform * position;\n"
|
||||
" gl_Position = transformedPosition;\n";
|
||||
|
||||
const char* gVS_Main_VertexAlpha =
|
||||
" alpha = vtxAlpha;\n";
|
||||
const char* gVS_Main_VertexAlpha = " alpha = vtxAlpha;\n";
|
||||
|
||||
const char* gVS_Main_HasRoundRectClip =
|
||||
" roundRectPos = ((roundRectInvTransform * transformedPosition).xy / roundRectRadius) - roundRectInnerRectLTWH.xy;\n";
|
||||
const char* gVS_Footer =
|
||||
"}\n\n";
|
||||
" roundRectPos = ((roundRectInvTransform * transformedPosition).xy / roundRectRadius) - "
|
||||
"roundRectInnerRectLTWH.xy;\n";
|
||||
const char* gVS_Footer = "}\n\n";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Fragment shaders snippets
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const char* gFS_Header_Start =
|
||||
"#version 100\n";
|
||||
const char* gFS_Header_Start = "#version 100\n";
|
||||
const char* gFS_Header_Extension_FramebufferFetch =
|
||||
"#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
|
||||
const char* gFS_Header_Extension_ExternalTexture =
|
||||
"#extension GL_OES_EGL_image_external : require\n\n";
|
||||
const char* gFS_Header =
|
||||
"precision mediump float;\n\n";
|
||||
const char* gFS_Uniforms_Color =
|
||||
"uniform vec4 color;\n";
|
||||
const char* gFS_Uniforms_TextureSampler =
|
||||
"uniform sampler2D baseSampler;\n";
|
||||
const char* gFS_Uniforms_ExternalTextureSampler =
|
||||
"uniform samplerExternalOES baseSampler;\n";
|
||||
const char* gFS_Header = "precision mediump float;\n\n";
|
||||
const char* gFS_Uniforms_Color = "uniform vec4 color;\n";
|
||||
const char* gFS_Uniforms_TextureSampler = "uniform sampler2D baseSampler;\n";
|
||||
const char* gFS_Uniforms_ExternalTextureSampler = "uniform samplerExternalOES baseSampler;\n";
|
||||
const char* gFS_Uniforms_GradientSampler[2] = {
|
||||
"uniform vec2 screenSize;\n"
|
||||
"uniform sampler2D gradientSampler;\n",
|
||||
|
||||
"uniform vec2 screenSize;\n"
|
||||
"uniform vec4 startColor;\n"
|
||||
"uniform vec4 endColor;\n"
|
||||
};
|
||||
const char* gFS_Uniforms_BitmapSampler =
|
||||
"uniform sampler2D bitmapSampler;\n";
|
||||
const char* gFS_Uniforms_BitmapExternalSampler =
|
||||
"uniform samplerExternalOES bitmapSampler;\n";
|
||||
"uniform vec4 endColor;\n"};
|
||||
const char* gFS_Uniforms_BitmapSampler = "uniform sampler2D bitmapSampler;\n";
|
||||
const char* gFS_Uniforms_BitmapExternalSampler = "uniform samplerExternalOES bitmapSampler;\n";
|
||||
const char* gFS_Uniforms_ColorOp[3] = {
|
||||
// None
|
||||
"",
|
||||
@@ -156,8 +129,7 @@ const char* gFS_Uniforms_ColorOp[3] = {
|
||||
"uniform mat4 colorMatrix;\n"
|
||||
"uniform vec4 colorMatrixVector;\n",
|
||||
// PorterDuff
|
||||
"uniform vec4 colorBlend;\n"
|
||||
};
|
||||
"uniform vec4 colorBlend;\n"};
|
||||
|
||||
const char* gFS_Uniforms_HasRoundRectClip =
|
||||
"uniform mediump vec4 roundRectInnerRectLTWH;\n"
|
||||
@@ -172,11 +144,8 @@ const char* gFS_Uniforms_TransferFunction[4] = {
|
||||
// In this order: g, a, b, c, d, e, f
|
||||
// See ColorSpace::TransferParameters
|
||||
// We'll use hardware sRGB conversion as much as possible
|
||||
"",
|
||||
"uniform float transferFunction[7];\n",
|
||||
"uniform float transferFunction[5];\n",
|
||||
"uniform float transferFunctionGamma;\n"
|
||||
};
|
||||
"", "uniform float transferFunction[7];\n", "uniform float transferFunction[5];\n",
|
||||
"uniform float transferFunctionGamma;\n"};
|
||||
|
||||
const char* gFS_OETF[2] = {
|
||||
R"__SHADER__(
|
||||
@@ -189,8 +158,7 @@ const char* gFS_OETF[2] = {
|
||||
vec4 OETF(const vec4 linear) {
|
||||
return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);
|
||||
}
|
||||
)__SHADER__"
|
||||
};
|
||||
)__SHADER__"};
|
||||
|
||||
const char* gFS_ColorConvert[3] = {
|
||||
// Just OETF
|
||||
@@ -274,8 +242,7 @@ const char* gFS_TransferFunction[4] = {
|
||||
pow(x.g, transferFunctionGamma),
|
||||
pow(x.b, transferFunctionGamma));
|
||||
}
|
||||
)__SHADER__"
|
||||
};
|
||||
)__SHADER__"};
|
||||
|
||||
// Dithering must be done in the quantization space
|
||||
// When we are writing to an sRGB framebuffer, we must do the following:
|
||||
@@ -327,16 +294,12 @@ const char* gFS_Main =
|
||||
"\nvoid main(void) {\n"
|
||||
" vec4 fragColor;\n";
|
||||
|
||||
const char* gFS_Main_AddDither =
|
||||
" fragColor = dither(fragColor);\n";
|
||||
const char* gFS_Main_AddDither = " fragColor = dither(fragColor);\n";
|
||||
|
||||
// General case
|
||||
const char* gFS_Main_FetchColor =
|
||||
" fragColor = color;\n";
|
||||
const char* gFS_Main_ModulateColor =
|
||||
" fragColor *= color.a;\n";
|
||||
const char* gFS_Main_ApplyVertexAlphaLinearInterp =
|
||||
" fragColor *= alpha;\n";
|
||||
const char* gFS_Main_FetchColor = " fragColor = color;\n";
|
||||
const char* gFS_Main_ModulateColor = " fragColor *= color.a;\n";
|
||||
const char* gFS_Main_ApplyVertexAlphaLinearInterp = " fragColor *= alpha;\n";
|
||||
const char* gFS_Main_ApplyVertexAlphaShadowInterp =
|
||||
// map alpha through shadow alpha sampler
|
||||
" fragColor *= texture2D(baseSampler, vec2(alpha, 0.5)).a;\n";
|
||||
@@ -344,8 +307,7 @@ const char* gFS_Main_FetchTexture[2] = {
|
||||
// Don't modulate
|
||||
" fragColor = colorConvert(texture2D(baseSampler, outTexCoords));\n",
|
||||
// Modulate
|
||||
" fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"
|
||||
};
|
||||
" fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"};
|
||||
const char* gFS_Main_FetchA8Texture[4] = {
|
||||
// Don't modulate
|
||||
" fragColor = texture2D(baseSampler, outTexCoords);\n",
|
||||
@@ -370,53 +332,46 @@ const char* gFS_Main_FetchGradient[6] = {
|
||||
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
|
||||
|
||||
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
|
||||
" vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
|
||||
};
|
||||
" vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, "
|
||||
"1.0));\n"};
|
||||
const char* gFS_Main_FetchBitmap =
|
||||
" vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n";
|
||||
const char* gFS_Main_FetchBitmapNpot =
|
||||
" vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, wrap(outBitmapTexCoords)));\n";
|
||||
const char* gFS_Main_BlendShadersBG =
|
||||
" fragColor = blendShaders(gradientColor, bitmapColor)";
|
||||
const char* gFS_Main_BlendShadersGB =
|
||||
" fragColor = blendShaders(bitmapColor, gradientColor)";
|
||||
" vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, "
|
||||
"wrap(outBitmapTexCoords)));\n";
|
||||
const char* gFS_Main_BlendShadersBG = " fragColor = blendShaders(gradientColor, bitmapColor)";
|
||||
const char* gFS_Main_BlendShadersGB = " fragColor = blendShaders(bitmapColor, gradientColor)";
|
||||
const char* gFS_Main_BlendShaders_Modulate[6] = {
|
||||
// Don't modulate
|
||||
";\n",
|
||||
";\n",
|
||||
";\n", ";\n",
|
||||
// Modulate
|
||||
" * color.a;\n",
|
||||
" * color.a;\n",
|
||||
" * color.a;\n", " * color.a;\n",
|
||||
// Modulate with alpha 8 texture
|
||||
" * texture2D(baseSampler, outTexCoords).a;\n",
|
||||
" * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n",
|
||||
};
|
||||
const char* gFS_Main_GradientShader_Modulate[6] = {
|
||||
// Don't modulate
|
||||
" fragColor = gradientColor;\n",
|
||||
" fragColor = gradientColor;\n",
|
||||
" fragColor = gradientColor;\n", " fragColor = gradientColor;\n",
|
||||
// Modulate
|
||||
" fragColor = gradientColor * color.a;\n",
|
||||
" fragColor = gradientColor * color.a;\n",
|
||||
" fragColor = gradientColor * color.a;\n", " fragColor = gradientColor * color.a;\n",
|
||||
// Modulate with alpha 8 texture
|
||||
" fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
|
||||
" fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, gradientColor.rgb);\n",
|
||||
};
|
||||
" fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, "
|
||||
"gradientColor.rgb);\n",
|
||||
};
|
||||
const char* gFS_Main_BitmapShader_Modulate[6] = {
|
||||
// Don't modulate
|
||||
" fragColor = bitmapColor;\n",
|
||||
" fragColor = bitmapColor;\n",
|
||||
" fragColor = bitmapColor;\n", " fragColor = bitmapColor;\n",
|
||||
// Modulate
|
||||
" fragColor = bitmapColor * color.a;\n",
|
||||
" fragColor = bitmapColor * color.a;\n",
|
||||
" fragColor = bitmapColor * color.a;\n", " fragColor = bitmapColor * color.a;\n",
|
||||
// Modulate with alpha 8 texture
|
||||
" fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
|
||||
" fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, bitmapColor.rgb);\n",
|
||||
};
|
||||
const char* gFS_Main_FragColor =
|
||||
" gl_FragColor = fragColor;\n";
|
||||
const char* gFS_Main_FragColor_HasColors =
|
||||
" gl_FragColor *= outColors;\n";
|
||||
" fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, "
|
||||
"bitmapColor.rgb);\n",
|
||||
};
|
||||
const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n";
|
||||
const char* gFS_Main_FragColor_HasColors = " gl_FragColor *= outColors;\n";
|
||||
const char* gFS_Main_FragColor_Blend =
|
||||
" gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
|
||||
const char* gFS_Main_FragColor_Blend_Swap =
|
||||
@@ -425,13 +380,12 @@ const char* gFS_Main_ApplyColorOp[3] = {
|
||||
// None
|
||||
"",
|
||||
// Matrix
|
||||
" fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply
|
||||
" fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply
|
||||
" fragColor *= colorMatrix;\n"
|
||||
" fragColor += colorMatrixVector;\n"
|
||||
" fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply
|
||||
" fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply
|
||||
// PorterDuff
|
||||
" fragColor = blendColors(colorBlend, fragColor);\n"
|
||||
};
|
||||
" fragColor = blendColors(colorBlend, fragColor);\n"};
|
||||
|
||||
// Note: LTWH (left top width height) -> xyzw
|
||||
// roundRectPos is now divided by roundRectRadius in vertex shader
|
||||
@@ -443,13 +397,12 @@ const char* gFS_Main_FragColor_HasRoundRectClip =
|
||||
// since distance is divided by radius, it's in [0;1] so precision is not an issue
|
||||
// this also lets us clamp(0.0, 1.0) instead of max() which is cheaper on GPUs
|
||||
" mediump vec2 dist = clamp(max(fragToLT, fragFromRB), 0.0, 1.0);\n"
|
||||
" mediump float linearDist = clamp(roundRectRadius - (length(dist) * roundRectRadius), 0.0, 1.0);\n"
|
||||
" mediump float linearDist = clamp(roundRectRadius - (length(dist) * roundRectRadius), "
|
||||
"0.0, 1.0);\n"
|
||||
" gl_FragColor *= linearDist;\n";
|
||||
|
||||
const char* gFS_Main_DebugHighlight =
|
||||
" gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
|
||||
const char* gFS_Footer =
|
||||
"}\n\n";
|
||||
const char* gFS_Main_DebugHighlight = " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
|
||||
const char* gFS_Footer = "}\n\n";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PorterDuff snippets
|
||||
@@ -480,7 +433,7 @@ const char* gBlendOps[18] = {
|
||||
"return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
|
||||
// Xor
|
||||
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
|
||||
"src.a + dst.a - 2.0 * src.a * dst.a);\n",
|
||||
"src.a + dst.a - 2.0 * src.a * dst.a);\n",
|
||||
// Plus
|
||||
"return min(src + dst, 1.0);\n",
|
||||
// Modulate
|
||||
@@ -489,16 +442,17 @@ const char* gBlendOps[18] = {
|
||||
"return src + dst - src * dst;\n",
|
||||
// Overlay
|
||||
"return clamp(vec4(mix("
|
||||
"2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
|
||||
"src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
|
||||
"step(dst.a, 2.0 * dst.rgb)), "
|
||||
"src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
|
||||
"2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
|
||||
"src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + "
|
||||
"dst.rgb * (1.0 - src.a), "
|
||||
"step(dst.a, 2.0 * dst.rgb)), "
|
||||
"src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
|
||||
// Darken
|
||||
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
|
||||
"min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
|
||||
"min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
|
||||
// Lighten
|
||||
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
|
||||
"max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
|
||||
"max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -507,8 +461,7 @@ const char* gBlendOps[18] = {
|
||||
|
||||
ProgramCache::ProgramCache(const Extensions& extensions)
|
||||
: mHasES3(extensions.getMajorGlVersion() >= 3)
|
||||
, mHasLinearBlending(extensions.hasLinearBlending()) {
|
||||
}
|
||||
, mHasLinearBlending(extensions.hasLinearBlending()) {}
|
||||
|
||||
ProgramCache::~ProgramCache() {
|
||||
clear();
|
||||
@@ -605,7 +558,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
|
||||
}
|
||||
|
||||
// Begin the shader
|
||||
shader.append(gVS_Main); {
|
||||
shader.append(gVS_Main);
|
||||
{
|
||||
if (description.hasTextureTransform) {
|
||||
shader.append(gVS_Main_OutTransformedTexCoords);
|
||||
} else if (description.hasTexture || description.hasExternalTexture) {
|
||||
@@ -637,8 +591,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
|
||||
return shader;
|
||||
}
|
||||
|
||||
static bool shaderOp(const ProgramDescription& description, String8& shader,
|
||||
const int modulateOp, const char** snippets) {
|
||||
static bool shaderOp(const ProgramDescription& description, String8& shader, const int modulateOp,
|
||||
const char** snippets) {
|
||||
int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
|
||||
op = op * 2 + description.hasGammaCorrection;
|
||||
shader.append(snippets[op]);
|
||||
@@ -652,8 +606,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
if (blendFramebuffer) {
|
||||
shader.append(gFS_Header_Extension_FramebufferFetch);
|
||||
}
|
||||
if (description.hasExternalTexture
|
||||
|| (description.hasBitmap && description.isShaderBitmapExternal)) {
|
||||
if (description.hasExternalTexture ||
|
||||
(description.hasBitmap && description.isShaderBitmapExternal)) {
|
||||
shader.append(gFS_Header_Extension_ExternalTexture);
|
||||
}
|
||||
|
||||
@@ -682,7 +636,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
// Uniforms
|
||||
int modulateOp = MODULATE_OP_NO_MODULATE;
|
||||
const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
|
||||
!description.hasGradient && !description.hasBitmap;
|
||||
!description.hasGradient && !description.hasBitmap;
|
||||
|
||||
if (description.modulate || singleColor) {
|
||||
shader.append(gFS_Uniforms_Color);
|
||||
@@ -701,7 +655,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
}
|
||||
|
||||
if (description.hasGammaCorrection) {
|
||||
shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma, 1.0f / Properties::textGamma);
|
||||
shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma,
|
||||
1.0f / Properties::textGamma);
|
||||
}
|
||||
|
||||
if (description.hasBitmap) {
|
||||
@@ -731,17 +686,19 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
if (description.useShaderBasedWrap) {
|
||||
generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
|
||||
}
|
||||
if (description.hasGradient || description.hasLinearTexture
|
||||
|| description.hasColorSpaceConversion) {
|
||||
if (description.hasGradient || description.hasLinearTexture ||
|
||||
description.hasColorSpaceConversion) {
|
||||
shader.append(gFS_sRGB_TransferFunctions);
|
||||
}
|
||||
if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) &&
|
||||
!description.hasAlpha8Texture)) {
|
||||
!description.hasAlpha8Texture)) {
|
||||
shader.append(gFS_TransferFunction[static_cast<int>(description.transferFunction)]);
|
||||
shader.append(gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion)
|
||||
&& !mHasLinearBlending]);
|
||||
shader.append(
|
||||
gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion) &&
|
||||
!mHasLinearBlending]);
|
||||
shader.append(gFS_ColorConvert[description.hasColorSpaceConversion
|
||||
? 1 + description.hasTranslucentConversion : 0]);
|
||||
? 1 + description.hasTranslucentConversion
|
||||
: 0]);
|
||||
}
|
||||
if (description.hasGradient) {
|
||||
shader.append(gFS_GradientFunctions);
|
||||
@@ -749,13 +706,14 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
}
|
||||
|
||||
// Begin the shader
|
||||
shader.append(gFS_Main); {
|
||||
shader.append(gFS_Main);
|
||||
{
|
||||
// Stores the result in fragColor directly
|
||||
if (description.hasTexture || description.hasExternalTexture) {
|
||||
if (description.hasAlpha8Texture) {
|
||||
if (!description.hasGradient && !description.hasBitmap) {
|
||||
shader.append(
|
||||
gFS_Main_FetchA8Texture[modulateOp * 2 + description.hasGammaCorrection]);
|
||||
shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
|
||||
description.hasGammaCorrection]);
|
||||
}
|
||||
} else {
|
||||
shader.append(gFS_Main_FetchTexture[modulateOp]);
|
||||
@@ -783,15 +741,15 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
} else {
|
||||
shader.append(gFS_Main_BlendShadersGB);
|
||||
}
|
||||
applyModulate = shaderOp(description, shader, modulateOp,
|
||||
gFS_Main_BlendShaders_Modulate);
|
||||
applyModulate =
|
||||
shaderOp(description, shader, modulateOp, gFS_Main_BlendShaders_Modulate);
|
||||
} else {
|
||||
if (description.hasGradient) {
|
||||
applyModulate = shaderOp(description, shader, modulateOp,
|
||||
gFS_Main_GradientShader_Modulate);
|
||||
applyModulate =
|
||||
shaderOp(description, shader, modulateOp, gFS_Main_GradientShader_Modulate);
|
||||
} else if (description.hasBitmap) {
|
||||
applyModulate = shaderOp(description, shader, modulateOp,
|
||||
gFS_Main_BitmapShader_Modulate);
|
||||
applyModulate =
|
||||
shaderOp(description, shader, modulateOp, gFS_Main_BitmapShader_Modulate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -818,8 +776,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
if (!blendFramebuffer) {
|
||||
shader.append(gFS_Main_FragColor);
|
||||
} else {
|
||||
shader.append(!description.swapSrcDst ?
|
||||
gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
|
||||
shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend
|
||||
: gFS_Main_FragColor_Blend_Swap);
|
||||
}
|
||||
if (description.hasColors) {
|
||||
shader.append(gFS_Main_FragColor_HasColors);
|
||||
@@ -835,8 +793,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
|
||||
shader.append(gFS_Footer);
|
||||
|
||||
#if DEBUG_PROGRAMS
|
||||
PROGRAM_LOGD("*** Generated fragment shader:\n\n");
|
||||
printLongString(shader);
|
||||
PROGRAM_LOGD("*** Generated fragment shader:\n\n");
|
||||
printLongString(shader);
|
||||
#endif
|
||||
|
||||
return shader;
|
||||
@@ -903,5 +861,5 @@ void ProgramCache::printLongString(const String8& shader) const {
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -60,9 +60,9 @@ private:
|
||||
|
||||
const bool mHasES3;
|
||||
const bool mHasLinearBlending;
|
||||
}; // class ProgramCache
|
||||
}; // class ProgramCache
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_HWUI_PROGRAM_CACHE_H
|
||||
#endif // ANDROID_HWUI_PROGRAM_CACHE_H
|
||||
|
||||
@@ -61,7 +61,9 @@ bool Properties::disableVsync = false;
|
||||
bool Properties::skpCaptureEnabled = false;
|
||||
|
||||
static int property_get_int(const char* key, int defaultValue) {
|
||||
char buf[PROPERTY_VALUE_MAX] = {'\0',};
|
||||
char buf[PROPERTY_VALUE_MAX] = {
|
||||
'\0',
|
||||
};
|
||||
|
||||
if (property_get(key, buf, "") > 0) {
|
||||
return atoi(buf);
|
||||
@@ -121,7 +123,7 @@ bool Properties::load() {
|
||||
|
||||
showDirtyRegions = property_get_bool(PROPERTY_DEBUG_SHOW_DIRTY_REGIONS, false);
|
||||
|
||||
debugLevel = (DebugLevel) property_get_int(PROPERTY_DEBUG, kDebugDisabled);
|
||||
debugLevel = (DebugLevel)property_get_int(PROPERTY_DEBUG, kDebugDisabled);
|
||||
|
||||
skipEmptyFrames = property_get_bool(PROPERTY_SKIP_EMPTY_DAMAGE, true);
|
||||
useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true);
|
||||
@@ -129,12 +131,11 @@ bool Properties::load() {
|
||||
|
||||
filterOutTestOverhead = property_get_bool(PROPERTY_FILTER_TEST_OVERHEAD, false);
|
||||
|
||||
skpCaptureEnabled = property_get_bool("ro.debuggable", false)
|
||||
&& property_get_bool(PROPERTY_CAPTURE_SKP_ENABLED, false);
|
||||
skpCaptureEnabled = property_get_bool("ro.debuggable", false) &&
|
||||
property_get_bool(PROPERTY_CAPTURE_SKP_ENABLED, false);
|
||||
|
||||
return (prevDebugLayersUpdates != debugLayersUpdates)
|
||||
|| (prevDebugOverdraw != debugOverdraw)
|
||||
|| (prevDebugStencilClip != debugStencilClip);
|
||||
return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
|
||||
(prevDebugStencilClip != debugStencilClip);
|
||||
}
|
||||
|
||||
void Properties::overrideProperty(const char* name, const char* value) {
|
||||
@@ -182,13 +183,13 @@ RenderPipelineType Properties::getRenderPipelineType() {
|
||||
}
|
||||
char prop[PROPERTY_VALUE_MAX];
|
||||
property_get(PROPERTY_RENDERER, prop, "skiagl");
|
||||
if (!strcmp(prop, "skiagl") ) {
|
||||
if (!strcmp(prop, "skiagl")) {
|
||||
ALOGD("Skia GL Pipeline");
|
||||
sRenderPipelineType = RenderPipelineType::SkiaGL;
|
||||
} else if (!strcmp(prop, "skiavk") ) {
|
||||
} else if (!strcmp(prop, "skiavk")) {
|
||||
ALOGD("Skia Vulkan Pipeline");
|
||||
sRenderPipelineType = RenderPipelineType::SkiaVulkan;
|
||||
} else { //"opengl"
|
||||
} else { //"opengl"
|
||||
ALOGD("HWUI GL Pipeline");
|
||||
sRenderPipelineType = RenderPipelineType::OpenGL;
|
||||
}
|
||||
@@ -203,9 +204,8 @@ void Properties::overrideRenderPipelineType(RenderPipelineType type) {
|
||||
|
||||
bool Properties::isSkiaEnabled() {
|
||||
auto renderType = getRenderPipelineType();
|
||||
return RenderPipelineType::SkiaGL == renderType
|
||||
|| RenderPipelineType::SkiaVulkan == renderType;
|
||||
return RenderPipelineType::SkiaGL == renderType || RenderPipelineType::SkiaVulkan == renderType;
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user