Home | History | Annotate | Download | only in hwc
      1 /*
      2 * Copyright (c) 2016 - 2017, The Linux Foundation. All rights reserved.
      3 *
      4 * Redistribution and use in source and binary forms, with or without
      5 * modification, are permitted provided that the following conditions are
      6 * met:
      7 *  * Redistributions of source code must retain the above copyright
      8 *    notice, this list of conditions and the following disclaimer.
      9 *  * Redistributions in binary form must reproduce the above
     10 *    copyright notice, this list of conditions and the following
     11 *    disclaimer in the documentation and/or other materials provided
     12 *    with the distribution.
     13 *  * Neither the name of The Linux Foundation nor the names of its
     14 *    contributors may be used to endorse or promote products derived
     15 *    from this software without specific prior written permission.
     16 *
     17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 */
     29 
     30 #include <alloc_controller.h>
     31 #include <gr.h>
     32 #include <gralloc_priv.h>
     33 #include <memalloc.h>
     34 #include <sync/sync.h>
     35 
     36 #include <TonemapFactory.h>
     37 
     38 #include <core/buffer_allocator.h>
     39 
     40 #include <utils/constants.h>
     41 #include <utils/debug.h>
     42 #include <utils/formats.h>
     43 #include <utils/rect.h>
     44 #include <utils/utils.h>
     45 
     46 #include <vector>
     47 
     48 #include "hwc_debugger.h"
     49 #include "hwc_tonemapper.h"
     50 
     51 #define __CLASS__ "HWCToneMapper"
     52 
     53 namespace sdm {
     54 
     55 ToneMapSession::~ToneMapSession() {
     56   delete gpu_tone_mapper_;
     57   gpu_tone_mapper_ = NULL;
     58   FreeIntermediateBuffers();
     59 }
     60 
     61 DisplayError ToneMapSession::AllocateIntermediateBuffers(int w, int h, int format, int usage) {
     62   for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
     63     int status = alloc_buffer(&intermediate_buffer_[i], w, h, format, usage);
     64     if (status < 0) {
     65       FreeIntermediateBuffers();
     66       return kErrorMemory;
     67     }
     68   }
     69 
     70   return kErrorNone;
     71 }
     72 
     73 void ToneMapSession::FreeIntermediateBuffers() {
     74   for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
     75     private_handle_t *buffer = intermediate_buffer_[i];
     76     if (buffer) {
     77       // Free the valid fence
     78       if (release_fence_fd_[i] >= 0) {
     79         CloseFd(&release_fence_fd_[i]);
     80       }
     81       free_buffer(buffer);
     82       intermediate_buffer_[i] = NULL;
     83     }
     84   }
     85 }
     86 
     87 void ToneMapSession::UpdateBuffer(int acquire_fence, LayerBuffer *buffer) {
     88   // Acquire fence will be closed by HWC Display.
     89   // Fence returned by GPU will be closed in PostCommit.
     90   buffer->acquire_fence_fd = acquire_fence;
     91   buffer->size = intermediate_buffer_[current_buffer_index_]->size;
     92   buffer->planes[0].fd = intermediate_buffer_[current_buffer_index_]->fd;
     93 }
     94 
     95 void ToneMapSession::SetReleaseFence(int fd) {
     96   CloseFd(&release_fence_fd_[current_buffer_index_]);
     97   // Used to give to GPU tonemapper along with input layer fd
     98   release_fence_fd_[current_buffer_index_] = dup(fd);
     99 }
    100 
    101 void ToneMapSession::SetToneMapConfig(Layer *layer) {
    102   // HDR -> SDR is FORWARD and SDR - > HDR is INVERSE
    103   tone_map_config_.type = layer->input_buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
    104   tone_map_config_.colorPrimaries = layer->input_buffer.color_metadata.colorPrimaries;
    105   tone_map_config_.transfer = layer->input_buffer.color_metadata.transfer;
    106   tone_map_config_.secure = layer->request.flags.secure;
    107   tone_map_config_.format = layer->request.format;
    108 }
    109 
    110 bool ToneMapSession::IsSameToneMapConfig(Layer *layer) {
    111   LayerBuffer& buffer = layer->input_buffer;
    112   private_handle_t *handle = intermediate_buffer_[0];
    113   int tonemap_type = buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
    114 
    115   return ((tonemap_type == tone_map_config_.type) &&
    116           (buffer.color_metadata.colorPrimaries == tone_map_config_.colorPrimaries) &&
    117           (buffer.color_metadata.transfer == tone_map_config_.transfer) &&
    118           (layer->request.flags.secure == tone_map_config_.secure) &&
    119           (layer->request.format == tone_map_config_.format) &&
    120           (layer->request.width == UINT32(handle->unaligned_width)) &&
    121           (layer->request.height == UINT32(handle->unaligned_height)));
    122 }
    123 
    124 int HWCToneMapper::HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
    125   uint32_t gpu_count = 0;
    126   DisplayError error = kErrorNone;
    127 
    128   for (uint32_t i = 0; i < layer_stack->layers.size(); i++) {
    129     uint32_t session_index = 0;
    130     Layer *layer = layer_stack->layers.at(i);
    131     if (layer->composition == kCompositionGPU) {
    132       gpu_count++;
    133     }
    134 
    135     if (layer->request.flags.tone_map) {
    136       switch (layer->composition) {
    137       case kCompositionGPUTarget:
    138         if (!gpu_count) {
    139           // When all layers are on FrameBuffer and if they do not update in the next draw cycle,
    140           // then SDM marks them for SDE Composition because the cached FB layer gets displayed.
    141           // GPU count will be 0 in this case. Try to use the existing tone-mapped frame buffer.
    142           // No ToneMap/Blit is required. Just update the buffer & acquire fence fd of FB layer.
    143           if (!tone_map_sessions_.empty()) {
    144             ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(fb_session_index_);
    145             fb_tone_map_session->UpdateBuffer(-1 /* acquire_fence */, &layer->input_buffer);
    146             fb_tone_map_session->layer_index_ = INT(i);
    147             fb_tone_map_session->acquired_ = true;
    148             return 0;
    149           }
    150         }
    151         error = AcquireToneMapSession(layer, &session_index);
    152         fb_session_index_ = session_index;
    153         break;
    154       default:
    155         error = AcquireToneMapSession(layer, &session_index);
    156         break;
    157       }
    158 
    159       if (error != kErrorNone) {
    160         Terminate();
    161         return -1;
    162       }
    163 
    164       ToneMapSession *session = tone_map_sessions_.at(session_index);
    165       ToneMap(&content_list->hwLayers[i], layer, session);
    166       session->layer_index_ = INT(i);
    167     }
    168   }
    169 
    170   return 0;
    171 }
    172 
    173 void HWCToneMapper::ToneMap(hwc_layer_1_t *hwc_layer, Layer* layer, ToneMapSession *session) {
    174   int fence_fd = -1;
    175   int acquire_fd = -1;
    176   int merged_fd = -1;
    177 
    178   uint8_t buffer_index = session->current_buffer_index_;
    179   const private_handle_t *dst_hnd = session->intermediate_buffer_[buffer_index];
    180   const private_handle_t *src_hnd = static_cast<const private_handle_t *>(hwc_layer->handle);
    181 
    182   acquire_fd = dup(layer->input_buffer.acquire_fence_fd);
    183   buffer_sync_handler_.SyncMerge(session->release_fence_fd_[buffer_index], acquire_fd, &merged_fd);
    184 
    185   if (acquire_fd >= 0) {
    186     CloseFd(&acquire_fd);
    187   }
    188 
    189   if (session->release_fence_fd_[buffer_index] >= 0) {
    190     CloseFd(&session->release_fence_fd_[buffer_index]);
    191   }
    192 
    193   DTRACE_BEGIN("GPU_TM_BLIT");
    194   fence_fd = session->gpu_tone_mapper_->blit(reinterpret_cast<const void *>(dst_hnd),
    195                                              reinterpret_cast<const void *>(src_hnd), merged_fd);
    196   DTRACE_END();
    197 
    198   DumpToneMapOutput(session, &fence_fd);
    199   session->UpdateBuffer(fence_fd, &layer->input_buffer);
    200 }
    201 
    202 void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
    203   auto it = tone_map_sessions_.begin();
    204   while (it != tone_map_sessions_.end()) {
    205     uint32_t session_index = UINT32(std::distance(tone_map_sessions_.begin(), it));
    206     ToneMapSession *session = tone_map_sessions_.at(session_index);
    207     Layer *layer = layer_stack->layers.at(UINT32(session->layer_index_));
    208     if (session->acquired_) {
    209       // Close the fd returned by GPU ToneMapper and set release fence.
    210       LayerBuffer &layer_buffer = layer->input_buffer;
    211       CloseFd(&layer_buffer.acquire_fence_fd);
    212       session->SetReleaseFence(layer_buffer.release_fence_fd);
    213       session->acquired_ = false;
    214       it++;
    215     } else {
    216       delete session;
    217       it = tone_map_sessions_.erase(it);
    218     }
    219   }
    220 }
    221 
    222 void HWCToneMapper::Terminate() {
    223   if (tone_map_sessions_.size()) {
    224     while (!tone_map_sessions_.empty()) {
    225       delete tone_map_sessions_.back();
    226       tone_map_sessions_.pop_back();
    227     }
    228     fb_session_index_ = 0;
    229   }
    230 }
    231 
    232 void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
    233   DLOGI("Dump FrameConfig count = %d", count);
    234   dump_frame_count_ = count;
    235   dump_frame_index_ = 0;
    236 }
    237 
    238 void HWCToneMapper::DumpToneMapOutput(ToneMapSession *session, int *acquire_fd) {
    239   if (!dump_frame_count_) {
    240     return;
    241   }
    242 
    243   private_handle_t *target_buffer = session->intermediate_buffer_[session->current_buffer_index_];
    244 
    245   if (*acquire_fd >= 0) {
    246     int error = sync_wait(*acquire_fd, 1000);
    247     if (error < 0) {
    248       DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
    249       return;
    250     }
    251   }
    252 
    253   size_t result = 0;
    254   char dump_file_name[PATH_MAX];
    255   snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
    256            "/tonemap_%dx%d_frame%d.raw", target_buffer->width, target_buffer->height,
    257            dump_frame_index_);
    258 
    259   FILE* fp = fopen(dump_file_name, "w+");
    260   if (fp) {
    261     DLOGI("base addr = %x", target_buffer->base);
    262     result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
    263     fclose(fp);
    264   }
    265   dump_frame_count_--;
    266   dump_frame_index_++;
    267   CloseFd(acquire_fd);
    268 }
    269 
    270 DisplayError HWCToneMapper::AcquireToneMapSession(Layer *layer, uint32_t *session_index) {
    271   Color10Bit *grid_entries = NULL;
    272   int grid_size = 0;
    273 
    274   if (layer->lut_3d.validGridEntries) {
    275     grid_entries = layer->lut_3d.gridEntries;
    276     grid_size = INT(layer->lut_3d.gridSize);
    277   }
    278 
    279   // When the property sdm.disable_hdr_lut_gen is set, the lutEntries and gridEntries in
    280   // the Lut3d will be NULL, clients needs to allocate the memory and set correct 3D Lut
    281   // for Tonemapping.
    282   if (!layer->lut_3d.lutEntries || !layer->lut_3d.dim) {
    283     // Atleast lutEntries must be valid for GPU Tonemapper.
    284     DLOGE("Invalid Lut Entries or lut dimension = %d", layer->lut_3d.dim);
    285     return kErrorParameters;
    286   }
    287 
    288   // Check if we can re-use an existing tone map session.
    289   for (uint32_t i = 0; i < tone_map_sessions_.size(); i++) {
    290     ToneMapSession *tonemap_session = tone_map_sessions_.at(i);
    291     if (!tonemap_session->acquired_ && tonemap_session->IsSameToneMapConfig(layer)) {
    292       tonemap_session->current_buffer_index_ = (tonemap_session->current_buffer_index_ + 1) %
    293                                                 ToneMapSession::kNumIntermediateBuffers;
    294       tonemap_session->acquired_ = true;
    295       *session_index = i;
    296       return kErrorNone;
    297     }
    298   }
    299 
    300   ToneMapSession *session = new ToneMapSession();
    301 
    302   session->SetToneMapConfig(layer);
    303   session->gpu_tone_mapper_ = TonemapperFactory_GetInstance(session->tone_map_config_.type,
    304                                                             layer->lut_3d.lutEntries,
    305                                                             layer->lut_3d.dim,
    306                                                             grid_entries, grid_size,
    307                                                             session->tone_map_config_.secure);
    308 
    309   if (session->gpu_tone_mapper_ == NULL) {
    310     DLOGE("Get Tonemapper failed!");
    311     delete session;
    312     return kErrorNotSupported;
    313   }
    314 
    315   int status, format;
    316   DisplayError error = kErrorNone;
    317   int usage = INT(GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | GRALLOC_USAGE_HW_TEXTURE);
    318 
    319   if (layer->request.flags.secure) {
    320     usage = INT(GRALLOC_USAGE_PRIVATE_MM_HEAP);
    321     usage |= INT(GRALLOC_USAGE_PROTECTED);
    322   }
    323 
    324   status = buffer_allocator_.SetBufferInfo(layer->request.format, &format, &usage);
    325   error = session->AllocateIntermediateBuffers(INT(layer->request.width),
    326                                                INT(layer->request.height), format, usage);
    327 
    328   if (error != kErrorNone) {
    329     DLOGE("Allocation of Intermediate Buffers failed!");
    330     delete session;
    331     return error;
    332   }
    333 
    334   session->acquired_ = true;
    335   tone_map_sessions_.push_back(session);
    336   *session_index = UINT32(tone_map_sessions_.size() - 1);
    337 
    338   return kErrorNone;
    339 }
    340 
    341 }  // namespace sdm
    342