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 
ToneMapSession(HWCBufferAllocator * buffer_allocator)52 ToneMapSession::ToneMapSession(HWCBufferAllocator *buffer_allocator)
53   : tone_map_task_(*this), buffer_allocator_(buffer_allocator) {
54   buffer_info_.resize(kNumIntermediateBuffers);
55 }
56 
~ToneMapSession()57 ToneMapSession::~ToneMapSession() {
58   tone_map_task_.PerformTask(ToneMapTaskCode::kCodeDestroy, nullptr);
59   FreeIntermediateBuffers();
60   buffer_info_.clear();
61 }
62 
OnTask(const ToneMapTaskCode & task_code,SyncTask<ToneMapTaskCode>::TaskContext * task_context)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 
AllocateIntermediateBuffers(const Layer * layer)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 
FreeIntermediateBuffers()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 
UpdateBuffer(int acquire_fence,LayerBuffer * buffer)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   buffer->handle_id = buffer_info_[current_buffer_index_].alloc_buffer_info.id;
142 }
143 
SetReleaseFence(int fd)144 void ToneMapSession::SetReleaseFence(int fd) {
145   CloseFd(&release_fence_fd_[current_buffer_index_]);
146   // Used to give to GPU tonemapper along with input layer fd
147   release_fence_fd_[current_buffer_index_] = dup(fd);
148 }
149 
SetToneMapConfig(Layer * layer,PrimariesTransfer blend_cs)150 void ToneMapSession::SetToneMapConfig(Layer *layer, PrimariesTransfer blend_cs) {
151   // HDR -> SDR is FORWARD and SDR - > HDR is INVERSE
152   tone_map_config_.type = layer->input_buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
153   tone_map_config_.blend_cs = blend_cs;
154   tone_map_config_.transfer = layer->input_buffer.color_metadata.transfer;
155   tone_map_config_.secure = layer->request.flags.secure;
156   tone_map_config_.format = layer->request.format;
157 }
158 
IsSameToneMapConfig(Layer * layer,PrimariesTransfer blend_cs)159 bool ToneMapSession::IsSameToneMapConfig(Layer *layer, PrimariesTransfer blend_cs) {
160   LayerBuffer& buffer = layer->input_buffer;
161   private_handle_t *handle = static_cast<private_handle_t *>(buffer_info_[0].private_data);
162   int tonemap_type = buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
163 
164   return ((tonemap_type == tone_map_config_.type) &&
165           (blend_cs == tone_map_config_.blend_cs) &&
166           (buffer.color_metadata.transfer == tone_map_config_.transfer) &&
167           (layer->request.flags.secure == tone_map_config_.secure) &&
168           (layer->request.format == tone_map_config_.format) &&
169           (layer->request.width == UINT32(handle->unaligned_width)) &&
170           (layer->request.height == UINT32(handle->unaligned_height)));
171 }
172 
HandleToneMap(LayerStack * layer_stack)173 int HWCToneMapper::HandleToneMap(LayerStack *layer_stack) {
174   uint32_t gpu_count = 0;
175   DisplayError error = kErrorNone;
176 
177   for (uint32_t i = 0; i < layer_stack->layers.size(); i++) {
178     uint32_t session_index = 0;
179     Layer *layer = layer_stack->layers.at(i);
180     if (layer->composition == kCompositionGPU) {
181       gpu_count++;
182     }
183 
184     if (layer->request.flags.tone_map) {
185       DLOGV_IF(kTagClient, "Tonemapping for layer at index %d", i);
186       switch (layer->composition) {
187       case kCompositionGPUTarget:
188         if (!gpu_count) {
189           // When all layers are on FrameBuffer and if they do not update in the next draw cycle,
190           // then SDM marks them for SDE Composition because the cached FB layer gets displayed.
191           // GPU count will be 0 in this case. Try to use the existing tone-mapped frame buffer.
192           // No ToneMap/Blit is required. Just update the buffer & acquire fence fd of FB layer.
193           if (!tone_map_sessions_.empty() && (fb_session_index_ >= 0)) {
194             ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(UINT32(fb_session_index_));
195             fb_tone_map_session->UpdateBuffer(-1 /* acquire_fence */, &layer->input_buffer);
196             fb_tone_map_session->layer_index_ = INT(i);
197             fb_tone_map_session->acquired_ = true;
198             return 0;
199           }
200         }
201         error = AcquireToneMapSession(layer, &session_index, layer_stack->blend_cs);
202         fb_session_index_ = INT(session_index);
203         break;
204       default:
205         error = AcquireToneMapSession(layer, &session_index, layer_stack->blend_cs);
206         break;
207       }
208 
209       if (error != kErrorNone) {
210         Terminate();
211         return -1;
212       }
213 
214       ToneMapSession *session = tone_map_sessions_.at(session_index);
215       ToneMap(layer, session);
216       DLOGI_IF(kTagClient, "Layer %d associated with session index %d", i, session_index);
217       session->layer_index_ = INT(i);
218     }
219   }
220 
221   return 0;
222 }
223 
ToneMap(Layer * layer,ToneMapSession * session)224 void HWCToneMapper::ToneMap(Layer* layer, ToneMapSession *session) {
225   ToneMapBlitContext ctx = {};
226   ctx.layer = layer;
227 
228   uint8_t buffer_index = session->current_buffer_index_;
229   int &release_fence_fd = session->release_fence_fd_[buffer_index];
230 
231   // use and close the layer->input_buffer acquire fence fd.
232   int acquire_fd = layer->input_buffer.acquire_fence_fd;
233   buffer_sync_handler_.SyncMerge(release_fence_fd, acquire_fd, &ctx.merged_fd);
234 
235   if (acquire_fd >= 0) {
236     CloseFd(&acquire_fd);
237   }
238 
239   if (release_fence_fd >= 0) {
240     CloseFd(&release_fence_fd);
241   }
242 
243   DTRACE_BEGIN("GPU_TM_BLIT");
244   session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeBlit, &ctx);
245   DTRACE_END();
246 
247   DumpToneMapOutput(session, &ctx.fence_fd);
248   session->UpdateBuffer(ctx.fence_fd, &layer->input_buffer);
249 }
250 
PostCommit(LayerStack * layer_stack)251 void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
252   auto it = tone_map_sessions_.begin();
253   while (it != tone_map_sessions_.end()) {
254     uint32_t session_index = UINT32(std::distance(tone_map_sessions_.begin(), it));
255     ToneMapSession *session = tone_map_sessions_.at(session_index);
256     if (session->acquired_) {
257       Layer *layer = layer_stack->layers.at(UINT32(session->layer_index_));
258       // Close the fd returned by GPU ToneMapper and set release fence.
259       LayerBuffer &layer_buffer = layer->input_buffer;
260       CloseFd(&layer_buffer.acquire_fence_fd);
261       session->SetReleaseFence(layer_buffer.release_fence_fd);
262       session->acquired_ = false;
263       it++;
264     } else {
265       DLOGI_IF(kTagClient, "Tone map session %d closed.", session_index);
266       delete session;
267       it = tone_map_sessions_.erase(it);
268       int deleted_session = INT(session_index);
269       // If FB tonemap session gets deleted, reset fb_session_index_, else update it.
270       if (deleted_session == fb_session_index_) {
271         fb_session_index_ = -1;
272       } else if (deleted_session < fb_session_index_) {
273         fb_session_index_--;
274       }
275     }
276   }
277 }
278 
Terminate()279 void HWCToneMapper::Terminate() {
280   if (tone_map_sessions_.size()) {
281     while (!tone_map_sessions_.empty()) {
282       delete tone_map_sessions_.back();
283       tone_map_sessions_.pop_back();
284     }
285     fb_session_index_ = -1;
286   }
287 }
288 
SetFrameDumpConfig(uint32_t count)289 void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
290   DLOGI("Dump FrameConfig count = %d", count);
291   dump_frame_count_ = count;
292   dump_frame_index_ = 0;
293 }
294 
DumpToneMapOutput(ToneMapSession * session,int * acquire_fd)295 void HWCToneMapper::DumpToneMapOutput(ToneMapSession *session, int *acquire_fd) {
296   DisplayError error = kErrorNone;
297   if (!dump_frame_count_) {
298     return;
299   }
300 
301   BufferInfo &buffer_info = session->buffer_info_[session->current_buffer_index_];
302   private_handle_t *target_buffer = static_cast<private_handle_t *>(buffer_info.private_data);
303 
304   if (*acquire_fd >= 0) {
305     int error = sync_wait(*acquire_fd, 1000);
306     if (error < 0) {
307       DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
308       return;
309     }
310   }
311 
312   error = buffer_allocator_->MapBuffer(target_buffer, *acquire_fd);
313   if (error != kErrorNone) {
314     DLOGE("MapBuffer failed, base addr = %x", target_buffer->base);
315     return;
316   }
317 
318   size_t result = 0;
319   char dump_file_name[PATH_MAX];
320   snprintf(dump_file_name, sizeof(dump_file_name), "%s/frame_dump_primary"
321            "/tonemap_%dx%d_frame%d.raw", HWCDebugHandler::DumpDir(), target_buffer->width,
322            target_buffer->height, dump_frame_index_);
323 
324   FILE* fp = fopen(dump_file_name, "w+");
325   if (fp) {
326     DLOGI("base addr = %x", target_buffer->base);
327     result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
328     fclose(fp);
329   }
330   dump_frame_count_--;
331   dump_frame_index_++;
332   CloseFd(acquire_fd);
333 }
334 
AcquireToneMapSession(Layer * layer,uint32_t * session_index,PrimariesTransfer blend_cs)335 DisplayError HWCToneMapper::AcquireToneMapSession(Layer *layer, uint32_t *session_index,
336                                                   PrimariesTransfer blend_cs) {
337   // When the property vendor.display.disable_hdr_lut_gen is set, the lutEntries and gridEntries in
338   // the Lut3d will be NULL, clients needs to allocate the memory and set correct 3D Lut
339   // for Tonemapping.
340   if (!layer->lut_3d.lutEntries || !layer->lut_3d.dim) {
341     // Atleast lutEntries must be valid for GPU Tonemapper.
342     DLOGE("Invalid Lut Entries or lut dimension = %d", layer->lut_3d.dim);
343     return kErrorParameters;
344   }
345 
346   // Check if we can re-use an existing tone map session.
347   for (uint32_t i = 0; i < tone_map_sessions_.size(); i++) {
348     ToneMapSession *tonemap_session = tone_map_sessions_.at(i);
349     if (!tonemap_session->acquired_ && tonemap_session->IsSameToneMapConfig(layer, blend_cs)) {
350       tonemap_session->current_buffer_index_ = (tonemap_session->current_buffer_index_ + 1) %
351                                                 ToneMapSession::kNumIntermediateBuffers;
352       tonemap_session->acquired_ = true;
353       *session_index = i;
354       return kErrorNone;
355     }
356   }
357 
358   ToneMapSession *session = new ToneMapSession(buffer_allocator_);
359   if (!session) {
360     return kErrorMemory;
361   }
362 
363   session->SetToneMapConfig(layer, blend_cs);
364 
365   ToneMapGetInstanceContext ctx;
366   ctx.layer = layer;
367   session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeGetInstance, &ctx);
368 
369   if (session->gpu_tone_mapper_ == NULL) {
370     DLOGE("Get Tonemapper failed!");
371     delete session;
372     return kErrorNotSupported;
373   }
374   DisplayError error = session->AllocateIntermediateBuffers(layer);
375   if (error != kErrorNone) {
376     DLOGE("Allocation of Intermediate Buffers failed!");
377     delete session;
378     return error;
379   }
380 
381   session->acquired_ = true;
382   tone_map_sessions_.push_back(session);
383   *session_index = UINT32(tone_map_sessions_.size() - 1);
384 
385   return kErrorNone;
386 }
387 
388 }  // namespace sdm
389