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