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 }
142
SetReleaseFence(int fd)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
SetToneMapConfig(Layer * layer)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
IsSameToneMapConfig(Layer * layer)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
HandleToneMap(LayerStack * layer_stack)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
ToneMap(Layer * layer,ToneMapSession * session)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
PostCommit(LayerStack * layer_stack)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
Terminate()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
SetFrameDumpConfig(uint32_t count)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
DumpToneMapOutput(ToneMapSession * session,int * acquire_fd)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
AcquireToneMapSession(Layer * layer,uint32_t * session_index)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