diff options
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 348 |
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; |