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

Commit 9a78c90c authored by Jamie Gennis's avatar Jamie Gennis
Browse files

Fix remote GraphicBuffer allocation in SurfaceFlinger.

This change fixes a horrible hack that I did to allow application
processes to create GraphicBuffer objects by making a binder call to
SurfaceFlinger.  This change introduces a new binder interface
specifically for doing this, and does it in such a way that
SurfaceFlinger will maintain a reference to the buffers until the app is
done with them.

Change-Id: Icb240397c6c206d7f69124c1497a829f051cb49b
parent e5366c56
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -26,12 +26,15 @@
#include <ui/GraphicBuffer.h>

#include <utils/threads.h>
#include <utils/Vector.h>

#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"

namespace android {
// ----------------------------------------------------------------------------

class IGraphicBufferAlloc;

class SurfaceTexture : public BnSurfaceTexture {
public:
    enum { MIN_BUFFER_SLOTS = 3 };
@@ -140,6 +143,12 @@ private:
    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
    int mCurrentTexture;

    // mCurrentTextureBuf is the graphic buffer of the current texture. It's
    // possible that this buffer is not associated with any buffer slot, so we
    // must track it separately in order to properly use
    // IGraphicBufferAlloc::freeAllGraphicBuffersExcept.
    sp<GraphicBuffer> mCurrentTextureBuf;

    // mCurrentCrop is the crop rectangle that applies to the current texture.
    // It gets set to mLastQueuedCrop each time updateTexImage is called.
    Rect mCurrentCrop;
@@ -176,6 +185,16 @@ private:
    // changed with a call to setTexName.
    const GLuint mTexName;

    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
    // allocate new GraphicBuffer objects.
    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;

    // mAllocdBuffers is mirror of the list of buffers that SurfaceFlinger is
    // referencing. This is kept so that gralloc implementations do not need to
    // properly handle the case where SurfaceFlinger no longer holds a reference
    // to a buffer, but other processes do.
    Vector<sp<GraphicBuffer> > mAllocdBuffers;

    // mMutex is the mutex used to prevent concurrent access to the member
    // variables of SurfaceTexture objects. It must be locked whenever the
    // member variables are accessed.
+64 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_SF_IGRAPHIC_BUFFER_ALLOC_H
#define ANDROID_SF_IGRAPHIC_BUFFER_ALLOC_H

#include <stdint.h>
#include <sys/types.h>

#include <utils/RefBase.h>

#include <binder/IInterface.h>

namespace android {
// ----------------------------------------------------------------------------

class IGraphicBufferAlloc : public IInterface
{
public:
    DECLARE_META_INTERFACE(GraphicBufferAlloc);

    /* Create a new GraphicBuffer for the client to use.  The server will
     * maintain a reference to the newly created GraphicBuffer until
     * freeAllGraphicBuffers is called.
     */
    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
            PixelFormat format, uint32_t usage) = 0;

    /* Free all but one of the GraphicBuffer objects that the server is
     * currently referencing. If bufIndex is not a valid index of the buffers
     * the server is referencing, then all buffers are freed.
     */
    virtual void freeAllGraphicBuffersExcept(int bufIndex) = 0;
};

// ----------------------------------------------------------------------------

class BnGraphicBufferAlloc : public BnInterface<IGraphicBufferAlloc>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

// ----------------------------------------------------------------------------

}; // namespace android

#endif // ANDROID_SF_IGRAPHIC_BUFFER_ALLOC_H
+6 −8
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <ui/PixelFormat.h>

#include <surfaceflinger/ISurfaceComposerClient.h>
#include <surfaceflinger/IGraphicBufferAlloc.h>

namespace android {
// ----------------------------------------------------------------------------
@@ -96,6 +97,10 @@ public:
     */
    virtual sp<ISurfaceComposerClient> createClientConnection() = 0;

    /* create a graphic buffer allocator
     */
    virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;

    /* retrieve the control block */
    virtual sp<IMemoryHeap> getCblk() const = 0;

@@ -131,13 +136,6 @@ public:
     * This is an ASYNCHRONOUS call.
     */
    virtual void signal() const = 0;

