/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ *
+ *
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
mQueueItems(),
mLastFrameNumberReceived(0),
mUpdateTexImageFailed(false),
- mAutoRefresh(false)
+ mAutoRefresh(false),
+ mFreezePositionUpdates(false),
+ mTransformHint(0)
{
#ifdef USE_HWC2
ALOGV("Creating Layer %s", name.string());
#else
mCurrentState.alpha = 0xFF;
#endif
+ mCurrentState.blur = 0xFF;
mCurrentState.layerStack = 0;
mCurrentState.flags = layerFlags;
mCurrentState.sequence = 0;
mCurrentState.requested = mCurrentState.active;
+ mCurrentState.color = 0;
// drawing state & current state are identical
mDrawingState = mCurrentState;
for (auto& point : mRemoteSyncPoints) {
point->setTransactionApplied();
}
+ for (auto& point : mLocalSyncPoints) {
+ point->setFrameAvailable();
+ }
mFlinger->deleteTextureAsync(mTextureName);
mFrameTracker.logAndResetStats(mName);
}
ALOGE("Can't replace a frame on an empty queue");
return;
}
- mQueueItems.editItemAt(0) = item;
+ mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
// Wake up any pending callbacks
mLastFrameNumberReceived = item.mFrameNumber;
return crop;
}
-static Rect reduce(const Rect& win, const Region& exclude) {
+Rect Layer::reduce(const Rect& win, const Region& exclude) const{
if (CC_LIKELY(exclude.isEmpty())) {
return win;
}
uint32_t invTransform = mCurrentTransform;
if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
/*
- * the code below applies the display's inverse transform to the buffer
+ * the code below applies the primary display's inverse transform to the
+ * buffer
*/
- uint32_t invTransformOrient = hw->getOrientationTransform();
+ uint32_t invTransformOrient =
+ DisplayDevice::getPrimaryDisplayOrientationTransform();
// calculate the inverse transform
if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) {
invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
- // If the transform has been rotated the axis of flip has been swapped
- // so we need to swap which flip operations we are performing
- bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
- bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
- if (is_h_flipped != is_v_flipped) {
- invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
- NATIVE_WINDOW_TRANSFORM_FLIP_H;
- }
}
// and apply to the current transform
- invTransform = (Transform(invTransform) * Transform(invTransformOrient)).getOrientation();
+ invTransform = (Transform(invTransformOrient) * Transform(invTransform))
+ .getOrientation();
}
int winWidth = s.active.w;
to_string(error).c_str(), static_cast<int32_t>(error));
}
#else
+#if defined(QTI_BSP) && !defined(QCOM_BSP_LEGACY)
+ if (!isOpaque(s)) {
+#else
if (!isOpaque(s) || s.alpha != 0xFF) {
+#endif
layer.setBlending(mPremultipliedAlpha ?
HWC_BLENDING_PREMULT :
HWC_BLENDING_COVERAGE);
}
const Transform& tr(hw->getTransform());
layer.setFrame(tr.transform(frame));
+ setPosition(hw, layer, s);
layer.setCrop(computeCrop(hw));
layer.setPlaneAlpha(s.alpha);
#endif
if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
/*
- * the code below applies the display's inverse transform to the buffer
+ * the code below applies the primary display's inverse transform to the
+ * buffer
*/
-#ifdef USE_HWC2
- uint32_t invTransform = displayDevice->getOrientationTransform();
-#else
- uint32_t invTransform = hw->getOrientationTransform();
-#endif
- uint32_t t_orientation = transform.getOrientation();
+ uint32_t invTransform =
+ DisplayDevice::getPrimaryDisplayOrientationTransform();
// calculate the inverse transform
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
- // If the transform has been rotated the axis of flip has been swapped
- // so we need to swap which flip operations we are performing
- bool is_h_flipped = (t_orientation & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
- bool is_v_flipped = (t_orientation & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
- if (is_h_flipped != is_v_flipped) {
- t_orientation ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
- NATIVE_WINDOW_TRANSFORM_FLIP_H;
- }
}
// and apply to the current transform
- transform = Transform(t_orientation) * Transform(invTransform);
+ transform = Transform(invTransform) * transform;
}
// this gives us only the "orientation" component of the transform
surfaceDamageRegion.dump(LOG_TAG);
}
- auto compositionType = HWC2::Composition::Invalid;
+ // Sideband layers
if (mSidebandStream.get()) {
- compositionType = HWC2::Composition::Sideband;
- auto error = hwcLayer->setSidebandStream(mSidebandStream->handle());
+ setCompositionType(hwcId, HWC2::Composition::Sideband);
+ ALOGV("[%s] Requesting Sideband composition", mName.string());
+ error = hwcLayer->setSidebandStream(mSidebandStream->handle());
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set sideband stream %p: %s (%d)",
mName.string(), mSidebandStream->handle(),
to_string(error).c_str(), static_cast<int32_t>(error));
- return;
- }
- } else {
- if (mActiveBuffer == nullptr || mActiveBuffer->handle == nullptr) {
- compositionType = HWC2::Composition::Client;
- auto error = hwcLayer->setBuffer(nullptr, Fence::NO_FENCE);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set null buffer: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- return;
- }
- } else {
- if (mPotentialCursor) {
- compositionType = HWC2::Composition::Cursor;
- }
- auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
- auto error = hwcLayer->setBuffer(mActiveBuffer->handle,
- acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
- mActiveBuffer->handle, to_string(error).c_str(),
- static_cast<int32_t>(error));
- return;
- }
- // If it's not a cursor, default to device composition
}
+ return;
}
- if (mHwcLayers[hwcId].forceClientComposition) {
- ALOGV("[%s] Forcing Client composition", mName.string());
+ // Client or SolidColor layers
+ if (mActiveBuffer == nullptr || mActiveBuffer->handle == nullptr ||
+ mHwcLayers[hwcId].forceClientComposition) {
+ // TODO: This also includes solid color layers, but no API exists to
+ // setup a solid color layer yet
+ ALOGV("[%s] Requesting Client composition", mName.string());
setCompositionType(hwcId, HWC2::Composition::Client);
- } else if (compositionType != HWC2::Composition::Invalid) {
- ALOGV("[%s] Requesting %s composition", mName.string(),
- to_string(compositionType).c_str());
- setCompositionType(hwcId, compositionType);
+ return;
+ }
+
+ // Device or Cursor layers
+ if (mPotentialCursor) {
+ ALOGV("[%s] Requesting Cursor composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Cursor);
} else {
ALOGV("[%s] Requesting Device composition", mName.string());
setCompositionType(hwcId, HWC2::Composition::Device);
}
+
+ auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
+ error = hwcLayer->setBuffer(mActiveBuffer->handle, acquireFence);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
+ mActiveBuffer->handle, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
}
#else
void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
}
}
}
+ setAcquiredFenceIfBlit(fenceFd, layer);
layer.setAcquireFenceFd(fenceFd);
}
// drawing...
// ---------------------------------------------------------------------------
-void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const {
+void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) {
onDraw(hw, clip, false);
}
void Layer::draw(const sp<const DisplayDevice>& hw,
- bool useIdentityTransform) const {
+ bool useIdentityTransform) {
onDraw(hw, Region(hw->bounds()), useIdentityTransform);
}
-void Layer::draw(const sp<const DisplayDevice>& hw) const {
+void Layer::draw(const sp<const DisplayDevice>& hw) {
onDraw(hw, Region(hw->bounds()), false);
}
void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
- bool useIdentityTransform) const
+ bool useIdentityTransform)
{
ATRACE_CALL();
RenderEngine& engine(mFlinger->getRenderEngine());
- if (!blackOutLayer) {
+ if (!blackOutLayer ||
+ ((hw->getDisplayType() == HWC_DISPLAY_PRIMARY) && canAllowGPUForProtected())) {
// TODO: we could be more subtle with isFixedSize()
const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize();
if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
/*
- * the code below applies the display's inverse transform to the texture transform
+ * the code below applies the primary display's inverse transform to
+ * the texture transform
*/
// create a 4x4 transform matrix from the display transform flags
const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
mat4 tr;
- uint32_t transform = hw->getOrientationTransform();
+ uint32_t transform =
+ DisplayDevice::getPrimaryDisplayOrientationTransform();
if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90)
tr = tr * rot90;
if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H)
clearWithOpenGL(hw, clip, 0,0,0,0);
}
+void Layer::handleOpenGLDraw(const sp<const DisplayDevice>& /* hw */,
+ Mesh& mesh) const {
+ const State& s(getDrawingState());
+ RenderEngine& engine(mFlinger->getRenderEngine());
+
+ engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha);
+ engine.drawMesh(mesh);
+ engine.disableBlending();
+}
+
void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw,
const Region& /* clip */, bool useIdentityTransform) const {
const State& s(getDrawingState());
* minimal value)? Or, we could make GL behave like HWC -- but this feel
* like more of a hack.
*/
+#ifdef QTI_BSP
+ Rect win(s.active.w, s.active.h);
+
+ if (!s.crop.isEmpty()) {
+ win = s.crop;
+ }
+
+ win = s.active.transform.transform(win);
+ win.intersect(hw->getViewport(), &win);
+ win = s.active.transform.inverse().transform(win);
+ win.intersect(Rect(s.active.w, s.active.h), &win);
+ win = reduce(win, s.activeTransparentRegion);
+#else
Rect win(computeBounds());
if (!s.finalCrop.isEmpty()) {
win.clear();
}
}
-
+#endif
float left = float(win.left) / float(s.active.w);
float top = float(win.top) / float(s.active.h);
float right = float(win.right) / float(s.active.w);
texCoords[2] = vec2(right, 1.0f - bottom);
texCoords[3] = vec2(right, 1.0f - top);
- RenderEngine& engine(mFlinger->getRenderEngine());
- engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha);
- engine.drawMesh(mMesh);
- engine.disableBlending();
+ handleOpenGLDraw(hw, mMesh);
}
#ifdef USE_HWC2
if (!s.crop.isEmpty()) {
win.intersect(s.crop, &win);
}
- // subtract the transparent region and snap to the bounds
+#ifdef QTI_BSP
+ win = s.active.transform.transform(win);
+ win.intersect(hw->getViewport(), &win);
+ win = s.active.transform.inverse().transform(win);
+ win.intersect(Rect(s.active.w, s.active.h), &win);
win = reduce(win, s.activeTransparentRegion);
+ const Transform bufferOrientation(mCurrentTransform);
+ Transform transform(tr * s.active.transform * bufferOrientation);
+ if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
+ NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ }
+ transform = Transform(invTransform) * transform;
+ }
+ const uint32_t orientation = transform.getOrientation();
+ if (!(orientation | mCurrentTransform | mTransformHint)) {
+ if (!useIdentityTransform) {
+ win = s.active.transform.transform(win);
+ win.intersect(hw->getViewport(), &win);
+ }
+ }
+#else
+ win = reduce(win, s.activeTransparentRegion);
+#endif
+
+
+
+ // subtract the transparent region and snap to the bounds
+
vec2 lt = vec2(win.left, win.top);
vec2 lb = vec2(win.left, win.bottom);
vec2 rb = vec2(win.right, win.bottom);
vec2 rt = vec2(win.right, win.top);
if (!useIdentityTransform) {
- lt = s.active.transform.transform(lt);
- lb = s.active.transform.transform(lb);
- rb = s.active.transform.transform(rb);
- rt = s.active.transform.transform(rt);
+#ifdef QTI_BSP
+ if (orientation | mCurrentTransform | mTransformHint) {
+ lt = s.active.transform.transform(lt);
+ lb = s.active.transform.transform(lb);
+ rb = s.active.transform.transform(rb);
+ rt = s.active.transform.transform(rt);
+ }
+#else
+ lt = s.active.transform.transform(lt);
+ lb = s.active.transform.transform(lb);
+ rb = s.active.transform.transform(rb);
+ rt = s.active.transform.transform(rt);
+#endif
}
-
if (!s.finalCrop.isEmpty()) {
boundPoint(<, s.finalCrop);
boundPoint(&lb, s.finalCrop);
c.requested.w, c.requested.h);
}
+ const bool resizePending = (c.requested.w != c.active.w) ||
+ (c.requested.h != c.active.h);
if (!isFixedSize()) {
-
- const bool resizePending = (c.requested.w != c.active.w) ||
- (c.requested.h != c.active.h);
-
if (resizePending && mSidebandStream == NULL) {
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
- c.active = c.requested;
+ Layer::State& editCurrentState(getCurrentState());
+ if (mFreezePositionUpdates) {
+ float tx = c.active.transform.tx();
+ float ty = c.active.transform.ty();
+ c.active = c.requested;
+ c.active.transform.set(tx, ty);
+ editCurrentState.active = c.active;
+ } else {
+ editCurrentState.active = editCurrentState.requested;
+ c.active = c.requested;
+ }
}
if (s.active != c.active) {
(type >= Transform::SCALE));
}
+ // If the layer is hidden, signal and clear out all local sync points so
+ // that transactions for layers depending on this layer's frames becoming
+ // visible are not blocked
+ if (c.flags & layer_state_t::eLayerHidden) {
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+ for (auto& point : mLocalSyncPoints) {
+ point->setFrameAvailable();
+ }
+ mLocalSyncPoints.clear();
+ }
+
// Commit the transaction
commitTransaction(c);
return flags;
return android_atomic_or(flags, &mTransactionFlags);
}
-bool Layer::setPosition(float x, float y) {
+bool Layer::setPosition(float x, float y, bool immediate) {
if (mCurrentState.requested.transform.tx() == x && mCurrentState.requested.transform.ty() == y)
return false;
mCurrentState.sequence++;
// we want to apply the position portion of the transform matrix immediately,
// but still delay scaling when resizing a SCALING_MODE_FREEZE layer.
mCurrentState.requested.transform.set(x, y);
- mCurrentState.active.transform.set(x, y);
+ if (immediate && !mFreezePositionUpdates) {
+ mCurrentState.active.transform.set(x, y);
+ }
+ mFreezePositionUpdates = mFreezePositionUpdates || !immediate;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
+
bool Layer::setLayer(uint32_t z) {
if (mCurrentState.z == z)
return false;
setTransactionFlags(eTransactionNeeded);
return true;
}
+bool Layer::setBlur(uint8_t blur) {
+ if (mCurrentState.blur == blur)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.blur = blur;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
bool Layer::setSize(uint32_t w, uint32_t h) {
if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
return false;
if (scalingMode == mOverrideScalingMode)
return false;
mOverrideScalingMode = scalingMode;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
+bool Layer::setColor(uint32_t color) {
+ if (mCurrentState.color == color)
+ return false;
+ mCurrentState.sequence++;
+ mCurrentState.color = color;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
return true;
}
// NOTE: We don't need to hold the transaction lock here
// because State::active is only accessed from this thread.
current.active = front.active;
+ current.modified = true;
// recompute visible region
recomputeVisibleRegions = true;
// Remove any stale buffers that have been dropped during
// updateTexImage
- while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ while ((mQueuedFrames > 0) && (mQueueItems[0].mFrameNumber != currentFrameNumber)) {
mQueueItems.removeAt(0);
android_atomic_dec(&mQueuedFrames);
}
+ if (mQueuedFrames == 0) {
+ ALOGE("[%s] mQueuedFrames is zero !!", mName.string());
+ return outDirtyRegion;
+ }
+
mQueueItems.removeAt(0);
}
if (bufWidth != uint32_t(oldActiveBuffer->width) ||
bufHeight != uint32_t(oldActiveBuffer->height)) {
recomputeVisibleRegions = true;
+ mFreezePositionUpdates = false;
}
}
return usage;
}
-void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
+void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) {
uint32_t orientation = 0;
if (!mFlinger->mDebugDisableTransformHint) {
// The transform hint is used to improve performance, but we can
}
}
mSurfaceFlingerConsumer->setTransformHint(orientation);
+ mTransformHint = orientation;
}
// ----------------------------------------------------------------------------
"crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), "
"isOpaque=%1d, invalidate=%1d, "
#ifdef USE_HWC2
- "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
+ "alpha=%.3f, blur=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
#else
- "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
+ "alpha=0x%02x, blur=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
#endif
" client=%p\n",
s.layerStack, s.z, s.active.transform.tx(), s.active.transform.ty(), s.active.w, s.active.h,
s.finalCrop.left, s.finalCrop.top,
s.finalCrop.right, s.finalCrop.bottom,
isOpaque(s), contentDirty,
- s.alpha, s.flags,
+ s.alpha, s.blur, s.flags,
s.active.transform[0][0], s.active.transform[0][1],
s.active.transform[1][0], s.active.transform[1][1],
client.get());