blob: a88c06ff19552e67347d7280bd3b0687db879756 [file] [log] [blame]
Arun Kumar K.R51be3d12017-03-31 19:54:38 -07001/*
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
Dileep Marchya7061aea2017-06-05 12:52:56 +053052ToneMapSession::ToneMapSession(HWCBufferAllocator *buffer_allocator)
53 : tone_map_task_(*this), buffer_allocator_(buffer_allocator) {
Arun Kumar K.R51be3d12017-03-31 19:54:38 -070054 buffer_info_.resize(kNumIntermediateBuffers);
55}
56
57ToneMapSession::~ToneMapSession() {
Dileep Marchya7061aea2017-06-05 12:52:56 +053058 tone_map_task_.PerformTask(ToneMapTaskCode::kCodeDestroy, nullptr);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -070059 FreeIntermediateBuffers();
60 buffer_info_.clear();
61}
62
Dileep Marchya7061aea2017-06-05 12:52:56 +053063void ToneMapSession::OnTask(const ToneMapTaskCode &task_code,
64 SyncTask<ToneMapTaskCode>::TaskContext *task_context) {
65 switch (task_code) {
Naseer Ahmed0d146882019-10-18 15:19:43 -040066#ifndef TARGET_HEADLESS
Dileep Marchya7061aea2017-06-05 12:52:56 +053067 case ToneMapTaskCode::kCodeGetInstance: {
68 ToneMapGetInstanceContext *ctx = static_cast<ToneMapGetInstanceContext *>(task_context);
69 Lut3d &lut_3d = ctx->layer->lut_3d;
70 Color10Bit *grid_entries = NULL;
71 int grid_size = 0;
72 if (lut_3d.validGridEntries) {
73 grid_entries = lut_3d.gridEntries;
74 grid_size = INT(lut_3d.gridSize);
75 }
76 gpu_tone_mapper_ = TonemapperFactory_GetInstance(tone_map_config_.type,
77 lut_3d.lutEntries, lut_3d.dim,
78 grid_entries, grid_size,
79 tone_map_config_.secure);
80 }
81 break;
82
83 case ToneMapTaskCode::kCodeBlit: {
84 ToneMapBlitContext *ctx = static_cast<ToneMapBlitContext *>(task_context);
85 uint8_t buffer_index = current_buffer_index_;
86 const void *dst_hnd = reinterpret_cast<const void *>
87 (buffer_info_[buffer_index].private_data);
88 const void *src_hnd = reinterpret_cast<const void *>
89 (ctx->layer->input_buffer.buffer_id);
90 ctx->fence_fd = gpu_tone_mapper_->blit(dst_hnd, src_hnd, ctx->merged_fd);
91 }
92 break;
93
94 case ToneMapTaskCode::kCodeDestroy: {
95 delete gpu_tone_mapper_;
96 }
97 break;
98
Naseer Ahmed0d146882019-10-18 15:19:43 -040099#endif
Dileep Marchya7061aea2017-06-05 12:52:56 +0530100 default:
101 break;
102 }
103}
104
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700105DisplayError ToneMapSession::AllocateIntermediateBuffers(const Layer *layer) {
106 DisplayError error = kErrorNone;
107 for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
108 BufferInfo &buffer_info = buffer_info_[i];
109 buffer_info.buffer_config.width = layer->request.width;
110 buffer_info.buffer_config.height = layer->request.height;
111 buffer_info.buffer_config.format = layer->request.format;
112 buffer_info.buffer_config.secure = layer->request.flags.secure;
113 buffer_info.buffer_config.gfx_client = true;
114 error = buffer_allocator_->AllocateBuffer(&buffer_info);
115 if (error != kErrorNone) {
116 FreeIntermediateBuffers();
117 return error;
118 }
119 }
120
121 return kErrorNone;
122}
123
124void ToneMapSession::FreeIntermediateBuffers() {
125 for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
126 // Free the valid fence
127 if (release_fence_fd_[i] >= 0) {
128 CloseFd(&release_fence_fd_[i]);
129 }
130 BufferInfo &buffer_info = buffer_info_[i];
131 if (buffer_info.private_data) {
132 buffer_allocator_->FreeBuffer(&buffer_info);
133 }
134 }
135}
136
137void ToneMapSession::UpdateBuffer(int acquire_fence, LayerBuffer *buffer) {
138 // Acquire fence will be closed by HWC Display.
139 // Fence returned by GPU will be closed in PostCommit.
140 buffer->acquire_fence_fd = acquire_fence;
141 buffer->size = buffer_info_[current_buffer_index_].alloc_buffer_info.size;
142 buffer->planes[0].fd = buffer_info_[current_buffer_index_].alloc_buffer_info.fd;
Naseer Ahmed0ea696a2018-05-17 15:34:02 -0400143 buffer->handle_id = buffer_info_[current_buffer_index_].alloc_buffer_info.id;
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700144}
145
146void ToneMapSession::SetReleaseFence(int fd) {
147 CloseFd(&release_fence_fd_[current_buffer_index_]);
148 // Used to give to GPU tonemapper along with input layer fd
149 release_fence_fd_[current_buffer_index_] = dup(fd);
150}
151
Sushil Chauhan32c18692018-02-04 22:47:54 -0800152void ToneMapSession::SetToneMapConfig(Layer *layer, PrimariesTransfer blend_cs) {
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700153 // HDR -> SDR is FORWARD and SDR - > HDR is INVERSE
154 tone_map_config_.type = layer->input_buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
Sushil Chauhan32c18692018-02-04 22:47:54 -0800155 tone_map_config_.blend_cs = blend_cs;
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700156 tone_map_config_.transfer = layer->input_buffer.color_metadata.transfer;
157 tone_map_config_.secure = layer->request.flags.secure;
158 tone_map_config_.format = layer->request.format;
159}
160
Sushil Chauhan32c18692018-02-04 22:47:54 -0800161bool ToneMapSession::IsSameToneMapConfig(Layer *layer, PrimariesTransfer blend_cs) {
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700162 LayerBuffer& buffer = layer->input_buffer;
163 private_handle_t *handle = static_cast<private_handle_t *>(buffer_info_[0].private_data);
164 int tonemap_type = buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
165
166 return ((tonemap_type == tone_map_config_.type) &&
Sushil Chauhan32c18692018-02-04 22:47:54 -0800167 (blend_cs == tone_map_config_.blend_cs) &&
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700168 (buffer.color_metadata.transfer == tone_map_config_.transfer) &&
169 (layer->request.flags.secure == tone_map_config_.secure) &&
170 (layer->request.format == tone_map_config_.format) &&
171 (layer->request.width == UINT32(handle->unaligned_width)) &&
172 (layer->request.height == UINT32(handle->unaligned_height)));
173}
174
175int HWCToneMapper::HandleToneMap(LayerStack *layer_stack) {
176 uint32_t gpu_count = 0;
177 DisplayError error = kErrorNone;
178
179 for (uint32_t i = 0; i < layer_stack->layers.size(); i++) {
180 uint32_t session_index = 0;
181 Layer *layer = layer_stack->layers.at(i);
182 if (layer->composition == kCompositionGPU) {
183 gpu_count++;
184 }
185
186 if (layer->request.flags.tone_map) {
Saurabh Dubeyd90a6a42017-10-24 16:28:01 +0530187 DLOGV_IF(kTagClient, "Tonemapping for layer at index %d", i);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700188 switch (layer->composition) {
189 case kCompositionGPUTarget:
190 if (!gpu_count) {
191 // When all layers are on FrameBuffer and if they do not update in the next draw cycle,
192 // then SDM marks them for SDE Composition because the cached FB layer gets displayed.
193 // GPU count will be 0 in this case. Try to use the existing tone-mapped frame buffer.
194 // No ToneMap/Blit is required. Just update the buffer & acquire fence fd of FB layer.
Sushil Chauhan00e26b42017-07-25 16:43:52 -0700195 if (!tone_map_sessions_.empty() && (fb_session_index_ >= 0)) {
196 ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(UINT32(fb_session_index_));
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700197 fb_tone_map_session->UpdateBuffer(-1 /* acquire_fence */, &layer->input_buffer);
198 fb_tone_map_session->layer_index_ = INT(i);
199 fb_tone_map_session->acquired_ = true;
200 return 0;
201 }
202 }
Sushil Chauhan32c18692018-02-04 22:47:54 -0800203 error = AcquireToneMapSession(layer, &session_index, layer_stack->blend_cs);
Sushil Chauhan00e26b42017-07-25 16:43:52 -0700204 fb_session_index_ = INT(session_index);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700205 break;
206 default:
Sushil Chauhan32c18692018-02-04 22:47:54 -0800207 error = AcquireToneMapSession(layer, &session_index, layer_stack->blend_cs);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700208 break;
209 }
210
211 if (error != kErrorNone) {
212 Terminate();
213 return -1;
214 }
215
216 ToneMapSession *session = tone_map_sessions_.at(session_index);
217 ToneMap(layer, session);
Saurabh Dubeyd90a6a42017-10-24 16:28:01 +0530218 DLOGI_IF(kTagClient, "Layer %d associated with session index %d", i, session_index);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700219 session->layer_index_ = INT(i);
220 }
221 }
222
223 return 0;
224}
225
226void HWCToneMapper::ToneMap(Layer* layer, ToneMapSession *session) {
Dileep Marchya7061aea2017-06-05 12:52:56 +0530227 ToneMapBlitContext ctx = {};
228 ctx.layer = layer;
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700229
230 uint8_t buffer_index = session->current_buffer_index_;
Dileep Marchya7061aea2017-06-05 12:52:56 +0530231 int &release_fence_fd = session->release_fence_fd_[buffer_index];
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700232
233 // use and close the layer->input_buffer acquire fence fd.
Dileep Marchya7061aea2017-06-05 12:52:56 +0530234 int acquire_fd = layer->input_buffer.acquire_fence_fd;
235 buffer_sync_handler_.SyncMerge(release_fence_fd, acquire_fd, &ctx.merged_fd);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700236
237 if (acquire_fd >= 0) {
238 CloseFd(&acquire_fd);
239 }
240
Dileep Marchya7061aea2017-06-05 12:52:56 +0530241 if (release_fence_fd >= 0) {
242 CloseFd(&release_fence_fd);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700243 }
244
245 DTRACE_BEGIN("GPU_TM_BLIT");
Dileep Marchya7061aea2017-06-05 12:52:56 +0530246 session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeBlit, &ctx);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700247 DTRACE_END();
248
Dileep Marchya7061aea2017-06-05 12:52:56 +0530249 DumpToneMapOutput(session, &ctx.fence_fd);
250 session->UpdateBuffer(ctx.fence_fd, &layer->input_buffer);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700251}
252
253void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
254 auto it = tone_map_sessions_.begin();
255 while (it != tone_map_sessions_.end()) {
256 uint32_t session_index = UINT32(std::distance(tone_map_sessions_.begin(), it));
257 ToneMapSession *session = tone_map_sessions_.at(session_index);
258 if (session->acquired_) {
259 Layer *layer = layer_stack->layers.at(UINT32(session->layer_index_));
260 // Close the fd returned by GPU ToneMapper and set release fence.
261 LayerBuffer &layer_buffer = layer->input_buffer;
262 CloseFd(&layer_buffer.acquire_fence_fd);
263 session->SetReleaseFence(layer_buffer.release_fence_fd);
264 session->acquired_ = false;
265 it++;
266 } else {
Saurabh Dubeyd90a6a42017-10-24 16:28:01 +0530267 DLOGI_IF(kTagClient, "Tone map session %d closed.", session_index);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700268 delete session;
269 it = tone_map_sessions_.erase(it);
Sushil Chauhan00e26b42017-07-25 16:43:52 -0700270 int deleted_session = INT(session_index);
271 // If FB tonemap session gets deleted, reset fb_session_index_, else update it.
272 if (deleted_session == fb_session_index_) {
273 fb_session_index_ = -1;
274 } else if (deleted_session < fb_session_index_) {
275 fb_session_index_--;
276 }
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700277 }
278 }
279}
280
281void HWCToneMapper::Terminate() {
282 if (tone_map_sessions_.size()) {
283 while (!tone_map_sessions_.empty()) {
284 delete tone_map_sessions_.back();
285 tone_map_sessions_.pop_back();
286 }
Sushil Chauhan00e26b42017-07-25 16:43:52 -0700287 fb_session_index_ = -1;
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700288 }
289}
290
291void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
292 DLOGI("Dump FrameConfig count = %d", count);
293 dump_frame_count_ = count;
294 dump_frame_index_ = 0;
295}
296
297void HWCToneMapper::DumpToneMapOutput(ToneMapSession *session, int *acquire_fd) {
Ch Ganesh Kumar65788dc2017-07-04 18:56:12 +0530298 DisplayError error = kErrorNone;
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700299 if (!dump_frame_count_) {
300 return;
301 }
302
303 BufferInfo &buffer_info = session->buffer_info_[session->current_buffer_index_];
304 private_handle_t *target_buffer = static_cast<private_handle_t *>(buffer_info.private_data);
305
306 if (*acquire_fd >= 0) {
307 int error = sync_wait(*acquire_fd, 1000);
308 if (error < 0) {
309 DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
310 return;
311 }
312 }
313
Ch Ganesh Kumar65788dc2017-07-04 18:56:12 +0530314 error = buffer_allocator_->MapBuffer(target_buffer, *acquire_fd);
315 if (error != kErrorNone) {
316 DLOGE("MapBuffer failed, base addr = %x", target_buffer->base);
317 return;
318 }
319
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700320 size_t result = 0;
321 char dump_file_name[PATH_MAX];
Pramodh Kumar Mukundabc846952017-06-29 18:28:20 +0530322 snprintf(dump_file_name, sizeof(dump_file_name), "%s/frame_dump_primary"
323 "/tonemap_%dx%d_frame%d.raw", HWCDebugHandler::DumpDir(), target_buffer->width,
324 target_buffer->height, dump_frame_index_);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700325
326 FILE* fp = fopen(dump_file_name, "w+");
327 if (fp) {
328 DLOGI("base addr = %x", target_buffer->base);
329 result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
330 fclose(fp);
331 }
332 dump_frame_count_--;
333 dump_frame_index_++;
334 CloseFd(acquire_fd);
335}
336
Sushil Chauhan32c18692018-02-04 22:47:54 -0800337DisplayError HWCToneMapper::AcquireToneMapSession(Layer *layer, uint32_t *session_index,
338 PrimariesTransfer blend_cs) {
Uday Kiran Pichika5e656b22018-05-15 18:48:24 +0530339 // When the property vendor.display.disable_hdr_lut_gen is set, the lutEntries and gridEntries in
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700340 // the Lut3d will be NULL, clients needs to allocate the memory and set correct 3D Lut
341 // for Tonemapping.
342 if (!layer->lut_3d.lutEntries || !layer->lut_3d.dim) {
343 // Atleast lutEntries must be valid for GPU Tonemapper.
344 DLOGE("Invalid Lut Entries or lut dimension = %d", layer->lut_3d.dim);
345 return kErrorParameters;
346 }
347
348 // Check if we can re-use an existing tone map session.
349 for (uint32_t i = 0; i < tone_map_sessions_.size(); i++) {
350 ToneMapSession *tonemap_session = tone_map_sessions_.at(i);
Sushil Chauhan32c18692018-02-04 22:47:54 -0800351 if (!tonemap_session->acquired_ && tonemap_session->IsSameToneMapConfig(layer, blend_cs)) {
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700352 tonemap_session->current_buffer_index_ = (tonemap_session->current_buffer_index_ + 1) %
353 ToneMapSession::kNumIntermediateBuffers;
354 tonemap_session->acquired_ = true;
355 *session_index = i;
356 return kErrorNone;
357 }
358 }
359
360 ToneMapSession *session = new ToneMapSession(buffer_allocator_);
Dileep Marchya7061aea2017-06-05 12:52:56 +0530361 if (!session) {
362 return kErrorMemory;
363 }
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700364
Sushil Chauhan32c18692018-02-04 22:47:54 -0800365 session->SetToneMapConfig(layer, blend_cs);
Dileep Marchya7061aea2017-06-05 12:52:56 +0530366
367 ToneMapGetInstanceContext ctx;
368 ctx.layer = layer;
369 session->tone_map_task_.PerformTask(ToneMapTaskCode::kCodeGetInstance, &ctx);
Arun Kumar K.R51be3d12017-03-31 19:54:38 -0700370
371 if (session->gpu_tone_mapper_ == NULL) {
372 DLOGE("Get Tonemapper failed!");
373 delete session;
374 return kErrorNotSupported;
375 }
376 DisplayError error = session->AllocateIntermediateBuffers(layer);
377 if (error != kErrorNone) {
378 DLOGE("Allocation of Intermediate Buffers failed!");
379 delete session;
380 return error;
381 }
382
383 session->acquired_ = true;
384 tone_map_sessions_.push_back(session);
385 *session_index = UINT32(tone_map_sessions_.size() - 1);
386
387 return kErrorNone;
388}
389
390} // namespace sdm