Loading include/gui/SurfaceTexture.h +9 −0 Original line number Original line Diff line number Diff line Loading @@ -144,6 +144,10 @@ public: // updateTexImage() is called. // updateTexImage() is called. status_t setDefaultBufferSize(uint32_t width, uint32_t height); status_t setDefaultBufferSize(uint32_t width, uint32_t height); // setFilteringEnabled sets whether the transform matrix should be computed // for use with bilinear filtering. void setFilteringEnabled(bool enabled); // getCurrentBuffer returns the buffer associated with the current image. // getCurrentBuffer returns the buffer associated with the current image. sp<GraphicBuffer> getCurrentBuffer() const; sp<GraphicBuffer> getCurrentBuffer() const; Loading Loading @@ -289,6 +293,11 @@ private: uint32_t mDefaultWidth, mDefaultHeight; uint32_t mDefaultWidth, mDefaultHeight; // mFilteringEnabled indicates whether the transform matrix is computed for // use with bilinear filtering. It defaults to true and is changed by // setFilteringEnabled(). bool mFilteringEnabled; // mTexName is the name of the OpenGL texture to which streamed images will // mTexName is the name of the OpenGL texture to which streamed images will // be bound when updateTexImage is called. It is set at construction time // be bound when updateTexImage is called. It is set at construction time // and can be changed with a call to attachToContext. // and can be changed with a call to attachToContext. Loading libs/gui/SurfaceTexture.cpp +52 −32 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,7 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) : GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) : mCurrentTransform(0), mCurrentTransform(0), mCurrentTimestamp(0), mCurrentTimestamp(0), mFilteringEnabled(true), mTexName(tex), mTexName(tex), #ifdef USE_FENCE_SYNC #ifdef USE_FENCE_SYNC mUseFenceSync(useFenceSync), mUseFenceSync(useFenceSync), Loading Loading @@ -503,6 +504,15 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); } } void SurfaceTexture::setFilteringEnabled(bool enabled) { Mutex::Autolock lock(mMutex); bool needsRecompute = mFilteringEnabled != enabled; mFilteringEnabled = enabled; if (needsRecompute) { computeCurrentTransformMatrix(); } } void SurfaceTexture::computeCurrentTransformMatrix() { void SurfaceTexture::computeCurrentTransformMatrix() { ST_LOGV("computeCurrentTransformMatrix"); ST_LOGV("computeCurrentTransformMatrix"); Loading Loading @@ -534,39 +544,49 @@ void SurfaceTexture::computeCurrentTransformMatrix() { sp<GraphicBuffer>& buf(mCurrentTextureBuf); sp<GraphicBuffer>& buf(mCurrentTextureBuf); Rect cropRect = mCurrentCrop; Rect cropRect = mCurrentCrop; float tx, ty, sx, sy; float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; if (!cropRect.isEmpty()) { // In order to prevent bilinear sampling at the of the crop rectangle we // may need to shrink it by 2 texels in each direction. Normally this // would just need to take 1/2 a texel off each end, but because the // chroma channels will likely be subsampled we need to chop off a whole // texel. This will cause artifacts if someone does nearest sampling // with 1:1 pixel:texel ratio, but it's impossible to simultaneously // accomodate the bilinear and nearest sampling uses. // // If nearest sampling turns out to be a desirable usage of these // textures then we could add the ability to switch a SurfaceTexture to // nearest-mode. Preferably, however, the image producers (video // decoder, camera, etc.) would simply not use a crop rectangle (or at // least not tell the framework about it) so that the GPU can do the // correct edge behavior. const float shrinkAmount = 1.0f; // the amount that each edge is shrunk float bufferWidth = buf->getWidth(); float bufferWidth = buf->getWidth(); float bufferHeight = buf->getHeight(); 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: case PIXEL_FORMAT_RGBA_5551: case PIXEL_FORMAT_RGBA_4444: // We know there's no subsampling of any channels, so we // only need to shrink by a half a pixel. shrinkAmount = 0.5; default: // If we don't recognize the format, we must assume the // worst case (that we care about), which is YUV420. shrinkAmount = 1.0; } } // Only shrink the dimensions that are not the size of the buffer. if (cropRect.width() < bufferWidth) { tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight; sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth; bufferWidth; } if (cropRect.height() < bufferHeight) { ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight; sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; bufferHeight; } else { } tx = 0.0f; ty = 0.0f; sx = 1.0f; sy = 1.0f; } } float crop[16] = { float crop[16] = { sx, 0, 0, 0, sx, 0, 0, 0, Loading Loading
include/gui/SurfaceTexture.h +9 −0 Original line number Original line Diff line number Diff line Loading @@ -144,6 +144,10 @@ public: // updateTexImage() is called. // updateTexImage() is called. status_t setDefaultBufferSize(uint32_t width, uint32_t height); status_t setDefaultBufferSize(uint32_t width, uint32_t height); // setFilteringEnabled sets whether the transform matrix should be computed // for use with bilinear filtering. void setFilteringEnabled(bool enabled); // getCurrentBuffer returns the buffer associated with the current image. // getCurrentBuffer returns the buffer associated with the current image. sp<GraphicBuffer> getCurrentBuffer() const; sp<GraphicBuffer> getCurrentBuffer() const; Loading Loading @@ -289,6 +293,11 @@ private: uint32_t mDefaultWidth, mDefaultHeight; uint32_t mDefaultWidth, mDefaultHeight; // mFilteringEnabled indicates whether the transform matrix is computed for // use with bilinear filtering. It defaults to true and is changed by // setFilteringEnabled(). bool mFilteringEnabled; // mTexName is the name of the OpenGL texture to which streamed images will // mTexName is the name of the OpenGL texture to which streamed images will // be bound when updateTexImage is called. It is set at construction time // be bound when updateTexImage is called. It is set at construction time // and can be changed with a call to attachToContext. // and can be changed with a call to attachToContext. Loading
libs/gui/SurfaceTexture.cpp +52 −32 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,7 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) : GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) : mCurrentTransform(0), mCurrentTransform(0), mCurrentTimestamp(0), mCurrentTimestamp(0), mFilteringEnabled(true), mTexName(tex), mTexName(tex), #ifdef USE_FENCE_SYNC #ifdef USE_FENCE_SYNC mUseFenceSync(useFenceSync), mUseFenceSync(useFenceSync), Loading Loading @@ -503,6 +504,15 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); } } void SurfaceTexture::setFilteringEnabled(bool enabled) { Mutex::Autolock lock(mMutex); bool needsRecompute = mFilteringEnabled != enabled; mFilteringEnabled = enabled; if (needsRecompute) { computeCurrentTransformMatrix(); } } void SurfaceTexture::computeCurrentTransformMatrix() { void SurfaceTexture::computeCurrentTransformMatrix() { ST_LOGV("computeCurrentTransformMatrix"); ST_LOGV("computeCurrentTransformMatrix"); Loading Loading @@ -534,39 +544,49 @@ void SurfaceTexture::computeCurrentTransformMatrix() { sp<GraphicBuffer>& buf(mCurrentTextureBuf); sp<GraphicBuffer>& buf(mCurrentTextureBuf); Rect cropRect = mCurrentCrop; Rect cropRect = mCurrentCrop; float tx, ty, sx, sy; float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; if (!cropRect.isEmpty()) { // In order to prevent bilinear sampling at the of the crop rectangle we // may need to shrink it by 2 texels in each direction. Normally this // would just need to take 1/2 a texel off each end, but because the // chroma channels will likely be subsampled we need to chop off a whole // texel. This will cause artifacts if someone does nearest sampling // with 1:1 pixel:texel ratio, but it's impossible to simultaneously // accomodate the bilinear and nearest sampling uses. // // If nearest sampling turns out to be a desirable usage of these // textures then we could add the ability to switch a SurfaceTexture to // nearest-mode. Preferably, however, the image producers (video // decoder, camera, etc.) would simply not use a crop rectangle (or at // least not tell the framework about it) so that the GPU can do the // correct edge behavior. const float shrinkAmount = 1.0f; // the amount that each edge is shrunk float bufferWidth = buf->getWidth(); float bufferWidth = buf->getWidth(); float bufferHeight = buf->getHeight(); 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: case PIXEL_FORMAT_RGBA_5551: case PIXEL_FORMAT_RGBA_4444: // We know there's no subsampling of any channels, so we // only need to shrink by a half a pixel. shrinkAmount = 0.5; default: // If we don't recognize the format, we must assume the // worst case (that we care about), which is YUV420. shrinkAmount = 1.0; } } // Only shrink the dimensions that are not the size of the buffer. if (cropRect.width() < bufferWidth) { tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight; sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth; bufferWidth; } if (cropRect.height() < bufferHeight) { ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight; sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; bufferHeight; } else { } tx = 0.0f; ty = 0.0f; sx = 1.0f; sy = 1.0f; } } float crop[16] = { float crop[16] = { sx, 0, 0, 0, sx, 0, 0, 0, Loading