Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "GraphicBufferMapper"
     18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
     19 //#define LOG_NDEBUG 0
     20 
     21 #include <stdint.h>
     22 #include <errno.h>
     23 
     24 // We would eliminate the non-conforming zero-length array, but we can't since
     25 // this is effectively included from the Linux kernel
     26 #pragma clang diagnostic push
     27 #pragma clang diagnostic ignored "-Wzero-length-array"
     28 #include <sync/sync.h>
     29 #pragma clang diagnostic pop
     30 
     31 #include <utils/Errors.h>
     32 #include <utils/Log.h>
     33 #include <utils/Trace.h>
     34 
     35 #include <ui/Gralloc1On0Adapter.h>
     36 #include <ui/GraphicBufferMapper.h>
     37 #include <ui/Rect.h>
     38 
     39 #include <system/graphics.h>
     40 
     41 namespace android {
     42 // ---------------------------------------------------------------------------
     43 
     44 ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
     45 
     46 GraphicBufferMapper::GraphicBufferMapper()
     47   : mLoader(std::make_unique<Gralloc1::Loader>()),
     48     mDevice(mLoader->getDevice()) {}
     49 
     50 
     51 
     52 status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
     53 {
     54     ATRACE_CALL();
     55 
     56     gralloc1_error_t error = mDevice->retain(handle);
     57     ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
     58             handle, error);
     59 
     60     return error;
     61 }
     62 
     63 status_t GraphicBufferMapper::registerBuffer(const GraphicBuffer* buffer)
     64 {
     65     ATRACE_CALL();
     66 
     67     gralloc1_error_t error = mDevice->retain(buffer);
     68     ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
     69             buffer->getNativeBuffer()->handle, error);
     70 
     71     return error;
     72 }
     73 
     74 status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
     75 {
     76     ATRACE_CALL();
     77 
     78     gralloc1_error_t error = mDevice->release(handle);
     79     ALOGW_IF(error != GRALLOC1_ERROR_NONE, "unregisterBuffer(%p): failed %d",
     80             handle, error);
     81 
     82     return error;
     83 }
     84 
     85 static inline gralloc1_rect_t asGralloc1Rect(const Rect& rect) {
     86     gralloc1_rect_t outRect{};
     87     outRect.left = rect.left;
     88     outRect.top = rect.top;
     89     outRect.width = rect.width();
     90     outRect.height = rect.height();
     91     return outRect;
     92 }
     93 
     94 status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
     95         const Rect& bounds, void** vaddr)
     96 {
     97     return lockAsync(handle, usage, bounds, vaddr, -1);
     98 }
     99 
    100 status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage,
    101         const Rect& bounds, android_ycbcr *ycbcr)
    102 {
    103     return lockAsyncYCbCr(handle, usage, bounds, ycbcr, -1);
    104 }
    105 
    106 status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
    107 {
    108     int32_t fenceFd = -1;
    109     status_t error = unlockAsync(handle, &fenceFd);
    110     if (error == NO_ERROR) {
    111         sync_wait(fenceFd, -1);
    112         close(fenceFd);
    113     }
    114     return error;
    115 }
    116 
    117 status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
    118         uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
    119 {
    120     ATRACE_CALL();
    121 
    122     gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
    123     sp<Fence> fence = new Fence(fenceFd);
    124     gralloc1_error_t error = mDevice->lock(handle,
    125             static_cast<gralloc1_producer_usage_t>(usage),
    126             static_cast<gralloc1_consumer_usage_t>(usage),
    127             &accessRegion, vaddr, fence);
    128     ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lock(%p, ...) failed: %d", handle,
    129             error);
    130 
    131     return error;
    132 }
    133 
    134 static inline bool isValidYCbCrPlane(const android_flex_plane_t& plane) {
    135     if (plane.bits_per_component != 8) {
    136         ALOGV("Invalid number of bits per component: %d",
    137                 plane.bits_per_component);
    138         return false;
    139     }
    140     if (plane.bits_used != 8) {
    141         ALOGV("Invalid number of bits used: %d", plane.bits_used);
    142         return false;
    143     }
    144 
    145     bool hasValidIncrement = plane.h_increment == 1 ||
    146             (plane.component != FLEX_COMPONENT_Y && plane.h_increment == 2);
    147     hasValidIncrement = hasValidIncrement && plane.v_increment > 0;
    148     if (!hasValidIncrement) {
    149         ALOGV("Invalid increment: h %d v %d", plane.h_increment,
    150                 plane.v_increment);
    151         return false;
    152     }
    153 
    154     return true;
    155 }
    156 
    157 status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
    158         uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd)
    159 {
    160     ATRACE_CALL();
    161 
    162     gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
    163     sp<Fence> fence = new Fence(fenceFd);
    164 
    165     if (mDevice->hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
    166         gralloc1_error_t error = mDevice->lockYCbCr(handle,
    167                 static_cast<gralloc1_producer_usage_t>(usage),
    168                 static_cast<gralloc1_consumer_usage_t>(usage),
    169                 &accessRegion, ycbcr, fence);
    170         ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lockYCbCr(%p, ...) failed: %d",
    171                 handle, error);
    172         return error;
    173     }
    174 
    175     uint32_t numPlanes = 0;
    176     gralloc1_error_t error = mDevice->getNumFlexPlanes(handle, &numPlanes);
    177     if (error != GRALLOC1_ERROR_NONE) {
    178         ALOGV("Failed to retrieve number of flex planes: %d", error);
    179         return error;
    180     }
    181     if (numPlanes < 3) {
    182         ALOGV("Not enough planes for YCbCr (%u found)", numPlanes);
    183         return GRALLOC1_ERROR_UNSUPPORTED;
    184     }
    185 
    186     std::vector<android_flex_plane_t> planes(numPlanes);
    187     android_flex_layout_t flexLayout{};
    188     flexLayout.num_planes = numPlanes;
    189     flexLayout.planes = planes.data();
    190 
    191     error = mDevice->lockFlex(handle,
    192             static_cast<gralloc1_producer_usage_t>(usage),
    193             static_cast<gralloc1_consumer_usage_t>(usage),
    194             &accessRegion, &flexLayout, fence);
    195     if (error != GRALLOC1_ERROR_NONE) {
    196         ALOGW("lockFlex(%p, ...) failed: %d", handle, error);
    197         return error;
    198     }
    199     if (flexLayout.format != FLEX_FORMAT_YCbCr) {
    200         ALOGV("Unable to convert flex-format buffer to YCbCr");
    201         unlock(handle);
    202         return GRALLOC1_ERROR_UNSUPPORTED;
    203     }
    204 
    205     // Find planes
    206     auto yPlane = planes.cend();
    207     auto cbPlane = planes.cend();
    208     auto crPlane = planes.cend();
    209     for (auto planeIter = planes.cbegin(); planeIter != planes.cend();
    210             ++planeIter) {
    211         if (planeIter->component == FLEX_COMPONENT_Y) {
    212             yPlane = planeIter;
    213         } else if (planeIter->component == FLEX_COMPONENT_Cb) {
    214             cbPlane = planeIter;
    215         } else if (planeIter->component == FLEX_COMPONENT_Cr) {
    216             crPlane = planeIter;
    217         }
    218     }
    219     if (yPlane == planes.cend()) {
    220         ALOGV("Unable to find Y plane");
    221         unlock(handle);
    222         return GRALLOC1_ERROR_UNSUPPORTED;
    223     }
    224     if (cbPlane == planes.cend()) {
    225         ALOGV("Unable to find Cb plane");
    226         unlock(handle);
    227         return GRALLOC1_ERROR_UNSUPPORTED;
    228     }
    229     if (crPlane == planes.cend()) {
    230         ALOGV("Unable to find Cr plane");
    231         unlock(handle);
    232         return GRALLOC1_ERROR_UNSUPPORTED;
    233     }
    234 
    235     // Validate planes
    236     if (!isValidYCbCrPlane(*yPlane)) {
    237         ALOGV("Y plane is invalid");
    238         unlock(handle);
    239         return GRALLOC1_ERROR_UNSUPPORTED;
    240     }
    241     if (!isValidYCbCrPlane(*cbPlane)) {
    242         ALOGV("Cb plane is invalid");
    243         unlock(handle);
    244         return GRALLOC1_ERROR_UNSUPPORTED;
    245     }
    246     if (!isValidYCbCrPlane(*crPlane)) {
    247         ALOGV("Cr plane is invalid");
    248         unlock(handle);
    249         return GRALLOC1_ERROR_UNSUPPORTED;
    250     }
    251     if (cbPlane->v_increment != crPlane->v_increment) {
    252         ALOGV("Cb and Cr planes have different step (%d vs. %d)",
    253                 cbPlane->v_increment, crPlane->v_increment);
    254         unlock(handle);
    255         return GRALLOC1_ERROR_UNSUPPORTED;
    256     }
    257     if (cbPlane->h_increment != crPlane->h_increment) {
    258         ALOGV("Cb and Cr planes have different stride (%d vs. %d)",
    259                 cbPlane->h_increment, crPlane->h_increment);
    260         unlock(handle);
    261         return GRALLOC1_ERROR_UNSUPPORTED;
    262     }
    263 
    264     // Pack plane data into android_ycbcr struct
    265     ycbcr->y = yPlane->top_left;
    266     ycbcr->cb = cbPlane->top_left;
    267     ycbcr->cr = crPlane->top_left;
    268     ycbcr->ystride = static_cast<size_t>(yPlane->v_increment);
    269     ycbcr->cstride = static_cast<size_t>(cbPlane->v_increment);
    270     ycbcr->chroma_step = static_cast<size_t>(cbPlane->h_increment);
    271 
    272     return error;
    273 }
    274 
    275 status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
    276 {
    277     ATRACE_CALL();
    278 
    279     sp<Fence> fence = Fence::NO_FENCE;
    280     gralloc1_error_t error = mDevice->unlock(handle, &fence);
    281     if (error != GRALLOC1_ERROR_NONE) {
    282         ALOGE("unlock(%p) failed: %d", handle, error);
    283         return error;
    284     }
    285 
    286     *fenceFd = fence->dup();
    287     return error;
    288 }
    289 
    290 // ---------------------------------------------------------------------------
    291 }; // namespace android
    292