Home | History | Annotate | Download | only in sampleDriver
      1 /*
      2  * Copyright (C) 2016 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 #include "EvsGlDisplay.h"
     18 
     19 #include <ui/GraphicBufferAllocator.h>
     20 #include <ui/GraphicBufferMapper.h>
     21 
     22 
     23 namespace android {
     24 namespace hardware {
     25 namespace automotive {
     26 namespace evs {
     27 namespace V1_0 {
     28 namespace implementation {
     29 
     30 
     31 EvsGlDisplay::EvsGlDisplay() {
     32     ALOGD("EvsGlDisplay instantiated");
     33 
     34     // Set up our self description
     35     // NOTE:  These are arbitrary values chosen for testing
     36     mInfo.displayId             = "Mock Display";
     37     mInfo.vendorFlags           = 3870;
     38 }
     39 
     40 
     41 EvsGlDisplay::~EvsGlDisplay() {
     42     ALOGD("EvsGlDisplay being destroyed");
     43 	forceShutdown();
     44 }
     45 
     46 
     47 /**
     48  * This gets called if another caller "steals" ownership of the display
     49  */
     50 void EvsGlDisplay::forceShutdown()
     51 {
     52     ALOGD("EvsGlDisplay forceShutdown");
     53     std::lock_guard<std::mutex> lock(mAccessLock);
     54 
     55     // If the buffer isn't being held by a remote client, release it now as an
     56     // optimization to release the resources more quickly than the destructor might
     57     // get called.
     58     if (mBuffer.memHandle) {
     59         // Report if we're going away while a buffer is outstanding
     60         if (mFrameBusy) {
     61             ALOGE("EvsGlDisplay going down while client is holding a buffer");
     62         }
     63 
     64         // Drop the graphics buffer we've been using
     65         GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
     66         alloc.free(mBuffer.memHandle);
     67         mBuffer.memHandle = nullptr;
     68 
     69         mGlWrapper.shutdown();
     70     }
     71 
     72     // Put this object into an unrecoverable error state since somebody else
     73     // is going to own the display now.
     74     mRequestedState = DisplayState::DEAD;
     75 }
     76 
     77 
     78 /**
     79  * Returns basic information about the EVS display provided by the system.
     80  * See the description of the DisplayDesc structure for details.
     81  */
     82 Return<void> EvsGlDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb)  {
     83     ALOGD("getDisplayInfo");
     84 
     85     // Send back our self description
     86     _hidl_cb(mInfo);
     87     return Void();
     88 }
     89 
     90 
     91 /**
     92  * Clients may set the display state to express their desired state.
     93  * The HAL implementation must gracefully accept a request for any state
     94  * while in any other state, although the response may be to ignore the request.
     95  * The display is defined to start in the NOT_VISIBLE state upon initialization.
     96  * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and
     97  * then begin providing video.  When the display is no longer required, the client
     98  * is expected to request the NOT_VISIBLE state after passing the last video frame.
     99  */
    100 Return<EvsResult> EvsGlDisplay::setDisplayState(DisplayState state) {
    101     ALOGD("setDisplayState");
    102     std::lock_guard<std::mutex> lock(mAccessLock);
    103 
    104     if (mRequestedState == DisplayState::DEAD) {
    105         // This object no longer owns the display -- it's been superceeded!
    106         return EvsResult::OWNERSHIP_LOST;
    107     }
    108 
    109     // Ensure we recognize the requested state so we don't go off the rails
    110     if (state >= DisplayState::NUM_STATES) {
    111         return EvsResult::INVALID_ARG;
    112     }
    113 
    114     switch (state) {
    115     case DisplayState::NOT_VISIBLE:
    116         mGlWrapper.hideWindow();
    117         break;
    118     case DisplayState::VISIBLE:
    119         mGlWrapper.showWindow();
    120         break;
    121     default:
    122         break;
    123     }
    124 
    125     // Record the requested state
    126     mRequestedState = state;
    127 
    128     return EvsResult::OK;
    129 }
    130 
    131 
    132 /**
    133  * The HAL implementation should report the actual current state, which might
    134  * transiently differ from the most recently requested state.  Note, however, that
    135  * the logic responsible for changing display states should generally live above
    136  * the device layer, making it undesirable for the HAL implementation to
    137  * spontaneously change display states.
    138  */
    139 Return<DisplayState> EvsGlDisplay::getDisplayState()  {
    140     ALOGD("getDisplayState");
    141     std::lock_guard<std::mutex> lock(mAccessLock);
    142 
    143     return mRequestedState;
    144 }
    145 
    146 
    147 /**
    148  * This call returns a handle to a frame buffer associated with the display.
    149  * This buffer may be locked and written to by software and/or GL.  This buffer
    150  * must be returned via a call to returnTargetBufferForDisplay() even if the
    151  * display is no longer visible.
    152  */
    153 Return<void> EvsGlDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb)  {
    154     ALOGV("getTargetBuffer");
    155     std::lock_guard<std::mutex> lock(mAccessLock);
    156 
    157     if (mRequestedState == DisplayState::DEAD) {
    158         ALOGE("Rejecting buffer request from object that lost ownership of the display.");
    159         BufferDesc nullBuff = {};
    160         _hidl_cb(nullBuff);
    161         return Void();
    162     }
    163 
    164     // If we don't already have a buffer, allocate one now
    165     if (!mBuffer.memHandle) {
    166         // Initialize our display window
    167         // NOTE:  This will cause the display to become "VISIBLE" before a frame is actually
    168         // returned, which is contrary to the spec and will likely result in a black frame being
    169         // (briefly) shown.
    170         if (!mGlWrapper.initialize()) {
    171             // Report the failure
    172             ALOGE("Failed to initialize GL display");
    173             BufferDesc nullBuff = {};
    174             _hidl_cb(nullBuff);
    175             return Void();
    176         }
    177 
    178         // Assemble the buffer description we'll use for our render target
    179         mBuffer.width       = mGlWrapper.getWidth();
    180         mBuffer.height      = mGlWrapper.getHeight();
    181         mBuffer.format      = HAL_PIXEL_FORMAT_RGBA_8888;
    182         mBuffer.usage       = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
    183         mBuffer.bufferId    = 0x3870;  // Arbitrary magic number for self recognition
    184         mBuffer.pixelSize   = 4;
    185 
    186         // Allocate the buffer that will hold our displayable image
    187         buffer_handle_t handle = nullptr;
    188         GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
    189         status_t result = alloc.allocate(mBuffer.width, mBuffer.height,
    190                                          mBuffer.format, 1,
    191                                          mBuffer.usage, &handle,
    192                                          &mBuffer.stride,
    193                                          0, "EvsGlDisplay");
    194         if (result != NO_ERROR) {
    195             ALOGE("Error %d allocating %d x %d graphics buffer",
    196                   result, mBuffer.width, mBuffer.height);
    197             BufferDesc nullBuff = {};
    198             _hidl_cb(nullBuff);
    199             mGlWrapper.shutdown();
    200             return Void();
    201         }
    202         if (!handle) {
    203             ALOGE("We didn't get a buffer handle back from the allocator");
    204             BufferDesc nullBuff = {};
    205             _hidl_cb(nullBuff);
    206             mGlWrapper.shutdown();
    207             return Void();
    208         }
    209 
    210         mBuffer.memHandle = handle;
    211         ALOGD("Allocated new buffer %p with stride %u",
    212               mBuffer.memHandle.getNativeHandle(), mBuffer.stride);
    213         mFrameBusy = false;
    214     }
    215 
    216     // Do we have a frame available?
    217     if (mFrameBusy) {
    218         // This means either we have a 2nd client trying to compete for buffers
    219         // (an unsupported mode of operation) or else the client hasn't returned
    220         // a previously issued buffer yet (they're behaving badly).
    221         // NOTE:  We have to make the callback even if we have nothing to provide
    222         ALOGE("getTargetBuffer called while no buffers available.");
    223         BufferDesc nullBuff = {};
    224         _hidl_cb(nullBuff);
    225         return Void();
    226     } else {
    227         // Mark our buffer as busy
    228         mFrameBusy = true;
    229 
    230         // Send the buffer to the client
    231         ALOGV("Providing display buffer handle %p as id %d",
    232               mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
    233         _hidl_cb(mBuffer);
    234         return Void();
    235     }
    236 }
    237 
    238 
    239 /**
    240  * This call tells the display that the buffer is ready for display.
    241  * The buffer is no longer valid for use by the client after this call.
    242  */
    243 Return<EvsResult> EvsGlDisplay::returnTargetBufferForDisplay(const BufferDesc& buffer)  {
    244     ALOGV("returnTargetBufferForDisplay %p", buffer.memHandle.getNativeHandle());
    245     std::lock_guard<std::mutex> lock(mAccessLock);
    246 
    247     // Nobody should call us with a null handle
    248     if (!buffer.memHandle.getNativeHandle()) {
    249         ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
    250         return EvsResult::INVALID_ARG;
    251     }
    252     if (buffer.bufferId != mBuffer.bufferId) {
    253         ALOGE ("Got an unrecognized frame returned.\n");
    254         return EvsResult::INVALID_ARG;
    255     }
    256     if (!mFrameBusy) {
    257         ALOGE ("A frame was returned with no outstanding frames.\n");
    258         return EvsResult::BUFFER_NOT_AVAILABLE;
    259     }
    260 
    261     mFrameBusy = false;
    262 
    263     // If we've been displaced by another owner of the display, then we can't do anything else
    264     if (mRequestedState == DisplayState::DEAD) {
    265         return EvsResult::OWNERSHIP_LOST;
    266     }
    267 
    268     // If we were waiting for a new frame, this is it!
    269     if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
    270         mRequestedState = DisplayState::VISIBLE;
    271         mGlWrapper.showWindow();
    272     }
    273 
    274     // Validate we're in an expected state
    275     if (mRequestedState != DisplayState::VISIBLE) {
    276         // Not sure why a client would send frames back when we're not visible.
    277         ALOGW ("Got a frame returned while not visible - ignoring.\n");
    278     } else {
    279         // Update the texture contents with the provided data
    280 // TODO:  Why doesn't it work to pass in the buffer handle we got from HIDL?
    281 //        if (!mGlWrapper.updateImageTexture(buffer)) {
    282         if (!mGlWrapper.updateImageTexture(mBuffer)) {
    283             return EvsResult::UNDERLYING_SERVICE_ERROR;
    284         }
    285 
    286         // Put the image on the screen
    287         mGlWrapper.renderImageToScreen();
    288     }
    289 
    290     return EvsResult::OK;
    291 }
    292 
    293 } // namespace implementation
    294 } // namespace V1_0
    295 } // namespace evs
    296 } // namespace automotive
    297 } // namespace hardware
    298 } // namespace android
    299