1/*
2* Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without modification, are permitted
5* provided that the following conditions are met:
6*    * Redistributions of source code must retain the above copyright notice, this list of
7*      conditions and the following disclaimer.
8*    * Redistributions in binary form must reproduce the above copyright notice, this list of
9*      conditions and the following disclaimer in the documentation and/or other materials provided
10*      with the distribution.
11*    * Neither the name of The Linux Foundation nor the names of its contributors may be used to
12*      endorse or promote products derived from this software without specific prior written
13*      permission.
14*
15* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17* NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*/
24
25#include <utils/constants.h>
26#include <utils/debug.h>
27#include <core/buffer_allocator.h>
28
29#include "comp_manager.h"
30#include "strategy.h"
31
32#define __CLASS__ "CompManager"
33
34namespace sdm {
35
36DisplayError CompManager::Init(const HWResourceInfo &hw_res_info,
37                               ExtensionInterface *extension_intf,
38                               BufferSyncHandler *buffer_sync_handler) {
39  SCOPE_LOCK(locker_);
40
41  DisplayError error = kErrorNone;
42
43  if (extension_intf) {
44    error = extension_intf->CreateResourceExtn(hw_res_info, &resource_intf_, buffer_sync_handler);
45  } else {
46    resource_intf_ = &resource_default_;
47    error = resource_default_.Init(hw_res_info);
48  }
49
50  if (error != kErrorNone) {
51    return error;
52  }
53
54  hw_res_info_ = hw_res_info;
55  extension_intf_ = extension_intf;
56
57  return error;
58}
59
60DisplayError CompManager::Deinit() {
61  SCOPE_LOCK(locker_);
62
63  if (extension_intf_) {
64    extension_intf_->DestroyResourceExtn(resource_intf_);
65  } else {
66    resource_default_.Deinit();
67  }
68
69  return kErrorNone;
70}
71
72DisplayError CompManager::RegisterDisplay(DisplayType type,
73                                          const HWDisplayAttributes &display_attributes,
74                                          const HWPanelInfo &hw_panel_info,
75                                          const HWMixerAttributes &mixer_attributes,
76                                          const DisplayConfigVariableInfo &fb_config,
77                                          Handle *display_ctx) {
78  SCOPE_LOCK(locker_);
79
80  DisplayError error = kErrorNone;
81
82  DisplayCompositionContext *display_comp_ctx = new DisplayCompositionContext();
83  if (!display_comp_ctx) {
84    return kErrorMemory;
85  }
86
87  Strategy *&strategy = display_comp_ctx->strategy;
88  strategy = new Strategy(extension_intf_, type, hw_res_info_, hw_panel_info, mixer_attributes,
89                          display_attributes, fb_config);
90  if (!strategy) {
91    DLOGE("Unable to create strategy");
92    delete display_comp_ctx;
93    return kErrorMemory;
94  }
95
96  error = strategy->Init();
97  if (error != kErrorNone) {
98    delete strategy;
99    delete display_comp_ctx;
100    return error;
101  }
102
103  error = resource_intf_->RegisterDisplay(type, display_attributes, hw_panel_info, mixer_attributes,
104                                          &display_comp_ctx->display_resource_ctx);
105  if (error != kErrorNone) {
106    strategy->Deinit();
107    delete strategy;
108    delete display_comp_ctx;
109    display_comp_ctx = NULL;
110    return error;
111  }
112
113  registered_displays_[type] = 1;
114  display_comp_ctx->is_primary_panel = hw_panel_info.is_primary_panel;
115  display_comp_ctx->display_type = type;
116  *display_ctx = display_comp_ctx;
117  // New non-primary display device has been added, so move the composition mode to safe mode until
118  // resources for the added display is configured properly.
119  if (!display_comp_ctx->is_primary_panel) {
120    safe_mode_ = true;
121  }
122
123  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
124           "display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(),
125           display_comp_ctx->display_type);
126
127  return kErrorNone;
128}
129
130DisplayError CompManager::UnregisterDisplay(Handle comp_handle) {
131  SCOPE_LOCK(locker_);
132
133  DisplayCompositionContext *display_comp_ctx =
134                             reinterpret_cast<DisplayCompositionContext *>(comp_handle);
135
136  if (!display_comp_ctx) {
137    return kErrorParameters;
138  }
139
140  resource_intf_->UnregisterDisplay(display_comp_ctx->display_resource_ctx);
141
142  Strategy *&strategy = display_comp_ctx->strategy;
143  strategy->Deinit();
144  delete strategy;
145
146  registered_displays_[display_comp_ctx->display_type] = 0;
147  configured_displays_[display_comp_ctx->display_type] = 0;
148
149  if (display_comp_ctx->display_type == kHDMI) {
150    max_layers_ = kMaxSDELayers;
151  }
152
153  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
154           "display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(),
155           display_comp_ctx->display_type);
156
157  delete display_comp_ctx;
158  display_comp_ctx = NULL;
159  return kErrorNone;
160}
161
162DisplayError CompManager::ReconfigureDisplay(Handle comp_handle,
163                                             const HWDisplayAttributes &display_attributes,
164                                             const HWPanelInfo &hw_panel_info,
165                                             const HWMixerAttributes &mixer_attributes,
166                                             const DisplayConfigVariableInfo &fb_config) {
167  SCOPE_LOCK(locker_);
168
169  DisplayError error = kErrorNone;
170  DisplayCompositionContext *display_comp_ctx =
171                             reinterpret_cast<DisplayCompositionContext *>(comp_handle);
172
173  error = resource_intf_->ReconfigureDisplay(display_comp_ctx->display_resource_ctx,
174                                             display_attributes, hw_panel_info, mixer_attributes);
175  if (error != kErrorNone) {
176    return error;
177  }
178
179  if (display_comp_ctx->strategy) {
180    error = display_comp_ctx->strategy->Reconfigure(hw_panel_info, display_attributes,
181                                                    mixer_attributes, fb_config);
182    if (error != kErrorNone) {
183      DLOGE("Unable to Reconfigure strategy.");
184      display_comp_ctx->strategy->Deinit();
185      delete display_comp_ctx->strategy;
186      display_comp_ctx->strategy = NULL;
187      return error;
188    }
189  }
190
191  // For HDMI S3D mode, set max_layers_ to 0 so that primary display would fall back
192  // to GPU composition to release pipes for HDMI.
193  if (display_comp_ctx->display_type == kHDMI) {
194    if (hw_panel_info.s3d_mode != kS3DModeNone) {
195      max_layers_ = 0;
196    } else {
197      max_layers_ = kMaxSDELayers;
198    }
199  }
200
201  return error;
202}
203
204void CompManager::PrepareStrategyConstraints(Handle comp_handle, HWLayers *hw_layers) {
205  DisplayCompositionContext *display_comp_ctx =
206                             reinterpret_cast<DisplayCompositionContext *>(comp_handle);
207  StrategyConstraints *constraints = &display_comp_ctx->constraints;
208
209  constraints->safe_mode = safe_mode_;
210  constraints->use_cursor = false;
211  constraints->max_layers = max_layers_;
212
213  // Limit 2 layer SDE Comp if its not a Primary Display
214  if (!display_comp_ctx->is_primary_panel) {
215    constraints->max_layers = 2;
216  }
217
218  // If a strategy fails after successfully allocating resources, then set safe mode
219  if (display_comp_ctx->remaining_strategies != display_comp_ctx->max_strategies) {
220    constraints->safe_mode = true;
221  }
222
223  // Avoid idle fallback, if there is only one app layer.
224  // TODO(user): App layer count will change for hybrid composition
225  uint32_t app_layer_count = UINT32(hw_layers->info.stack->layers.size()) - 1;
226  if ((app_layer_count > 1 && display_comp_ctx->idle_fallback) || display_comp_ctx->fallback_) {
227    // Handle the idle timeout by falling back
228    constraints->safe_mode = true;
229  }
230
231  if (SupportLayerAsCursor(comp_handle, hw_layers)) {
232    constraints->use_cursor = true;
233  }
234}
235
236void CompManager::PrePrepare(Handle display_ctx, HWLayers *hw_layers) {
237  SCOPE_LOCK(locker_);
238  DisplayCompositionContext *display_comp_ctx =
239                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
240  display_comp_ctx->strategy->Start(&hw_layers->info, &display_comp_ctx->max_strategies,
241                                    display_comp_ctx->partial_update_enable);
242  display_comp_ctx->remaining_strategies = display_comp_ctx->max_strategies;
243}
244
245DisplayError CompManager::Prepare(Handle display_ctx, HWLayers *hw_layers) {
246  SCOPE_LOCK(locker_);
247
248  DisplayCompositionContext *display_comp_ctx =
249                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
250  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
251
252  DisplayError error = kErrorUndefined;
253
254  PrepareStrategyConstraints(display_ctx, hw_layers);
255
256  // Select a composition strategy, and try to allocate resources for it.
257  resource_intf_->Start(display_resource_ctx);
258
259  bool exit = false;
260  uint32_t &count = display_comp_ctx->remaining_strategies;
261  for (; !exit && count > 0; count--) {
262    error = display_comp_ctx->strategy->GetNextStrategy(&display_comp_ctx->constraints);
263    if (error != kErrorNone) {
264      // Composition strategies exhausted. Resource Manager could not allocate resources even for
265      // GPU composition. This will never happen.
266      exit = true;
267    }
268
269    if (!exit) {
270      error = resource_intf_->Acquire(display_resource_ctx, hw_layers);
271      // Exit if successfully allocated resource, else try next strategy.
272      exit = (error == kErrorNone);
273    }
274  }
275
276  if (error != kErrorNone) {
277    DLOGE("Composition strategies exhausted for display = %d", display_comp_ctx->display_type);
278  }
279
280  resource_intf_->Stop(display_resource_ctx);
281
282  return error;
283}
284
285DisplayError CompManager::PostPrepare(Handle display_ctx, HWLayers *hw_layers) {
286  SCOPE_LOCK(locker_);
287  DisplayCompositionContext *display_comp_ctx =
288                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
289  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
290
291  DisplayError error = kErrorNone;
292  error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers);
293  if (error != kErrorNone) {
294    return error;
295  }
296
297  display_comp_ctx->strategy->Stop();
298
299  return kErrorNone;
300}
301
302DisplayError CompManager::ReConfigure(Handle display_ctx, HWLayers *hw_layers) {
303  SCOPE_LOCK(locker_);
304
305  DisplayCompositionContext *display_comp_ctx =
306                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
307  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
308
309  DisplayError error = kErrorUndefined;
310  resource_intf_->Start(display_resource_ctx);
311  error = resource_intf_->Acquire(display_resource_ctx, hw_layers);
312
313  if (error != kErrorNone) {
314    DLOGE("Reconfigure failed for display = %d", display_comp_ctx->display_type);
315  }
316
317  resource_intf_->Stop(display_resource_ctx);
318  if (error != kErrorNone) {
319      error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers);
320  }
321
322  return error;
323}
324
325DisplayError CompManager::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
326  SCOPE_LOCK(locker_);
327
328  DisplayError error = kErrorNone;
329  DisplayCompositionContext *display_comp_ctx =
330                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
331  configured_displays_[display_comp_ctx->display_type] = 1;
332  if (configured_displays_ == registered_displays_) {
333    safe_mode_ = false;
334  }
335
336  error = resource_intf_->PostCommit(display_comp_ctx->display_resource_ctx, hw_layers);
337  if (error != kErrorNone) {
338    return error;
339  }
340
341  display_comp_ctx->idle_fallback = false;
342
343  DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
344           "display type %d", registered_displays_, configured_displays_,
345           display_comp_ctx->display_type);
346
347  return kErrorNone;
348}
349
350void CompManager::Purge(Handle display_ctx) {
351  SCOPE_LOCK(locker_);
352
353  DisplayCompositionContext *display_comp_ctx =
354                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
355
356  resource_intf_->Purge(display_comp_ctx->display_resource_ctx);
357}
358
359void CompManager::ProcessIdleTimeout(Handle display_ctx) {
360  SCOPE_LOCK(locker_);
361
362  DisplayCompositionContext *display_comp_ctx =
363                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
364
365  if (!display_comp_ctx) {
366    return;
367  }
368
369  display_comp_ctx->idle_fallback = true;
370}
371
372void CompManager::ProcessThermalEvent(Handle display_ctx, int64_t thermal_level) {
373  SCOPE_LOCK(locker_);
374
375  DisplayCompositionContext *display_comp_ctx =
376          reinterpret_cast<DisplayCompositionContext *>(display_ctx);
377
378  if (thermal_level >= kMaxThermalLevel) {
379    display_comp_ctx->fallback_ = true;
380  } else {
381    display_comp_ctx->fallback_ = false;
382  }
383}
384
385DisplayError CompManager::SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) {
386  SCOPE_LOCK(locker_);
387
388  DisplayError error = kErrorNone;
389  DisplayCompositionContext *display_comp_ctx =
390                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
391
392  if (display_comp_ctx) {
393    error = resource_intf_->SetMaxMixerStages(display_comp_ctx->display_resource_ctx,
394                                              max_mixer_stages);
395  }
396
397  return error;
398}
399
400void CompManager::ControlPartialUpdate(Handle display_ctx, bool enable) {
401  SCOPE_LOCK(locker_);
402
403  DisplayCompositionContext *display_comp_ctx =
404                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
405  display_comp_ctx->partial_update_enable = enable;
406}
407
408void CompManager::AppendDump(char *buffer, uint32_t length) {
409  SCOPE_LOCK(locker_);
410}
411
412DisplayError CompManager::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
413                                          bool rotate90) {
414  return resource_intf_->ValidateScaling(crop, dst, rotate90, Debug::IsUbwcTiledFrameBuffer(),
415                                         true /* use_rotator_downscale */);
416}
417
418DisplayError CompManager::ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers,
419                                                 int x, int y) {
420  DisplayCompositionContext *display_comp_ctx =
421                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
422  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
423
424  return resource_intf_->ValidateCursorPosition(display_resource_ctx, hw_layers, x, y);
425}
426
427bool CompManager::SupportLayerAsCursor(Handle comp_handle, HWLayers *hw_layers) {
428  DisplayCompositionContext *display_comp_ctx =
429                             reinterpret_cast<DisplayCompositionContext *>(comp_handle);
430  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
431  LayerStack *layer_stack = hw_layers->info.stack;
432  bool supported = false;
433  int32_t gpu_index = -1;
434
435  if (!layer_stack->flags.cursor_present) {
436    return supported;
437  }
438
439  for (int32_t i = INT32(layer_stack->layers.size() - 1); i >= 0; i--) {
440    Layer *layer = layer_stack->layers.at(UINT32(i));
441    if (layer->composition == kCompositionGPUTarget) {
442      gpu_index = i;
443      break;
444    }
445  }
446  if (gpu_index <= 0) {
447    return supported;
448  }
449  Layer *cursor_layer = layer_stack->layers.at(UINT32(gpu_index) - 1);
450  if (cursor_layer->flags.cursor && resource_intf_->ValidateCursorConfig(display_resource_ctx,
451                                    cursor_layer, true) == kErrorNone) {
452    supported = true;
453  }
454
455  return supported;
456}
457
458DisplayError CompManager::SetMaxBandwidthMode(HWBwModes mode) {
459  if ((hw_res_info_.has_dyn_bw_support == false) || (mode >= kBwModeMax)) {
460    return kErrorNotSupported;
461  }
462
463  return resource_intf_->SetMaxBandwidthMode(mode);
464}
465
466bool CompManager::CanSetIdleTimeout(Handle display_ctx) {
467  DisplayCompositionContext *display_comp_ctx =
468                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
469
470  if (!display_comp_ctx) {
471    return false;
472  }
473
474  if (!display_comp_ctx->idle_fallback) {
475    return true;
476  }
477
478  return false;
479}
480
481DisplayError CompManager::GetScaleLutConfig(HWScaleLutInfo *lut_info) {
482  return resource_intf_->GetScaleLutConfig(lut_info);
483}
484
485DisplayError CompManager::SetDetailEnhancerData(Handle display_ctx,
486                                                const DisplayDetailEnhancerData &de_data) {
487  SCOPE_LOCK(locker_);
488
489  DisplayCompositionContext *display_comp_ctx =
490                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
491
492  return resource_intf_->SetDetailEnhancerData(display_comp_ctx->display_resource_ctx, de_data);
493}
494
495}  // namespace sdm
496
497