[3171580] SurfaceFlinger Bypass mode. (DO NOT MERGE)
This is a poor's man precursor to the h/w composer HAL. Basically we detect when a window is full screen and in that case we bypass surfaceflinger's composition step, which yields to much improved performance. Change-Id: Ie03796ae81a1c951949b771c9323044b980cb347
This commit is contained in:
@@ -25,6 +25,7 @@ ifeq ($(TARGET_BOARD_PLATFORM), omap3)
|
||||
endif
|
||||
ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
|
||||
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
|
||||
LOCAL_CFLAGS += -DUSE_COMPOSITION_BYPASS
|
||||
endif
|
||||
|
||||
|
||||
|
||||
@@ -339,6 +339,12 @@ void DisplayHardware::flip(const Region& dirty) const
|
||||
//glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
status_t DisplayHardware::postBypassBuffer(const native_handle_t* handle) const
|
||||
{
|
||||
framebuffer_device_t *fbDev = (framebuffer_device_t *)mNativeWindow->getDevice();
|
||||
return fbDev->post(fbDev, handle);
|
||||
}
|
||||
|
||||
uint32_t DisplayHardware::getFlags() const
|
||||
{
|
||||
return mFlags;
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
// Flip the front and back buffers if the back buffer is "dirty". Might
|
||||
// be instantaneous, might involve copying the frame buffer around.
|
||||
void flip(const Region& dirty) const;
|
||||
status_t postBypassBuffer(const native_handle_t* handle) const;
|
||||
|
||||
float getDpiX() const;
|
||||
float getDpiY() const;
|
||||
|
||||
@@ -57,7 +57,8 @@ Layer::Layer(SurfaceFlinger* flinger,
|
||||
mSecure(false),
|
||||
mTextureManager(),
|
||||
mBufferManager(mTextureManager),
|
||||
mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
|
||||
mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false),
|
||||
mBypassState(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -251,6 +252,29 @@ void Layer::onDraw(const Region& clip) const
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_COMPOSITION_BYPASS
|
||||
sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
|
||||
if ((buffer != NULL) && (buffer->transform)) {
|
||||
// Here we have a "bypass" buffer, but we need to composite it
|
||||
// most likely because it's not fullscreen anymore.
|
||||
// Since the buffer may have a transformation applied by the client
|
||||
// we need to inverse this transformation here.
|
||||
|
||||
// calculate the inverse of the buffer transform
|
||||
const uint32_t mask = HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
|
||||
const uint32_t bufferTransformInverse = buffer->transform ^ mask;
|
||||
|
||||
// To accomplish the inverse transform, we use "mBufferTransform"
|
||||
// which is not used by Layer.cpp
|
||||
const_cast<Layer*>(this)->mBufferTransform = bufferTransformInverse;
|
||||
drawWithOpenGL(clip, tex);
|
||||
// reset to "no transfrom"
|
||||
const_cast<Layer*>(this)->mBufferTransform = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
drawWithOpenGL(clip, tex);
|
||||
}
|
||||
|
||||
@@ -311,11 +335,12 @@ sp<GraphicBuffer> Layer::requestBuffer(int index,
|
||||
* buffer 'index' as our front buffer.
|
||||
*/
|
||||
|
||||
status_t err = NO_ERROR;
|
||||
uint32_t w, h, f;
|
||||
uint32_t w, h, f, bypass;
|
||||
{ // scope for the lock
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
bypass = mBypassState;
|
||||
|
||||
// zero means default
|
||||
mFixedSize = reqWidth && reqHeight;
|
||||
if (!reqFormat) reqFormat = mFormat;
|
||||
@@ -340,9 +365,40 @@ sp<GraphicBuffer> Layer::requestBuffer(int index,
|
||||
// here we have to reallocate a new buffer because the buffer could be
|
||||
// used as the front buffer, or by a client in our process
|
||||
// (eg: status bar), and we can't release the handle under its feet.
|
||||
const uint32_t effectiveUsage = getEffectiveUsage(usage);
|
||||
buffer = new GraphicBuffer(w, h, f, effectiveUsage);
|
||||
err = buffer->initCheck();
|
||||
uint32_t effectiveUsage = getEffectiveUsage(usage);
|
||||
|
||||
status_t err = NO_MEMORY;
|
||||
|
||||
#ifdef USE_COMPOSITION_BYPASS
|
||||
if (!mSecure && bypass && (effectiveUsage & GRALLOC_USAGE_HW_RENDER)) {
|
||||
// always allocate a buffer matching the screen size. the size
|
||||
// may be different from (w,h) if the buffer is rotated.
|
||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||
int32_t w = hw.getWidth();
|
||||
int32_t h = hw.getHeight();
|
||||
int32_t f = hw.getFormat();
|
||||
|
||||
buffer = new GraphicBuffer(w, h, f, effectiveUsage | GRALLOC_USAGE_HW_FB);
|
||||
err = buffer->initCheck();
|
||||
buffer->transform = uint8_t(getOrientation());
|
||||
|
||||
if (err != NO_ERROR) {
|
||||
// allocation didn't succeed, probably because an older bypass
|
||||
// window hasn't released all its resources yet.
|
||||
ClientRef::Access sharedClient(mUserClientRef);
|
||||
SharedBufferServer* lcblk(sharedClient.get());
|
||||
if (lcblk) {
|
||||
// all buffers need reallocation
|
||||
lcblk->reallocateAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (err != NO_ERROR) {
|
||||
buffer = new GraphicBuffer(w, h, f, effectiveUsage);
|
||||
err = buffer->initCheck();
|
||||
}
|
||||
|
||||
if (err || buffer->handle == 0) {
|
||||
GraphicBuffer::dumpAllocationsToSystemLog();
|
||||
@@ -389,6 +445,27 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const
|
||||
return usage;
|
||||
}
|
||||
|
||||
bool Layer::setBypass(bool enable)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
if (mNeedsScaling || mNeedsFiltering) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mBypassState != enable) {
|
||||
mBypassState = enable;
|
||||
ClientRef::Access sharedClient(mUserClientRef);
|
||||
SharedBufferServer* lcblk(sharedClient.get());
|
||||
if (lcblk) {
|
||||
// all buffers need reallocation
|
||||
lcblk->reallocateAll();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t Layer::doTransaction(uint32_t flags)
|
||||
{
|
||||
const Layer::State& front(drawingState());
|
||||
@@ -639,9 +716,9 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const
|
||||
snprintf(buffer, SIZE,
|
||||
" "
|
||||
"format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
|
||||
" freezeLock=%p, dq-q-time=%u us\n",
|
||||
" freezeLock=%p, bypass=%d, dq-q-time=%u us\n",
|
||||
mFormat, w0, h0, s0, w1, h1, s1,
|
||||
getFreezeLock().get(), totalTime);
|
||||
getFreezeLock().get(), mBypassState, totalTime);
|
||||
|
||||
result.append(buffer);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,10 @@ public:
|
||||
virtual sp<Surface> createSurface() const;
|
||||
virtual status_t ditch();
|
||||
virtual void onRemoved();
|
||||
virtual bool setBypass(bool enable);
|
||||
|
||||
inline sp<GraphicBuffer> getBypassBuffer() const {
|
||||
return mBufferManager.getActiveBuffer(); }
|
||||
|
||||
// only for debugging
|
||||
inline sp<GraphicBuffer> getBuffer(int i) const {
|
||||
@@ -232,6 +236,7 @@ private:
|
||||
uint32_t mReqFormat;
|
||||
bool mNeedsScaling;
|
||||
bool mFixedSize;
|
||||
bool mBypassState;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#include <pixelflinger/pixelflinger.h>
|
||||
|
||||
#include "DisplayHardware/DisplayHardware.h"
|
||||
#include "Transform.h"
|
||||
|
||||
namespace android {
|
||||
@@ -117,6 +118,11 @@ public:
|
||||
virtual void draw(const Region& clip) const;
|
||||
virtual void drawForSreenShot() const;
|
||||
|
||||
/**
|
||||
* bypass mode
|
||||
*/
|
||||
virtual bool setBypass(bool enable) { return false; }
|
||||
|
||||
/**
|
||||
* onDraw - draws the surface.
|
||||
*/
|
||||
|
||||
@@ -61,6 +61,10 @@
|
||||
#define AID_GRAPHICS 1003
|
||||
#endif
|
||||
|
||||
#ifdef USE_COMPOSITION_BYPASS
|
||||
#warning "using COMPOSITION_BYPASS"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_COUNT 1
|
||||
|
||||
namespace android {
|
||||
@@ -373,8 +377,15 @@ bool SurfaceFlinger::threadLoop()
|
||||
|
||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||
if (LIKELY(hw.canDraw() && !isFrozen())) {
|
||||
// repaint the framebuffer (if needed)
|
||||
|
||||
#ifdef USE_COMPOSITION_BYPASS
|
||||
if (handleBypassLayer()) {
|
||||
unlockClients();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// repaint the framebuffer (if needed)
|
||||
const int index = hw.getCurrentBufferIndex();
|
||||
GraphicLog& logger(GraphicLog::getInstance());
|
||||
|
||||
@@ -401,6 +412,20 @@ bool SurfaceFlinger::threadLoop()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SurfaceFlinger::handleBypassLayer()
|
||||
{
|
||||
sp<Layer> bypassLayer(mBypassLayer.promote());
|
||||
if (bypassLayer != 0) {
|
||||
sp<GraphicBuffer> buffer(bypassLayer->getBypassBuffer());
|
||||
if (buffer!=0 && (buffer->usage & GRALLOC_USAGE_HW_FB)) {
|
||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||
hw.postBypassBuffer(buffer->handle);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SurfaceFlinger::postFramebuffer()
|
||||
{
|
||||
if (!mInvalidRegion.isEmpty()) {
|
||||
@@ -696,6 +721,28 @@ void SurfaceFlinger::commitTransaction()
|
||||
mTransactionCV.broadcast();
|
||||
}
|
||||
|
||||
void SurfaceFlinger::setBypassLayer(const sp<LayerBase>& layer)
|
||||
{
|
||||
// if this layer is already the bypass layer, do nothing
|
||||
sp<Layer> cur(mBypassLayer.promote());
|
||||
if (mBypassLayer == layer)
|
||||
return;
|
||||
|
||||
// clear the current bypass layer
|
||||
mBypassLayer.clear();
|
||||
if (cur != 0) {
|
||||
cur->setBypass(false);
|
||||
cur.clear();
|
||||
}
|
||||
|
||||
// set new bypass layer
|
||||
if (layer != 0) {
|
||||
if (layer->setBypass(true)) {
|
||||
mBypassLayer = static_cast<Layer*>(layer.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceFlinger::handlePageFlip()
|
||||
{
|
||||
bool visibleRegions = mVisibleRegionsDirty;
|
||||
@@ -721,6 +768,21 @@ void SurfaceFlinger::handlePageFlip()
|
||||
mVisibleLayersSortedByZ.add(currentLayers[i]);
|
||||
}
|
||||
|
||||
#ifdef USE_COMPOSITION_BYPASS
|
||||
sp<LayerBase> bypassLayer;
|
||||
const size_t numVisibleLayers = mVisibleLayersSortedByZ.size();
|
||||
if (numVisibleLayers == 1) {
|
||||
const sp<LayerBase>& candidate(mVisibleLayersSortedByZ[0]);
|
||||
const Region& visibleRegion(candidate->visibleRegionScreen);
|
||||
const Region reminder(screenRegion.subtract(visibleRegion));
|
||||
if (reminder.isEmpty()) {
|
||||
// fullscreen candidate!
|
||||
bypassLayer = candidate;
|
||||
}
|
||||
}
|
||||
setBypassLayer(bypassLayer);
|
||||
#endif
|
||||
|
||||
mWormholeRegion = screenRegion.subtract(opaqueRegion);
|
||||
mVisibleRegionsDirty = false;
|
||||
}
|
||||
@@ -1416,9 +1478,9 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
|
||||
mWormholeRegion.dump(result, "WormholeRegion");
|
||||
const DisplayHardware& hw(graphicPlane(0).displayHardware());
|
||||
snprintf(buffer, SIZE,
|
||||
" display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
|
||||
" display frozen: %s, freezeCount=%d, orientation=%d, bypass=%p, canDraw=%d\n",
|
||||
mFreezeDisplay?"yes":"no", mFreezeCount,
|
||||
mCurrentState.orientation, hw.canDraw());
|
||||
mCurrentState.orientation, mBypassLayer.unsafe_get(), hw.canDraw());
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE,
|
||||
" last eglSwapBuffers() time: %f us\n"
|
||||
|
||||
@@ -307,6 +307,7 @@ private:
|
||||
bool lockPageFlip(const LayerVector& currentLayers);
|
||||
void unlockPageFlip(const LayerVector& currentLayers);
|
||||
void handleRepaint();
|
||||
bool handleBypassLayer();
|
||||
void postFramebuffer();
|
||||
void composeSurfaces(const Region& dirty);
|
||||
void unlockClients();
|
||||
@@ -322,6 +323,7 @@ private:
|
||||
uint32_t setTransactionFlags(uint32_t flags);
|
||||
void commitTransaction();
|
||||
|
||||
void setBypassLayer(const sp<LayerBase>& layer);
|
||||
|
||||
status_t captureScreenImplLocked(DisplayID dpy,
|
||||
sp<IMemoryHeap>* heap,
|
||||
@@ -399,6 +401,7 @@ private:
|
||||
int32_t mFreezeCount;
|
||||
nsecs_t mFreezeDisplayTime;
|
||||
Vector< sp<LayerBase> > mVisibleLayersSortedByZ;
|
||||
wp<Layer> mBypassLayer;
|
||||
|
||||
|
||||
// don't use a lock for these, we don't care
|
||||
|
||||
Reference in New Issue
Block a user