summaryrefslogtreecommitdiffstats
path: root/libs/gui/SurfaceTexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui/SurfaceTexture.cpp')
-rw-r--r--libs/gui/SurfaceTexture.cpp239
1 files changed, 239 insertions, 0 deletions
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 6a26e6ae6b3..8f628ac3386 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -142,6 +142,10 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
mUseFenceSync(false),
#endif
mTexTarget(texTarget),
+#ifdef STE_HARDWARE
+ mNextBlitSlot(0),
+ mNeedsConversion(false),
+#endif
#ifdef QCOM_HARDWARE
mS3DFormat(0),
#endif
@@ -160,11 +164,30 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
mNextBufferInfo.height = 0;
mNextBufferInfo.format = 0;
#endif
+#ifdef STE_HARDWARE
+
+ for (int i = 0; i < NUM_BLIT_BUFFER_SLOTS; i++) {
+ mBlitSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mBlitSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ }
+
+ hw_module_t const* module;
+ mBlitEngine = 0;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
+ LOGE_IF(!mBlitEngine, "\nCannot open copybit mBlitEngine=%p", mBlitEngine);
+#endif
}
SurfaceTexture::~SurfaceTexture() {
ST_LOGV("~SurfaceTexture");
freeAllBuffersLocked();
+#ifdef STE_HARDWARE
+ if (mBlitEngine) {
+ copybit_close(mBlitEngine);
+ }
+#endif
}
status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
@@ -482,6 +505,7 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+#ifndef STE_HARDWARE
#ifdef QCOM_HARDWARE
qBufGeometry currentGeometry;
if (buffer != NULL)
@@ -511,6 +535,14 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
mGraphicBufferAlloc->freeGraphicBufferAtIndex(buf);
}
#endif
+#else
+ if ((buffer == NULL) ||
+ (uint32_t(buffer->width) != w) ||
+ (uint32_t(buffer->height) != h) ||
+ (uint32_t(buffer->format) != format) ||
+ ((uint32_t(buffer->usage) & usage) != usage))
+ {
+#endif
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
status_t error;
sp<GraphicBuffer> graphicBuffer(
@@ -849,7 +881,16 @@ status_t SurfaceTexture::setScalingMode(int mode) {
return OK;
}
+#ifndef STE_HARDWARE
status_t SurfaceTexture::updateTexImage(bool isComposition) {
+#else
+status_t SurfaceTexture::updateTexImage() {
+ return updateTexImage(false);
+}
+
+#define STE_DEFERDBG 0
+status_t SurfaceTexture::updateTexImage(bool deferConversion) {
+#endif
ST_LOGV("updateTexImage");
Mutex::Autolock lock(mMutex);
@@ -865,6 +906,7 @@ status_t SurfaceTexture::updateTexImage(bool isComposition) {
int buf = *front;
// Update the GL texture object.
+#ifndef STE_HARDWARE
EGLImageKHR image = mSlots[buf].mEglImage;
EGLDisplay dpy = eglGetCurrentDisplay();
#ifdef QCOM_HARDWARE
@@ -894,6 +936,101 @@ status_t SurfaceTexture::updateTexImage(bool isComposition) {
// NOTE: if dpy was invalid, createImage() is guaranteed to
// fail. so we'd end up here.
return -EINVAL;
+#else
+ EGLImageKHR image;
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ sp<GraphicBuffer> graphicBuffer;
+ if (conversionIsNeeded(mSlots[buf].mGraphicBuffer)) {
+ mNeedsConversion = deferConversion;
+ // If color conversion is needed we can't use the graphic buffers
+ // located in mSlots for the textures (wrong color format). Instead
+ // color convert it into a buffer in mBlitSlots and use that instead.
+ image = mBlitSlots[mNextBlitSlot].mEglImage;
+
+ // If there exists an image already, make sure that
+ // the dimensions match the current source buffer.
+ // Otherwise, destroy the buffer and let a new one be allocated.
+ if (image != EGL_NO_IMAGE_KHR &&
+ mSlots[buf].mGraphicBuffer != NULL &&
+ mBlitSlots[mNextBlitSlot].mGraphicBuffer != NULL) {
+ sp<GraphicBuffer> &srcBuf = mSlots[buf].mGraphicBuffer;
+ sp<GraphicBuffer> &bltBuf =
+ mBlitSlots[mNextBlitSlot].mGraphicBuffer;
+ if (srcBuf->getWidth() != bltBuf->getWidth() ||
+ srcBuf->getHeight() != bltBuf->getHeight()) {
+ eglDestroyImageKHR(mBlitSlots[mNextBlitSlot].mEglDisplay,
+ image);
+ mBlitSlots[mNextBlitSlot].mEglImage = EGL_NO_IMAGE_KHR;
+ mBlitSlots[mNextBlitSlot].mGraphicBuffer = NULL;
+ image = EGL_NO_IMAGE_KHR;
+ }
+ }
+ if (image == EGL_NO_IMAGE_KHR) {
+ sp<GraphicBuffer> &srcBuf = mSlots[buf].mGraphicBuffer;
+ status_t res = 0;
+
+ sp<GraphicBuffer> blitBuffer(
+ mGraphicBufferAlloc->createGraphicBuffer(
+ srcBuf->getWidth(), srcBuf->getHeight(),
+ PIXEL_FORMAT_RGBA_8888, srcBuf->getUsage(),
+ &res));
+ if (blitBuffer == 0) {
+ ST_LOGE("updateTexImage: SurfaceComposer::createGraphicBuffer failed");
+ return NO_MEMORY;
+ }
+ if (res != NO_ERROR) {
+ ST_LOGW("updateTexImage: SurfaceComposer::createGraphicBuffer error=%#04x", res);
+ }
+ mBlitSlots[mNextBlitSlot].mGraphicBuffer = blitBuffer;
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ image = createImage(dpy, blitBuffer);
+ mBlitSlots[mNextBlitSlot].mEglImage = image;
+ mBlitSlots[mNextBlitSlot].mEglDisplay = dpy;
+ }
+
+ if (deferConversion) {
+ graphicBuffer = mSlots[buf].mGraphicBuffer;
+ mConversionSrcSlot = buf;
+ mConversionBltSlot = mNextBlitSlot;
+ // At this point graphicBuffer and image do not point
+ // at matching buffers. This is intentional as this
+ // surface might end up being taken care of by HWComposer,
+ // which needs access to the original buffer.
+ // GL however, is fed an EGLImage that is created from
+ // a conversion buffer. It will have its
+ // content updated once the surface is actually drawn
+ // in Layer::onDraw()
+ } else {
+ if (convert(mSlots[buf].mGraphicBuffer,
+ mBlitSlots[mNextBlitSlot].mGraphicBuffer) != OK) {
+ LOGE("updateTexImage: convert failed");
+ return UNKNOWN_ERROR;
+ }
+ graphicBuffer = mBlitSlots[mNextBlitSlot].mGraphicBuffer;
+ }
+ // mBlitSlots contains several buffers (NUM_BLIT_BUFFER_SLOTS),
+ // advance (potentially wrap) the index
+ mNextBlitSlot = (mNextBlitSlot + 1) % NUM_BLIT_BUFFER_SLOTS;
+ } else {
+ mNeedsConversion = false;
+ image = mSlots[buf].mEglImage;
+ graphicBuffer = mSlots[buf].mGraphicBuffer;
+ if (image == EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ if (graphicBuffer == 0) {
+ ST_LOGE("buffer at slot %d is null", buf);
+ return BAD_VALUE;
+ }
+ image = createImage(dpy, graphicBuffer);
+ mSlots[buf].mEglImage = image;
+ mSlots[buf].mEglDisplay = dpy;
+ if (image == EGL_NO_IMAGE_KHR) {
+ // NOTE: if dpy was invalid, createImage() is guaranteed to
+ // fail. so we'd end up here.
+ return -EINVAL;
+ }
+#endif
}
}
@@ -947,7 +1084,11 @@ status_t SurfaceTexture::updateTexImage(bool isComposition) {
// Update the SurfaceTexture state.
mCurrentTexture = buf;
+#ifndef STE_HARDWARE
mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
+#else
+ mCurrentTextureBuf = graphicBuffer;
+#endif
mCurrentCrop = mSlots[buf].mCrop;
mCurrentTransform = mSlots[buf].mTransform;
mCurrentScalingMode = mSlots[buf].mScalingMode;
@@ -973,8 +1114,18 @@ bool SurfaceTexture::isExternalFormat(uint32_t format)
case HAL_PIXEL_FORMAT_YV12:
// Legacy/deprecated YUV formats
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+#ifndef STE_HARDWARE
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+#else
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+#endif
case HAL_PIXEL_FORMAT_YCbCr_422_I:
+#ifdef STE_HARDWARE
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_422_P:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_P:
+#endif
return true;
}
@@ -1119,6 +1270,16 @@ void SurfaceTexture::freeAllBuffersLocked() {
#ifdef QCOM_HARDWARE
mGraphicBufferAlloc->freeAllGraphicBuffersExcept(-1);
#endif
+#ifdef STE_HARDWARE
+ for (int i = 0; i < NUM_BLIT_BUFFER_SLOTS; i++) {
+ mBlitSlots[i].mGraphicBuffer = 0;
+ if (mBlitSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mBlitSlots[i].mEglDisplay, mBlitSlots[i].mEglImage);
+ mBlitSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mBlitSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ }
+ }
+#endif
}
void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
@@ -1331,6 +1492,84 @@ void SurfaceTexture::dump(String8& result, const char* prefix,
}
}
+#ifdef STE_HARDWARE
+bool SurfaceTexture::conversionIsNeeded(const sp<GraphicBuffer>& graphicBuffer) {
+ int fmt = graphicBuffer->getPixelFormat();
+ return (fmt == PIXEL_FORMAT_YCBCR42XMBN) || (fmt == PIXEL_FORMAT_YCbCr_420_P);
+}
+
+status_t SurfaceTexture::convert() {
+ if (!mNeedsConversion)
+ return NO_ERROR;
+
+ if (mConversionBltSlot < 0 ||
+ mConversionBltSlot >= NUM_BLIT_BUFFER_SLOTS ||
+ mConversionSrcSlot < 0 ||
+ mConversionSrcSlot >= NUM_BUFFER_SLOTS) {
+ LOGE_IF(STE_DEFERDBG, "%s: Incorrect setup for deferred "
+ "texture conversion:\n"
+ "mConversionSrcSlot=%d mConversionBltSlot=%d", __FUNCTION__,
+ mConversionSrcSlot, mConversionBltSlot);
+ return BAD_VALUE;
+ }
+
+ if (mSlots[mConversionSrcSlot].mGraphicBuffer == NULL) {
+ LOGI_IF(STE_DEFERDBG, "%s: NULL source for deferred texture conversion.",
+ __FUNCTION__);
+ return OK;
+ }
+
+ if (mBlitSlots[mConversionBltSlot].mGraphicBuffer == NULL) {
+ LOGI_IF(STE_DEFERDBG, "%s: NULL destination for deferred "
+ "texture conversion.", __FUNCTION__);
+ return OK;
+ }
+
+ return convert(mSlots[mConversionSrcSlot].mGraphicBuffer,
+ mBlitSlots[mConversionBltSlot].mGraphicBuffer);
+}
+
+status_t SurfaceTexture::convert(sp<GraphicBuffer> &srcBuf, sp<GraphicBuffer> &dstBuf) {
+ copybit_image_t dstImg;
+ dstImg.w = dstBuf->getWidth();
+ dstImg.h = dstBuf->getHeight();
+ dstImg.format = dstBuf->getPixelFormat();
+ dstImg.handle = (native_handle_t*) dstBuf->getNativeBuffer()->handle;
+
+ copybit_image_t srcImg;
+ srcImg.w = srcBuf->getWidth();
+ srcImg.h = srcBuf->getHeight();
+ srcImg.format = srcBuf->getPixelFormat();
+ srcImg.base = NULL;
+ srcImg.handle = (native_handle_t*) srcBuf->getNativeBuffer()->handle;
+
+ copybit_rect_t dstCrop;
+ dstCrop.l = 0;
+ dstCrop.t = 0;
+ dstCrop.r = dstBuf->getWidth();
+ dstCrop.b = dstBuf->getHeight();
+
+ copybit_rect_t srcCrop;
+ srcCrop.l = 0;
+ srcCrop.t = 0;
+ srcCrop.r = srcBuf->getWidth();
+ srcCrop.b = srcBuf->getHeight();
+
+ region_iterator clip(Region(Rect(dstCrop.r, dstCrop.b)));
+ mBlitEngine->set_parameter(mBlitEngine, COPYBIT_TRANSFORM, 0);
+ mBlitEngine->set_parameter(mBlitEngine, COPYBIT_PLANE_ALPHA, 0xFF);
+ mBlitEngine->set_parameter(mBlitEngine, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+ int err = mBlitEngine->stretch(
+ mBlitEngine, &dstImg, &srcImg, &dstCrop, &srcCrop, &clip);
+ if (err != 0) {
+ LOGE("\nError: Blit stretch operation failed (err:%d)\n", err);
+ return UNKNOWN_ERROR;
+ }
+ return OK;
+}
+#endif
+
static void mtxMul(float out[16], const float a[16], const float b[16]) {
out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];