Merge "rework how we take screenshots for a CPU consumer" into jb-mr2-dev
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 47f9552..9018b87 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -95,14 +95,6 @@
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& 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<IBinder>& display, sp<IMemoryHeap>* 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 @@
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& 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 @@
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 38c931d..23655c7 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -30,6 +30,7 @@
#include <ui/PixelFormat.h>
+#include <gui/CpuConsumer.h>
#include <gui/SurfaceControl.h>
namespace android {
@@ -38,7 +39,6 @@
class DisplayInfo;
class Composer;
-class IMemoryHeap;
class ISurfaceComposerClient;
class IGraphicBufferProducer;
class Region;
@@ -164,10 +164,9 @@
uint32_t minLayerZ, uint32_t maxLayerZ);
private:
- sp<IMemoryHeap> mHeap;
- uint32_t mWidth;
- uint32_t mHeight;
- PixelFormat mFormat;
+ mutable sp<CpuConsumer> mCpuConsumer;
+ CpuConsumer::LockedBuffer mBuffer;
+ bool mHaveBuffer;
public:
ScreenshotClient();
@@ -180,6 +179,8 @@
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ);
+ sp<CpuConsumer> getCpuConsumer() const;
+
// release memory occupied by the screenshot
void release();
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 0a79ff7..6442a86 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -102,31 +102,11 @@
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t captureScreen(
- const sp<IBinder>& display, sp<IMemoryHeap>* 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<IMemoryHeap>(reply.readStrongBinder());
- *width = reply.readInt32();
- *height = reply.readInt32();
- *format = reply.readInt32();
- return reply.readInt32();
- }
-
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& 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 @@
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 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
- case CAPTURE_SCREEN_DEPRECATED: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- uint32_t reqWidth = data.readInt32();
- uint32_t reqHeight = data.readInt32();
- uint32_t minLayerZ = data.readInt32();
- uint32_t maxLayerZ = data.readInt32();
- sp<IMemoryHeap> 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<IBinder> display = data.readStrongBinder();
@@ -312,8 +275,10 @@
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 4a4c0c8..ec46fce 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -31,6 +31,7 @@
#include <ui/DisplayInfo.h>
+#include <gui/CpuConsumer.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
@@ -617,30 +618,21 @@
sp<ISurfaceComposer> 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<IBinder>& display) {
- sp<ISurfaceComposer> 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<IBinder>& display,
- uint32_t reqWidth, uint32_t reqHeight) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
- 0, -1UL);
+sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
+ if (mCpuConsumer == NULL) {
+ mCpuConsumer = new CpuConsumer(1);
+ mCpuConsumer->setName(String8("ScreenshotClient"));
+ }
+ return mCpuConsumer;
}
status_t ScreenshotClient::update(const sp<IBinder>& display,
@@ -648,38 +640,66 @@
uint32_t minLayerZ, uint32_t maxLayerZ) {
sp<ISurfaceComposer> 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> 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<IBinder>& display) {
+ return ScreenshotClient::update(display, 0, 0, 0, -1UL);
+}
+
+status_t ScreenshotClient::update(const sp<IBinder>& 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 7fcbd2e..8546920 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2416,7 +2416,6 @@
break;
}
case CAPTURE_SCREEN:
- case CAPTURE_SCREEN_DEPRECATED:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
@@ -2511,7 +2510,8 @@
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& 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 @@
sp<IGraphicBufferProducer> producer;
uint32_t reqWidth, reqHeight;
uint32_t minLayerZ,maxLayerZ;
+ 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)
+ 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 @@
virtual bool handler() {
Mutex::Autolock _l(flinger->mStateLock);
sp<const DisplayDevice> 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<MessageBase> 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<MessageCaptureScreen*>( msg.get() )->getResult();
@@ -2655,18 +2667,15 @@
}
eglDestroySurface(mEGLDisplay, eglSurface);
+
return NO_ERROR;
}
-// ---------------------------------------------------------------------------
-// Capture screen into an IMemoryHeap (legacy)
-// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::captureScreenImplLocked(
+status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked(
const sp<const DisplayDevice>& hw,
- sp<IMemoryHeap>* heap,
- uint32_t* w, uint32_t* h, PixelFormat* f,
- uint32_t sw, uint32_t sh,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ)
{
ATRACE_CALL();
@@ -2689,7 +2698,7 @@
// 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 @@
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 = sw * sh * 4;
+ reqWidth = consumer->getCurrentBuffer()->getWidth();
+ reqHeight = consumer->getCurrentBuffer()->getHeight();
- // allocate shared memory large enough to hold the
- // screen capture
- sp<MemoryHeapBase> 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<Surface> 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<GraphicBuffer> buf =
+ static_cast<GraphicBuffer*>(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 ; y<reqHeight ; y++) {
+ memcpy((uint32_t*)vaddr + y*buffer->stride,
+ 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 @@
return result;
}
-status_t SurfaceFlinger::captureScreen(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)
-{
- if (CC_UNLIKELY(display == 0))
- return BAD_VALUE;
-
- class MessageCaptureScreen : public MessageBase {
- SurfaceFlinger* flinger;
- 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;
- status_t result;
- public:
- 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),
- 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<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,
- outWidth, outHeight, outFormat,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
- status_t res = postMessageSync(msg);
- if (res == NO_ERROR) {
- res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
- }
- return res;
-}
-
// ---------------------------------------------------------------------------
SurfaceFlinger::LayerVector::LayerVector() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e6734d2..2aacfe7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -185,14 +185,10 @@
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const;
virtual sp<IDisplayEventConnection> createDisplayEventConnection();
- virtual status_t captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* 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<IBinder>& display,
const sp<IGraphicBufferProducer>& 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<IBinder>& display);
// called when screen is turning back on
@@ -297,17 +293,17 @@
status_t captureScreenImplLocked(
const sp<const DisplayDevice>& hw,
- sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
- uint32_t maxLayerZ);
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
- status_t captureScreenImplLocked(
+ status_t captureScreenImplCpuConsumerLocked(
const sp<const DisplayDevice>& hw,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ);
+
/* ------------------------------------------------------------------------
* EGL
*/