Merge "better fix for [2420565] Surface.lockCanvas() updates the dirty region too often" into kraken
This commit is contained in:
committed by
Android (Google) Code Review
commit
33c8e2b8e0
@@ -324,7 +324,7 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
|
|||||||
|
|
||||||
SkRegion clipReg;
|
SkRegion clipReg;
|
||||||
if (dirtyRegion.isRect()) { // very common case
|
if (dirtyRegion.isRect()) { // very common case
|
||||||
const Rect& b(dirtyRegion.getBounds());
|
const Rect b(dirtyRegion.getBounds());
|
||||||
clipReg.setRect(b.left, b.top, b.right, b.bottom);
|
clipReg.setRect(b.left, b.top, b.right, b.bottom);
|
||||||
} else {
|
} else {
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ private:
|
|||||||
sp<GraphicBuffer> mLockedBuffer;
|
sp<GraphicBuffer> mLockedBuffer;
|
||||||
sp<GraphicBuffer> mPostedBuffer;
|
sp<GraphicBuffer> mPostedBuffer;
|
||||||
mutable Region mOldDirtyRegion;
|
mutable Region mOldDirtyRegion;
|
||||||
bool mNeedFullUpdate;
|
bool mReserved;
|
||||||
|
|
||||||
// query() must be called from dequeueBuffer() thread
|
// query() must be called from dequeueBuffer() thread
|
||||||
uint32_t mWidth;
|
uint32_t mWidth;
|
||||||
|
|||||||
@@ -540,9 +540,15 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
|
|||||||
mFlinger->signalEvent();
|
mFlinger->signalEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mPostedDirtyRegion.isEmpty()) {
|
/* a buffer was posted, so we need to call reloadTexture(), which
|
||||||
reloadTexture( mPostedDirtyRegion );
|
* will update our internal data structures (eg: EGLImageKHR or
|
||||||
}
|
* texture names). we need to do this even if mPostedDirtyRegion is
|
||||||
|
* empty -- it's orthogonal to the fact that a new buffer was posted,
|
||||||
|
* for instance, a degenerate case could be that the user did an empty
|
||||||
|
* update but repainted the buffer with appropriate content (after a
|
||||||
|
* resize for instance).
|
||||||
|
*/
|
||||||
|
reloadTexture( mPostedDirtyRegion );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::unlockPageFlip(
|
void Layer::unlockPageFlip(
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
|
|||||||
mOrientation(0),
|
mOrientation(0),
|
||||||
mLeft(0), mTop(0),
|
mLeft(0), mTop(0),
|
||||||
mTransactionFlags(0),
|
mTransactionFlags(0),
|
||||||
mPremultipliedAlpha(true), mDebug(false),
|
mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
|
||||||
mInvalidate(0)
|
mInvalidate(0)
|
||||||
{
|
{
|
||||||
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
|
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
|
||||||
|
|||||||
@@ -84,10 +84,14 @@ status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
|
|||||||
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
|
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
|
||||||
return BAD_INDEX;
|
return BAD_INDEX;
|
||||||
|
|
||||||
// in the current implementation we only send a single rectangle
|
FlatRegion& reg(buffers[buffer].dirtyRegion);
|
||||||
|
if (dirty.isEmpty()) {
|
||||||
|
reg.count = 0;
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
size_t count;
|
size_t count;
|
||||||
Rect const* r = dirty.getArray(&count);
|
Rect const* r = dirty.getArray(&count);
|
||||||
FlatRegion& reg(buffers[buffer].dirtyRegion);
|
|
||||||
if (count > FlatRegion::NUM_RECT_MAX) {
|
if (count > FlatRegion::NUM_RECT_MAX) {
|
||||||
const Rect bounds(dirty.getBounds());
|
const Rect bounds(dirty.getBounds());
|
||||||
reg.count = 1;
|
reg.count = 1;
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
#define LOG_TAG "Surface"
|
#define LOG_TAG "Surface"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -28,8 +26,6 @@
|
|||||||
#include <utils/CallStack.h>
|
#include <utils/CallStack.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
|
|
||||||
#include <pixelflinger/pixelflinger.h>
|
|
||||||
|
|
||||||
#include <binder/IPCThreadState.h>
|
#include <binder/IPCThreadState.h>
|
||||||
#include <binder/IMemory.h>
|
#include <binder/IMemory.h>
|
||||||
|
|
||||||
@@ -55,6 +51,8 @@ static status_t copyBlt(
|
|||||||
const sp<GraphicBuffer>& src,
|
const sp<GraphicBuffer>& src,
|
||||||
const Region& reg)
|
const Region& reg)
|
||||||
{
|
{
|
||||||
|
// src and dst with, height and format must be identical. no verification
|
||||||
|
// is done here.
|
||||||
status_t err;
|
status_t err;
|
||||||
uint8_t const * src_bits = NULL;
|
uint8_t const * src_bits = NULL;
|
||||||
err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
|
err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
|
||||||
@@ -67,7 +65,6 @@ static status_t copyBlt(
|
|||||||
Region::const_iterator head(reg.begin());
|
Region::const_iterator head(reg.begin());
|
||||||
Region::const_iterator tail(reg.end());
|
Region::const_iterator tail(reg.end());
|
||||||
if (head != tail && src_bits && dst_bits) {
|
if (head != tail && src_bits && dst_bits) {
|
||||||
// NOTE: dst and src must be the same format
|
|
||||||
const size_t bpp = bytesPerPixel(src->format);
|
const size_t bpp = bytesPerPixel(src->format);
|
||||||
const size_t dbpr = dst->stride * bpp;
|
const size_t dbpr = dst->stride * bpp;
|
||||||
const size_t sbpr = src->stride * bpp;
|
const size_t sbpr = src->stride * bpp;
|
||||||
@@ -354,7 +351,6 @@ void Surface::init()
|
|||||||
// be default we request a hardware surface
|
// be default we request a hardware surface
|
||||||
mUsage = GRALLOC_USAGE_HW_RENDER;
|
mUsage = GRALLOC_USAGE_HW_RENDER;
|
||||||
mConnected = 0;
|
mConnected = 0;
|
||||||
mNeedFullUpdate = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface::~Surface()
|
Surface::~Surface()
|
||||||
@@ -734,37 +730,38 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
|
|||||||
LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
|
LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
|
||||||
backBuffer->getIndex(), strerror(-err));
|
backBuffer->getIndex(), strerror(-err));
|
||||||
if (err == NO_ERROR) {
|
if (err == NO_ERROR) {
|
||||||
// we handle copy-back here...
|
|
||||||
|
|
||||||
const Rect bounds(backBuffer->width, backBuffer->height);
|
const Rect bounds(backBuffer->width, backBuffer->height);
|
||||||
Region scratch(bounds);
|
const Region boundsRegion(bounds);
|
||||||
|
Region scratch(boundsRegion);
|
||||||
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
|
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
|
||||||
|
newDirtyRegion &= boundsRegion;
|
||||||
|
|
||||||
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
|
// figure out if we can copy the frontbuffer back
|
||||||
if (mNeedFullUpdate) {
|
|
||||||
mNeedFullUpdate = false;
|
|
||||||
Region uninitialized(bounds);
|
|
||||||
uninitialized.subtractSelf(copyback | newDirtyRegion);
|
|
||||||
// reset newDirtyRegion to bounds when a buffer is reallocated
|
|
||||||
// and we have nothing to copy back to it
|
|
||||||
if (!uninitialized.isEmpty())
|
|
||||||
newDirtyRegion.set(bounds);
|
|
||||||
}
|
|
||||||
newDirtyRegion.andSelf(bounds);
|
|
||||||
|
|
||||||
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
|
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
|
||||||
if (frontBuffer != 0 &&
|
const bool canCopyBack = (frontBuffer != 0 &&
|
||||||
backBuffer->width == frontBuffer->width &&
|
backBuffer->width == frontBuffer->width &&
|
||||||
backBuffer->height == frontBuffer->height &&
|
backBuffer->height == frontBuffer->height &&
|
||||||
!(mFlags & ISurfaceComposer::eDestroyBackbuffer))
|
backBuffer->format == frontBuffer->format &&
|
||||||
{
|
!(mFlags & ISurfaceComposer::eDestroyBackbuffer));
|
||||||
if (!copyback.isEmpty()) {
|
|
||||||
// copy front to back
|
// the dirty region we report to surfaceflinger is the one
|
||||||
|
// given by the user (as opposed to the one *we* return to the
|
||||||
|
// user).
|
||||||
|
mDirtyRegion = newDirtyRegion;
|
||||||
|
|
||||||
|
if (canCopyBack) {
|
||||||
|
// copy the area that is invalid and not repainted this round
|
||||||
|
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
|
||||||
|
if (!copyback.isEmpty())
|
||||||
copyBlt(backBuffer, frontBuffer, copyback);
|
copyBlt(backBuffer, frontBuffer, copyback);
|
||||||
}
|
} else {
|
||||||
|
// if we can't copy-back anything, modify the user's dirty
|
||||||
|
// region to make sure they redraw the whole buffer
|
||||||
|
newDirtyRegion = boundsRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
mDirtyRegion = newDirtyRegion;
|
// keep track of the are of the buffer that is "clean"
|
||||||
|
// (ie: that will be redrawn)
|
||||||
mOldDirtyRegion = newDirtyRegion;
|
mOldDirtyRegion = newDirtyRegion;
|
||||||
|
|
||||||
void* vaddr;
|
void* vaddr;
|
||||||
@@ -843,7 +840,6 @@ status_t Surface::getBufferLocked(int index, int usage)
|
|||||||
if (err == NO_ERROR) {
|
if (err == NO_ERROR) {
|
||||||
currentBuffer = buffer;
|
currentBuffer = buffer;
|
||||||
currentBuffer->setIndex(index);
|
currentBuffer->setIndex(index);
|
||||||
mNeedFullUpdate = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = err<0 ? err : NO_MEMORY;
|
err = err<0 ? err : NO_MEMORY;
|
||||||
|
|||||||
Reference in New Issue
Block a user