summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger')
-rw-r--r--services/surfaceflinger/Client.cpp2
-rw-r--r--services/surfaceflinger/DdmConnection.cpp2
-rw-r--r--services/surfaceflinger/DispSync.h2
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp11
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h2
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp9
-rw-r--r--services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h2
-rw-r--r--services/surfaceflinger/Layer.cpp132
-rw-r--r--services/surfaceflinger/Layer.h12
-rw-r--r--services/surfaceflinger/MonitoredProducer.cpp8
-rw-r--r--services/surfaceflinger/MonitoredProducer.h2
-rw-r--r--services/surfaceflinger/RenderEngine/Description.cpp4
-rw-r--r--services/surfaceflinger/RenderEngine/Description.h1
-rw-r--r--services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp8
-rw-r--r--services/surfaceflinger/RenderEngine/GLES11RenderEngine.h3
-rw-r--r--services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp78
-rw-r--r--services/surfaceflinger/RenderEngine/GLES20RenderEngine.h4
-rw-r--r--services/surfaceflinger/RenderEngine/Mesh.cpp30
-rw-r--r--services/surfaceflinger/RenderEngine/ProgramCache.cpp2
-rw-r--r--services/surfaceflinger/RenderEngine/RenderEngine.h10
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp113
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h13
-rw-r--r--services/surfaceflinger/SurfaceFlingerConsumer.cpp12
-rw-r--r--services/surfaceflinger/SurfaceFlingerConsumer.h8
-rw-r--r--services/surfaceflinger/tests/Transaction_test.cpp46
25 files changed, 341 insertions, 175 deletions
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index f7d32d0..49389e0 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -93,7 +93,7 @@ status_t Client::onTransact(
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
const int self_pid = getpid();
- if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
+ if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)) {
// we're called from a different process, do the real check
if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
{
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
index a000a84..659c2c8 100644
--- a/services/surfaceflinger/DdmConnection.cpp
+++ b/services/surfaceflinger/DdmConnection.cpp
@@ -66,7 +66,7 @@ void DdmConnection::start(const char* name) {
jint (*registerNatives)(JNIEnv* env, jclass clazz);
registerNatives = reinterpret_cast<decltype(registerNatives)>(
dlsym(libandroid_runtime_dso,
- "Java_com_android_internal_util_WithFramework_registerNatives"));
+ "Java_com_android_internal_util_WithFramework_registerNatives"));
ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror());
if (!JNI_CreateJavaVM || !registerNatives) {
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 96efc34..67142b6 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -139,7 +139,7 @@ private:
enum { MAX_RESYNC_SAMPLES = 32 };
enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
enum { NUM_PRESENT_SAMPLES = 8 };
- enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 12 };
+ enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
// mPeriod is the computed period of the modeled vsync events in
// nanoseconds.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c8b36ec..2dad005 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -305,13 +305,16 @@ void HWComposer::vsync(int disp, int64_t timestamp) {
}
void HWComposer::hotplug(int disp, int connected) {
- if (disp == HWC_DISPLAY_PRIMARY || disp >= VIRTUAL_DISPLAY_ID_BASE) {
+ if (disp >= VIRTUAL_DISPLAY_ID_BASE) {
ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
disp, connected);
return;
}
queryDisplayProperties(disp);
- mEventHandler.onHotplugReceived(disp, bool(connected));
+ // Do not teardown or recreate the primary display
+ if (disp != HWC_DISPLAY_PRIMARY) {
+ mEventHandler.onHotplugReceived(disp, bool(connected));
+ }
}
static float getDefaultDensity(uint32_t width, uint32_t height) {
@@ -461,7 +464,7 @@ sp<Fence> HWComposer::getDisplayFence(int disp) const {
}
uint32_t HWComposer::getFormat(int disp) const {
- if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
+ if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) {
return HAL_PIXEL_FORMAT_RGBA_8888;
} else {
return mDisplayData[disp].format;
@@ -632,6 +635,7 @@ status_t HWComposer::setFramebufferTarget(int32_t id,
}
status_t HWComposer::prepare() {
+ Mutex::Autolock _l(mDisplayLock);
for (size_t i=0 ; i<mNumDisplays ; i++) {
DisplayData& disp(mDisplayData[i]);
if (disp.framebufferTarget) {
@@ -1142,6 +1146,7 @@ static String8 getFormatStr(PixelFormat format) {
}
void HWComposer::dump(String8& result) const {
+ Mutex::Autolock _l(mDisplayLock);
if (mHwc) {
result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc));
result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 28d8c65..cc98b4c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -354,6 +354,8 @@ private:
// mLists[i>0] can be NULL. that display is to be ignored
struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS];
DisplayData mDisplayData[MAX_HWC_DISPLAYS];
+ // protect mDisplayData from races between prepare and dump
+ mutable Mutex mDisplayLock;
size_t mNumDisplays;
cb_context* mCBContext;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 11cbdc6..ba4c198 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -530,6 +530,15 @@ status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) {
return INVALID_OPERATION;
}
+status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) {
+ ALOGE("setGenerationNumber not supported on VirtualDisplaySurface");
+ return INVALID_OPERATION;
+}
+
+String8 VirtualDisplaySurface::getConsumerName() const {
+ return String8("VirtualDisplaySurface");
+}
+
void VirtualDisplaySurface::updateQueueBufferOutput(
const QueueBufferOutput& qbo) {
uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 97af980..6298751 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -116,6 +116,8 @@ private:
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage);
virtual status_t allowAllocation(bool allow);
+ virtual status_t setGenerationNumber(uint32_t generationNumber);
+ virtual String8 getConsumerName() const override;
//
// Utility methods
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2944c63..5ff79a9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -76,11 +76,15 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
mFiltering(false),
mNeedsFiltering(false),
mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2),
- mSecure(false),
mProtectedByApp(false),
mHasSurface(false),
mClientRef(client),
- mPotentialCursor(false)
+ mPotentialCursor(false),
+ mQueueItemLock(),
+ mQueueItemCondition(),
+ mQueueItems(),
+ mLastFrameNumberReceived(0),
+ mUpdateTexImageFailed(false)
{
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -91,6 +95,8 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
layerFlags |= layer_state_t::eLayerHidden;
if (flags & ISurfaceComposerClient::eOpaque)
layerFlags |= layer_state_t::eLayerOpaque;
+ if (flags & ISurfaceComposerClient::eSecure)
+ layerFlags |= layer_state_t::eLayerSecure;
if (flags & ISurfaceComposerClient::eNonPremultiplied)
mPremultipliedAlpha = false;
@@ -163,20 +169,54 @@ void Layer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
+
+ // Reset the frame number tracker when we receive the first buffer after
+ // a frame number reset
+ if (item.mFrameNumber == 1) {
+ mLastFrameNumberReceived = 0;
+ }
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+ ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
mQueueItems.push_back(item);
+ android_atomic_inc(&mQueuedFrames);
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
}
- android_atomic_inc(&mQueuedFrames);
mFlinger->signalLayerUpdate();
}
void Layer::onFrameReplaced(const BufferItem& item) {
Mutex::Autolock lock(mQueueItemLock);
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+ ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
if (mQueueItems.empty()) {
ALOGE("Can't replace a frame on an empty queue");
return;
}
mQueueItems.editItemAt(0) = item;
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
}
void Layer::onSidebandStreamChanged() {
@@ -217,7 +257,6 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
mFormat = format;
mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
- mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false;
mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
mCurrentOpacity = getOpacityForFormat(format);
@@ -512,16 +551,7 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
const Transform& tr = hw->getTransform();
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible);
-
- // Pass full-surface damage down untouched
- if (surfaceDamageRegion.isRect() &&
- surfaceDamageRegion.getBounds() == Rect::INVALID_RECT) {
- layer.setSurfaceDamage(surfaceDamageRegion);
- } else {
- Region surfaceDamage =
- tr.transform(surfaceDamageRegion.intersect(hw->getViewport()));
- layer.setSurfaceDamage(surfaceDamage);
- }
+ layer.setSurfaceDamage(surfaceDamageRegion);
if (mSidebandStream.get()) {
layer.setSidebandStream(mSidebandStream);
@@ -821,6 +851,12 @@ bool Layer::isOpaque(const Layer::State& s) const
return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
}
+bool Layer::isSecure() const
+{
+ const Layer::State& s(mDrawingState);
+ return (s.flags & layer_state_t::eLayerSecure);
+}
+
bool Layer::isProtected() const
{
const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
@@ -1065,11 +1101,26 @@ void Layer::useEmptyDamage() {
// ----------------------------------------------------------------------------
bool Layer::shouldPresentNow(const DispSync& dispSync) const {
+ if (mSidebandStreamChanged) {
+ return true;
+ }
+
Mutex::Autolock lock(mQueueItemLock);
+ if (mQueueItems.empty()) {
+ return false;
+ }
+ auto timestamp = mQueueItems[0].mTimestamp;
nsecs_t expectedPresent =
mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
- return mQueueItems.empty() ?
- false : mQueueItems[0].mTimestamp < expectedPresent;
+
+ // Ignore timestamps more than a second in the future
+ bool isPlausible = timestamp < (expectedPresent + s2ns(1));
+ ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible "
+ "relative to expectedPresent %" PRId64, mName.string(), timestamp,
+ expectedPresent);
+
+ bool isDue = timestamp < expectedPresent;
+ return isDue || !isPlausible;
}
bool Layer::onPreComposition() {
@@ -1120,6 +1171,10 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
// mSidebandStreamChanged was true
mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+ if (mSidebandStream != NULL) {
+ setTransactionFlags(eTransactionNeeded);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
recomputeVisibleRegions = true;
const State& s(getDrawingState());
@@ -1252,21 +1307,62 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0);
+ uint64_t maxFrameNumber = 0;
+ {
+ Mutex::Autolock lock(mQueueItemLock);
+ maxFrameNumber = mLastFrameNumberReceived;
+ }
+
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync);
+ mFlinger->mPrimaryDispSync, maxFrameNumber);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
mFlinger->signalLayerUpdate();
return outDirtyRegion;
+ } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+ // If the buffer has been rejected, remove it from the shadow queue
+ // and return early
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ return outDirtyRegion;
+ } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+ // This can occur if something goes wrong when trying to create the
+ // EGLImage for this buffer. If this happens, the buffer has already
+ // been released, so we need to clean up the queue and bug out
+ // early.
+ {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.clear();
+ android_atomic_and(0, &mQueuedFrames);
+ }
+
+ // Once we have hit this state, the shadow queue may no longer
+ // correctly reflect the incoming BufferQueue's contents, so even if
+ // updateTexImage starts working, the only safe course of action is
+ // to continue to ignore updates.
+ mUpdateTexImageFailed = true;
+
+ return outDirtyRegion;
}
- // Remove this buffer from our internal queue tracker
{ // Autolock scope
+ auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
Mutex::Autolock lock(mQueueItemLock);
+
+ // Remove any stale buffers that have been dropped during
+ // updateTexImage
+ while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+
mQueueItems.removeAt(0);
}
+
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if (android_atomic_dec(&mQueuedFrames) > 1) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 46c17e5..c1e5e9f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -174,7 +174,7 @@ public:
* isSecure - true if this surface is secure, that is if it prevents
* screenshots or VNC servers.
*/
- virtual bool isSecure() const { return mSecure; }
+ virtual bool isSecure() const;
/*
* isProtected - true if the layer may contain protected content in the
@@ -339,9 +339,9 @@ protected:
private:
// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
- virtual void onFrameAvailable(const BufferItem& item);
- virtual void onFrameReplaced(const BufferItem& item);
- virtual void onSidebandStreamChanged();
+ virtual void onFrameAvailable(const BufferItem& item) override;
+ virtual void onFrameReplaced(const BufferItem& item) override;
+ virtual void onSidebandStreamChanged() override;
void commitTransaction();
@@ -402,7 +402,6 @@ private:
mutable Texture mTexture;
// page-flip thread (currently main thread)
- bool mSecure; // no screenshots
bool mProtectedByApp; // application requires protected path to external sink
// protected by mLock
@@ -416,7 +415,10 @@ private:
// Local copy of the queued contents of the incoming BufferQueue
mutable Mutex mQueueItemLock;
+ Condition mQueueItemCondition;
Vector<BufferItem> mQueueItems;
+ uint64_t mLastFrameNumberReceived;
+ bool mUpdateTexImageFailed; // This is only modified from the main thread
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 9fb555b..fb7af97 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -114,6 +114,14 @@ status_t MonitoredProducer::allowAllocation(bool allow) {
return mProducer->allowAllocation(allow);
}
+status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) {
+ return mProducer->setGenerationNumber(generationNumber);
+}
+
+String8 MonitoredProducer::getConsumerName() const {
+ return mProducer->getConsumerName();
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return IInterface::asBinder(mProducer).get();
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index b2f8293..da95766 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -54,6 +54,8 @@ public:
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage);
virtual status_t allowAllocation(bool allow);
+ virtual status_t setGenerationNumber(uint32_t generationNumber);
+ virtual String8 getConsumerName() const override;
virtual IBinder* onAsBinder();
private:
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 1adcd1f..0dab872 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -88,5 +88,9 @@ void Description::setColorMatrix(const mat4& mtx) {
mColorMatrixEnabled = (mtx != identity);
}
+const mat4& Description::getColorMatrix() const {
+ return mColorMatrix;
+}
+
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 43b835f..8a3447c 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -66,6 +66,7 @@ public:
void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void setProjectionMatrix(const mat4& mtx);
void setColorMatrix(const mat4& mtx);
+ const mat4& getColorMatrix() const;
private:
bool mUniformsDirty;
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 2e6af49..1a9f59b 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -262,14 +262,6 @@ void GLES11RenderEngine::drawMesh(const Mesh& mesh) {
}
}
-void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) {
- // doesn't do anything in GLES 1.1
-}
-
-void GLES11RenderEngine::endGroup() {
- // doesn't do anything in GLES 1.1
-}
-
void GLES11RenderEngine::dump(String8& result) {
RenderEngine::dump(result);
}
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
index 87eb3e4..08de646 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -62,9 +62,6 @@ protected:
virtual void drawMesh(const Mesh& mesh);
- virtual void beginGroup(const mat4& colorTransform);
- virtual void endGroup();
-
virtual size_t getMaxTextureSize() const;
virtual size_t getMaxViewportDims() const;
};
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 8712c9a..1fabaf5 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -169,6 +169,12 @@ void GLES20RenderEngine::setupLayerBlackedOut() {
mState.setTexture(texture);
}
+mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
+ mat4 oldTransform = mState.getColorMatrix();
+ mState.setColorMatrix(colorTransform);
+ return oldTransform;
+}
+
void GLES20RenderEngine::disableTexturing() {
mState.disableTexture();
}
@@ -237,78 +243,6 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
}
}
-void GLES20RenderEngine::beginGroup(const mat4& colorTransform) {
-
- GLuint tname, name;
- // create the texture
- glGenTextures(1, &tname);
- glBindTexture(GL_TEXTURE_2D, tname);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
- // create a Framebuffer Object to render into
- glGenFramebuffers(1, &name);
- glBindFramebuffer(GL_FRAMEBUFFER, name);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
-
- Group group;
- group.texture = tname;
- group.fbo = name;
- group.width = mVpWidth;
- group.height = mVpHeight;
- group.colorTransform = colorTransform;
-
- mGroupStack.push(group);
-}
-
-void GLES20RenderEngine::endGroup() {
-
- const Group group(mGroupStack.top());
- mGroupStack.pop();
-
- // activate the previous render target
- GLuint fbo = 0;
- if (!mGroupStack.isEmpty()) {
- fbo = mGroupStack.top().fbo;
- }
- glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-
- // set our state
- Texture texture(Texture::TEXTURE_2D, group.texture);
- texture.setDimensions(group.width, group.height);
- glBindTexture(GL_TEXTURE_2D, group.texture);
-
- mState.setPlaneAlpha(1.0f);
- mState.setPremultipliedAlpha(true);
- mState.setOpaque(false);
- mState.setTexture(texture);
- mState.setColorMatrix(group.colorTransform);
- glDisable(GL_BLEND);
-
- Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
- Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>());
- position[0] = vec2(0, 0);
- position[1] = vec2(group.width, 0);
- position[2] = vec2(group.width, group.height);
- position[3] = vec2(0, group.height);
- texCoord[0] = vec2(0, 0);
- texCoord[1] = vec2(1, 0);
- texCoord[2] = vec2(1, 1);
- texCoord[3] = vec2(0, 1);
- drawMesh(mesh);
-
- // reset color matrix
- mState.setColorMatrix(mat4());
-
- // free our fbo and texture
- glDeleteFramebuffers(1, &group.fbo);
- glDeleteTextures(1, &group.texture);
-}
-
void GLES20RenderEngine::dump(String8& result) {
RenderEngine::dump(result);
}
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 3d6243e..819356a 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,14 +72,12 @@ protected:
virtual void setupLayerTexturing(const Texture& texture);
virtual void setupLayerBlackedOut();
virtual void setupFillWithColor(float r, float g, float b, float a);
+ virtual mat4 setupColorTransform(const mat4& colorTransform);
virtual void disableTexturing();
virtual void disableBlending();
virtual void drawMesh(const Mesh& mesh);
- virtual void beginGroup(const mat4& colorTransform);
- virtual void endGroup();
-
virtual size_t getMaxTextureSize() const;
virtual size_t getMaxViewportDims() const;
};
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index 3f50cb0..ffd9be2 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -16,14 +16,40 @@
#include "Mesh.h"
+#include <utils/Log.h>
+
namespace android {
Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
: mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize),
mPrimitive(primitive)
{
- mVertices = new float[(vertexSize + texCoordSize) * vertexCount];
- mStride = mVertexSize + mTexCoordsSize;
+ if (vertexCount == 0) {
+ mVertices = new float[1];
+ mVertices[0] = 0.0f;
+ mStride = 0;
+ return;
+ }
+
+ size_t stride = vertexSize + texCoordSize;
+ size_t remainder = (stride * vertexCount) / vertexCount;
+ // Since all of the input parameters are unsigned, if stride is less than
+ // either vertexSize or texCoordSize, it must have overflowed. remainder
+ // will be equal to stride as long as stride * vertexCount doesn't overflow.
+ if ((stride < vertexSize) || (remainder != stride)) {
+ ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize,
+ texCoordSize);
+ mVertices = new float[1];
+ mVertices[0] = 0.0f;
+ mVertexCount = 0;
+ mVertexSize = 0;
+ mTexCoordsSize = 0;
+ mStride = 0;
+ return;
+ }
+
+ mVertices = new float[stride * vertexCount];
+ mStride = stride;
}
Mesh::~Mesh() {
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 0de5cca..ba11259 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -199,10 +199,8 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) {
// un-premultiply if needed before linearization
fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
}
- fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(2.2));";
fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);";
fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;";
- fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));";
if (!needs.isOpaque() && needs.isPremultiplied()) {
// and re-premultiply if needed after gamma correction
fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;";
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 8d7529c..31a961e 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -99,18 +99,16 @@ public:
virtual void setupLayerBlackedOut() = 0;
virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
+ virtual mat4 setupColorTransform(const mat4& /* colorTransform */) {
+ return mat4();
+ }
+
virtual void disableTexturing() = 0;
virtual void disableBlending() = 0;
// drawing
virtual void drawMesh(const Mesh& mesh) = 0;
- // grouping
- // creates a color-transform group, everything drawn in the group will be
- // transformed by the given color transform when endGroup() is called.
- virtual void beginGroup(const mat4& colorTransform) = 0;
- virtual void endGroup() = 0;
-
// queries
virtual size_t getMaxTextureSize() const = 0;
virtual size_t getMaxViewportDims() const = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index df4ac2e..de0f921 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -149,7 +149,11 @@ SurfaceFlinger::SurfaceFlinger()
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
- mHasColorMatrix(false)
+ mHasColorMatrix(false),
+ mHasPoweredOff(false),
+ mFrameBuckets(),
+ mTotalTime(0),
+ mLastSwapTime(0)
{
ALOGI("SurfaceFlinger is starting");
@@ -546,7 +550,7 @@ bool SurfaceFlinger::authenticateSurfaceTexture(
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
Vector<DisplayInfo>* configs) {
- if (configs == NULL) {
+ if ((configs == NULL) || (display.get() == NULL)) {
return BAD_VALUE;
}
@@ -997,8 +1001,8 @@ void SurfaceFlinger::postComposition()
}
}
+ const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (kIgnorePresentFences) {
- const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (hw->isDisplayOn()) {
enableHardwareVsync();
}
@@ -1017,6 +1021,26 @@ void SurfaceFlinger::postComposition()
}
mAnimFrameTracker.advanceFrame();
}
+
+ if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+ return;
+ }
+
+ nsecs_t currentTime = systemTime();
+ if (mHasPoweredOff) {
+ mHasPoweredOff = false;
+ } else {
+ nsecs_t period = mPrimaryDispSync.getPeriod();
+ nsecs_t elapsedTime = currentTime - mLastSwapTime;
+ size_t numPeriods = static_cast<size_t>(elapsedTime / period);
+ if (numPeriods < NUM_BUCKETS - 1) {
+ mFrameBuckets[numPeriods] += elapsedTime;
+ } else {
+ mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+ }
+ mTotalTime += elapsedTime;
+ }
+ mLastSwapTime = currentTime;
}
void SurfaceFlinger::rebuildLayerStacks() {
@@ -1848,9 +1872,9 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
if (mDaltonize) {
colorMatrix = colorMatrix * mDaltonizer();
}
- engine.beginGroup(colorMatrix);
+ mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
doComposeSurfaces(hw, dirtyRegion);
- engine.endGroup();
+ engine.setupColorTransform(oldMatrix);
}
// update the swap region and clear the dirty region
@@ -1994,18 +2018,25 @@ void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Regio
engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
}
-void SurfaceFlinger::addClientLayer(const sp<Client>& client,
+status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc,
const sp<Layer>& lbc)
{
+ // add this layer to the current state list
+ {
+ Mutex::Autolock _l(mStateLock);
+ if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
+ return NO_MEMORY;
+ }
+ mCurrentState.layersSortedByZ.add(lbc);
+ mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+ }
+
// attach this layer to the client
client->attachLayer(handle, lbc);
- // add this layer to the current state list
- Mutex::Autolock _l(mStateLock);
- mCurrentState.layersSortedByZ.add(lbc);
- mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+ return NO_ERROR;
}
status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
@@ -2204,9 +2235,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(
if (layer->setTransparentRegionHint(s.transparentRegion))
flags |= eTraversalNeeded;
}
- if ((what & layer_state_t::eVisibilityChanged) ||
- (what & layer_state_t::eOpacityChanged)) {
- // TODO: should we just use an eFlagsChanged for this?
+ if (what & layer_state_t::eFlagsChanged) {
if (layer->setFlags(s.flags, s.mask))
flags |= eTraversalNeeded;
}
@@ -2262,10 +2291,16 @@ status_t SurfaceFlinger::createLayer(
break;
}
- if (result == NO_ERROR) {
- addClientLayer(client, *handle, *gbp, layer);
- setTransactionFlags(eTransactionNeeded);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ result = addClientLayer(client, *handle, *gbp, layer);
+ if (result != NO_ERROR) {
+ return result;
}
+
+ setTransactionFlags(eTransactionNeeded);
return result;
}
@@ -2398,6 +2433,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
}
mVisibleRegionsDirty = true;
+ mHasPoweredOff = true;
repaintEverything();
} else if (mode == HWC_POWER_MODE_OFF) {
if (type == DisplayDevice::DISPLAY_PRIMARY) {
@@ -2498,6 +2534,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
mPrimaryDispSync.dump(result);
dumpAll = false;
}
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--static-screen"))) {
+ index++;
+ dumpStaticScreenStats(result);
+ dumpAll = false;
+ }
}
if (dumpAll) {
@@ -2601,6 +2644,23 @@ void SurfaceFlinger::logFrameStats() {
result.append(config);
}
+void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
+{
+ result.appendFormat("Static screen stats:\n");
+ for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
+ float bucketTimeSec = mFrameBuckets[b] / 1e9;
+ float percent = 100.0f *
+ static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+ result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n",
+ b + 1, bucketTimeSec, percent);
+ }
+ float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+ float percent = 100.0f *
+ static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+ result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n",
+ NUM_BUCKETS - 1, bucketTimeSec, percent);
+}
+
void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
String8& result) const
{
@@ -2647,6 +2707,11 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
result.append("\n");
+ // Dump static screen stats
+ result.append("\n");
+ dumpStaticScreenStats(result);
+ result.append("\n");
+
/*
* Dump the visible layer list
*/
@@ -2794,7 +2859,7 @@ status_t SurfaceFlinger::onTransact(
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- if ((uid != AID_GRAPHICS) &&
+ if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
!PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
ALOGE("Permission Denial: "
"can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
@@ -3253,8 +3318,12 @@ status_t SurfaceFlinger::captureScreenImplLocked(
ATRACE_CALL();
// get screen geometry
- const uint32_t hw_w = hw->getWidth();
- const uint32_t hw_h = hw->getHeight();
+ uint32_t hw_w = hw->getWidth();
+ uint32_t hw_h = hw->getHeight();
+
+ if (rotation & Transform::ROT_90) {
+ std::swap(hw_w, hw_h);
+ }
if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
ALOGE("size mismatch (%d, %d) > (%d, %d)",
@@ -3270,8 +3339,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(
sp<Surface> sur = new Surface(producer, false);
ANativeWindow* window = sur.get();
- status_t result = NO_ERROR;
- if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) {
+ status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (result == NO_ERROR) {
uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
@@ -3361,7 +3430,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(
result = BAD_VALUE;
}
// queueBuffer takes ownership of syncFd
- window->queueBuffer(window, buffer, syncFd);
+ result = window->queueBuffer(window, buffer, syncFd);
}
} else {
result = BAD_VALUE;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a06d1be..3759a92 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -144,6 +144,8 @@ private:
// every half hour.
enum { LOG_FRAME_STATS_PERIOD = 30*60*60 };
+ static const size_t MAX_LAYERS = 4096;
+
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -305,7 +307,7 @@ private:
status_t removeLayer(const sp<Layer>& layer);
// add a layer to SurfaceFlinger
- void addClientLayer(const sp<Client>& client,
+ status_t addClientLayer(const sp<Client>& client,
const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc,
const sp<Layer>& lbc);
@@ -416,6 +418,8 @@ private:
void logFrameStats();
+ void dumpStaticScreenStats(String8& result) const;
+
/* ------------------------------------------------------------------------
* Attributes
*/
@@ -494,6 +498,13 @@ private:
mat4 mColorMatrix;
bool mHasColorMatrix;
+
+ // Static screen stats
+ bool mHasPoweredOff;
+ static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
+ nsecs_t mFrameBuckets[NUM_BUCKETS];
+ nsecs_t mTotalTime;
+ nsecs_t mLastSwapTime;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 19c497a..ed1f31b 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -32,7 +32,7 @@ namespace android {
// ---------------------------------------------------------------------------
status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
- const DispSync& dispSync)
+ const DispSync& dispSync, uint64_t maxFrameNumber)
{
ATRACE_CALL();
ALOGV("updateTexImage");
@@ -54,7 +54,8 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
+ err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
+ maxFrameNumber);
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
@@ -74,7 +75,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
int buf = item.mBuf;
if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
- return NO_ERROR;
+ return BUFFER_REJECTED;
}
// Release the previous buffer.
@@ -104,8 +105,9 @@ status_t SurfaceFlingerConsumer::bindTextureImage()
}
status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
- nsecs_t presentWhen) {
- status_t result = GLConsumer::acquireBufferLocked(item, presentWhen);
+ nsecs_t presentWhen, uint64_t maxFrameNumber) {
+ status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
+ maxFrameNumber);
if (result == NO_ERROR) {
mTransformToDisplayInverse = item->mTransformToDisplayInverse;
mSurfaceDamage = item->mSurfaceDamage;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 1aaba18..779e5b7 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -28,6 +28,8 @@ namespace android {
*/
class SurfaceFlingerConsumer : public GLConsumer {
public:
+ static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
+
struct ContentsChangedListener: public FrameAvailableListener {
virtual void onSidebandStreamChanged() = 0;
};
@@ -47,13 +49,15 @@ public:
virtual ~BufferRejecter() { }
};
- virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+ virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+ uint64_t maxFrameNumber = 0) override;
// This version of updateTexImage() takes a functor that may be used to
// reject the newly acquired buffer. Unlike the GLConsumer version,
// this does not guarantee that the buffer has been bound to the GL
// texture.
- status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync);
+ status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+ uint64_t maxFrameNumber = 0);
// See GLConsumer::bindTextureImageLocked().
status_t bindTextureImage();
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4d363c8..dcde512 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -16,6 +16,8 @@
#include <gtest/gtest.h>
+#include <android/native_window.h>
+
#include <binder/IMemory.h>
#include <gui/ISurfaceComposer.h>
@@ -53,21 +55,23 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
class ScreenCapture : public RefBase {
public:
static void captureScreen(sp<ScreenCapture>* sc) {
- sp<IMemoryHeap> heap;
- uint32_t w=0, h=0;
- PixelFormat fmt=0;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+ sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 0, 0,
- 0, INT_MAX));
- ASSERT_TRUE(heap != NULL);
- ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt);
- *sc = new ScreenCapture(w, h, heap);
+ sp<IBinder> display(sf->getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0,
+ 0, INT_MAX, false));
+ *sc = new ScreenCapture(cpuConsumer);
}
void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
- const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base());
- const uint8_t* pixel = img + (4 * (y*mWidth + x));
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format);
+ const uint8_t* img = static_cast<const uint8_t*>(mBuf.data);
+ const uint8_t* pixel = img + (4 * (y * mBuf.stride + x));
if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
String8 err(String8::format("pixel @ (%3d, %3d): "
"expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
@@ -77,15 +81,17 @@ public:
}
private:
- ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) :
- mWidth(w),
- mHeight(h),
- mHeap(heap)
- {}
-
- const uint32_t mWidth;
- const uint32_t mHeight;
- sp<IMemoryHeap> mHeap;
+ ScreenCapture(const sp<CpuConsumer>& cc) :
+ mCC(cc) {
+ EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf));
+ }
+
+ ~ScreenCapture() {
+ mCC->unlockBuffer(mBuf);
+ }
+
+ sp<CpuConsumer> mCC;
+ CpuConsumer::LockedBuffer mBuf;
};
class LayerUpdateTest : public ::testing::Test {