diff options
Diffstat (limited to 'services/surfaceflinger')
20 files changed, 793 insertions, 517 deletions
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index ec296d3..f2051dd 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -18,6 +18,8 @@ LOCAL_SRC_FILES:= \ DisplayHardware/HWComposer.cpp \ DisplayHardware/PowerHAL.cpp \ DisplayHardware/VirtualDisplaySurface.cpp \ + EventLog/EventLogTags.logtags \ + EventLog/EventLog.cpp LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES @@ -41,6 +43,8 @@ ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),) LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) endif +LOCAL_CFLAGS += -fvisibility=hidden + LOCAL_SHARED_LIBRARIES := \ libcutils \ liblog \ diff --git a/services/surfaceflinger/Colorizer.h b/services/surfaceflinger/Colorizer.h new file mode 100644 index 0000000..6524481 --- /dev/null +++ b/services/surfaceflinger/Colorizer.h @@ -0,0 +1,65 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SURFACE_FLINGER_COLORIZER_H +#define ANDROID_SURFACE_FLINGER_COLORIZER_H + +namespace android { + +// --------------------------------------------------------------------------- + +class Colorizer { + bool mEnabled; +public: + enum color { + RED = 31, + GREEN = 32, + YELLOW = 33, + BLUE = 34, + MAGENTA = 35, + CYAN = 36, + WHITE = 37 + }; + + Colorizer(bool enabled) + : mEnabled(enabled) { + } + + void colorize(String8& out, color c) { + if (mEnabled) { + out.appendFormat("\e[%dm", c); + } + } + + void bold(String8& out) { + if (mEnabled) { + out.append("\e[1m"); + } + } + + void reset(String8& out) { + if (mEnabled) { + out.append("\e[0m"); + } + } +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + + +#endif /* ANDROID_SURFACE_FLINGER_COLORIZER_H */ diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 68b0b7f..b001bdb 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -416,7 +416,7 @@ void DisplayDevice::setProjection(int orientation, mScissor = mGlobalTransform.transform(viewport); if (mScissor.isEmpty()) { - mScissor.set(getBounds()); + mScissor = getBounds(); } mOrientation = orientation; @@ -424,9 +424,9 @@ void DisplayDevice::setProjection(int orientation, mFrame = frame; } -void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const { +void DisplayDevice::dump(String8& result) const { const Transform& tr(mGlobalTransform); - snprintf(buffer, SIZE, + result.appendFormat( "+ DisplayDevice: %s\n" " type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), " "flips=%u, isSecure=%d, secureVis=%d, acquired=%d, numLayers=%u\n" @@ -443,8 +443,6 @@ void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const { tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); - result.append(buffer); - String8 surfaceDump; mDisplaySurface->dump(surfaceDump); result.append(surfaceDump); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 377d924..047eecd 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -153,7 +153,7 @@ public: * Debugging */ uint32_t getPageFlipCount() const; - void dump(String8& result, char* buffer, size_t SIZE) const; + void dump(String8& result) const; private: /* diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 54a3ce8..10bca38 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -103,8 +103,8 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && item.mBuf != mCurrentBufferSlot) { // Release the previous buffer. - err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); + err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) { ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); return err; @@ -144,7 +144,8 @@ void FramebufferSurface::onFrameCommitted() { sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType); if (fence->isValid() && mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { - status_t err = addReleaseFence(mCurrentBufferSlot, fence); + status_t err = addReleaseFence(mCurrentBufferSlot, + mCurrentBuffer, fence); ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", strerror(-err), err); } @@ -175,11 +176,10 @@ void FramebufferSurface::dump(String8& result) const { ConsumerBase::dump(result); } -void FramebufferSurface::dumpLocked(String8& result, const char* prefix, - char* buffer, size_t SIZE) const +void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const { mHwc.fbDump(result); - ConsumerBase::dumpLocked(result, prefix, buffer, SIZE); + ConsumerBase::dumpLocked(result, prefix); } // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 2fde789..c86e9ae 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -55,8 +55,7 @@ private: virtual void onFrameAvailable(); virtual void freeBufferLocked(int slotIndex); - virtual void dumpLocked(String8& result, const char* prefix, - char* buffer, size_t SIZE) const; + virtual void dumpLocked(String8& result, const char* prefix) const; // nextBuffer waits for and then latches the next buffer from the // BufferQueue and releases the previously latched buffer to the diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index a9afbe5..5082192 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -550,9 +550,6 @@ status_t HWComposer::setFramebufferTarget(int32_t id, // triggers a Surface::queueBuffer() on some // devices (!?) -- log and ignore. ALOGE("HWComposer: framebufferTarget is null"); -// CallStack stack; -// stack.update(); -// stack.dump(""); return NO_ERROR; } @@ -962,7 +959,7 @@ HWComposer::LayerListIterator HWComposer::end(int32_t id) { return getLayerIterator(id, numLayers); } -void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const { +void HWComposer::dump(String8& result) const { if (mHwc) { result.appendFormat("Hardware Composer state (version %8x):\n", hwcApiVersion(mHwc)); result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); @@ -1030,6 +1027,8 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const { } if (mHwc && mHwc->dump) { + const size_t SIZE = 4096; + char buffer[SIZE]; mHwc->dump(mHwc, buffer, SIZE); result.append(buffer); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 604de38..a20da08 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -275,7 +275,7 @@ public: friend class VSyncThread; // for debugging ---------------------------------------------------------- - void dump(String8& out, char* scratch, size_t SIZE) const; + void dump(String8& out) const; private: void loadHwcModule(); diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp new file mode 100644 index 0000000..815242b --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLog.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <cutils/log.h> +#include <utils/String8.h> + +#include "EventLog.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(EventLog) + + +EventLog::EventLog() { +} + +void EventLog::doLogJank(const String8& window, int32_t value) { + EventLog::TagBuffer buffer(LOGTAG_SF_JANK); + buffer.startList(2); + buffer.writeString8(window); + buffer.writeInt32(value); + buffer.endList(); + buffer.log(); +} + +void EventLog::logJank(const String8& window, int32_t value) { + EventLog::getInstance().doLogJank(window, value); +} + +// --------------------------------------------------------------------------- + +EventLog::TagBuffer::TagBuffer(int32_t tag) + : mPos(0), mTag(tag), mOverflow(false) { +} + +void EventLog::TagBuffer::log() { + if (mOverflow) { + ALOGW("couldn't log to binary event log: overflow."); + } else if (android_bWriteLog(mTag, mStorage, mPos) < 0) { + ALOGE("couldn't log to EventLog: %s", strerror(errno)); + } + // purge the buffer + mPos = 0; + mOverflow = false; +} + +void EventLog::TagBuffer::startList(int8_t count) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(count); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_LIST; + mStorage[mPos + 1] = count; + mPos += needed; +} + +void EventLog::TagBuffer::endList() { + if (mOverflow) return; + const size_t needed = 1; + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = '\n'; + mPos += needed; +} + +void EventLog::TagBuffer::writeInt32(int32_t value) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(value); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_INT; + memcpy(&mStorage[mPos + 1], &value, sizeof(value)); + mPos += needed; +} + +void EventLog::TagBuffer::writeInt64(int64_t value) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(value); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_LONG; + memcpy(&mStorage[mPos + 1], &value, sizeof(value)); + mPos += needed; +} + +void EventLog::TagBuffer::writeString8(const String8& value) { + if (mOverflow) return; + const int32_t stringLen = value.length(); + const size_t needed = 1 + sizeof(int32_t) + stringLen; + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_STRING; + memcpy(&mStorage[mPos + 1], &stringLen, sizeof(int32_t)); + memcpy(&mStorage[mPos + 5], value.string(), stringLen); + mPos += needed; +} + +// --------------------------------------------------------------------------- +}// namespace android + +// --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h new file mode 100644 index 0000000..2f1cd9b --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLog.h @@ -0,0 +1,83 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <utils/Errors.h> +#include <utils/Singleton.h> + +#ifndef ANDROID_SF_EVENTLOG_H +#define ANDROID_SF_EVENTLOG_H + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class String8; + +class EventLog : public Singleton<EventLog> { + +public: + static void logJank(const String8& window, int32_t value); + +protected: + EventLog(); + +private: + /* + * EventLogBuffer is a helper class to construct an in-memory event log + * tag. In this version the buffer is not dynamic, so write operation can + * fail if there is not enough space in the temporary buffer. + * Once constructed, the buffer can be logger by calling the log() + * method. + */ + + class TagBuffer { + enum { STORAGE_MAX_SIZE = 128 }; + int32_t mPos; + int32_t mTag; + bool mOverflow; + char mStorage[STORAGE_MAX_SIZE]; + public: + TagBuffer(int32_t tag); + + // starts list of items + void startList(int8_t count); + // terminates the list + void endList(); + // write a 32-bit integer + void writeInt32(int32_t value); + // write a 64-bit integer + void writeInt64(int64_t value); + // write a C string + void writeString8(const String8& value); + + // outputs the the buffer to the log + void log(); + }; + + friend class Singleton<EventLog>; + EventLog(const EventLog&); + EventLog& operator =(const EventLog&); + + enum { LOGTAG_SF_JANK = 60100 }; + void doLogJank(const String8& window, int32_t value); +}; + +// --------------------------------------------------------------------------- +}// namespace android +// --------------------------------------------------------------------------- + +#endif /* ANDROID_SF_EVENTLOG_H */ diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/EventLog/EventLogTags.logtags new file mode 100644 index 0000000..c83692f --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLogTags.logtags @@ -0,0 +1,38 @@ +# The entries in this file map a sparse set of log tag numbers to tag names. +# This is installed on the device, in /system/etc, and parsed by logcat. +# +# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the +# negative values alone for now.) +# +# Tag names are one or more ASCII letters and numbers or underscores, i.e. +# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former +# impacts log readability, the latter makes regex searches more annoying). +# +# Tag numbers and names are separated by whitespace. Blank lines and lines +# starting with '#' are ignored. +# +# Optionally, after the tag names can be put a description for the value(s) +# of the tag. Description are in the format +# (<name>|data type[|data unit]) +# Multiple values are separated by commas. +# +# The data type is a number from the following values: +# 1: int +# 2: long +# 3: string +# 4: list +# +# The data unit is a number taken from the following list: +# 1: Number of objects +# 2: Number of bytes +# 3: Number of milliseconds +# 4: Number of allocations +# 5: Id +# 6: Percent +# Default value for data of type int/long is 2 (bytes). + +# surfaceflinger +60100 sf_jank (window|3),(value|1) + +# NOTE - the range 1000000-2000000 is reserved for partners and others who +# want to define their own log tags without conflicting with the core platform. diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 4d0fc79..4126c8a 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -320,7 +320,7 @@ void EventThread::disableVSyncLocked() { mDebugVsyncEnabled = false; } -void EventThread::dump(String8& result, char* buffer, size_t SIZE) const { +void EventThread::dump(String8& result) const { Mutex::Autolock _l(mLock); result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled?"enabled":"disabled"); diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index 1934f98..f6bd676 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -84,7 +84,7 @@ public: Vector< sp<EventThread::Connection> > waitForEvent( DisplayEventReceiver::Event* event); - void dump(String8& result, char* buffer, size_t SIZE) const; + void dump(String8& result) const; private: virtual bool threadLoop(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4779804..b08b8d1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -36,6 +36,7 @@ #include <gui/Surface.h> #include "clz.h" +#include "Colorizer.h" #include "DisplayDevice.h" #include "GLExtensions.h" #include "Layer.h" @@ -164,7 +165,7 @@ void Layer::onRemoved() { // set-up // --------------------------------------------------------------------------- -String8 Layer::getName() const { +const String8& Layer::getName() const { return mName; } @@ -269,13 +270,24 @@ uint32_t Layer::getContentTransform() const { return mCurrentTransform; } +static Rect reduce(const Rect& win, const Region& exclude) { + if (CC_LIKELY(exclude.isEmpty())) { + return win; + } + if (exclude.isRect()) { + return win.reduce(exclude.getBounds()); + } + return Region(win).subtract(exclude).getBounds(); +} + Rect Layer::computeBounds() const { - const Layer::State& s(drawingState()); + const Layer::State& s(getDrawingState()); Rect win(s.active.w, s.active.h); if (!s.active.crop.isEmpty()) { win.intersect(s.active.crop, &win); } - return win; + // subtract the transparent region and snap to the bounds + return reduce(win, s.activeTransparentRegion); } Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { @@ -293,7 +305,7 @@ Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { // the active.crop is the area of the window that gets cropped, but not // scaled in any ways. - const State& s(drawingState()); + const State& s(getDrawingState()); // apply the projection's clipping to the window crop in // layerstack space, and convert-back to layer space. @@ -309,6 +321,9 @@ Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { // window's bounds activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop); + // subtract the transparent region and snap to the bounds + activeCrop = reduce(activeCrop, s.activeTransparentRegion); + if (!activeCrop.isEmpty()) { // Transform the window crop to match the buffer coordinate system, // which means using the inverse of the current transform set on the @@ -357,7 +372,7 @@ void Layer::setGeometry( } // this gives us only the "orientation" component of the transform - const State& s(drawingState()); + const State& s(getDrawingState()); if (!isOpaque() || s.alpha != 0xFF) { layer.setBlending(mPremultipliedAlpha ? HWC_BLENDING_PREMULT : @@ -544,31 +559,88 @@ void Layer::clearWithOpenGL( clearWithOpenGL(hw, clip, 0,0,0,0); } +static void setupOpenGL10(bool premultipliedAlpha, bool opaque, int alpha) { + // OpenGL ES 1.0 doesn't support texture combiners. + // This path doesn't properly handle opaque layers that have non-opaque + // alpha values. The alpha channel will be copied into the framebuffer or + // screenshot, so if the framebuffer or screenshot is blended on top of + // something else, whatever is below the window will incorrectly show + // through. + if (CC_UNLIKELY(alpha < 0xFF)) { + GLfloat floatAlpha = alpha * (1.0f / 255.0f); + if (premultipliedAlpha) { + glColor4f(floatAlpha, floatAlpha, floatAlpha, floatAlpha); + } else { + glColor4f(1.0f, 1.0f, 1.0f, floatAlpha); + } + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } else { + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } +} + +static void setupOpenGL11(bool premultipliedAlpha, bool opaque, int alpha) { + GLenum combineRGB; + GLenum combineAlpha; + GLenum src0Alpha; + GLfloat envColor[4]; + + if (CC_UNLIKELY(alpha < 0xFF)) { + // Cv = premultiplied ? Cs*alpha : Cs + // Av = !opaque ? alpha*As : 1.0 + combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE; + combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE; + src0Alpha = GL_CONSTANT; + envColor[0] = alpha * (1.0f / 255.0f); + } else { + // Cv = Cs + // Av = opaque ? 1.0 : As + combineRGB = GL_REPLACE; + combineAlpha = GL_REPLACE; + src0Alpha = opaque ? GL_CONSTANT : GL_TEXTURE; + envColor[0] = 1.0f; + } + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, combineRGB); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + if (combineRGB == GL_MODULATE) { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + } + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, combineAlpha); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, src0Alpha); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + if (combineAlpha == GL_MODULATE) { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + } + if (combineRGB == GL_MODULATE || src0Alpha == GL_CONSTANT) { + envColor[1] = envColor[0]; + envColor[2] = envColor[0]; + envColor[3] = envColor[0]; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor); + } +} + void Layer::drawWithOpenGL( const sp<const DisplayDevice>& hw, const Region& clip) const { const uint32_t fbHeight = hw->getHeight(); - const State& s(drawingState()); + const State& s(getDrawingState()); - GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; - if (CC_UNLIKELY(s.alpha < 0xFF)) { - const GLfloat alpha = s.alpha * (1.0f/255.0f); - if (mPremultipliedAlpha) { - glColor4f(alpha, alpha, alpha, alpha); - } else { - glColor4f(1, 1, 1, alpha); - } + if (mFlinger->getGlesVersion() == GLES_VERSION_1_0) { + setupOpenGL10(mPremultipliedAlpha, isOpaque(), s.alpha); + } else { + setupOpenGL11(mPremultipliedAlpha, isOpaque(), s.alpha); + } + + if (s.alpha < 0xFF || !isOpaque()) { glEnable(GL_BLEND); - glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBlendFunc(mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA); } else { - glColor4f(1, 1, 1, 1); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - if (!isOpaque()) { - glEnable(GL_BLEND); - glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); - } else { - glDisable(GL_BLEND); - } + glDisable(GL_BLEND); } LayerMesh mesh; @@ -658,13 +730,15 @@ bool Layer::getOpacityForFormat(uint32_t format) void Layer::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const { - const Layer::State& s(drawingState()); + const Layer::State& s(getDrawingState()); const Transform tr(hw->getTransform() * s.transform); const uint32_t hw_h = hw->getHeight(); Rect win(s.active.w, s.active.h); if (!s.active.crop.isEmpty()) { win.intersect(s.active.crop, &win); } + // subtract the transparent region and snap to the bounds + win = reduce(win, s.activeTransparentRegion); if (mesh) { tr.transform(mesh->mVertices[0], win.left, win.top); tr.transform(mesh->mVertices[1], win.left, win.bottom); @@ -731,11 +805,11 @@ void Layer::setVisibleNonTransparentRegion(const Region& uint32_t Layer::doTransaction(uint32_t flags) { ATRACE_CALL(); - const Layer::State& front(drawingState()); - const Layer::State& temp(currentState()); + const Layer::State& s(getDrawingState()); + const Layer::State& c(getCurrentState()); - const bool sizeChanged = (temp.requested.w != front.requested.w) || - (temp.requested.h != front.requested.h); + const bool sizeChanged = (c.requested.w != s.requested.w) || + (c.requested.h != s.requested.h); if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer @@ -745,46 +819,46 @@ uint32_t Layer::doTransaction(uint32_t flags) { " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n" " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n", - this, (const char*) getName(), mCurrentTransform, mCurrentScalingMode, - temp.active.w, temp.active.h, - temp.active.crop.left, - temp.active.crop.top, - temp.active.crop.right, - temp.active.crop.bottom, - temp.active.crop.getWidth(), - temp.active.crop.getHeight(), - temp.requested.w, temp.requested.h, - temp.requested.crop.left, - temp.requested.crop.top, - temp.requested.crop.right, - temp.requested.crop.bottom, - temp.requested.crop.getWidth(), - temp.requested.crop.getHeight(), - front.active.w, front.active.h, - front.active.crop.left, - front.active.crop.top, - front.active.crop.right, - front.active.crop.bottom, - front.active.crop.getWidth(), - front.active.crop.getHeight(), - front.requested.w, front.requested.h, - front.requested.crop.left, - front.requested.crop.top, - front.requested.crop.right, - front.requested.crop.bottom, - front.requested.crop.getWidth(), - front.requested.crop.getHeight()); + this, getName().string(), mCurrentTransform, mCurrentScalingMode, + c.active.w, c.active.h, + c.active.crop.left, + c.active.crop.top, + c.active.crop.right, + c.active.crop.bottom, + c.active.crop.getWidth(), + c.active.crop.getHeight(), + c.requested.w, c.requested.h, + c.requested.crop.left, + c.requested.crop.top, + c.requested.crop.right, + c.requested.crop.bottom, + c.requested.crop.getWidth(), + c.requested.crop.getHeight(), + s.active.w, s.active.h, + s.active.crop.left, + s.active.crop.top, + s.active.crop.right, + s.active.crop.bottom, + s.active.crop.getWidth(), + s.active.crop.getHeight(), + s.requested.w, s.requested.h, + s.requested.crop.left, + s.requested.crop.top, + s.requested.crop.right, + s.requested.crop.bottom, + s.requested.crop.getWidth(), + s.requested.crop.getHeight()); // record the new size, form this point on, when the client request // a buffer, it'll get the new size. mSurfaceFlingerConsumer->setDefaultBufferSize( - temp.requested.w, temp.requested.h); + c.requested.w, c.requested.h); } if (!isFixedSize()) { - const bool resizePending = (temp.requested.w != temp.active.w) || - (temp.requested.h != temp.active.h); + const bool resizePending = (c.requested.w != c.active.w) || + (c.requested.h != c.active.h); if (resizePending) { // don't let Layer::doTransaction update the drawing state @@ -804,23 +878,23 @@ uint32_t Layer::doTransaction(uint32_t flags) { // this is used by Layer, which special cases resizes. if (flags & eDontUpdateGeometryState) { } else { - Layer::State& editTemp(currentState()); - editTemp.active = temp.requested; + Layer::State& editCurrentState(getCurrentState()); + editCurrentState.active = c.requested; } - if (front.active != temp.active) { + if (s.active != c.active) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; } - if (temp.sequence != front.sequence) { + if (c.sequence != s.sequence) { // invalidate and recompute the visible regions if needed flags |= eVisibleRegion; this->contentDirty = true; // we may use linear filtering, if the matrix scales us - const uint8_t type = temp.transform.getType(); - mNeedsFiltering = (!temp.transform.preserveRects() || + const uint8_t type = c.transform.getType(); + mNeedsFiltering = (!c.transform.preserveRects() || (type >= Transform::SCALE)); } @@ -1085,7 +1159,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) }; - Reject r(mDrawingState, currentState(), recomputeVisibleRegions); + Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions); if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) { // something happened! @@ -1139,11 +1213,11 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // FIXME: postedRegion should be dirty & bounds - const Layer::State& front(drawingState()); - Region dirtyRegion(Rect(front.active.w, front.active.h)); + const Layer::State& s(getDrawingState()); + Region dirtyRegion(Rect(s.active.w, s.active.h)); // transform the dirty region to window-manager space - outDirtyRegion = (front.transform.transform(dirtyRegion)); + outDirtyRegion = (s.transform.transform(dirtyRegion)); } return outDirtyRegion; } @@ -1178,21 +1252,21 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { // debugging // ---------------------------------------------------------------------------- -void Layer::dump(String8& result, char* buffer, size_t SIZE) const +void Layer::dump(String8& result, Colorizer& colorizer) const { - const Layer::State& s(drawingState()); + const Layer::State& s(getDrawingState()); - snprintf(buffer, SIZE, + colorizer.colorize(result, Colorizer::GREEN); + result.appendFormat( "+ %s %p (%s)\n", getTypeId(), this, getName().string()); - result.append(buffer); + colorizer.reset(result); s.activeTransparentRegion.dump(result, "transparentRegion"); visibleRegion.dump(result, "visibleRegion"); sp<Client> client(mClientRef.promote()); - snprintf(buffer, SIZE, - " " + result.appendFormat( " " "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" @@ -1205,7 +1279,6 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const s.transform[0][0], s.transform[0][1], s.transform[1][0], s.transform[1][1], client.get()); - result.append(buffer); sp<const GraphicBuffer> buf0(mActiveBuffer); uint32_t w0=0, h0=0, s0=0, f0=0; @@ -1215,26 +1288,19 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const s0 = buf0->getStride(); f0 = buf0->format; } - snprintf(buffer, SIZE, + result.appendFormat( " " "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," " queued-frames=%d, mRefreshPending=%d\n", mFormat, w0, h0, s0,f0, mQueuedFrames, mRefreshPending); - result.append(buffer); - if (mSurfaceFlingerConsumer != 0) { - mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE); + mSurfaceFlingerConsumer->dump(result, " "); } } - -void Layer::shortDump(String8& result, char* scratch, size_t size) const { - Layer::dump(result, scratch, size); -} - -void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const { +void Layer::dumpStats(String8& result) const { mFrameTracker.dump(result); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2765db1..f79bf2d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -51,6 +51,7 @@ namespace android { // --------------------------------------------------------------------------- class Client; +class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; @@ -130,6 +131,7 @@ public: Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags); + virtual ~Layer(); // the this layer's size and format @@ -146,8 +148,6 @@ public: bool setCrop(const Rect& crop); bool setLayerStack(uint32_t layerStack); - void commitTransaction(); - uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); @@ -156,79 +156,104 @@ public: sp<IBinder> getHandle(); sp<BufferQueue> getBufferQueue() const; - String8 getName() const; + const String8& getName() const; // ----------------------------------------------------------------------- + // Virtuals virtual const char* getTypeId() const { return "Layer"; } - virtual void setGeometry(const sp<const DisplayDevice>& hw, + /* + * isOpaque - true if this surface is opaque + */ + virtual bool isOpaque() const; + + /* + * isSecure - true if this surface is secure, that is if it prevents + * screenshots or VNC servers. + */ + virtual bool isSecure() const { return mSecure; } + + /* + * isProtected - true if the layer may contain protected content in the + * GRALLOC_USAGE_PROTECTED sense. + */ + virtual bool isProtected() const; + + /* + * isVisible - true if this layer is visible, false otherwise + */ + virtual bool isVisible() const; + + /* + * isFixedSize - true if content has a fixed size + */ + virtual bool isFixedSize() const; + +protected: + /* + * onDraw - draws the surface. + */ + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; + +public: + // ----------------------------------------------------------------------- + + void setGeometry(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); - virtual void setPerFrameData(const sp<const DisplayDevice>& hw, + void setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); - virtual void setAcquireFence(const sp<const DisplayDevice>& hw, + void setAcquireFence(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); /* * called after page-flip */ - virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw, + void onLayerDisplayed(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface* layer); /* * called before composition. * returns true if the layer has pending updates. */ - virtual bool onPreComposition(); + bool onPreComposition(); /* * called after composition. */ - virtual void onPostComposition(); + void onPostComposition(); /* * draw - performs some global clipping optimizations * and calls onDraw(). - * Typically this method is not overridden, instead implement onDraw() - * to perform the actual drawing. - */ - virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; - virtual void draw(const sp<const DisplayDevice>& hw); - - /* - * onDraw - draws the surface. */ - virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; - - /* - * needsLinearFiltering - true if this surface's state requires filtering - */ - virtual bool needsFiltering(const sp<const DisplayDevice>& hw) const; + void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; + void draw(const sp<const DisplayDevice>& hw); /* * doTransaction - process the transaction. This is a good place to figure * out which attributes of the surface have changed. */ - virtual uint32_t doTransaction(uint32_t transactionFlags); + uint32_t doTransaction(uint32_t transactionFlags); /* * setVisibleRegion - called to set the new visible region. This gives * a chance to update the new visible region or record the fact it changed. */ - virtual void setVisibleRegion(const Region& visibleRegion); + void setVisibleRegion(const Region& visibleRegion); /* * setCoveredRegion - called when the covered region changes. The covered * region corresponds to any area of the surface that is covered * (transparently or not) by another surface. */ - virtual void setCoveredRegion(const Region& coveredRegion); + void setCoveredRegion(const Region& coveredRegion); /* * setVisibleNonTransparentRegion - called when the visible and * non-transparent region changes. */ - virtual void setVisibleNonTransparentRegion(const Region& + void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion); /* @@ -237,57 +262,30 @@ public: * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - virtual Region latchBuffer(bool& recomputeVisibleRegions); - - /* - * isOpaque - true if this surface is opaque - */ - virtual bool isOpaque() const; - - /* - * isSecure - true if this surface is secure, that is if it prevents - * screenshots or VNC servers. - */ - virtual bool isSecure() const { return mSecure; } - - /* - * isProtected - true if the layer may contain protected content in the - * GRALLOC_USAGE_PROTECTED sense. - */ - virtual bool isProtected() const; - - /* - * isVisible - true if this layer is visible, false otherwise - */ - virtual bool isVisible() const; - - /* - * isFixedSize - true if content has a fixed size - */ - virtual bool isFixedSize() const; + Region latchBuffer(bool& recomputeVisibleRegions); /* * called with the state lock when the surface is removed from the * current list */ - virtual void onRemoved(); + void onRemoved(); // Updates the transform hint in our SurfaceFlingerConsumer to match // the current orientation of the display device. - virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const; + void updateTransformHint(const sp<const DisplayDevice>& hw) const; /* * returns the rectangle that crops the content of the layer and scales it * to the layer's size. */ - virtual Rect getContentCrop() const; + Rect getContentCrop() const; /* * returns the transform bits (90 rotation / h-flip / v-flip) of the * layer's content */ - virtual uint32_t getContentTransform() const; + uint32_t getContentTransform() const; // ----------------------------------------------------------------------- @@ -298,16 +296,15 @@ public: // only for debugging inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; } - inline const State& drawingState() const { return mDrawingState; } - inline const State& currentState() const { return mCurrentState; } - inline State& currentState() { return mCurrentState; } + inline const State& getDrawingState() const { return mDrawingState; } + inline const State& getCurrentState() const { return mCurrentState; } + inline State& getCurrentState() { return mCurrentState; } /* always call base class first */ - virtual void dump(String8& result, char* scratch, size_t size) const; - virtual void shortDump(String8& result, char* scratch, size_t size) const; - virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const; - virtual void clearStats(); + void dump(String8& result, Colorizer& colorizer) const; + void dumpStats(String8& result) const; + void clearStats(); protected: // constant @@ -333,6 +330,10 @@ private: // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener virtual void onFrameAvailable(); + void commitTransaction(); + + // needsLinearFiltering - true if this surface's state requires filtering + bool needsFiltering(const sp<const DisplayDevice>& hw) const; uint32_t getEffectiveUsage(uint32_t usage) const; Rect computeCrop(const sp<const DisplayDevice>& hw) const; diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index 36bafdb..f4adeeb 100644 --- a/services/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp @@ -43,7 +43,7 @@ LayerDim::~LayerDim() { void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const { - const State& s(drawingState()); + const State& s(getDrawingState()); if (s.alpha>0) { const GLfloat alpha = s.alpha/255.0f; const uint32_t fbHeight = hw->getHeight(); @@ -71,7 +71,7 @@ void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) con } bool LayerDim::isVisible() const { - const Layer::State& s(drawingState()); + const Layer::State& s(getDrawingState()); return !(s.flags & layer_state_t::eLayerHidden) && s.alpha; } diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index e19bf52..2a96149 100644 --- a/services/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h @@ -36,13 +36,10 @@ public: const String8& name, uint32_t w, uint32_t h, uint32_t flags); virtual ~LayerDim(); + virtual const char* getTypeId() const { return "LayerDim"; } virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; virtual bool isOpaque() const { return false; } virtual bool isSecure() const { return false; } - virtual bool isProtectedByApp() const { return false; } - virtual bool isProtectedByDRM() const { return false; } - virtual const char* getTypeId() const { return "LayerDim"; } - virtual bool isFixedSize() const { return true; } virtual bool isVisible() const; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ef0d521..fc193e5 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -55,10 +55,11 @@ #include <private/android_filesystem_config.h> #include <private/gui/SyncFeatures.h> +#include "Client.h" #include "clz.h" +#include "Colorizer.h" #include "DdmConnection.h" #include "DisplayDevice.h" -#include "Client.h" #include "EventThread.h" #include "GLExtensions.h" #include "Layer.h" @@ -413,6 +414,22 @@ EGLContext SurfaceFlinger::createGLContext(EGLDisplay display, EGLConfig config) return ctxt; } +static GlesVersion parseGlesVersion(const char* str) { + int major, minor; + if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { + ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); + return GLES_VERSION_1_0; + } + + if (major == 1 && minor == 0) return GLES_VERSION_1_0; + if (major == 1 && minor >= 1) return GLES_VERSION_1_1; + if (major == 2 && minor >= 0) return GLES_VERSION_2_0; + if (major == 3 && minor >= 0) return GLES_VERSION_3_0; + + ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); + return GLES_VERSION_1_0; +} + void SurfaceFlinger::initializeGL(EGLDisplay display) { GLExtensions& extensions(GLExtensions::getInstance()); extensions.initWithGLStrings( @@ -424,6 +441,8 @@ void SurfaceFlinger::initializeGL(EGLDisplay display) { eglQueryString(display, EGL_VERSION), eglQueryString(display, EGL_EXTENSIONS)); + mGlesVersion = parseGlesVersion(extensions.getVersion()); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); @@ -837,10 +856,10 @@ void SurfaceFlinger::doDebugFlashRegions() void SurfaceFlinger::preComposition() { bool needExtraInvalidate = false; - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const size_t count = currentLayers.size(); + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - if (currentLayers[i]->onPreComposition()) { + if (layers[i]->onPreComposition()) { needExtraInvalidate = true; } } @@ -851,10 +870,10 @@ void SurfaceFlinger::preComposition() void SurfaceFlinger::postComposition() { - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const size_t count = currentLayers.size(); + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - currentLayers[i]->onPostComposition(); + layers[i]->onPostComposition(); } if (mAnimCompositionPending) { @@ -881,7 +900,7 @@ void SurfaceFlinger::rebuildLayerStacks() { mVisibleRegionsDirty = false; invalidateHwcGeometry(); - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + const LayerVector& layers(mDrawingState.layersSortedByZ); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { Region opaqueRegion; Region dirtyRegion; @@ -890,13 +909,13 @@ void SurfaceFlinger::rebuildLayerStacks() { const Transform& tr(hw->getTransform()); const Rect bounds(hw->getBounds()); if (hw->canDraw()) { - SurfaceFlinger::computeVisibleRegions(currentLayers, + SurfaceFlinger::computeVisibleRegions(layers, hw->getLayerStack(), dirtyRegion, opaqueRegion); - const size_t count = currentLayers.size(); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<Layer>& layer(currentLayers[i]); - const Layer::State& s(layer->drawingState()); + const sp<Layer>& layer(layers[i]); + const Layer::State& s(layer->getDrawingState()); if (s.layerStack == hw->getLayerStack()) { Region drawRegion(tr.transform( layer->visibleNonTransparentRegion)); @@ -1037,6 +1056,12 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { ATRACE_CALL(); + // here we keep a copy of the drawing state (that is the state that's + // going to be overwritten by handleTransactionLocked()) outside of + // mStateLock so that the side-effects of the State assignment + // don't happen with mStateLock held (which can cause deadlocks). + State drawingState(mDrawingState); + Mutex::Autolock _l(mStateLock); const nsecs_t now = systemTime(); mDebugInTransaction = now; @@ -1232,7 +1257,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // layerStack first (so we don't have to traverse the list // of displays for every layer). const sp<Layer>& layer(currentLayers[i]); - uint32_t layerStack = layer->drawingState().layerStack; + uint32_t layerStack = layer->getDrawingState().layerStack; if (i==0 || currentlayerStack != layerStack) { currentlayerStack = layerStack; // figure out if this layerstack is mirrored @@ -1269,8 +1294,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) * Perform our own transaction if needed */ - const LayerVector& previousLayers(mDrawingState.layersSortedByZ); - if (currentLayers.size() > previousLayers.size()) { + const LayerVector& layers(mDrawingState.layersSortedByZ); + if (currentLayers.size() > layers.size()) { // layers have been added mVisibleRegionsDirty = true; } @@ -1280,15 +1305,15 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; - const size_t count = previousLayers.size(); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<Layer>& layer(previousLayers[i]); + const sp<Layer>& layer(layers[i]); if (currentLayers.indexOf(layer) < 0) { // this layer is not visible anymore // TODO: we could traverse the tree from front to back and // compute the actual visible region // TODO: we could cache the transformed region - const Layer::State& s(layer->drawingState()); + const Layer::State& s(layer->getDrawingState()); Region visibleReg = s.transform.transform( Region(Rect(s.active.w, s.active.h))); invalidateLayerStack(s.layerStack, visibleReg); @@ -1336,7 +1361,7 @@ void SurfaceFlinger::computeVisibleRegions( const sp<Layer>& layer = currentLayers[i]; // start with the whole surface at its current location - const Layer::State& s(layer->drawingState()); + const Layer::State& s(layer->getDrawingState()); // only consider the layers on the given layer stack if (s.layerStack != layerStack) @@ -1473,12 +1498,12 @@ void SurfaceFlinger::handlePageFlip() Region dirtyRegion; bool visibleRegions = false; - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const size_t count = currentLayers.size(); + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<Layer>& layer(currentLayers[i]); + const sp<Layer>& layer(layers[i]); const Region dirty(layer->latchBuffer(visibleRegions)); - const Layer::State& s(layer->drawingState()); + const Layer::State& s(layer->getDrawingState()); invalidateLayerStack(s.layerStack, dirty); } @@ -2145,19 +2170,15 @@ void SurfaceFlinger::blank(const sp<IBinder>& display) { status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) { - const size_t SIZE = 4096; - char buffer[SIZE]; String8 result; - IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { - snprintf(buffer, SIZE, "Permission Denial: " + result.appendFormat("Permission Denial: " "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); - result.append(buffer); } else { // Try to get the main lock, but don't insist if we can't // (this would indicate SF is stuck, but we want to be able to @@ -2168,10 +2189,9 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) } const bool locked(retry >= 0); if (!locked) { - snprintf(buffer, SIZE, + result.append( "SurfaceFlinger appears to be unresponsive, " "dumping anyways (no locks held)\n"); - result.append(buffer); } bool dumpAll = true; @@ -2181,27 +2201,27 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) if ((index < numArgs) && (args[index] == String16("--list"))) { index++; - listLayersLocked(args, index, result, buffer, SIZE); + listLayersLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--latency"))) { index++; - dumpStatsLocked(args, index, result, buffer, SIZE); + dumpStatsLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--latency-clear"))) { index++; - clearStatsLocked(args, index, result, buffer, SIZE); + clearStatsLocked(args, index, result); dumpAll = false; } } if (dumpAll) { - dumpAllLocked(result, buffer, SIZE); + dumpAllLocked(args, index, result); } if (locked) { @@ -2213,19 +2233,18 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) } void SurfaceFlinger::listLayersLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const + String8& result) const { const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(currentLayers[i]); - snprintf(buffer, SIZE, "%s\n", layer->getName().string()); - result.append(buffer); + result.appendFormat("%s\n", layer->getName().string()); } } void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const + String8& result) const { String8 name; if (index < args.size()) { @@ -2245,14 +2264,14 @@ void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(currentLayers[i]); if (name == layer->getName()) { - layer->dumpStats(result, buffer, SIZE); + layer->dumpStats(result); } } } } void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) + String8& result) { String8 name; if (index < args.size()) { @@ -2292,9 +2311,18 @@ void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& inde result.append(config); } -void SurfaceFlinger::dumpAllLocked( - String8& result, char* buffer, size_t SIZE) const +void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, + String8& result) const { + bool colorize = false; + if (index < args.size() + && (args[index] == String16("--color"))) { + colorize = true; + index++; + } + + Colorizer colorizer(colorize); + // figure out if we're stuck somewhere const nsecs_t now = systemTime(); const nsecs_t inSwapBuffers(mDebugInSwapBuffers); @@ -2305,13 +2333,18 @@ void SurfaceFlinger::dumpAllLocked( /* * Dump library configuration. */ + + colorizer.bold(result); result.append("Build configuration:"); + colorizer.reset(result); appendSfConfigString(result); appendUiConfigString(result); appendGuiConfigString(result); result.append("\n"); + colorizer.bold(result); result.append("Sync configuration: "); + colorizer.reset(result); result.append(SyncFeatures::getInstance().toString()); result.append("\n"); @@ -2320,56 +2353,57 @@ void SurfaceFlinger::dumpAllLocked( */ const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); - snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count); - result.append(buffer); + colorizer.bold(result); + result.appendFormat("Visible layers (count = %d)\n", count); + colorizer.reset(result); for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(currentLayers[i]); - layer->dump(result, buffer, SIZE); + layer->dump(result, colorizer); } /* * Dump Display state */ - snprintf(buffer, SIZE, "Displays (%d entries)\n", mDisplays.size()); - result.append(buffer); + colorizer.bold(result); + result.appendFormat("Displays (%d entries)\n", mDisplays.size()); + colorizer.reset(result); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { const sp<const DisplayDevice>& hw(mDisplays[dpy]); - hw->dump(result, buffer, SIZE); + hw->dump(result); } /* * Dump SurfaceFlinger global state */ - snprintf(buffer, SIZE, "SurfaceFlinger global state:\n"); - result.append(buffer); + colorizer.bold(result); + result.append("SurfaceFlinger global state:\n"); + colorizer.reset(result); HWComposer& hwc(getHwComposer()); sp<const DisplayDevice> hw(getDefaultDisplayDevice()); const GLExtensions& extensions(GLExtensions::getInstance()); - snprintf(buffer, SIZE, "EGL implementation : %s\n", + colorizer.bold(result); + result.appendFormat("EGL implementation : %s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION)); - result.append(buffer); - snprintf(buffer, SIZE, "%s\n", + colorizer.reset(result); + result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); - result.append(buffer); - snprintf(buffer, SIZE, "GLES: %s, %s, %s\n", + colorizer.bold(result); + result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), extensions.getVersion()); - result.append(buffer); - snprintf(buffer, SIZE, "%s\n", extensions.getExtension()); - result.append(buffer); + colorizer.reset(result); + result.appendFormat("%s\n", extensions.getExtension()); hw->undefinedRegion.dump(result, "undefinedRegion"); - snprintf(buffer, SIZE, - " orientation=%d, canDraw=%d\n", + result.appendFormat(" orientation=%d, canDraw=%d\n", hw->getOrientation(), hw->canDraw()); - result.append(buffer); - snprintf(buffer, SIZE, + result.appendFormat( " last eglSwapBuffers() time: %f us\n" " last transaction time : %f us\n" " transaction-flags : %08x\n" @@ -2387,31 +2421,28 @@ void SurfaceFlinger::dumpAllLocked( hwc.getDpiY(HWC_DISPLAY_PRIMARY), mEGLNativeVisualId, !mGpuToCpuSupported); - result.append(buffer); - snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", + result.appendFormat(" eglSwapBuffers time: %f us\n", inSwapBuffersDuration/1000.0); - result.append(buffer); - snprintf(buffer, SIZE, " transaction time: %f us\n", + result.appendFormat(" transaction time: %f us\n", inTransactionDuration/1000.0); - result.append(buffer); /* * VSYNC state */ - mEventThread->dump(result, buffer, SIZE); + mEventThread->dump(result); /* * Dump HWComposer state */ - snprintf(buffer, SIZE, "h/w composer state:\n"); - result.append(buffer); - snprintf(buffer, SIZE, " h/w composer %s and %s\n", + colorizer.bold(result); + result.append("h/w composer state:\n"); + colorizer.reset(result); + result.appendFormat(" h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled"); - result.append(buffer); - hwc.dump(result, buffer, SIZE); + hwc.dump(result); /* * Dump gralloc state @@ -2571,86 +2602,6 @@ void SurfaceFlinger::repaintEverything() { // Capture screen into an IGraphiBufferProducer // --------------------------------------------------------------------------- -/* The code below is here to handle b/8734824 - * - * We create a IGraphicBufferProducer wrapper that forwards all calls - * to the calling binder thread, where they are executed. This allows - * the calling thread to be reused (on the other side) and not - * depend on having "enough" binder threads to handle the requests. - * - */ - -class GraphicProducerWrapper : public BBinder, public MessageHandler { - sp<IGraphicBufferProducer> impl; - sp<Looper> looper; - status_t result; - bool exitPending; - bool exitRequested; - mutable Barrier barrier; - volatile int32_t memoryBarrier; - uint32_t code; - Parcel const* data; - Parcel* reply; - - enum { - MSG_API_CALL, - MSG_EXIT - }; - - /* - * this is called by our "fake" BpGraphicBufferProducer. We package the - * data and reply Parcel and forward them to the calling thread. - */ - virtual status_t transact(uint32_t code, - const Parcel& data, Parcel* reply, uint32_t flags) { - this->code = code; - this->data = &data; - this->reply = reply; - android_atomic_acquire_store(0, &memoryBarrier); - if (exitPending) { - // if we've exited, we run the message synchronously right here - handleMessage(Message(MSG_API_CALL)); - } else { - barrier.close(); - looper->sendMessage(this, Message(MSG_API_CALL)); - barrier.wait(); - } - return NO_ERROR; - } - - /* - * here we run on the binder calling thread. All we've got to do is - * call the real BpGraphicBufferProducer. - */ - virtual void handleMessage(const Message& message) { - android_atomic_release_load(&memoryBarrier); - if (message.what == MSG_API_CALL) { - impl->asBinder()->transact(code, data[0], reply); - barrier.open(); - } else if (message.what == MSG_EXIT) { - exitRequested = true; - } - } - -public: - GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl) : - impl(impl), looper(new Looper(true)), result(NO_ERROR), - exitPending(false), exitRequested(false) { - } - - status_t waitForResponse() { - do { - looper->pollOnce(-1); - } while (!exitRequested); - return result; - } - - void exit(status_t result) { - exitPending = true; - looper->sendMessage(this, Message(MSG_EXIT)); - } -}; - status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, @@ -2663,25 +2614,24 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, if (CC_UNLIKELY(producer == 0)) return BAD_VALUE; - class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; sp<IBinder> display; sp<IGraphicBufferProducer> producer; uint32_t reqWidth, reqHeight; uint32_t minLayerZ,maxLayerZ; - bool useReadPixels; + bool isCpuConsumer; status_t result; public: MessageCaptureScreen(SurfaceFlinger* flinger, const sp<IBinder>& display, const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ, bool useReadPixels) + uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer) : flinger(flinger), display(display), producer(producer), reqWidth(reqWidth), reqHeight(reqHeight), minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), - useReadPixels(useReadPixels), + isCpuConsumer(isCpuConsumer), result(PERMISSION_DENIED) { } @@ -2691,14 +2641,11 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); sp<const DisplayDevice> hw(flinger->getDisplayDevice(display)); - if (!useReadPixels) { - result = flinger->captureScreenImplLocked(hw, - producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); - } else { - result = flinger->captureScreenImplCpuConsumerLocked(hw, - producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); - } - static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(result); + bool useReadPixels = isCpuConsumer && !flinger->mGpuToCpuSupported; + result = flinger->captureScreenImplLocked(hw, + producer, reqWidth, reqHeight, minLayerZ, maxLayerZ, + useReadPixels); + return true; } }; @@ -2710,40 +2657,12 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, // scheduled at this time, this will end-up being a no-op as well. mEventQueue.invalidateTransactionNow(); - bool useReadPixels = false; - if (isCpuConsumer) { - bool formatSupportedBytBitmap = - (mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBA_8888) || - (mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBX_8888); - if (formatSupportedBytBitmap == false) { - // the pixel format we have is not compatible with - // Bitmap.java, which is the likely client of this API, - // so we just revert to glReadPixels() in that case. - useReadPixels = true; - } - if (mGpuToCpuSupported == false) { - // When we know the GL->CPU path works, we can call - // captureScreenImplLocked() directly, instead of using the - // glReadPixels() workaround. - useReadPixels = true; - } - } - - // this creates a "fake" BBinder which will serve as a "fake" remote - // binder to receive the marshaled calls and forward them to the - // real remote (a BpGraphicBufferProducer) - sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer); - - // the asInterface() call below creates our "fake" BpGraphicBufferProducer - // which does the marshaling work forwards to our "fake remote" above. sp<MessageBase> msg = new MessageCaptureScreen(this, - display, IGraphicBufferProducer::asInterface( wrapper ), - reqWidth, reqHeight, minLayerZ, maxLayerZ, - useReadPixels); - - status_t res = postMessageAsync(msg); + display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ, + isCpuConsumer); + status_t res = postMessageSync(msg); if (res == NO_ERROR) { - res = wrapper->waitForResponse(); + res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); } return res; } @@ -2786,7 +2705,7 @@ void SurfaceFlinger::renderScreenImplLocked( const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<Layer>& layer(layers[i]); - const Layer::State& state(layer->drawingState()); + const Layer::State& state(layer->getDrawingState()); if (state.layerStack == hw->getLayerStack()) { if (state.z >= minLayerZ && state.z <= maxLayerZ) { if (layer->isVisible()) { @@ -2807,73 +2726,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( const sp<const DisplayDevice>& hw, const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) -{ - ATRACE_CALL(); - - // get screen geometry - const uint32_t hw_w = hw->getWidth(); - const uint32_t hw_h = hw->getHeight(); - - // if we have secure windows on this display, never allow the screen capture - if (hw->getSecureLayerVisible()) { - ALOGW("FB is protected: PERMISSION_DENIED"); - return PERMISSION_DENIED; - } - - if ((reqWidth > hw_w) || (reqHeight > hw_h)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - reqWidth, reqHeight, hw_w, hw_h); - return BAD_VALUE; - } - - reqWidth = (!reqWidth) ? hw_w : reqWidth; - reqHeight = (!reqHeight) ? hw_h : reqHeight; - - // Create a surface to render into - sp<Surface> surface = new Surface(producer); - ANativeWindow* const window = surface.get(); - - // set the buffer size to what the user requested - native_window_set_buffers_user_dimensions(window, reqWidth, reqHeight); - - // and create the corresponding EGLSurface - EGLSurface eglSurface = eglCreateWindowSurface( - mEGLDisplay, mEGLConfig, window, NULL); - if (eglSurface == EGL_NO_SURFACE) { - ALOGE("captureScreenImplLocked: eglCreateWindowSurface() failed 0x%4x", - eglGetError()); - return BAD_VALUE; - } - - if (!eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) { - ALOGE("captureScreenImplLocked: eglMakeCurrent() failed 0x%4x", - eglGetError()); - eglDestroySurface(mEGLDisplay, eglSurface); - return BAD_VALUE; - } - - renderScreenImplLocked(hw, reqWidth, reqHeight, minLayerZ, maxLayerZ, false); - - // and finishing things up... - if (eglSwapBuffers(mEGLDisplay, eglSurface) != EGL_TRUE) { - ALOGE("captureScreenImplLocked: eglSwapBuffers() failed 0x%4x", - eglGetError()); - eglDestroySurface(mEGLDisplay, eglSurface); - return BAD_VALUE; - } - - eglDestroySurface(mEGLDisplay, eglSurface); - - return NO_ERROR; -} - - -status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useReadPixels) { ATRACE_CALL(); @@ -2900,67 +2754,103 @@ status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked( reqWidth = (!reqWidth) ? hw_w : reqWidth; reqHeight = (!reqHeight) ? hw_h : reqHeight; - GLuint tname; - glGenRenderbuffersOES(1, &tname); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, reqWidth, reqHeight); + // create a surface (because we're a producer, and we need to + // dequeue/queue a buffer) + sp<Surface> sur = new Surface(producer); + ANativeWindow* window = sur.get(); - // create a FBO - GLuint name; - glGenFramebuffersOES(1, &name); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, - GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); + status_t result = NO_ERROR; + if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) { + uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; + if (!useReadPixels) { + usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; + } - GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + int err = 0; + err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); + err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); + err |= native_window_set_usage(window, usage); - status_t result = NO_ERROR; - if (status == GL_FRAMEBUFFER_COMPLETE_OES) { - - renderScreenImplLocked(hw, reqWidth, reqHeight, minLayerZ, maxLayerZ, true); - - // Below we render the screenshot into the - // CpuConsumer using glReadPixels from our FBO. - // Some older drivers don't support the GL->CPU path so we - // have to wrap it with a CPU->CPU path, which is what - // glReadPixels essentially is. - - sp<Surface> sur = new Surface(producer); - ANativeWindow* window = sur.get(); - - if (native_window_api_connect(window, NATIVE_WINDOW_API_CPU) == NO_ERROR) { - int err = 0; - err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); - err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); - err |= native_window_set_usage(window, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - - if (err == NO_ERROR) { - ANativeWindowBuffer* buffer; - if (native_window_dequeue_buffer_and_wait(window, &buffer) == NO_ERROR) { - sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(buffer); - void* vaddr; - if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) { - glReadPixels(0, 0, buffer->stride, reqHeight, - GL_RGBA, GL_UNSIGNED_BYTE, vaddr); - buf->unlock(); + if (err == NO_ERROR) { + ANativeWindowBuffer* buffer; + /* TODO: Once we have the sync framework everywhere this can use + * server-side waits on the fence that dequeueBuffer returns. + */ + result = native_window_dequeue_buffer_and_wait(window, &buffer); + if (result == NO_ERROR) { + // create an EGLImage from the buffer so we can later + // turn it into a texture + EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); + if (image != EGL_NO_IMAGE_KHR) { + GLuint tname, name; + if (!useReadPixels) { + // turn our EGLImage into a texture + glGenTextures(1, &tname); + glBindTexture(GL_TEXTURE_2D, tname); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); + // create a Framebuffer Object to render into + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); + } else { + // since we're going to use glReadPixels() anyways, + // use an intermediate renderbuffer instead + glGenRenderbuffersOES(1, &tname); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, reqWidth, reqHeight); + // create a FBO to render into + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); + } + + GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + if (status == GL_FRAMEBUFFER_COMPLETE_OES) { + // this will in fact render into our dequeued buffer + // via an FBO, which means we didn't have to create + // an EGLSurface and therefore we're not + // dependent on the context's EGLConfig. + renderScreenImplLocked(hw, reqWidth, reqHeight, + minLayerZ, maxLayerZ, true); + + if (useReadPixels) { + sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(buffer); + void* vaddr; + if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) { + glReadPixels(0, 0, buffer->stride, reqHeight, + GL_RGBA, GL_UNSIGNED_BYTE, vaddr); + buf->unlock(); + } + } + } else { + ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); + result = INVALID_OPERATION; } - window->queueBuffer(window, buffer, -1); + + // back to main framebuffer + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + glDeleteFramebuffersOES(1, &name); + if (!useReadPixels) { + glDeleteTextures(1, &tname); + } else { + glDeleteRenderbuffersOES(1, &tname); + } + // destroy our image + eglDestroyImageKHR(mEGLDisplay, image); + } else { + result = BAD_VALUE; } + window->queueBuffer(window, buffer, -1); } - native_window_api_disconnect(window, NATIVE_WINDOW_API_CPU); + } else { + result = BAD_VALUE; } - - } else { - ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES while taking screenshot"); - result = INVALID_OPERATION; + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } - // back to main framebuffer - glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); - glDeleteRenderbuffersOES(1, &tname); - glDeleteFramebuffersOES(1, &name); - DisplayDevice::setViewportAndProjection(hw); return result; @@ -2982,13 +2872,13 @@ int SurfaceFlinger::LayerVector::do_compare(const void* lhs, const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs)); const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs)); - uint32_t ls = l->currentState().layerStack; - uint32_t rs = r->currentState().layerStack; + uint32_t ls = l->getCurrentState().layerStack; + uint32_t rs = r->getCurrentState().layerStack; if (ls != rs) return ls - rs; - uint32_t lz = l->currentState().z; - uint32_t rz = r->currentState().z; + uint32_t lz = l->getCurrentState().z; + uint32_t rz = r->getCurrentState().z; if (lz != rz) return lz - rz; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 739099c..089c265 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -72,6 +72,13 @@ enum { eTransactionMask = 0x07 }; +enum GlesVersion { + GLES_VERSION_1_0 = 0x10000, + GLES_VERSION_1_1 = 0x10001, + GLES_VERSION_2_0 = 0x20000, + GLES_VERSION_3_0 = 0x30000, +}; + class SurfaceFlinger : public BinderService<SurfaceFlinger>, public BnSurfaceComposer, private IBinder::DeathRecipient, @@ -79,11 +86,11 @@ class SurfaceFlinger : public BinderService<SurfaceFlinger>, private HWComposer::EventHandler { public: - static char const* getServiceName() { + static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } - SurfaceFlinger(); + SurfaceFlinger() ANDROID_API; enum { EVENT_VSYNC = HWC_EVENT_VSYNC @@ -121,6 +128,11 @@ public: // TODO: this should be made accessible only to HWComposer const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id); + // return the version of the OpenGL ES composition context + GlesVersion getGlesVersion() const { + return mGlesVersion; + } + private: friend class Client; friend class DisplayEventConnection; @@ -298,14 +310,8 @@ private: const sp<const DisplayDevice>& hw, const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); - - status_t captureScreenImplCpuConsumerLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); - + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useReadPixels); /* ------------------------------------------------------------------------ * EGL @@ -385,12 +391,13 @@ private: * Debugging & dumpsys */ void listLayersLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; + String8& result) const; void dumpStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; + String8& result) const; void clearStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE); - void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const; + String8& result); + void dumpAllLocked(const Vector<String16>& args, size_t& index, + String8& result) const; bool startDdmConnection(); static void appendSfConfigString(String8& result); @@ -426,6 +433,7 @@ private: EGLConfig mEGLConfig; EGLDisplay mEGLDisplay; EGLint mEGLNativeVisualId; + GlesVersion mGlesVersion; sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_DISPLAY_TYPES]; // Can only accessed from the main thread, these members diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 2869250..6912dc0 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -69,7 +69,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter) // reject buffers which have the wrong size int buf = item.mBuf; if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { - releaseBufferLocked(buf, EGL_NO_SYNC_KHR); + releaseBufferLocked(buf, item.mGraphicBuffer, EGL_NO_SYNC_KHR); return NO_ERROR; } |