Home | History | Annotate | Download | only in hwc2
      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 <gralloc_priv.h>
     31 #include <sync/sync.h>
     32 
     33 #include <TonemapFactory.h>
     34 
     35 #include <core/buffer_allocator.h>
     36 
     37 #include <utils/constants.h>
     38 #include <utils/debug.h>
     39 #include <utils/formats.h>
     40 #include <utils/rect.h>
     41 #include <utils/utils.h>
     42 
     43 #include <vector>
     44 
     45 #include "hwc_debugger.h"
     46 #include "hwc_tonemapper.h"
     47 
     48 #define __CLASS__ "HWCToneMapper"
     49 
     50 namespace sdm {
     51 
     52 ToneMapSession::ToneMapSession(HWCBufferAllocator *buffer_allocator)
     53   : tone_map_task_(*this), buffer_allocator_(buffer_allocator) {
     54   buffer_info_.resize(kNumIntermediateBuffers);
     55 }
     56 
     57 ToneMapSession::~ToneMapSession() {
     58   tone_map_task_.PerformTask(ToneMapTaskCode::kCodeDestroy, nullptr);
     59   FreeIntermediateBuffers();
     60   buffer_info_.clear();
     61 }
     62 
     63 void ToneMapSession::OnTask(const ToneMapTaskCode &task_code,
     64                             SyncTask<ToneMapTaskCode>::TaskContext *task_context) {
     65   switch (task_code) {
     66     case ToneMapTaskCode::kCodeGetInstance: {
     67         ToneMapGetInstanceContext *ctx = static_cast<ToneMapGetInstanceContext *>(task_context);
     68         Lut3d &lut_3d = ctx->layer->lut_3d;
     69         Color10Bit *grid_entries = NULL;
     70         int grid_size = 0;
     71         if (lut_3d.validGridEntries) {
     72           grid_entries = lut_3d.gridEntries;
     73           grid_size = INT(lut_3d.gridSize);
     74         }
     75         gpu_tone_mapper_ = TonemapperFactory_GetInstance(tone_map_config_.type,
     76                                                          lut_3d.lutEntries, lut_3d.dim,
     77                                                          grid_entries, grid_size,
     78                                                          tone_map_config_.secure);
     79       }
     80       break;
     81 
     82     case ToneMapTaskCode::kCodeBlit: {
     83         ToneMapBlitContext *ctx = static_cast<ToneMapBlitContext *>(task_context);
     84         uint8_t buffer_index = current_buffer_index_;
     85         const void *dst_hnd = reinterpret_cast<const void *>
     86                                 (buffer_info_[buffer_index].private_data);
     87         const void *src_hnd = reinterpret_cast<const void *>
     88                                 (ctx->layer->input_buffer.buffer_id);
     89         ctx->fence_fd = gpu_tone_mapper_->blit(dst_hnd, src_hnd, ctx->merged_fd);
     90       }
     91       break;
     92 
     93     case ToneMapTaskCode::kCodeDestroy: {
     94         delete gpu_tone_mapper_;
     95       }
     96       break;
     97 
     98     default:
     99       break;
    100   }
    101 }
    102 
    103 DisplayError ToneMapSession::AllocateIntermediateBuffers(const Layer *layer) {
    104   DisplayError error = kErrorNone;
    105   for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
    106     BufferInfo &buffer_info = buffer_info_[i];
    107     buffer_info.buffer_config.width = layer->request.width;
    108     buffer_info.buffer_config.height = layer->request.height;
    109     buffer_info.buffer_config.format = layer->request.format;
    110     buffer_info.buffer_config.secure = layer->request.flags.secure;
    111     buffer_info.buffer_config.gfx_client = true;
    112     error = buffer_allocator_->AllocateBuffer(&buffer_info);
    113     if (error != kErrorNone) {
    114       FreeIntermediateBuffers();
    115       return error;
    116     }
    117   }
    118 
    119   return kErrorNone;
    120 }
    121 
    122 void ToneMapSession::FreeIntermediateBuffers() {
    123   for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
    124     // Free the valid fence
    125     if (release_fence_fd_[i] >= 0) {
    126       CloseFd(&release_fence_fd_[i]);
    127     }
    128     BufferInfo &buffer_info = buffer_info_[i];
    129     if (buffer_info.private_data) {
    130       buffer_allocator_->FreeBuffer(&buffer_info);
    131     }
    132   }
    133 }
    134 
    135 void ToneMapSession::UpdateBuffer(int acquire_fence, LayerBuffer *buffer) {
    136   // Acquire fence will be closed by HWC Display.
    137   // Fence returned by GPU will be closed in PostCommit.
    138   buffer->acquire_fence_fd = acquire_fence;
    139   buffer->size = buffer_info_[current_buffer_index_].alloc_buffer_info.size;
    140   buffer->planes[0].fd = buffer_info_[current_buffer_index_].alloc_buffer_info.fd;
    141 }
    142 
    143 void ToneMapSession::SetReleaseFence(int fd) {
    144   CloseFd(&release_fence_fd_[current_buffer_index_]);
    145   // Used to give to GPU tonemapper along with input layer fd
    146   release_fence_fd_[current_buffer_index_] = dup(fd);
    147 }
    148 
    149 void ToneMapSession::SetToneMapConfig(Layer *layer) {
    150   // HDR -> SDR is FORWARD and SDR - > HDR is INVERSE
    151   tone_map_config_.type = layer->input_buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
    152   tone_map_config_.colorPrimaries = layer->input_buffer.color_metadata.colorPrimaries;
    153   tone_map_config_.transfer = layer->input_buffer.color_metadata.transfer;
    154   tone_map_config_.secure = layer->request.flags.secure;
    155   tone_map_config_.format = layer->request.format;
    156 }
    157 
    158 bool ToneMapSession::IsSameToneMapConfig(Layer *layer) {
    159   LayerBuffer& buffer = layer->input_buffer;
    160   private_handle_t *handle = static_cast<private_handle_t *>(buffer_info_[0].private_data);
    161   int tonemap_type = buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
    162 
    163   return ((tonemap_type == tone_map_config_.type) &&
    164           (buffer.color_metadata.colorPrimaries == tone_map_config_.colorPrimaries) &&
    165           (buffer.color_metadata.transfer == tone_map_config_.transfer) &&
    166           (layer->request.flags.secure == tone_map_config_.secure) &&
    167           (layer->request.format == tone_map_config_.format) &&
    168           (layer->request.width == UINT32(handle->unaligned_width)) &&
    169           (layer->request.height == UINT32(handle->unaligned_height)));
    170 }
    171 
    172 int HWCToneMapper::HandleToneMap(LayerStack *layer_stack) {
    173   uint32_t gpu_count = 0;
    174   DisplayError error = kErrorNone;
    175 
    176   for (uint32_t i = 0; i < layer_stack->layers.size(); i++) {
    177     uint32_t session_index = 0;
    178     Layer *layer = layer_stack->layers.at(i);
    179     if (layer->composition == kCompositionGPU) {
    180       gpu_count++;
    181     }
    182 
    183     if (layer->request.flags.tone_map) {
    184       switch (layer->composition) {
    185       case kCompositionGPUTarget:
    186         if (!gpu_count) {
    187           // When all layers are on FrameBuffer and if they do not update in the next draw cycle,
    188           // then SDM marks them for SDE Composition because the cached FB layer gets displayed.
    189           // GPU count will be 0 in this case. Try to use the existing tone-mapped frame buffer.
    190           // No ToneMap/Blit is required. Just update the buffer & acquire fence fd of FB layer.
    191           if (!tone_map_sessions_.empty()) {
    192             ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(fb_session_index_);
    193             fb_tone_map_session->UpdateBuffer(-1 /* acquire_fence */, &layer->input_buffer);
    194             fb_tone_map_session->layer_index_ = INT(i);
    195             fb_tone_map_session->acquired_ = true;
    196             return 0;
    197           }
    198         }
    199         error = AcquireToneMapSession(layer, &session_index);
    200         fb_session_index_ = session_index;
    201         break;
    202       default:
    203         error = AcquireToneMapSession(layer, &session_index);
    204         break;
    205       }
    206 
    207       if (error != kErrorNone) {
    208         Terminate();
    209         return -1;
    210       }
    211 
    212       ToneMapSession *session = tone_map_sessions_.at(session_index);
    213       ToneMap(layer, session);
    214       session->layer_index_ = INT(i);
    215     }
    216   }
    217 
    218   return 0;
    219 }
    220 
    221 void HWCToneMapper::ToneMap(Layer* layer, ToneMapSession *session) {
    222   ToneMapBlitContext ctx = {};
    223   ctx.layer = layer;
    224 
    225   uint8_t buffer_index = session->current_buffer_index_;
    226   int &release_fence_fd = session->release_fence_fd_[buffer_index];
    227 
    228   // use and close the layer->input_buffer acquire fence fd.
    229   int acquire_fd = layer->input_buffer.acquire_fence_fd;
    230   buffer_sync_handler_.SyncMerge(release_fence_fd, acquire_fd, &ctx.merged_fd);
    231 
    232   if (acquire_fd >= 0) {
    233     CloseFd(&acquire_fd);
    234   }
    235 
    236   if (release_fence_fd >= 0) {
    237     CloseFd(&release_fence_fd);
    238   }
    239 
    240   DTRACE_BEGIN("GPU_TM_BLIT");
    241   session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeBlit, &ctx);
    242   DTRACE_END();
    243 
    244   DumpToneMapOutput(session, &ctx.fence_fd);
    245   session->UpdateBuffer(ctx.fence_fd, &layer->input_buffer);
    246 }
    247 
    248 void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
    249   auto it = tone_map_sessions_.begin();
    250   while (it != tone_map_sessions_.end()) {
    251     uint32_t session_index = UINT32(std::distance(tone_map_sessions_.begin(), it));
    252     ToneMapSession *session = tone_map_sessions_.at(session_index);
    253     if (session->acquired_) {
    254       Layer *layer = layer_stack->layers.at(UINT32(session->layer_index_));
    255       // Close the fd returned by GPU ToneMapper and set release fence.
    256       LayerBuffer &layer_buffer = layer->input_buffer;
    257       CloseFd(&layer_buffer.acquire_fence_fd);
    258       session->SetReleaseFence(layer_buffer.release_fence_fd);
    259       session->acquired_ = false;
    260       it++;
    261     } else {
    262       delete session;
    263       it = tone_map_sessions_.erase(it);
    264     }
    265   }
    266 }
    267 
    268 void HWCToneMapper::Terminate() {
    269   if (tone_map_sessions_.size()) {
    270     while (!tone_map_sessions_.empty()) {
    271       delete tone_map_sessions_.back();
    272       tone_map_sessions_.pop_back();
    273     }
    274     fb_session_index_ = 0;
    275   }
    276 }
    277 
    278 void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
    279   DLOGI("Dump FrameConfig count = %d", count);
    280   dump_frame_count_ = count;
    281   dump_frame_index_ = 0;
    282 }
    283 
    284 void HWCToneMapper::DumpToneMapOutput(ToneMapSession *session, int *acquire_fd) {
    285   if (!dump_frame_count_) {
    286     return;
    287   }
    288 
    289   BufferInfo &buffer_info = session->buffer_info_[session->current_buffer_index_];
    290   private_handle_t *target_buffer = static_cast<private_handle_t *>(buffer_info.private_data);
    291 
    292   if (*acquire_fd >= 0) {
    293     int error = sync_wait(*acquire_fd, 1000);
    294     if (error < 0) {
    295       DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
    296       return;
    297     }
    298   }
    299 
    300   size_t result = 0;
    301   char dump_file_name[PATH_MAX];
    302   snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
    303            "/tonemap_%dx%d_frame%d.raw", target_buffer->width, target_buffer->height,
    304            dump_frame_index_);
    305 
    306   FILE* fp = fopen(dump_file_name, "w+");
    307   if (fp) {
    308     DLOGI("base addr = %x", target_buffer->base);
    309     result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
    310     fclose(fp);
    311   }
    312   dump_frame_count_--;
    313   dump_frame_index_++;
    314   CloseFd(acquire_fd);
    315 }
    316 
    317 DisplayError HWCToneMapper::AcquireToneMapSession(Layer *layer, uint32_t *session_index) {
    318   // When the property sdm.disable_hdr_lut_gen is set, the lutEntries and gridEntries in
    319   // the Lut3d will be NULL, clients needs to allocate the memory and set correct 3D Lut
    320   // for Tonemapping.
    321   if (!layer->lut_3d.lutEntries || !layer->lut_3d.dim) {
    322     // Atleast lutEntries must be valid for GPU Tonemapper.
    323     DLOGE("Invalid Lut Entries or lut dimension = %d", layer->lut_3d.dim);
    324     return kErrorParameters;
    325   }
    326 
    327   // Check if we can re-use an existing tone map session.
    328   for (uint32_t i = 0; i < tone_map_sessions_.size(); i++) {
    329     ToneMapSession *tonemap_session = tone_map_sessions_.at(i);
    330     if (!tonemap_session->acquired_ && tonemap_session->IsSameToneMapConfig(layer)) {
    331       tonemap_session->current_buffer_index_ = (tonemap_session->current_buffer_index_ + 1) %
    332                                                 ToneMapSession::kNumIntermediateBuffers;
    333       tonemap_session->acquired_ = true;
    334       *session_index = i;
    335       return kErrorNone;
    336     }
    337   }
    338 
    339   ToneMapSession *session = new ToneMapSession(buffer_allocator_);
    340   if (!session) {
    341     return kErrorMemory;
    342   }
    343 
    344   session->SetToneMapConfig(layer);
    345 
    346   ToneMapGetInstanceContext ctx;
    347   ctx.layer = layer;
    348   session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeGetInstance, &ctx);
    349 
    350   if (session->gpu_tone_mapper_ == NULL) {
    351     DLOGE("Get Tonemapper failed!");
    352     delete session;
    353     return kErrorNotSupported;
    354   }
    355   DisplayError error = session->AllocateIntermediateBuffers(layer);
    356   if (error != kErrorNone) {
    357     DLOGE("Allocation of Intermediate Buffers failed!");
    358     delete session;
    359     return error;
    360   }
    361 
    362   session->acquired_ = true;
    363   tone_map_sessions_.push_back(session);
    364   *session_index = UINT32(tone_map_sessions_.size() - 1);
    365 
    366   return kErrorNone;
    367 }
    368 
    369 }  // namespace sdm
    370