summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger/SurfaceFlinger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp348
1 files changed, 152 insertions, 196 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e647275..735c822 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"
@@ -2141,19 +2142,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
@@ -2164,10 +2161,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;
@@ -2177,27 +2173,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) {
@@ -2209,19 +2205,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()) {
@@ -2241,14 +2236,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()) {
@@ -2288,9 +2283,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);
@@ -2301,13 +2305,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");
@@ -2316,56 +2325,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"
@@ -2383,31 +2393,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
@@ -2606,33 +2613,11 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
virtual bool handler() {
Mutex::Autolock _l(flinger->mStateLock);
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
+ bool useReadPixels = isCpuConsumer && !flinger->mGpuToCpuSupported;
+ result = flinger->captureScreenImplLocked(hw,
+ producer, reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ useReadPixels);
- bool useReadPixels = false;
- if (isCpuConsumer) {
- bool formatSupportedBytBitmap =
- (flinger->mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBA_8888) ||
- (flinger->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 (flinger->mGpuToCpuSupported == false) {
- // When we know the GL->CPU path works, we can call
- // captureScreenImplLocked() directly, instead of using the
- // glReadPixels() workaround.
- useReadPixels = true;
- }
- }
-
- if (!useReadPixels) {
- result = flinger->captureScreenImplLocked(hw,
- producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
- } else {
- result = flinger->captureScreenImplCpuConsumerLocked(hw,
- producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
- }
return true;
}
};
@@ -2713,73 +2698,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();
@@ -2806,67 +2726,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;