    /* Create a new GraphicBuffer for the client to use.  SurfaceFlinger will
     * not maintain a reference to the GraphicBuffer, so the underlying native
     * handle will be freed once the client references are released.
     */
    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
            PixelFormat format, uint32_t usage) const = 0;
};

// ----------------------------------------------------------------------------
@@ -151,7 +149,7 @@ public:
        BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
        CREATE_CONNECTION,
        CREATE_CLIENT_CONNECTION,
        CREATE_GRAPHIC_BUFFER,
        CREATE_GRAPHIC_BUFFER_ALLOC,
        GET_CBLK,
        OPEN_GLOBAL_TRANSACTION,
        CLOSE_GLOBAL_TRANSACTION,
+30 −13
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@

#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/IGraphicBufferAlloc.h>

#include <utils/Log.h>

@@ -83,6 +84,8 @@ SurfaceTexture::SurfaceTexture(GLuint tex) :
        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
        mSlots[i].mOwnedByClient = false;
    }
    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
}

SurfaceTexture::~SurfaceTexture() {
@@ -110,9 +113,8 @@ sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
        return 0;
    }
    usage |= GraphicBuffer::USAGE_HW_TEXTURE;
    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
    sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h,
            format, usage));
    sp<GraphicBuffer> graphicBuffer(
            mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage));
    if (graphicBuffer == 0) {
        LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
    } else {
@@ -122,6 +124,7 @@ sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
            mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
        }
        mAllocdBuffers.add(graphicBuffer);
    }
    return graphicBuffer;
}
@@ -204,27 +207,28 @@ status_t SurfaceTexture::updateTexImage() {
    // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
    // so this check will fail until a buffer gets queued.
    if (mCurrentTexture != mLastQueued) {
        // Update the SurfaceTexture state.
        mCurrentTexture = mLastQueued;
        mCurrentCrop = mLastQueuedCrop;
        mCurrentTransform = mLastQueuedTransform;

        // Update the GL texture object.
        EGLImageKHR image = mSlots[mCurrentTexture].mEglImage;
        EGLImageKHR image = mSlots[mLastQueued].mEglImage;
        if (image == EGL_NO_IMAGE_KHR) {
            EGLDisplay dpy = eglGetCurrentDisplay();
            sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer;
            sp<GraphicBuffer> graphicBuffer = mSlots[mLastQueued].mGraphicBuffer;
            image = createImage(dpy, graphicBuffer);
            mSlots[mCurrentTexture].mEglImage = image;
            mSlots[mCurrentTexture].mEglDisplay = dpy;
            mSlots[mLastQueued].mEglImage = image;
            mSlots[mLastQueued].mEglDisplay = dpy;
        }
        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
        GLint error = glGetError();
        if (error != GL_NO_ERROR) {
            LOGE("error binding external texture image %p (slot %d): %#04x",
                    image, mCurrentTexture, error);
                    image, mLastQueued, error);
            return -EINVAL;
        }

        // Update the SurfaceTexture state.
        mCurrentTexture = mLastQueued;
        mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
        mCurrentCrop = mLastQueuedCrop;
        mCurrentTransform = mLastQueuedTransform;
    }
    return OK;
}
@@ -282,6 +286,19 @@ void SurfaceTexture::freeAllBuffers() {
            mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
        }
    }

    int exceptBuf = -1;
    for (size_t i = 0; i < mAllocdBuffers.size(); i++) {
        if (mAllocdBuffers[i] == mCurrentTextureBuf) {
            exceptBuf = i;
            break;
        }
    }
    mAllocdBuffers.clear();
    if (exceptBuf >= 0) {
        mAllocdBuffers.add(mCurrentTextureBuf);
    }
    mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf);
}

EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \
	ISurfaceComposer.cpp \
	ISurface.cpp \
	ISurfaceComposerClient.cpp \
	IGraphicBufferAlloc.cpp \
	LayerState.cpp \
	SharedBufferStack.cpp \
	Surface.cpp \
Loading