diff options
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 333 |
1 files changed, 177 insertions, 156 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5cc74a7..8fa0800 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2020,6 +2020,7 @@ sp<LayerScreenshot> SurfaceFlinger::createScreenshotLayer( uint32_t w, uint32_t h, uint32_t flags) { sp<LayerScreenshot> layer = new LayerScreenshot(this, client); + layer->setBuffers(w, h, PIXEL_FORMAT_RGBA_8888, flags); return layer; } @@ -2605,86 +2606,158 @@ void SurfaceFlinger::repaintEverything() { } // --------------------------------------------------------------------------- +// Capture screen into an IGraphiBufferProducer +// --------------------------------------------------------------------------- -status_t SurfaceFlinger::renderScreenToTexture(uint32_t layerStack, - GLuint* textureName, GLfloat* uOut, GLfloat* vOut) -{ - Mutex::Autolock _l(mStateLock); - return renderScreenToTextureLocked(layerStack, textureName, uOut, vOut); +status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, + const sp<IGraphicBufferProducer>& producer, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ) { + + if (CC_UNLIKELY(display == 0)) + return BAD_VALUE; + + 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; + 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) + : flinger(flinger), display(display), producer(producer), + reqWidth(reqWidth), reqHeight(reqHeight), + minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), + result(PERMISSION_DENIED) + { + } + status_t getResult() const { + return result; + } + virtual bool handler() { + Mutex::Autolock _l(flinger->mStateLock); + sp<const DisplayDevice> hw(flinger->getDisplayDevice(display)); + result = flinger->captureScreenImplLocked(hw, producer, + reqWidth, reqHeight, minLayerZ, maxLayerZ); + return true; + } + }; + + sp<MessageBase> msg = new MessageCaptureScreen(this, + display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); + status_t res = postMessageSync(msg); + if (res == NO_ERROR) { + res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); + } + return res; } -status_t SurfaceFlinger::renderScreenToTextureLocked(uint32_t layerStack, - GLuint* textureName, GLfloat* uOut, GLfloat* vOut) +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(); - if (!GLExtensions::getInstance().haveFramebufferObject()) - return INVALID_OPERATION; - // get screen geometry - // FIXME: figure out what it means to have a screenshot texture w/ multi-display - sp<const DisplayDevice> hw(getDefaultDisplayDevice()); const uint32_t hw_w = hw->getWidth(); const uint32_t hw_h = hw->getHeight(); - GLfloat u = 1; - GLfloat v = 1; + + // 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; + const bool filtering = reqWidth != hw_w || reqWidth != hw_h; + + // 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; + } // make sure to clear all GL error flags while ( glGetError() != GL_NO_ERROR ) ; - // create a FBO - GLuint name, tname; - glGenTextures(1, &tname); - glBindTexture(GL_TEXTURE_2D, tname); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - if (glGetError() != GL_NO_ERROR) { - while ( glGetError() != GL_NO_ERROR ) ; - GLint tw = (2 << (31 - clz(hw_w))); - GLint th = (2 << (31 - clz(hw_h))); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - u = GLfloat(hw_w) / tw; - v = GLfloat(hw_h) / th; - } - glGenFramebuffersOES(1, &name); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); - glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, - GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); - - DisplayDevice::setViewportAndProjection(hw); + // set-up our viewport + glViewport(0, 0, reqWidth, reqHeight); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(0, hw_w, 0, hw_h, 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); // redraw the screen entirely... glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); - layer->draw(hw); + const uint32_t z = layer->drawingState().z; + if (z >= minLayerZ && z <= maxLayerZ) { + if (filtering) layer->setFiltering(true); + layer->draw(hw); + if (filtering) layer->setFiltering(false); + } } - hw->compositionComplete(); - - // back to main framebuffer - glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); - glDeleteFramebuffersOES(1, &name); + // and finishing things up... + if (eglSwapBuffers(mEGLDisplay, eglSurface) != EGL_TRUE) { + ALOGE("captureScreenImplLocked: eglSwapBuffers() failed 0x%4x", + eglGetError()); + eglDestroySurface(mEGLDisplay, eglSurface); + return BAD_VALUE; + } - *textureName = tname; - *uOut = u; - *vOut = v; + eglDestroySurface(mEGLDisplay, eglSurface); return NO_ERROR; } // --------------------------------------------------------------------------- +// Capture screen into an IMemoryHeap (legacy) +// --------------------------------------------------------------------------- -status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display, +status_t SurfaceFlinger::captureScreenImplLocked( + const sp<const DisplayDevice>& hw, sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, uint32_t sw, uint32_t sh, @@ -2692,85 +2765,41 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display, { ATRACE_CALL(); - status_t result = PERMISSION_DENIED; - if (!GLExtensions::getInstance().haveFramebufferObject()) { return INVALID_OPERATION; } - // get screen geometry - sp<const DisplayDevice> hw(getDisplayDevice(display)); - 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 ((sw > hw_w) || (sh > hw_h)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", sw, sh, hw_w, hw_h); - return BAD_VALUE; - } - - sw = (!sw) ? hw_w : sw; - sh = (!sh) ? hw_h : sh; - const size_t size = sw * sh * 4; - const bool filtering = sw != hw_w || sh != hw_h; - -// ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d", -// sw, sh, minLayerZ, maxLayerZ); - - // make sure to clear all GL error flags - while ( glGetError() != GL_NO_ERROR ) ; - - // create a FBO - GLuint name, tname; - glGenRenderbuffersOES(1, &tname); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh); - - 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) { - - // invert everything, b/c glReadPixel() below will invert the FB - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - glViewport(0, 0, sw, sh); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrthof(0, hw_w, hw_h, 0, 0, 1); - glMatrixMode(GL_MODELVIEW); + // create the texture that will receive the screenshot, later we'll + // attach a FBO to it so we can call glReadPixels(). + GLuint tname; + glGenTextures(1, &tname); + glBindTexture(GL_TEXTURE_2D, tname); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // redraw the screen entirely... - glClearColor(0,0,0,1); - glClear(GL_COLOR_BUFFER_BIT); + // the GLConsumer will provide the BufferQueue + sp<GLConsumer> consumer = new GLConsumer(tname, true, GL_TEXTURE_2D); + consumer->getBufferQueue()->setDefaultBufferFormat(HAL_PIXEL_FORMAT_RGBA_8888); + + // call the new screenshot taking code, passing a BufferQueue to it + status_t result = captureScreenImplLocked(hw, + consumer->getBufferQueue(), sw, sh, minLayerZ, maxLayerZ); + + if (result == NO_ERROR) { + result = consumer->updateTexImage(); + if (result == NO_ERROR) { + // create a FBO + GLuint name; + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); + + sp<GraphicBuffer> buf(consumer->getCurrentBuffer()); + sw = buf->getWidth(); + sh = buf->getHeight(); + size_t size = buf->getStride() * sh * 4; - const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); - const size_t count = layers.size(); - for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer(layers[i]); - const uint32_t z = layer->drawingState().z; - if (z >= minLayerZ && z <= maxLayerZ) { - if (filtering) layer->setFiltering(true); - layer->draw(hw); - if (filtering) layer->setFiltering(false); - } - } - - // check for errors and return screen capture - if (glGetError() != GL_NO_ERROR) { - // error while rendering - result = INVALID_OPERATION; - } else { // allocate shared memory large enough to hold the // screen capture sp<MemoryHeapBase> base( @@ -2790,59 +2819,48 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display, } else { result = NO_MEMORY; } + + // back to main framebuffer + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + glDeleteFramebuffersOES(1, &name); } - glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - } else { - result = BAD_VALUE; } - // release FBO resources - glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); - glDeleteRenderbuffersOES(1, &tname); - glDeleteFramebuffersOES(1, &name); - - hw->compositionComplete(); - -// ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK"); + glDeleteTextures(1, &tname); return result; } - status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t sw, uint32_t sh, + uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat, + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ) { if (CC_UNLIKELY(display == 0)) return BAD_VALUE; - if (!GLExtensions::getInstance().haveFramebufferObject()) - return INVALID_OPERATION; - class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; sp<IBinder> display; sp<IMemoryHeap>* heap; - uint32_t* w; - uint32_t* h; - PixelFormat* f; - uint32_t sw; - uint32_t sh; + uint32_t* outWidth; + uint32_t* outHeight; + PixelFormat* outFormat; + uint32_t reqWidth; + uint32_t reqHeight; uint32_t minLayerZ; uint32_t maxLayerZ; status_t result; public: - MessageCaptureScreen(SurfaceFlinger* flinger, const sp<IBinder>& display, - sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, - uint32_t sw, uint32_t sh, + MessageCaptureScreen(SurfaceFlinger* flinger, + const sp<IBinder>& display, sp<IMemoryHeap>* heap, + uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat, + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ) - : flinger(flinger), display(display), - heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), + : flinger(flinger), display(display), heap(heap), + outWidth(outWidth), outHeight(outHeight), outFormat(outFormat), + reqWidth(reqWidth), reqHeight(reqHeight), minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), result(PERMISSION_DENIED) { @@ -2852,14 +2870,17 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, } virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); - result = flinger->captureScreenImplLocked(display, - heap, w, h, f, sw, sh, minLayerZ, maxLayerZ); + sp<const DisplayDevice> hw(flinger->getDisplayDevice(display)); + result = flinger->captureScreenImplLocked(hw, heap, + outWidth, outHeight, outFormat, + reqWidth, reqHeight, minLayerZ, maxLayerZ); return true; } }; - sp<MessageBase> msg = new MessageCaptureScreen(this, - display, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ); + sp<MessageBase> msg = new MessageCaptureScreen(this, display, heap, + outWidth, outHeight, outFormat, + reqWidth, reqHeight, minLayerZ, maxLayerZ); status_t res = postMessageSync(msg); if (res == NO_ERROR) { res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); |