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
50namespace sdm {
51
52ToneMapSession::ToneMapSession(HWCBufferAllocator *buffer_allocator)
53  : tone_map_task_(*this), buffer_allocator_(buffer_allocator) {
54  buffer_info_.resize(kNumIntermediateBuffers);
55}
56
57ToneMapSession::~ToneMapSession() {
58  tone_map_task_.PerformTask(ToneMapTaskCode::kCodeDestroy, nullptr);
59  FreeIntermediateBuffers();
60  buffer_info_.clear();
61}
62
63void 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
103DisplayError 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
122void 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
135void 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
143void 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
149void 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
158bool 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
172int 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
221void 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
248void 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
268void 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
278void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
279  DLOGI("Dump FrameConfig count = %d", count);
280  dump_frame_count_ = count;
281  dump_frame_index_ = 0;
282}
283
284void 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
317DisplayError 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