diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h index 47f955282..9018b87a2 100644 --- a/include/gui/ISurfaceComposer.h +++ b/include/gui/ISurfaceComposer.h @@ -95,14 +95,6 @@ public: virtual bool authenticateSurfaceTexture( const sp& surface) const = 0; - /* Capture the specified screen. requires READ_FRAME_BUFFER permission - * This function will fail if there is a secure window on screen. - */ - virtual status_t captureScreen(const sp& display, sp* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) = 0; - /* triggers screen off and waits for it to complete * requires ACCESS_SURFACE_FLINGER permission. */ @@ -123,7 +115,8 @@ public: virtual status_t captureScreen(const sp& display, const sp& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) = 0; + uint32_t minLayerZ, uint32_t maxLayerZ, + bool isCpuConsumer) = 0; }; // ---------------------------------------------------------------------------- @@ -141,7 +134,6 @@ public: GET_BUILT_IN_DISPLAY, SET_TRANSACTION_STATE, AUTHENTICATE_SURFACE, - CAPTURE_SCREEN_DEPRECATED, BLANK, UNBLANK, GET_DISPLAY_INFO, diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h index 38c931d23..23655c7ec 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/include/gui/SurfaceComposerClient.h @@ -30,6 +30,7 @@ #include +#include #include namespace android { @@ -38,7 +39,6 @@ namespace android { class DisplayInfo; class Composer; -class IMemoryHeap; class ISurfaceComposerClient; class IGraphicBufferProducer; class Region; @@ -164,10 +164,9 @@ public: uint32_t minLayerZ, uint32_t maxLayerZ); private: - sp mHeap; - uint32_t mWidth; - uint32_t mHeight; - PixelFormat mFormat; + mutable sp mCpuConsumer; + CpuConsumer::LockedBuffer mBuffer; + bool mHaveBuffer; public: ScreenshotClient(); @@ -180,6 +179,8 @@ public: uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ); + sp getCpuConsumer() const; + // release memory occupied by the screenshot void release(); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0a79ff763..6442a8600 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -102,31 +102,11 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureScreen( - const sp& display, sp* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - data.writeInt32(reqWidth); - data.writeInt32(reqHeight); - data.writeInt32(minLayerZ); - data.writeInt32(maxLayerZ); - remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN_DEPRECATED, data, &reply); - *heap = interface_cast(reply.readStrongBinder()); - *width = reply.readInt32(); - *height = reply.readInt32(); - *format = reply.readInt32(); - return reply.readInt32(); - } - virtual status_t captureScreen(const sp& display, const sp& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) + uint32_t minLayerZ, uint32_t maxLayerZ, + bool isCpuConsumer) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -136,6 +116,7 @@ public: data.writeInt32(reqHeight); data.writeInt32(minLayerZ); data.writeInt32(maxLayerZ); + data.writeInt32(isCpuConsumer); remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); return reply.readInt32(); } @@ -285,24 +266,6 @@ status_t BnSurfaceComposer::onTransact( CHECK_INTERFACE(ISurfaceComposer, data, reply); bootFinished(); } break; - case CAPTURE_SCREEN_DEPRECATED: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp display = data.readStrongBinder(); - uint32_t reqWidth = data.readInt32(); - uint32_t reqHeight = data.readInt32(); - uint32_t minLayerZ = data.readInt32(); - uint32_t maxLayerZ = data.readInt32(); - sp heap; - uint32_t w, h; - PixelFormat f; - status_t res = captureScreen(display, &heap, &w, &h, &f, - reqWidth, reqHeight, minLayerZ, maxLayerZ); - reply->writeStrongBinder(heap->asBinder()); - reply->writeInt32(w); - reply->writeInt32(h); - reply->writeInt32(f); - reply->writeInt32(res); - } break; case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); @@ -312,8 +275,10 @@ status_t BnSurfaceComposer::onTransact( uint32_t reqHeight = data.readInt32(); uint32_t minLayerZ = data.readInt32(); uint32_t maxLayerZ = data.readInt32(); + bool isCpuConsumer = data.readInt32(); status_t res = captureScreen(display, producer, - reqWidth, reqHeight, minLayerZ, maxLayerZ); + reqWidth, reqHeight, minLayerZ, maxLayerZ, + isCpuConsumer); reply->writeInt32(res); } break; case AUTHENTICATE_SURFACE: { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 4a4c0c8df..ec46fce40 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -31,6 +31,7 @@ #include +#include #include #include #include @@ -617,30 +618,21 @@ status_t ScreenshotClient::capture( sp s(ComposerService::getComposerService()); if (s == NULL) return NO_INIT; return s->captureScreen(display, producer, - reqWidth, reqHeight, minLayerZ, maxLayerZ); + reqWidth, reqHeight, minLayerZ, maxLayerZ, + false); } ScreenshotClient::ScreenshotClient() - : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) { + : mHaveBuffer(false) { + memset(&mBuffer, 0, sizeof(mBuffer)); } -status_t ScreenshotClient::update(const sp& display) { - sp s(ComposerService::getComposerService()); - if (s == NULL) return NO_INIT; - mHeap = 0; - return s->captureScreen(display, &mHeap, - &mWidth, &mHeight, &mFormat, 0, 0, - 0, -1UL); -} - -status_t ScreenshotClient::update(const sp& display, - uint32_t reqWidth, uint32_t reqHeight) { - sp s(ComposerService::getComposerService()); - if (s == NULL) return NO_INIT; - mHeap = 0; - return s->captureScreen(display, &mHeap, - &mWidth, &mHeight, &mFormat, reqWidth, reqHeight, - 0, -1UL); +sp ScreenshotClient::getCpuConsumer() const { + if (mCpuConsumer == NULL) { + mCpuConsumer = new CpuConsumer(1); + mCpuConsumer->setName(String8("ScreenshotClient")); + } + return mCpuConsumer; } status_t ScreenshotClient::update(const sp& display, @@ -648,38 +640,66 @@ status_t ScreenshotClient::update(const sp& display, uint32_t minLayerZ, uint32_t maxLayerZ) { sp s(ComposerService::getComposerService()); if (s == NULL) return NO_INIT; - mHeap = 0; - return s->captureScreen(display, &mHeap, - &mWidth, &mHeight, &mFormat, reqWidth, reqHeight, - minLayerZ, maxLayerZ); + sp cpuConsumer = getCpuConsumer(); + + if (mHaveBuffer) { + mCpuConsumer->unlockBuffer(mBuffer); + memset(&mBuffer, 0, sizeof(mBuffer)); + mHaveBuffer = false; + } + + status_t err = s->captureScreen(display,cpuConsumer->getBufferQueue(), + reqWidth, reqHeight, minLayerZ, maxLayerZ, true); + + if (err == NO_ERROR) { + err = mCpuConsumer->lockNextBuffer(&mBuffer); + if (err == NO_ERROR) { + mHaveBuffer = true; + } + } + return err; +} + +status_t ScreenshotClient::update(const sp& display) { + return ScreenshotClient::update(display, 0, 0, 0, -1UL); +} + +status_t ScreenshotClient::update(const sp& display, + uint32_t reqWidth, uint32_t reqHeight) { + return ScreenshotClient::update(display, reqWidth, reqHeight, 0, -1UL); } void ScreenshotClient::release() { - mHeap = 0; + if (mHaveBuffer) { + mCpuConsumer->unlockBuffer(mBuffer); + memset(&mBuffer, 0, sizeof(mBuffer)); + mHaveBuffer = false; + } + mCpuConsumer.clear(); } void const* ScreenshotClient::getPixels() const { - return mHeap->getBase(); + return mBuffer.data; } uint32_t ScreenshotClient::getWidth() const { - return mWidth; + return mBuffer.width; } uint32_t ScreenshotClient::getHeight() const { - return mHeight; + return mBuffer.height; } PixelFormat ScreenshotClient::getFormat() const { - return mFormat; + return mBuffer.format; } uint32_t ScreenshotClient::getStride() const { - return mWidth; + return mBuffer.stride; } size_t ScreenshotClient::getSize() const { - return mHeap->getSize(); + return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format); } // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7fcbd2e6a..854692056 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2416,7 +2416,6 @@ status_t SurfaceFlinger::onTransact( break; } case CAPTURE_SCREEN: - case CAPTURE_SCREEN_DEPRECATED: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); @@ -2511,7 +2510,8 @@ void SurfaceFlinger::repaintEverything() { status_t SurfaceFlinger::captureScreen(const sp& display, const sp& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) { + uint32_t minLayerZ, uint32_t maxLayerZ, + bool isCpuConsumer) { if (CC_UNLIKELY(display == 0)) return BAD_VALUE; @@ -2525,16 +2525,18 @@ status_t SurfaceFlinger::captureScreen(const sp& display, sp producer; uint32_t reqWidth, reqHeight; uint32_t minLayerZ,maxLayerZ; + bool isCpuConsumer; status_t result; public: MessageCaptureScreen(SurfaceFlinger* flinger, const sp& display, const sp& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) + uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer) : flinger(flinger), display(display), producer(producer), reqWidth(reqWidth), reqHeight(reqHeight), minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), + isCpuConsumer(isCpuConsumer), result(PERMISSION_DENIED) { } @@ -2544,14 +2546,24 @@ status_t SurfaceFlinger::captureScreen(const sp& display, virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); sp hw(flinger->getDisplayDevice(display)); - result = flinger->captureScreenImplLocked(hw, producer, - reqWidth, reqHeight, minLayerZ, maxLayerZ); + // TODO: if we know the GL->CPU path works, we can call + // captureScreenImplLocked() directly, instead of using the + // "CpuConsumer" version, which is much less efficient -- it is + // however needed by some older drivers. + if (isCpuConsumer) { + result = flinger->captureScreenImplCpuConsumerLocked(hw, + producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); + } else { + result = flinger->captureScreenImplLocked(hw, + producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); + } return true; } }; sp msg = new MessageCaptureScreen(this, - display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); + display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ, + isCpuConsumer); status_t res = postMessageSync(msg); if (res == NO_ERROR) { res = static_cast( msg.get() )->getResult(); @@ -2655,18 +2667,15 @@ status_t SurfaceFlinger::captureScreenImplLocked( } eglDestroySurface(mEGLDisplay, eglSurface); + return NO_ERROR; } -// --------------------------------------------------------------------------- -// Capture screen into an IMemoryHeap (legacy) -// --------------------------------------------------------------------------- -status_t SurfaceFlinger::captureScreenImplLocked( +status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked( const sp& hw, - sp* heap, - uint32_t* w, uint32_t* h, PixelFormat* f, - uint32_t sw, uint32_t sh, + const sp& producer, + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ) { ATRACE_CALL(); @@ -2689,7 +2698,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( // call the new screenshot taking code, passing a BufferQueue to it status_t result = captureScreenImplLocked(hw, - consumer->getBufferQueue(), sw, sh, minLayerZ, maxLayerZ); + consumer->getBufferQueue(), reqWidth, reqHeight, minLayerZ, maxLayerZ); if (result == NO_ERROR) { result = consumer->updateTexImage(); @@ -2701,31 +2710,64 @@ status_t SurfaceFlinger::captureScreenImplLocked( glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); - sp buf(consumer->getCurrentBuffer()); - sw = buf->getWidth(); - sh = buf->getHeight(); - size_t size = sw * sh * 4; + reqWidth = consumer->getCurrentBuffer()->getWidth(); + reqHeight = consumer->getCurrentBuffer()->getHeight(); - // allocate shared memory large enough to hold the - // screen capture - sp base( - new MemoryHeapBase(size, 0, "screen-capture") ); - void* const ptr = base->getBase(); - if (ptr != MAP_FAILED) { - // capture the screen with glReadPixels() - ScopedTrace _t(ATRACE_TAG, "glReadPixels"); - glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr); - if (glGetError() == GL_NO_ERROR) { - *heap = base; - *w = sw; - *h = sh; - *f = PIXEL_FORMAT_RGBA_8888; - result = NO_ERROR; - } else { - result = NO_MEMORY; + { + // in this block we render the screenshot into the + // CpuConsumer using glReadPixels from our GLConsumer, + // Some older drivers don't support the GL->CPU path so + // have to wrap it with a CPU->CPU path, which is what + // glReadPixels essentially is + + sp sur = new Surface(producer); + ANativeWindow* window = sur.get(); + ANativeWindowBuffer* buffer; + void* vaddr; + + 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) { + if (native_window_dequeue_buffer_and_wait(window, + &buffer) == NO_ERROR) { + sp buf = + static_cast(buffer); + if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, + &vaddr) == NO_ERROR) { + if (buffer->stride != int(reqWidth)) { + // we're unlucky here, glReadPixels is + // not able to deal with a stride not + // equal to the width. + uint32_t* tmp = new uint32_t[reqWidth*reqHeight]; + if (tmp != NULL) { + glReadPixels(0, 0, reqWidth, reqHeight, + GL_RGBA, GL_UNSIGNED_BYTE, tmp); + for (size_t y=0 ; ystride, + tmp + y*reqWidth, reqWidth*4); + } + delete [] tmp; + } + } else { + glReadPixels(0, 0, reqWidth, reqHeight, + GL_RGBA, GL_UNSIGNED_BYTE, vaddr); + } + buf->unlock(); + } + window->queueBuffer(window, buffer, -1); + } + } + native_window_api_disconnect(window, NATIVE_WINDOW_API_CPU); } - } else { - result = NO_MEMORY; } // back to main framebuffer @@ -2742,63 +2784,6 @@ status_t SurfaceFlinger::captureScreenImplLocked( return result; } -status_t SurfaceFlinger::captureScreen(const sp& display, - sp* heap, - 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; - - class MessageCaptureScreen : public MessageBase { - SurfaceFlinger* flinger; - sp display; - sp* heap; - 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& display, sp* 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), - outWidth(outWidth), outHeight(outHeight), outFormat(outFormat), - 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 hw(flinger->getDisplayDevice(display)); - result = flinger->captureScreenImplLocked(hw, heap, - outWidth, outHeight, outFormat, - reqWidth, reqHeight, minLayerZ, maxLayerZ); - return true; - } - }; - - sp 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( msg.get() )->getResult(); - } - return res; -} - // --------------------------------------------------------------------------- SurfaceFlinger::LayerVector::LayerVector() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e6734d2c1..2aacfe753 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -185,14 +185,10 @@ private: virtual bool authenticateSurfaceTexture( const sp& bufferProducer) const; virtual sp createDisplayEventConnection(); - virtual status_t captureScreen(const sp& display, sp* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, - uint32_t maxLayerZ); virtual status_t captureScreen(const sp& display, const sp& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); + uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer); // called when screen needs to turn off virtual void blank(const sp& display); // called when screen is turning back on @@ -297,17 +293,17 @@ private: status_t captureScreenImplLocked( const sp& hw, - sp* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, - uint32_t maxLayerZ); + const sp& producer, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ); - status_t captureScreenImplLocked( + status_t captureScreenImplCpuConsumerLocked( const sp& hw, const sp& producer, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ); + /* ------------------------------------------------------------------------ * EGL */