diff options
| -rw-r--r-- | include/gui/SurfaceTexture.h | 13 | ||||
| -rw-r--r-- | include/surfaceflinger/Surface.h | 6 | ||||
| -rw-r--r-- | libs/gui/SurfaceTexture.cpp | 88 | ||||
| -rw-r--r-- | libs/gui/SurfaceTextureClient.cpp | 4 | ||||
| -rw-r--r-- | opengl/libs/EGL/egl.cpp | 35 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 25 |
6 files changed, 137 insertions, 34 deletions
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 002e48b6d9..79c33f54f5 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -40,6 +40,10 @@ public: enum { MIN_BUFFER_SLOTS = 3 }; enum { NUM_BUFFER_SLOTS = 32 }; + struct FrameAvailableListener : public virtual RefBase { + virtual void onFrameAvailable() = 0; + }; + // tex indicates the name OpenGL texture to which images are to be streamed. // This texture name cannot be changed once the SurfaceTexture is created. SurfaceTexture(GLuint tex); @@ -93,6 +97,10 @@ public: // functions. void getTransformMatrix(float mtx[16]); + // setFrameAvailableListener sets the listener object that will be notified + // when a new frame becomes available. + void setFrameAvailableListener(const sp<FrameAvailableListener>& l); + private: // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for @@ -195,6 +203,11 @@ private: // to a buffer, but other processes do. Vector<sp<GraphicBuffer> > mAllocdBuffers; + // mFrameAvailableListener is the listener object that will be called when a + // new frame becomes available. If it is not NULL it will be called from + // queueBuffer. + sp<FrameAvailableListener> mFrameAvailableListener; + // mMutex is the mutex used to prevent concurrent access to the member // variables of SurfaceTexture objects. It must be locked whenever the // member variables are accessed. diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 5532052864..d783caff2a 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -100,6 +100,9 @@ private: friend class MediaPlayer; // for testing friend class Test; + // videoEditor preview classes + friend class VideoEditorPreviewController; + const sp<ISurface>& getISurface() const { return mSurface; } @@ -181,6 +184,9 @@ private: friend class SoftwareRenderer; // this is just to be able to write some unit tests friend class Test; + // videoEditor preview classes + friend class VideoEditorPreviewController; + friend class PreviewRenderer; private: friend class SurfaceComposerClient; diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 447de76508..1dadd53891 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -166,6 +166,9 @@ status_t SurfaceTexture::queueBuffer(int buf) { mLastQueued = buf; mLastQueuedCrop = mNextCrop; mLastQueuedTransform = mNextTransform; + if (mFrameAvailableListener != 0) { + mFrameAvailableListener->onFrameAvailable(); + } return OK; } @@ -237,43 +240,68 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { LOGV("SurfaceTexture::updateTexImage"); Mutex::Autolock lock(mMutex); - float* xform = mtxIdentity; - switch (mCurrentTransform) { - case 0: - xform = mtxIdentity; - break; - case NATIVE_WINDOW_TRANSFORM_FLIP_H: - xform = mtxFlipH; - break; - case NATIVE_WINDOW_TRANSFORM_FLIP_V: - xform = mtxFlipV; - break; - case NATIVE_WINDOW_TRANSFORM_ROT_90: - xform = mtxRot90; - break; - case NATIVE_WINDOW_TRANSFORM_ROT_180: - xform = mtxRot180; - break; - case NATIVE_WINDOW_TRANSFORM_ROT_270: - xform = mtxRot270; - break; - default: - LOGE("getTransformMatrix: unknown transform: %d", mCurrentTransform); + float xform[16]; + for (int i = 0; i < 16; i++) { + xform[i] = mtxIdentity[i]; + } + if (mCurrentTransform & 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) { + 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) { + float result[16]; + mtxMul(result, xform, mtxRot90); + for (int i = 0; i < 16; i++) { + xform[i] = result[i]; + } } sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer); - float tx = float(mCurrentCrop.left) / float(buf->getWidth()); - float ty = float(mCurrentCrop.bottom) / float(buf->getHeight()); - float sx = float(mCurrentCrop.width()) / float(buf->getWidth()); - float sy = float(mCurrentCrop.height()) / float(buf->getHeight()); + float tx, ty, sx, sy; + if (!mCurrentCrop.isEmpty()) { + tx = float(mCurrentCrop.left) / float(buf->getWidth()); + ty = float(buf->getHeight() - mCurrentCrop.bottom) / + float(buf->getHeight()); + sx = float(mCurrentCrop.width()) / float(buf->getWidth()); + sy = float(mCurrentCrop.height()) / float(buf->getHeight()); + } else { + tx = 0.0f; + ty = 0.0f; + sx = 1.0f; + sy = 1.0f; + } float crop[16] = { - sx, 0, 0, sx*tx, - 0, sy, 0, sy*ty, + sx, 0, 0, 0, + 0, sy, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 1, + sx*tx, sy*ty, 0, 1, }; - mtxMul(mtx, crop, xform); + float mtxBeforeFlipV[16]; + mtxMul(mtxBeforeFlipV, crop, xform); + + // SurfaceFlinger expects the top of its window textures to be at a Y + // coordinate of 0, so SurfaceTexture 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(mtx, mtxFlipV, mtxBeforeFlipV); +} + +void SurfaceTexture::setFrameAvailableListener( + const sp<FrameAvailableListener>& l) { + LOGV("SurfaceTexture::setFrameAvailableListener"); + Mutex::Autolock lock(mMutex); + mFrameAvailableListener = l; } void SurfaceTexture::freeAllBuffers() { diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 24cee24d4d..0ed8be528b 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -111,7 +111,7 @@ int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) { LOGV("SurfaceTextureClient::cancelBuffer"); Mutex::Autolock lock(mMutex); for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].get() == buffer) { + if (mSlots[i]->handle == buffer->handle) { mSurfaceTexture->cancelBuffer(i); return OK; } @@ -129,7 +129,7 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { LOGV("SurfaceTextureClient::queueBuffer"); Mutex::Autolock lock(mMutex); for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].get() == GraphicBuffer::getSelf(buffer)) { + if (mSlots[i]->handle == buffer->handle) { return mSurfaceTexture->queueBuffer(i); } } diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 386cc5d052..ed3617182c 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -62,6 +62,8 @@ static char const * const gExtensionString = "EGL_KHR_image_base " "EGL_KHR_image_pixmap " "EGL_KHR_gl_texture_2D_image " + "EGL_KHR_gl_texture_cubemap_image " + "EGL_KHR_gl_renderbuffer_image " "EGL_KHR_fence_sync " "EGL_ANDROID_image_native_buffer " "EGL_ANDROID_swap_rectangle " @@ -1471,6 +1473,29 @@ EGLint eglGetError(void) return result; } +// Note: Similar implementations of these functions also exist in +// gl2.cpp and gl.cpp, and are used by applications that call the +// exported entry points directly. +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); + +static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL; +static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL; + +static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image) +{ + GLeglImageOES implImage = + (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); + glEGLImageTargetTexture2DOES_impl(target, implImage); +} + +static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image) +{ + GLeglImageOES implImage = + (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); + glEGLImageTargetRenderbufferStorageOES_impl(target, implImage); +} + __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) { // eglGetProcAddress() could be the very first function called @@ -1531,6 +1556,16 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) } if (found) { addr = gExtensionForwarders[slot]; + + if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) { + glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr; + addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper; + } + if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) { + glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr; + addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper; + } + gGLExtentionMap.add(name, addr); gGLExtentionSlot++; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 154b8224c3..65ad9568b3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2132,6 +2132,9 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, sh = (!sh) ? hw_h : sh; const size_t size = sw * sh * 4; + LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d", + sw, sh, minLayerZ, maxLayerZ); + // make sure to clear all GL error flags while ( glGetError() != GL_NO_ERROR ) ; @@ -2146,6 +2149,9 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + + LOGD("screenshot: FBO created, status=0x%x", status); + if (status == GL_FRAMEBUFFER_COMPLETE_OES) { // invert everything, b/c glReadPixel() below will invert the FB @@ -2161,6 +2167,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); + LOGD("screenshot: glClear() issued"); + const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { @@ -2171,6 +2179,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, } } + LOGD("screenshot: All layers rendered"); + // XXX: this is needed on tegra glScissor(0, 0, sw, sh); @@ -2185,6 +2195,10 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, new MemoryHeapBase(size, 0, "screen-capture") ); void* const ptr = base->getBase(); if (ptr) { + + LOGD("screenshot: about to call glReadPixels(0,0,%d,%d,...,%p)", + sw, sh, ptr); + // capture the screen with glReadPixels() glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr); if (glGetError() == GL_NO_ERROR) { @@ -2197,25 +2211,32 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, } else { result = NO_MEMORY; } + + LOGD("screenshot: glReadPixels() returned %s", strerror(result)); + } glEnable(GL_SCISSOR_TEST); glViewport(0, 0, hw_w, hw_h); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - - } else { result = BAD_VALUE; } + LOGD("screenshot: about to release FBO resources"); + // release FBO resources glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glDeleteRenderbuffersOES(1, &tname); glDeleteFramebuffersOES(1, &name); + LOGD("screenshot: about to call compositionComplete()"); + hw.compositionComplete(); + LOGD("screenshot: result = %s", strerror(result)); + return result; } |