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