Format the world (or just HWUI)

Test: No code changes, just ran through clang-format
Change-Id: Id23aa4ec7eebc0446fe3a30260f33e7fd455bb8c
This commit is contained in:
John Reck
2017-11-03 10:12:19 -07:00
parent 30ec71c0fe
commit 1bcacfdcab
370 changed files with 9959 additions and 11328 deletions

View File

@@ -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(&currentSpike,
innerNext, centroid3d);
int extraVerticesNumber =
getEdgeExtraAndUpdateSpike(&currentSpike, 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,5 +26,5 @@ public:
virtual void notify(const int64_t* buffer);
};
}; // namespace uirenderer
}; // namespace android
}; // namespace uirenderer
}; // namespace android

View File

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

View File

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

View File

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

View File

@@ -28,5 +28,5 @@ public:
virtual void onGlFunctorReleased(Functor* functor) = 0;
};
}; // namespace uirenderer
}; // namespace android
}; // namespace uirenderer
}; // namespace android

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -39,5 +39,5 @@ void LayerUpdateQueue::enqueueLayerWithDamage(RenderNode* renderNode, Rect damag
}
}
} // namespace uirenderer
} // namespace android
} // namespace uirenderer
} // namespace android

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,5 +29,5 @@ public:
static const char* opName(const RecordedOp& op);
};
}; // namespace uirenderer
}; // namespace android
}; // namespace uirenderer
}; // namespace android

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,6 +24,7 @@ namespace uirenderer {
class ProfileDataContainer {
PREVENT_COPY_AND_ASSIGN(ProfileDataContainer);
public:
explicit ProfileDataContainer() {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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