Return the transform to apply in getLastQueuedBuffer
Bug: 28428955
Change-Id: Id48f7d3bf3f5deb074cf0a6a52a41caac875db41
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 73f61c5..3e26e05 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -31,6 +31,7 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
+#include <gui/GLConsumer.h>
#include <gui/IConsumerListener.h>
#include <gui/IGraphicBufferAlloc.h>
#include <gui/IProducerListener.h>
@@ -923,6 +924,8 @@
mLastQueueBufferFence->waitForever("Throttling EGL Production");
}
mLastQueueBufferFence = fence;
+ mLastQueuedCrop = item.mCrop;
+ mLastQueuedTransform = item.mTransform;
return NO_ERROR;
}
@@ -1372,7 +1375,7 @@
}
status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
- sp<Fence>* outFence) {
+ sp<Fence>* outFence, float outTransformMatrix[16]) {
ATRACE_CALL();
BQ_LOGV("getLastQueuedBuffer");
@@ -1386,6 +1389,14 @@
*outBuffer = mSlots[mCore->mLastQueuedSlot].mGraphicBuffer;
*outFence = mLastQueueBufferFence;
+ // Currently only SurfaceFlinger internally ever changes
+ // GLConsumer's filtering mode, so we just use 'true' here as
+ // this is slightly specialized for the current client of this API,
+ // which does want filtering.
+ GLConsumer::computeTransformMatrix(outTransformMatrix,
+ mSlots[mCore->mLastQueuedSlot].mGraphicBuffer, mLastQueuedCrop,
+ mLastQueuedTransform, true /* filter */);
+
return NO_ERROR;
}
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 3acd3ab..9937399 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -787,26 +787,40 @@
void GLConsumer::computeCurrentTransformMatrixLocked() {
GLC_LOGV("computeCurrentTransformMatrixLocked");
+ sp<GraphicBuffer> buf = (mCurrentTextureImage == nullptr) ?
+ nullptr : mCurrentTextureImage->graphicBuffer();
+ if (buf == nullptr) {
+ GLC_LOGD("computeCurrentTransformMatrixLocked: "
+ "mCurrentTextureImage is NULL");
+ }
+ computeTransformMatrix(mCurrentTransformMatrix, buf,
+ isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
+ mCurrentTransform, mFilteringEnabled);
+}
+
+void GLConsumer::computeTransformMatrix(float outTransform[16],
+ const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
+ bool filtering) {
float xform[16];
for (int i = 0; i < 16; i++) {
xform[i] = mtxIdentity[i];
}
- if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
float result[16];
mtxMul(result, xform, mtxFlipH);
for (int i = 0; i < 16; i++) {
xform[i] = result[i];
}
}
- if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
float result[16];
mtxMul(result, xform, mtxFlipV);
for (int i = 0; i < 16; i++) {
xform[i] = result[i];
}
}
- if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
float result[16];
mtxMul(result, xform, mtxRot90);
for (int i = 0; i < 16; i++) {
@@ -814,59 +828,49 @@
}
}
- sp<GraphicBuffer> buf = (mCurrentTextureImage == NULL) ?
- NULL : mCurrentTextureImage->graphicBuffer();
-
- if (buf == NULL) {
- GLC_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL");
- }
-
float mtxBeforeFlipV[16];
- if (!isEglImageCroppable(mCurrentCrop)) {
- Rect cropRect = mCurrentCrop;
+ if (!cropRect.isEmpty()) {
float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
float bufferWidth = buf->getWidth();
float bufferHeight = buf->getHeight();
- if (!cropRect.isEmpty()) {
- float shrinkAmount = 0.0f;
- if (mFilteringEnabled) {
- // In order to prevent bilinear sampling beyond the edge of the
- // crop rectangle we may need to shrink it by 2 texels in each
- // dimension. Normally this would just need to take 1/2 a texel
- // off each end, but because the chroma channels of YUV420 images
- // are subsampled we may need to shrink the crop region by a whole
- // texel on each side.
- switch (buf->getPixelFormat()) {
- case PIXEL_FORMAT_RGBA_8888:
- case PIXEL_FORMAT_RGBX_8888:
- case PIXEL_FORMAT_RGB_888:
- case PIXEL_FORMAT_RGB_565:
- case PIXEL_FORMAT_BGRA_8888:
- // We know there's no subsampling of any channels, so we
- // only need to shrink by a half a pixel.
- shrinkAmount = 0.5;
- break;
+ float shrinkAmount = 0.0f;
+ if (filtering) {
+ // In order to prevent bilinear sampling beyond the edge of the
+ // crop rectangle we may need to shrink it by 2 texels in each
+ // dimension. Normally this would just need to take 1/2 a texel
+ // off each end, but because the chroma channels of YUV420 images
+ // are subsampled we may need to shrink the crop region by a whole
+ // texel on each side.
+ switch (buf->getPixelFormat()) {
+ case PIXEL_FORMAT_RGBA_8888:
+ case PIXEL_FORMAT_RGBX_8888:
+ case PIXEL_FORMAT_RGB_888:
+ case PIXEL_FORMAT_RGB_565:
+ case PIXEL_FORMAT_BGRA_8888:
+ // We know there's no subsampling of any channels, so we
+ // only need to shrink by a half a pixel.
+ shrinkAmount = 0.5;
+ break;
- default:
- // If we don't recognize the format, we must assume the
- // worst case (that we care about), which is YUV420.
- shrinkAmount = 1.0;
- break;
- }
+ default:
+ // If we don't recognize the format, we must assume the
+ // worst case (that we care about), which is YUV420.
+ shrinkAmount = 1.0;
+ break;
}
+ }
- // Only shrink the dimensions that are not the size of the buffer.
- if (cropRect.width() < bufferWidth) {
- tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
- sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
- bufferWidth;
- }
- if (cropRect.height() < bufferHeight) {
- ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
- bufferHeight;
- sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
- bufferHeight;
- }
+ // Only shrink the dimensions that are not the size of the buffer.
+ if (cropRect.width() < bufferWidth) {
+ tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
+ sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) /
+ bufferWidth;
+ }
+ if (cropRect.height() < bufferHeight) {
+ ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) /
+ bufferHeight;
+ sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
+ bufferHeight;
}
float crop[16] = {
sx, 0, 0, 0,
@@ -886,7 +890,7 @@
// coordinate of 0, so GLConsumer must behave the same way. We don't
// want to expose this to applications, however, so we must add an
// additional vertical flip to the transform after all the other transforms.
- mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
+ mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV);
}
nsecs_t GLConsumer::getTimestamp() {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 137a54b..2c48d83 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -382,7 +382,7 @@
}
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
- sp<Fence>* outFence) override {
+ sp<Fence>* outFence, float outTransformMatrix[16]) override {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
status_t result = remote()->transact(GET_LAST_QUEUED_BUFFER, data,
@@ -400,6 +400,9 @@
if (hasBuffer) {
buffer = new GraphicBuffer();
result = reply.read(*buffer);
+ if (result == NO_ERROR) {
+ result = reply.read(outTransformMatrix, sizeof(float) * 16);
+ }
}
if (result != NO_ERROR) {
ALOGE("getLastQueuedBuffer failed to read buffer: %d", result);
@@ -630,7 +633,8 @@
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
sp<GraphicBuffer> buffer(nullptr);
sp<Fence> fence(Fence::NO_FENCE);
- status_t result = getLastQueuedBuffer(&buffer, &fence);
+ float transform[16] = {};
+ status_t result = getLastQueuedBuffer(&buffer, &fence, transform);
reply->writeInt32(result);
if (result != NO_ERROR) {
return result;
@@ -640,6 +644,9 @@
} else {
reply->writeBool(true);
result = reply->write(*buffer);
+ if (result == NO_ERROR) {
+ reply->write(transform, sizeof(float) * 16);
+ }
}
if (result != NO_ERROR) {
ALOGE("getLastQueuedBuffer failed to write buffer: %d", result);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index b304633..6811269 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -128,8 +128,9 @@
}
status_t Surface::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
- sp<Fence>* outFence) {
- return mGraphicBufferProducer->getLastQueuedBuffer(outBuffer, outFence);
+ sp<Fence>* outFence, float outTransformMatrix[16]) {
+ return mGraphicBufferProducer->getLastQueuedBuffer(outBuffer, outFence,
+ outTransformMatrix);
}
int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 9876d94..85d63b4 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -842,8 +842,10 @@
// Make sure we got the second buffer back
sp<GraphicBuffer> returnedBuffer;
sp<Fence> returnedFence;
+ float transform[16];
ASSERT_EQ(OK,
- mProducer->getLastQueuedBuffer(&returnedBuffer, &returnedFence));
+ mProducer->getLastQueuedBuffer(&returnedBuffer, &returnedFence,
+ transform));
ASSERT_EQ(secondBuffer->getNativeBuffer()->handle,
returnedBuffer->getNativeBuffer()->handle);
}