SurfaceTexture: improve texture matrix computation
This change reduces the shrinking of the crop rectangle in some cases. It adds a way to inform the SurfaceTexture that its texture will be used without bilinear interpolation, and uses knowledge of the pixel format to avoid shrinking unecessarily. Change-Id: I72365f39f74ecb7fcc51b4cf42f2d0fa97727212
This commit is contained in:
parent
d72f233ffa
commit
5c1139fea3
@ -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;
|
||||||
|
|
||||||
@ -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.
|
||||||
|
@ -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),
|
||||||
@ -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");
|
||||||
|
|
||||||
@ -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…
Reference in New Issue
Block a user