| /* | |
| * Copyright (C) 2010 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #define LOG_TAG "GLConsumerUtils" | |
| //#define LOG_NDEBUG 0 | |
| #include <gui/GLConsumer.h> | |
| #include <math/mat4.h> | |
| #include <system/window.h> | |
| #include <utils/Log.h> | |
| namespace android { | |
| void GLConsumer::computeTransformMatrix(float outTransform[16], | |
| const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, | |
| bool filtering) { | |
| // Transform matrices | |
| static const mat4 mtxFlipH( | |
| -1, 0, 0, 0, | |
| 0, 1, 0, 0, | |
| 0, 0, 1, 0, | |
| 1, 0, 0, 1 | |
| ); | |
| static const mat4 mtxFlipV( | |
| 1, 0, 0, 0, | |
| 0, -1, 0, 0, | |
| 0, 0, 1, 0, | |
| 0, 1, 0, 1 | |
| ); | |
| static const mat4 mtxRot90( | |
| 0, 1, 0, 0, | |
| -1, 0, 0, 0, | |
| 0, 0, 1, 0, | |
| 1, 0, 0, 1 | |
| ); | |
| mat4 xform; | |
| if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { | |
| xform *= mtxFlipH; | |
| } | |
| if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { | |
| xform *= mtxFlipV; | |
| } | |
| if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { | |
| xform *= mtxRot90; | |
| } | |
| if (!cropRect.isEmpty()) { | |
| float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; | |
| float bufferWidth = buf->getWidth(); | |
| float bufferHeight = buf->getHeight(); | |
| 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_RGBA_FP16: | |
| case PIXEL_FORMAT_RGBA_1010102: | |
| 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; | |
| } | |
| } | |
| // 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; | |
| } | |
| mat4 crop( | |
| sx, 0, 0, 0, | |
| 0, sy, 0, 0, | |
| 0, 0, 1, 0, | |
| tx, ty, 0, 1 | |
| ); | |
| xform = crop * xform; | |
| } | |
| // GLConsumer uses the GL convention where (0, 0) is the bottom-left | |
| // corner and (1, 1) is the top-right corner. Add an additional vertical | |
| // flip after all other transforms to map from GL convention to buffer | |
| // queue memory layout, where (0, 0) is the top-left corner. | |
| xform = mtxFlipV * xform; | |
| memcpy(outTransform, xform.asArray(), sizeof(xform)); | |
| } | |
| }; // namespace android |