Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff7c2342 authored by Mathias Agopian's avatar Mathias Agopian Committed by Android (Google) Code Review
Browse files

Merge "rework how we take screenshots for a CPU consumer" into jb-mr2-dev

parents a6c1ab52 abe815dd
Loading
Loading
Loading
Loading
+2 −10
Original line number Diff line number Diff line
@@ -95,14 +95,6 @@ public:
    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 @@ public:
    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 @@ public:
        GET_BUILT_IN_DISPLAY,
        SET_TRANSACTION_STATE,
        AUTHENTICATE_SURFACE,
        CAPTURE_SCREEN_DEPRECATED,
        BLANK,
        UNBLANK,
        GET_DISPLAY_INFO,
+6 −5
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@

#include <ui/PixelFormat.h>

#include <gui/CpuConsumer.h>
#include <gui/SurfaceControl.h>

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<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 @@ public:
            uint32_t reqWidth, uint32_t reqHeight,
            uint32_t minLayerZ, uint32_t maxLayerZ);

    sp<CpuConsumer> getCpuConsumer() const;

    // release memory occupied by the screenshot
    void release();

+6 −41
Original line number Diff line number Diff line
@@ -102,31 +102,11 @@ public:
        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 @@ 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<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 @@ 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: {
+49 −29
Original line number Diff line number Diff line
@@ -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 @@ status_t ScreenshotClient::capture(
    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);
sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
    if (mCpuConsumer == NULL) {
        mCpuConsumer = new CpuConsumer(1);
        mCpuConsumer->setName(String8("ScreenshotClient"));
    }

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);
    return mCpuConsumer;
}

status_t ScreenshotClient::update(const sp<IBinder>& display,
@@ -648,38 +640,66 @@ status_t ScreenshotClient::update(const sp<IBinder>& display,
        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);
}

// ----------------------------------------------------------------------------
+80 −95
Original line number Diff line number Diff line
@@ -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<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 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
        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 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
        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 @@ 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<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 @@ 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<GraphicBuffer> buf(consumer->getCurrentBuffer());
            sw = buf->getWidth();
            sh = buf->getHeight();
            size_t size = sw * sh * 4;

            // 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;
            reqWidth = consumer->getCurrentBuffer()->getWidth();
            reqHeight = consumer->getCurrentBuffer()->getHeight();

            {
                // 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 {
                result = NO_MEMORY;
                                    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);
                }
            }

            // back to main framebuffer
@@ -2742,63 +2784,6 @@ status_t SurfaceFlinger::captureScreenImplLocked(
    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() {
Loading