Merge "Fix a bug where non-cropped layer could be scaled incorrectly" into klp-dev
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 79b6689..9708ee3 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -198,6 +198,10 @@
mPageFlipCount++;
}
+status_t DisplayDevice::beginFrame() const {
+ return mDisplaySurface->beginFrame();
+}
+
status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
DisplaySurface::CompositionType compositionType;
bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
@@ -218,13 +222,15 @@
}
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
- // We need to call eglSwapBuffers() unless:
- // (a) there was no GLES composition this frame, or
- // (b) we're using a legacy HWC with no framebuffer target support (in
- // which case HWComposer::commit() handles things).
+ // We need to call eglSwapBuffers() if:
+ // (1) we don't have a hardware composer, or
+ // (2) we did GLES composition this frame, and either
+ // (a) we have framebuffer target support (not present on legacy
+ // devices, where HWComposer::commit() handles things); or
+ // (b) this is a virtual display
if (hwc.initCheck() != NO_ERROR ||
(hwc.hasGlesComposition(mHwcDisplayId) &&
- hwc.supportsFramebufferTarget())) {
+ (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {
EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
if (!success) {
EGLint error = eglGetError();
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index eec0396..e0b1370 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -122,6 +122,7 @@
int32_t getHwcDisplayId() const { return mHwcDisplayId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
+ status_t beginFrame() const;
status_t prepareFrame(const HWComposer& hwc) const;
void swapBuffers(HWComposer& hwc) const;
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index 9192db5..48bf3f2 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -30,6 +30,11 @@
class DisplaySurface : public virtual RefBase {
public:
+ // beginFrame is called at the beginning of the composition loop, before
+ // the configuration is known. The DisplaySurface should do anything it
+ // needs to do to enable HWComposer to decide how to compose the frame.
+ virtual status_t beginFrame() = 0;
+
// prepareFrame is called after the composition configuration is known but
// before composition takes place. The DisplaySurface can use the
// composition type to decide how to manage the flow of buffers between
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 807d4e1..8c634ed 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -68,6 +68,10 @@
mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
}
+status_t FramebufferSurface::beginFrame() {
+ return NO_ERROR;
+}
+
status_t FramebufferSurface::prepareFrame(CompositionType compositionType) {
return NO_ERROR;
}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index fcda287..1d67446 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -39,6 +39,7 @@
public:
FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
+ virtual status_t beginFrame();
virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index ef07f18..e7d0d23 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -987,9 +987,9 @@
disp.list->numHwLayers, disp.list->flags);
result.append(
- " type | handle | hints | flags | tr | blend | format | source crop | frame name \n"
- "------------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
- // " __________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
+ " type | handle | hints | flags | tr | blend | format | source crop | frame name \n"
+ "------------+----------+----------+----------+----+-------+----------+---------------------------------+--------------------------------\n");
+ // " __________ | ________ | ________ | ________ | __ | _____ | ________ | [_____._,_____._,_____._,_____._] | [_____,_____,_____,_____]
for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
const hwc_layer_1_t&l = disp.list->hwLayers[i];
int32_t format = -1;
@@ -1020,13 +1020,23 @@
if (type >= NELEM(compositionTypeName))
type = NELEM(compositionTypeName) - 1;
- result.appendFormat(
- " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
- compositionTypeName[type],
- intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
- l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
- l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
- name.string());
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ result.appendFormat(
+ " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%7.1f,%7.1f,%7.1f,%7.1f] | [%5d,%5d,%5d,%5d] %s\n",
+ compositionTypeName[type],
+ intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
+ l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ name.string());
+ } else {
+ result.appendFormat(
+ " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%7d,%7d,%7d,%7d] | [%5d,%5d,%5d,%5d] %s\n",
+ compositionTypeName[type],
+ intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
+ l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ name.string());
+ }
}
}
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 89c87c7..01ca38a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -71,11 +71,26 @@
VirtualDisplaySurface::~VirtualDisplaySurface() {
}
-status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
+status_t VirtualDisplaySurface::beginFrame() {
if (mDisplayId < 0)
return NO_ERROR;
VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
+ "Unexpected beginFrame() in %s state", dbgStateStr());
+ mDbgState = DBG_STATE_BEGUN;
+
+ uint32_t transformHint, numPendingBuffers;
+ mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
+ &transformHint, &numPendingBuffers);
+
+ return refreshOutputBuffer();
+}
+
+status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
+ if (mDisplayId < 0)
+ return NO_ERROR;
+
+ VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN,
"Unexpected prepareFrame() in %s state", dbgStateStr());
mDbgState = DBG_STATE_PREPARED;
@@ -109,31 +124,11 @@
}
mDbgState = DBG_STATE_HWC;
- status_t result;
- sp<Fence> outFence;
- if (mCompositionType != COMPOSITION_GLES) {
- // Dequeue an output buffer from the sink
- uint32_t transformHint, numPendingBuffers;
- mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
- &transformHint, &numPendingBuffers);
- int sslot;
- result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence, false);
- if (result < 0)
- return result;
- mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
- }
-
if (mCompositionType == COMPOSITION_HWC) {
- // We just dequeued the output buffer, use it for FB as well
+ // Use the output buffer for the FB as well, though conceptually the
+ // FB is unused on this frame.
mFbProducerSlot = mOutputProducerSlot;
- mFbFence = outFence;
- } else if (mCompositionType == COMPOSITION_GLES) {
- mOutputProducerSlot = mFbProducerSlot;
- outFence = mFbFence;
- } else {
- // mFbFence and mFbProducerSlot were set in queueBuffer,
- // and mOutputProducerSlot and outFence were set above when dequeueing
- // the sink buffer.
+ mFbFence = mOutputFence;
}
if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) {
@@ -152,12 +147,7 @@
mFbProducerSlot, fbBuffer.get(),
mOutputProducerSlot, outBuffer.get());
- result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
- if (result == NO_ERROR) {
- result = mHwc.setOutputBuffer(mDisplayId, outFence, outBuffer);
- }
-
- return result;
+ return mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
}
void VirtualDisplaySurface::onFrameCommitted() {
@@ -256,17 +246,39 @@
VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
+ status_t result = NO_ERROR;
mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
Source source = fbSourceForCompositionType(mCompositionType);
+
if (source == SOURCE_SINK) {
- mSinkBufferWidth = w;
- mSinkBufferHeight = h;
+ // We already dequeued the output buffer. If the GLES driver wants
+ // something incompatible, we have to cancel and get a new one. This
+ // will mean that HWC will see a different output buffer between
+ // prepare and set, but since we're in GLES-only mode already it
+ // shouldn't matter.
+
+ const sp<GraphicBuffer>& buf = mProducerBuffers[mOutputProducerSlot];
+ if ((mProducerUsage & ~buf->getUsage()) != 0 ||
+ (format != 0 && format != (uint32_t)buf->getPixelFormat()) ||
+ (w != 0 && w != mSinkBufferWidth) ||
+ (h != 0 && h != mSinkBufferHeight)) {
+ VDS_LOGV("dequeueBuffer: output buffer doesn't satisfy GLES "
+ "request, getting a new buffer");
+ result = refreshOutputBuffer();
+ if (result < 0)
+ return result;
+ }
}
- int sslot;
- status_t result = dequeueBuffer(source, format, &sslot, fence, async);
- if (result >= 0) {
- *pslot = mapSource2ProducerSlot(source, sslot);
+ if (source == SOURCE_SINK) {
+ *pslot = mOutputProducerSlot;
+ *fence = mOutputFence;
+ } else {
+ int sslot;
+ result = dequeueBuffer(source, format, &sslot, fence, async);
+ if (result >= 0) {
+ *pslot = mapSource2ProducerSlot(source, sslot);
+ }
}
return result;
}
@@ -318,6 +330,7 @@
&transform, &async, &mFbFence);
mFbProducerSlot = pslot;
+ mOutputFence = mFbFence;
}
*output = mQueueBufferOutput;
@@ -365,10 +378,30 @@
mSinkBufferWidth = 0;
mSinkBufferHeight = 0;
mFbFence = Fence::NO_FENCE;
+ mOutputFence = Fence::NO_FENCE;
mFbProducerSlot = -1;
mOutputProducerSlot = -1;
}
+status_t VirtualDisplaySurface::refreshOutputBuffer() {
+ if (mOutputProducerSlot >= 0) {
+ mSource[SOURCE_SINK]->cancelBuffer(
+ mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
+ mOutputFence);
+ }
+
+ int sslot;
+ status_t result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &mOutputFence, false);
+ if (result < 0)
+ return result;
+ mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
+
+ result = mHwc.setOutputBuffer(mDisplayId, mOutputFence,
+ mProducerBuffers[mOutputProducerSlot]);
+
+ return result;
+}
+
// This slot mapping function is its own inverse, so two copies are unnecessary.
// Both are kept to make the intent clear where the function is called, and for
// the (unlikely) chance that we switch to a different mapping function.
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 64a8dce..4ab80e4 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -79,6 +79,7 @@
//
// DisplaySurface interface
//
+ virtual status_t beginFrame();
virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
@@ -112,6 +113,7 @@
int* sslot, sp<Fence>* fence, bool async);
void updateQueueBufferOutput(const QueueBufferOutput& qbo);
void resetPerFrameState();
+ status_t refreshOutputBuffer();
// Both the sink and scratch buffer pools have their own set of slots
// ("source slots", or "sslot"). We have to merge these into the single
@@ -169,6 +171,10 @@
// target buffer.
sp<Fence> mFbFence;
+ // mOutputFence is the fence HWC should wait for before writing to the
+ // output buffer.
+ sp<Fence> mOutputFence;
+
// Producer slot numbers for the buffers to use for HWC framebuffer target
// and output.
int mFbProducerSlot;
@@ -181,7 +187,8 @@
// +-----------+-------------------+-------------+
// | State | Event || Next State |
// +-----------+-------------------+-------------+
- // | IDLE | prepareFrame || PREPARED |
+ // | IDLE | beginFrame || BEGUN |
+ // | BEGUN | prepareFrame || PREPARED |
// | PREPARED | dequeueBuffer [1] || GLES |
// | PREPARED | advanceFrame [2] || HWC |
// | GLES | queueBuffer || GLES_DONE |
@@ -194,7 +201,10 @@
enum DbgState {
// no buffer dequeued, don't know anything about the next frame
DBG_STATE_IDLE,
- // no buffer dequeued, but we know the buffer source for the frame
+ // output buffer dequeued, framebuffer source not yet known
+ DBG_STATE_BEGUN,
+ // output buffer dequeued, framebuffer source known but not provided
+ // to GLES yet.
DBG_STATE_PREPARED,
// GLES driver has a buffer dequeued
DBG_STATE_GLES,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7e62dae..3058af7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -850,6 +850,10 @@
}
void SurfaceFlinger::setUpHWComposer() {
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ mDisplays[dpy]->beginFrame();
+ }
+
HWComposer& hwc(getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
// build the h/w work list