• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2014-2019, 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 <cutils/properties.h>
31 #include <sync/sync.h>
32 #include <utils/constants.h>
33 #include <utils/debug.h>
34 #include <utils/utils.h>
35 #include <stdarg.h>
36 #include <sys/mman.h>
37 
38 #include <map>
39 #include <string>
40 #include <vector>
41 
42 #include "hwc_display_builtin.h"
43 #include "hwc_debugger.h"
44 #include "hwc_session.h"
45 
46 #define __CLASS__ "HWCDisplayBuiltIn"
47 
48 namespace sdm {
49 
Init()50 DisplayError HWCDisplayBuiltIn::PMICInterface::Init() {
51   std::string str_lcd_bias("/sys/class/lcd_bias/secure_mode");
52   fd_lcd_bias_ = ::open(str_lcd_bias.c_str(), O_WRONLY);
53   if (fd_lcd_bias_ < 0) {
54     DLOGW("File '%s' could not be opened. errno = %d, desc = %s", str_lcd_bias.c_str(), errno,
55           strerror(errno));
56     return kErrorHardware;
57   }
58 
59   std::string str_leds_wled("/sys/class/leds/wled/secure_mode");
60   fd_wled_ = ::open(str_leds_wled.c_str(), O_WRONLY);
61   if (fd_wled_ < 0) {
62     DLOGW("File '%s' could not be opened. errno = %d, desc = %s", str_leds_wled.c_str(), errno,
63           strerror(errno));
64     return kErrorHardware;
65   }
66 
67   return kErrorNone;
68 }
69 
Deinit()70 void HWCDisplayBuiltIn::PMICInterface::Deinit() {
71   ::close(fd_lcd_bias_);
72   ::close(fd_wled_);
73 }
74 
Notify(SecureEvent event)75 DisplayError HWCDisplayBuiltIn::PMICInterface::Notify(SecureEvent event) {
76   std::string str_event = (event == kSecureDisplayStart) ? std::to_string(1) : std::to_string(0);
77   ssize_t err = ::pwrite(fd_lcd_bias_, str_event.c_str(), str_event.length(), 0);
78   if (err <= 0) {
79     DLOGW("Write failed for lcd_bias, Error = %s", strerror(errno));
80     return kErrorHardware;
81   }
82 
83   err = ::pwrite(fd_wled_, str_event.c_str(), str_event.length(), 0);
84   if (err <= 0) {
85     DLOGW("Write failed for wled, Error = %s", strerror(errno));
86     return kErrorHardware;
87   }
88 
89   DLOGI("Successfully notifed about secure display %s to PMIC driver",
90         (event == kSecureDisplayStart) ? "start": "end");
91   return kErrorNone;
92 }
93 
Create(CoreInterface * core_intf,BufferAllocator * buffer_allocator,HWCCallbacks * callbacks,HWCDisplayEventHandler * event_handler,qService::QService * qservice,hwc2_display_t id,int32_t sdm_id,HWCDisplay ** hwc_display)94 int HWCDisplayBuiltIn::Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
95                               HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
96                               qService::QService *qservice, hwc2_display_t id, int32_t sdm_id,
97                               HWCDisplay **hwc_display) {
98   int status = 0;
99   uint32_t builtin_width = 0;
100   uint32_t builtin_height = 0;
101 
102   HWCDisplay *hwc_display_builtin =
103       new HWCDisplayBuiltIn(core_intf, buffer_allocator, callbacks, event_handler, qservice, id,
104                             sdm_id);
105   status = hwc_display_builtin->Init();
106   if (status) {
107     delete hwc_display_builtin;
108     return status;
109   }
110 
111   hwc_display_builtin->GetMixerResolution(&builtin_width, &builtin_height);
112   int width = 0, height = 0;
113   HWCDebugHandler::Get()->GetProperty(FB_WIDTH_PROP, &width);
114   HWCDebugHandler::Get()->GetProperty(FB_HEIGHT_PROP, &height);
115   if (width > 0 && height > 0) {
116     builtin_width = UINT32(width);
117     builtin_height = UINT32(height);
118   }
119 
120   status = hwc_display_builtin->SetFrameBufferResolution(builtin_width, builtin_height);
121   if (status) {
122     Destroy(hwc_display_builtin);
123     return status;
124   }
125 
126   *hwc_display = hwc_display_builtin;
127 
128   return status;
129 }
130 
Destroy(HWCDisplay * hwc_display)131 void HWCDisplayBuiltIn::Destroy(HWCDisplay *hwc_display) {
132   hwc_display->Deinit();
133   delete hwc_display;
134 }
135 
HWCDisplayBuiltIn(CoreInterface * core_intf,BufferAllocator * buffer_allocator,HWCCallbacks * callbacks,HWCDisplayEventHandler * event_handler,qService::QService * qservice,hwc2_display_t id,int32_t sdm_id)136 HWCDisplayBuiltIn::HWCDisplayBuiltIn(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
137                                      HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
138                                      qService::QService *qservice, hwc2_display_t id,
139                                      int32_t sdm_id)
140     : HWCDisplay(core_intf, buffer_allocator, callbacks, event_handler, qservice, kBuiltIn, id,
141                  sdm_id, true, DISPLAY_CLASS_BUILTIN),
142       buffer_allocator_(buffer_allocator),
143       cpu_hint_(NULL) {
144 }
145 
Init()146 int HWCDisplayBuiltIn::Init() {
147   cpu_hint_ = new CPUHint();
148   if (cpu_hint_->Init(static_cast<HWCDebugHandler *>(HWCDebugHandler::Get())) != kErrorNone) {
149     delete cpu_hint_;
150     cpu_hint_ = NULL;
151   }
152 
153   use_metadata_refresh_rate_ = true;
154   int disable_metadata_dynfps = 0;
155   HWCDebugHandler::Get()->GetProperty(DISABLE_METADATA_DYNAMIC_FPS_PROP, &disable_metadata_dynfps);
156   if (disable_metadata_dynfps) {
157     use_metadata_refresh_rate_ = false;
158   }
159 
160   int status = HWCDisplay::Init();
161   if (status) {
162     return status;
163   }
164   color_mode_ = new HWCColorMode(display_intf_);
165   color_mode_->Init();
166   HWCDebugHandler::Get()->GetProperty(ENABLE_DEFAULT_COLOR_MODE,
167                                       &default_mode_status_);
168 
169   int optimize_refresh = 0;
170   HWCDebugHandler::Get()->GetProperty(ENABLE_OPTIMIZE_REFRESH, &optimize_refresh);
171   enable_optimize_refresh_ = (optimize_refresh == 1);
172   if (enable_optimize_refresh_) {
173     DLOGI("Drop redundant drawcycles %d", id_);
174   }
175   pmic_intf_ = new PMICInterface();
176   pmic_intf_->Init();
177 
178   if (int vsyncs;
179       HWCDebugHandler::Get()->GetProperty(DEFER_FPS_FRAME_COUNT, &vsyncs) == kErrorNone) {
180     if (vsyncs > 0) {
181       HWCDisplay::SetVsyncsApplyRateChange(UINT32(vsyncs));
182     }
183   }
184 
185   return status;
186 }
187 
Deinit()188 int HWCDisplayBuiltIn::Deinit() {
189     int status = HWCDisplay::Deinit();
190 
191     histogram.stop();
192 
193     if (status) {
194       return status;
195     }
196     pmic_intf_->Deinit();
197     delete pmic_intf_;
198 
199     return 0;
200 }
201 
Dump()202 std::string HWCDisplayBuiltIn::Dump() {
203     return HWCDisplay::Dump() + histogram.Dump();
204 }
205 
Validate(uint32_t * out_num_types,uint32_t * out_num_requests)206 HWC2::Error HWCDisplayBuiltIn::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
207   auto status = HWC2::Error::None;
208   DisplayError error = kErrorNone;
209 
210   DTRACE_SCOPED();
211   if (display_paused_) {
212     MarkLayersForGPUBypass();
213     return status;
214   }
215 
216   if (color_tranform_failed_) {
217     // Must fall back to client composition
218     MarkLayersForClientComposition();
219   }
220 
221   // Fill in the remaining blanks in the layers and add them to the SDM layerstack
222   BuildLayerStack();
223   // Checks and replaces layer stack for solid fill
224   SolidFillPrepare();
225 
226   // Apply current Color Mode and Render Intent.
227   if (color_mode_->ApplyCurrentColorModeWithRenderIntent(
228       static_cast<bool>(layer_stack_.flags.hdr_present)) != HWC2::Error::None) {
229     // Fallback to GPU Composition, if Color Mode can't be applied.
230     MarkLayersForClientComposition();
231   }
232 
233   bool pending_output_dump = dump_frame_count_ && dump_output_to_file_;
234 
235   if (readback_buffer_queued_ || pending_output_dump) {
236     CloseFd(&output_buffer_.release_fence_fd);
237     // RHS values were set in FrameCaptureAsync() called from a binder thread. They are picked up
238     // here in a subsequent draw round. Readback is not allowed for any secure use case.
239     readback_configured_ = !layer_stack_.flags.secure_present;
240     if (readback_configured_) {
241       DisablePartialUpdateOneFrame();
242       layer_stack_.output_buffer = &output_buffer_;
243       layer_stack_.flags.post_processed_output = post_processed_output_;
244     }
245   }
246   // Todo: relook this case
247   if (layer_stack_.flags.hdr_present != hdr_present_) {
248     error = display_intf_->ControlIdlePowerCollapse(!layer_stack_.flags.hdr_present, true);
249     hdr_present_ = layer_stack_.flags.hdr_present;
250   }
251 
252   uint32_t num_updating_layers = GetUpdatingLayersCount();
253   bool one_updating_layer = (num_updating_layers == 1);
254   if (num_updating_layers != 0) {
255     ToggleCPUHint(one_updating_layer);
256   }
257 
258   uint32_t refresh_rate = GetOptimalRefreshRate(one_updating_layer);
259   error = display_intf_->SetRefreshRate(refresh_rate, force_refresh_rate_);
260 
261   // Get the refresh rate set.
262   display_intf_->GetRefreshRate(&refresh_rate);
263   bool vsync_source = (callbacks_->GetVsyncSource() == id_);
264 
265   if (error == kErrorNone) {
266     if (vsync_source && (current_refresh_rate_ < refresh_rate)) {
267       DTRACE_BEGIN("HWC2::Vsync::Enable");
268       // Display is ramping up from idle.
269       // Client realizes need for resync upon change in config.
270       // Since we know config has changed, triggering vsync proactively
271       // can help in reducing pipeline delays to enable events.
272       SetVsyncEnabled(HWC2::Vsync::Enable);
273       DTRACE_END();
274     }
275     // On success, set current refresh rate to new refresh rate.
276     current_refresh_rate_ = refresh_rate;
277   }
278 
279   if (layer_set_.empty()) {
280     // Avoid flush for Command mode panel.
281     flush_ = !client_connected_;
282     validated_ = true;
283     return status;
284   }
285 
286   status = PrepareLayerStack(out_num_types, out_num_requests);
287   pending_commit_ = true;
288   return status;
289 }
290 
CommitLayerStack()291 HWC2::Error HWCDisplayBuiltIn::CommitLayerStack() {
292   skip_commit_ = CanSkipCommit();
293   return HWCDisplay::CommitLayerStack();
294 }
295 
CanSkipCommit()296 bool HWCDisplayBuiltIn::CanSkipCommit() {
297   if (layer_stack_invalid_) {
298     return false;
299   }
300 
301   // Reject repeated drawcycle requests if it satisfies all conditions.
302   // 1. None of the layerstack attributes changed.
303   // 2. No new buffer latched.
304   // 3. No refresh request triggered by HWC.
305   // 4. This display is not source of vsync.
306   bool buffers_latched = false;
307   for (auto &hwc_layer : layer_set_) {
308     buffers_latched |= hwc_layer->BufferLatched();
309     hwc_layer->ResetBufferFlip();
310   }
311 
312   bool vsync_source = (callbacks_->GetVsyncSource() == id_);
313   bool skip_commit = enable_optimize_refresh_ && !pending_commit_ && !buffers_latched &&
314                      !pending_refresh_ && !vsync_source;
315   pending_refresh_ = false;
316 
317   return skip_commit;
318 }
319 
Present(int32_t * out_retire_fence)320 HWC2::Error HWCDisplayBuiltIn::Present(int32_t *out_retire_fence) {
321   auto status = HWC2::Error::None;
322 
323   DTRACE_SCOPED();
324   ATRACE_INT("PartialUpdate", partial_update_enabled_);
325   ATRACE_INT("FastPath", layer_stack_.flags.fast_path);
326   ATRACE_INT("GeometryChanged", layer_stack_.flags.geometry_changed);
327   ATRACE_INT("NumLayers", static_cast <int32_t> (layer_stack_.layers.size()));
328   ATRACE_INT("SF_MarkedSkipLayer", HasForceClientComposition());
329   ATRACE_INT("HWC_MarkedSkipLayer", (HasClientComposition() &&
330              !HasForceClientComposition()));
331 
332   if (display_paused_) {
333     DisplayError error = display_intf_->Flush(&layer_stack_);
334     validated_ = false;
335     if (error != kErrorNone) {
336       DLOGE("Flush failed. Error = %d", error);
337     }
338   } else {
339     status = CommitLayerStack();
340     if (status == HWC2::Error::None) {
341       HandleFrameOutput();
342       SolidFillCommit();
343       status = PostCommitLayerStack(out_retire_fence);
344     }
345   }
346 
347   if (CC_UNLIKELY(!has_init_light_server_)) {
348     using ILight = ::hardware::google::light::V1_0::ILight;
349     hardware_ILight_ = ILight::getService();
350     if (hardware_ILight_ != nullptr) {
351       hardware_ILight_->setHbm(false);
352     } else {
353       DLOGE("failed to get vendor light service");
354     }
355 
356     uint32_t panel_x, panel_y;
357     GetPanelResolution(&panel_x, &panel_y);
358     hbm_threshold_px_ = float(panel_x * panel_y) * hbm_threshold_pct_;
359     DLOGI("Configure hbm_threshold_px_ to %f", hbm_threshold_px_);
360 
361     has_init_light_server_ = true;
362   }
363 
364   const bool enable_hbm(hdr_largest_layer_px_ > hbm_threshold_px_);
365   if (high_brightness_mode_ != enable_hbm && hardware_ILight_ != nullptr) {
366     using ::android::hardware::light::V2_0::Status;
367     if (Status::SUCCESS == hardware_ILight_->setHbm(enable_hbm)) {
368       high_brightness_mode_ = enable_hbm;
369     } else {
370       DLOGE("failed to setHbm to %d", enable_hbm);
371     }
372   }
373 
374   CloseFd(&output_buffer_.acquire_fence_fd);
375   pending_commit_ = false;
376   return status;
377 }
378 
GetColorModes(uint32_t * out_num_modes,ColorMode * out_modes)379 HWC2::Error HWCDisplayBuiltIn::GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes) {
380   if (out_modes == nullptr) {
381     *out_num_modes = color_mode_->GetColorModeCount();
382   } else {
383     color_mode_->GetColorModes(out_num_modes, out_modes);
384   }
385 
386   return HWC2::Error::None;
387 }
388 
GetRenderIntents(ColorMode mode,uint32_t * out_num_intents,RenderIntent * out_intents)389 HWC2::Error HWCDisplayBuiltIn::GetRenderIntents(ColorMode mode, uint32_t *out_num_intents,
390                                                 RenderIntent *out_intents) {
391   if (out_intents == nullptr) {
392     *out_num_intents = color_mode_->GetRenderIntentCount(mode);
393   } else {
394     color_mode_->GetRenderIntents(mode, out_num_intents, out_intents);
395   }
396   return HWC2::Error::None;
397 }
398 
SetColorMode(ColorMode mode)399 HWC2::Error HWCDisplayBuiltIn::SetColorMode(ColorMode mode) {
400   return SetColorModeWithRenderIntent(mode, RenderIntent::COLORIMETRIC);
401 }
402 
SetColorModeWithRenderIntent(ColorMode mode,RenderIntent intent)403 HWC2::Error HWCDisplayBuiltIn::SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent) {
404   auto status = color_mode_->CacheColorModeWithRenderIntent(mode, intent);
405   if (status != HWC2::Error::None) {
406     DLOGE("failed for mode = %d intent = %d", mode, intent);
407     return status;
408   }
409   callbacks_->Refresh(id_);
410   validated_ = false;
411   return status;
412 }
413 
SetColorModeById(int32_t color_mode_id)414 HWC2::Error HWCDisplayBuiltIn::SetColorModeById(int32_t color_mode_id) {
415   auto status = color_mode_->SetColorModeById(color_mode_id);
416   if (status != HWC2::Error::None) {
417     DLOGE("failed for mode = %d", color_mode_id);
418     return status;
419   }
420 
421   callbacks_->Refresh(id_);
422   validated_ = false;
423 
424   return status;
425 }
426 
SetColorModeFromClientApi(int32_t color_mode_id)427 HWC2::Error HWCDisplayBuiltIn::SetColorModeFromClientApi(int32_t color_mode_id) {
428   DisplayError error = kErrorNone;
429   std::string mode_string;
430 
431   error = display_intf_->GetColorModeName(color_mode_id, &mode_string);
432   if (error) {
433     DLOGE("Failed to get mode name for mode %d", color_mode_id);
434     return HWC2::Error::BadParameter;
435   }
436 
437   auto status = color_mode_->SetColorModeFromClientApi(mode_string);
438   if (status != HWC2::Error::None) {
439     DLOGE("Failed to set mode = %d", color_mode_id);
440     return status;
441   }
442 
443   return status;
444 }
445 
RestoreColorTransform()446 HWC2::Error HWCDisplayBuiltIn::RestoreColorTransform() {
447   auto status = color_mode_->RestoreColorTransform();
448   if (status != HWC2::Error::None) {
449     DLOGE("failed to RestoreColorTransform");
450     return status;
451   }
452 
453   callbacks_->Refresh(id_);
454 
455   return status;
456 }
457 
SetColorTransform(const float * matrix,android_color_transform_t hint)458 HWC2::Error HWCDisplayBuiltIn::SetColorTransform(const float *matrix,
459                                                  android_color_transform_t hint) {
460   if (!matrix) {
461     return HWC2::Error::BadParameter;
462   }
463 
464   auto status = color_mode_->SetColorTransform(matrix, hint);
465   if (status != HWC2::Error::None) {
466     DLOGE("failed for hint = %d", hint);
467     color_tranform_failed_ = true;
468     return status;
469   }
470 
471   callbacks_->Refresh(id_);
472   color_tranform_failed_ = false;
473   validated_ = false;
474 
475   return status;
476 }
477 
SetReadbackBuffer(const native_handle_t * buffer,int32_t acquire_fence,bool post_processed_output)478 HWC2::Error HWCDisplayBuiltIn::SetReadbackBuffer(const native_handle_t *buffer,
479                                                  int32_t acquire_fence,
480                                                  bool post_processed_output) {
481   const private_handle_t *handle = reinterpret_cast<const private_handle_t *>(buffer);
482   if (!handle || (handle->fd < 0)) {
483     return HWC2::Error::BadParameter;
484   }
485 
486   // Configure the output buffer as Readback buffer
487   output_buffer_.width = UINT32(handle->width);
488   output_buffer_.height = UINT32(handle->height);
489   output_buffer_.unaligned_width = UINT32(handle->unaligned_width);
490   output_buffer_.unaligned_height = UINT32(handle->unaligned_height);
491   output_buffer_.format = HWCLayer::GetSDMFormat(handle->format, handle->flags);
492   output_buffer_.planes[0].fd = handle->fd;
493   output_buffer_.planes[0].stride = UINT32(handle->width);
494   output_buffer_.acquire_fence_fd = dup(acquire_fence);
495   output_buffer_.release_fence_fd = -1;
496   output_buffer_.handle_id = handle->id;
497 
498   post_processed_output_ = post_processed_output;
499   readback_buffer_queued_ = true;
500   readback_configured_ = false;
501   validated_ = false;
502 
503   return HWC2::Error::None;
504 }
505 
GetReadbackBufferFence(int32_t * release_fence)506 HWC2::Error HWCDisplayBuiltIn::GetReadbackBufferFence(int32_t *release_fence) {
507   auto status = HWC2::Error::None;
508 
509   if (readback_configured_ && (output_buffer_.release_fence_fd >= 0)) {
510     *release_fence = output_buffer_.release_fence_fd;
511   } else {
512     status = HWC2::Error::Unsupported;
513     *release_fence = -1;
514   }
515 
516   post_processed_output_ = false;
517   readback_buffer_queued_ = false;
518   readback_configured_ = false;
519   output_buffer_ = {};
520 
521   return status;
522 }
523 
TeardownConcurrentWriteback(void)524 DisplayError HWCDisplayBuiltIn::TeardownConcurrentWriteback(void) {
525   DisplayError error = kErrorNotSupported;
526 
527   if (output_buffer_.release_fence_fd >= 0) {
528     int32_t release_fence_fd = dup(output_buffer_.release_fence_fd);
529     int ret = sync_wait(output_buffer_.release_fence_fd, 1000);
530     if (ret < 0) {
531       DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
532     }
533 
534     ::close(release_fence_fd);
535     if (ret)
536       return kErrorResources;
537   }
538 
539   if (display_intf_) {
540     error = display_intf_->TeardownConcurrentWriteback();
541   }
542 
543   return error;
544 }
545 
SetDisplayDppsAdROI(uint32_t h_start,uint32_t h_end,uint32_t v_start,uint32_t v_end,uint32_t factor_in,uint32_t factor_out)546 HWC2::Error HWCDisplayBuiltIn::SetDisplayDppsAdROI(uint32_t h_start, uint32_t h_end,
547                                                    uint32_t v_start, uint32_t v_end,
548                                                    uint32_t factor_in, uint32_t factor_out) {
549   DisplayError error = kErrorNone;
550   DisplayDppsAd4RoiCfg dpps_ad4_roi_cfg = {};
551   uint32_t panel_width = 0, panel_height = 0;
552   constexpr uint16_t kMaxFactorVal = 0xffff;
553 
554   if (h_start >= h_end || v_start >= v_end || factor_in > kMaxFactorVal ||
555       factor_out > kMaxFactorVal) {
556     DLOGE("Invalid roi region = [%u, %u, %u, %u, %u, %u]",
557            h_start, h_end, v_start, v_end, factor_in, factor_out);
558     return HWC2::Error::BadParameter;
559   }
560 
561   GetPanelResolution(&panel_width, &panel_height);
562 
563   if (h_start >= panel_width || h_end > panel_width ||
564       v_start >= panel_height || v_end > panel_height) {
565     DLOGE("Invalid roi region = [%u, %u, %u, %u], panel resolution = [%u, %u]",
566            h_start, h_end, v_start, v_end, panel_width, panel_height);
567     return HWC2::Error::BadParameter;
568   }
569 
570   dpps_ad4_roi_cfg.h_start = h_start;
571   dpps_ad4_roi_cfg.h_end = h_end;
572   dpps_ad4_roi_cfg.v_start = v_start;
573   dpps_ad4_roi_cfg.v_end = v_end;
574   dpps_ad4_roi_cfg.factor_in = factor_in;
575   dpps_ad4_roi_cfg.factor_out = factor_out;
576 
577   error = display_intf_->SetDisplayDppsAdROI(&dpps_ad4_roi_cfg);
578   if (error)
579     return HWC2::Error::BadConfig;
580 
581   callbacks_->Refresh(id_);
582 
583   return HWC2::Error::None;
584 }
585 
Perform(uint32_t operation,...)586 int HWCDisplayBuiltIn::Perform(uint32_t operation, ...) {
587   va_list args;
588   va_start(args, operation);
589   int val = 0;
590   LayerSolidFill *solid_fill_color;
591   LayerRect *rect = NULL;
592 
593   switch (operation) {
594     case SET_METADATA_DYN_REFRESH_RATE:
595       val = va_arg(args, int32_t);
596       SetMetaDataRefreshRateFlag(val);
597       break;
598     case SET_BINDER_DYN_REFRESH_RATE:
599       val = va_arg(args, int32_t);
600       ForceRefreshRate(UINT32(val));
601       break;
602     case SET_DISPLAY_MODE:
603       val = va_arg(args, int32_t);
604       SetDisplayMode(UINT32(val));
605       break;
606     case SET_QDCM_SOLID_FILL_INFO:
607       solid_fill_color = va_arg(args, LayerSolidFill*);
608       SetQDCMSolidFillInfo(true, *solid_fill_color);
609       break;
610     case UNSET_QDCM_SOLID_FILL_INFO:
611       solid_fill_color = va_arg(args, LayerSolidFill*);
612       SetQDCMSolidFillInfo(false, *solid_fill_color);
613       break;
614     case SET_QDCM_SOLID_FILL_RECT:
615       rect = va_arg(args, LayerRect*);
616       solid_fill_rect_ = *rect;
617       break;
618     default:
619       DLOGW("Invalid operation %d", operation);
620       va_end(args);
621       return -EINVAL;
622   }
623   va_end(args);
624   validated_ = false;
625 
626   return 0;
627 }
628 
SetDisplayMode(uint32_t mode)629 DisplayError HWCDisplayBuiltIn::SetDisplayMode(uint32_t mode) {
630   DisplayError error = kErrorNone;
631 
632   if (display_intf_) {
633     error = display_intf_->SetDisplayMode(mode);
634     if (error == kErrorNone) {
635       DisplayConfigFixedInfo fixed_info = {};
636       display_intf_->GetConfig(&fixed_info);
637       is_cmd_mode_ = fixed_info.is_cmdmode;
638       partial_update_enabled_ = fixed_info.partial_update;
639       for (auto hwc_layer : layer_set_) {
640         hwc_layer->SetPartialUpdate(partial_update_enabled_);
641       }
642       client_target_->SetPartialUpdate(partial_update_enabled_);
643     }
644   }
645 
646   return error;
647 }
648 
SetMetaDataRefreshRateFlag(bool enable)649 void HWCDisplayBuiltIn::SetMetaDataRefreshRateFlag(bool enable) {
650   int disable_metadata_dynfps = 0;
651 
652   HWCDebugHandler::Get()->GetProperty(DISABLE_METADATA_DYNAMIC_FPS_PROP, &disable_metadata_dynfps);
653   if (disable_metadata_dynfps) {
654     return;
655   }
656   use_metadata_refresh_rate_ = enable;
657 }
658 
SetQDCMSolidFillInfo(bool enable,const LayerSolidFill & color)659 void HWCDisplayBuiltIn::SetQDCMSolidFillInfo(bool enable, const LayerSolidFill &color) {
660   solid_fill_enable_ = enable;
661   solid_fill_color_ = color;
662 }
663 
ToggleCPUHint(bool set)664 void HWCDisplayBuiltIn::ToggleCPUHint(bool set) {
665   if (!cpu_hint_) {
666     return;
667   }
668 
669   if (set) {
670     cpu_hint_->Set();
671   } else {
672     cpu_hint_->Reset();
673   }
674 }
675 
HandleSecureSession(const std::bitset<kSecureMax> & secure_sessions,bool * power_on_pending)676 int HWCDisplayBuiltIn::HandleSecureSession(const std::bitset<kSecureMax> &secure_sessions,
677                                            bool *power_on_pending) {
678   if (!power_on_pending) {
679     return -EINVAL;
680   }
681 
682   if (current_power_mode_ != HWC2::PowerMode::On) {
683     return 0;
684   }
685 
686   if (active_secure_sessions_[kSecureDisplay] != secure_sessions[kSecureDisplay]) {
687     SecureEvent secure_event =
688         secure_sessions.test(kSecureDisplay) ? kSecureDisplayStart : kSecureDisplayEnd;
689     DisplayError err = display_intf_->HandleSecureEvent(secure_event, &layer_stack_);
690     if (err != kErrorNone) {
691       DLOGE("Set secure event failed");
692       return err;
693     }
694     if (secure_event == kSecureDisplayStart) {
695       pmic_intf_->Notify(kSecureDisplayStart);
696     } else {
697       pmic_notification_pending_ = true;
698     }
699 
700     DLOGI("SecureDisplay state changed from %d to %d for display %d",
701           active_secure_sessions_.test(kSecureDisplay), secure_sessions.test(kSecureDisplay),
702           type_);
703   }
704   active_secure_sessions_ = secure_sessions;
705   *power_on_pending = false;
706   return 0;
707 }
708 
ForceRefreshRate(uint32_t refresh_rate)709 void HWCDisplayBuiltIn::ForceRefreshRate(uint32_t refresh_rate) {
710   if ((refresh_rate && (refresh_rate < min_refresh_rate_ || refresh_rate > max_refresh_rate_)) ||
711       force_refresh_rate_ == refresh_rate) {
712     // Cannot honor force refresh rate, as its beyond the range or new request is same
713     return;
714   }
715 
716   force_refresh_rate_ = refresh_rate;
717 
718   callbacks_->Refresh(id_);
719 
720   return;
721 }
722 
GetOptimalRefreshRate(bool one_updating_layer)723 uint32_t HWCDisplayBuiltIn::GetOptimalRefreshRate(bool one_updating_layer) {
724   if (force_refresh_rate_) {
725     return force_refresh_rate_;
726   } else if (use_metadata_refresh_rate_ && one_updating_layer && metadata_refresh_rate_) {
727     return metadata_refresh_rate_;
728   }
729 
730   return max_refresh_rate_;
731 }
732 
Refresh()733 DisplayError HWCDisplayBuiltIn::Refresh() {
734   DisplayError error = kErrorNone;
735 
736   callbacks_->Refresh(id_);
737 
738   return error;
739 }
740 
SetIdleTimeoutMs(uint32_t timeout_ms)741 void HWCDisplayBuiltIn::SetIdleTimeoutMs(uint32_t timeout_ms) {
742   display_intf_->SetIdleTimeoutMs(timeout_ms);
743   validated_ = false;
744 }
745 
HandleFrameOutput()746 void HWCDisplayBuiltIn::HandleFrameOutput() {
747   if (readback_buffer_queued_) {
748     validated_ = false;
749   }
750 
751   if (frame_capture_buffer_queued_) {
752     HandleFrameCapture();
753   } else if (dump_output_to_file_) {
754     HandleFrameDump();
755   }
756 }
757 
HandleFrameCapture()758 void HWCDisplayBuiltIn::HandleFrameCapture() {
759   if (readback_configured_ && (output_buffer_.release_fence_fd >= 0)) {
760     frame_capture_status_ = sync_wait(output_buffer_.release_fence_fd, 1000);
761     ::close(output_buffer_.release_fence_fd);
762     output_buffer_.release_fence_fd = -1;
763   }
764 
765   frame_capture_buffer_queued_ = false;
766   readback_buffer_queued_ = false;
767   post_processed_output_ = false;
768   readback_configured_ = false;
769   output_buffer_ = {};
770 }
771 
HandleFrameDump()772 void HWCDisplayBuiltIn::HandleFrameDump() {
773   if (!readback_configured_) {
774     dump_frame_count_ = 0;
775   }
776 
777   if (dump_frame_count_ && output_buffer_.release_fence_fd >= 0) {
778     int ret = sync_wait(output_buffer_.release_fence_fd, 1000);
779     ::close(output_buffer_.release_fence_fd);
780     output_buffer_.release_fence_fd = -1;
781     if (ret < 0) {
782       DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
783     } else {
784       DumpOutputBuffer(output_buffer_info_, output_buffer_base_, layer_stack_.retire_fence_fd);
785       readback_buffer_queued_ = false;
786       validated_ = false;
787     }
788   }
789 
790   if (0 == dump_frame_count_) {
791     dump_output_to_file_ = false;
792     // Unmap and Free buffer
793     if (munmap(output_buffer_base_, output_buffer_info_.alloc_buffer_info.size) != 0) {
794       DLOGE("unmap failed with err %d", errno);
795     }
796     if (buffer_allocator_->FreeBuffer(&output_buffer_info_) != 0) {
797       DLOGE("FreeBuffer failed");
798     }
799 
800     readback_buffer_queued_ = false;
801     post_processed_output_ = false;
802     readback_configured_ = false;
803 
804     output_buffer_ = {};
805     output_buffer_info_ = {};
806     output_buffer_base_ = nullptr;
807   }
808 }
809 
SetFrameDumpConfig(uint32_t count,uint32_t bit_mask_layer_type,int32_t format,bool post_processed)810 HWC2::Error HWCDisplayBuiltIn::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type,
811                                                   int32_t format, bool post_processed) {
812   HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type, format, post_processed);
813   dump_output_to_file_ = bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP);
814   DLOGI("output_layer_dump_enable %d", dump_output_to_file_);
815 
816   if (!count || !dump_output_to_file_ || (output_buffer_info_.alloc_buffer_info.fd >= 0)) {
817     return HWC2::Error::None;
818   }
819 
820   // Allocate and map output buffer
821   if (post_processed) {
822     // To dump post-processed (DSPP) output, use Panel resolution.
823     GetPanelResolution(&output_buffer_info_.buffer_config.width,
824                        &output_buffer_info_.buffer_config.height);
825   } else {
826     // To dump Layer Mixer output, use FrameBuffer resolution.
827     GetFrameBufferResolution(&output_buffer_info_.buffer_config.width,
828                              &output_buffer_info_.buffer_config.height);
829   }
830 
831   output_buffer_info_.buffer_config.format = HWCLayer::GetSDMFormat(format, 0);
832   output_buffer_info_.buffer_config.buffer_count = 1;
833   if (buffer_allocator_->AllocateBuffer(&output_buffer_info_) != 0) {
834     DLOGE("Buffer allocation failed");
835     output_buffer_info_ = {};
836     return HWC2::Error::NoResources;
837   }
838 
839   void *buffer = mmap(NULL, output_buffer_info_.alloc_buffer_info.size, PROT_READ | PROT_WRITE,
840                       MAP_SHARED, output_buffer_info_.alloc_buffer_info.fd, 0);
841 
842   if (buffer == MAP_FAILED) {
843     DLOGE("mmap failed with err %d", errno);
844     buffer_allocator_->FreeBuffer(&output_buffer_info_);
845     output_buffer_info_ = {};
846     return HWC2::Error::NoResources;
847   }
848 
849   output_buffer_base_ = buffer;
850   const native_handle_t *handle = static_cast<native_handle_t *>(output_buffer_info_.private_data);
851   SetReadbackBuffer(handle, -1, post_processed);
852 
853   return HWC2::Error::None;
854 }
855 
FrameCaptureAsync(const BufferInfo & output_buffer_info,bool post_processed_output)856 int HWCDisplayBuiltIn::FrameCaptureAsync(const BufferInfo &output_buffer_info,
857                                          bool post_processed_output) {
858   // Note: This function is called in context of a binder thread and a lock is already held
859   if (output_buffer_info.alloc_buffer_info.fd < 0) {
860     DLOGE("Invalid fd %d", output_buffer_info.alloc_buffer_info.fd);
861     return -1;
862   }
863 
864   auto panel_width = 0u;
865   auto panel_height = 0u;
866   auto fb_width = 0u;
867   auto fb_height = 0u;
868 
869   GetPanelResolution(&panel_width, &panel_height);
870   GetFrameBufferResolution(&fb_width, &fb_height);
871 
872   if (post_processed_output && (output_buffer_info.buffer_config.width < panel_width ||
873                                 output_buffer_info.buffer_config.height < panel_height)) {
874     DLOGE("Buffer dimensions should not be less than panel resolution");
875     return -1;
876   } else if (!post_processed_output && (output_buffer_info.buffer_config.width < fb_width ||
877                                         output_buffer_info.buffer_config.height < fb_height)) {
878     DLOGE("Buffer dimensions should not be less than FB resolution");
879     return -1;
880   }
881 
882   const native_handle_t *buffer = static_cast<native_handle_t *>(output_buffer_info.private_data);
883   SetReadbackBuffer(buffer, -1, post_processed_output);
884   frame_capture_buffer_queued_ = true;
885   frame_capture_status_ = -EAGAIN;
886 
887   return 0;
888 }
889 
SetDetailEnhancerConfig(const DisplayDetailEnhancerData & de_data)890 DisplayError HWCDisplayBuiltIn::SetDetailEnhancerConfig
891                                    (const DisplayDetailEnhancerData &de_data) {
892   DisplayError error = kErrorNotSupported;
893 
894   if (display_intf_) {
895     error = display_intf_->SetDetailEnhancerData(de_data);
896     validated_ = false;
897   }
898   return error;
899 }
900 
ControlPartialUpdate(bool enable,uint32_t * pending)901 DisplayError HWCDisplayBuiltIn::ControlPartialUpdate(bool enable, uint32_t *pending) {
902   DisplayError error = kErrorNone;
903 
904   if (display_intf_) {
905     error = display_intf_->ControlPartialUpdate(enable, pending);
906     validated_ = false;
907   }
908 
909   return error;
910 }
911 
DisablePartialUpdateOneFrame()912 DisplayError HWCDisplayBuiltIn::DisablePartialUpdateOneFrame() {
913   DisplayError error = kErrorNone;
914 
915   if (display_intf_) {
916     error = display_intf_->DisablePartialUpdateOneFrame();
917     validated_ = false;
918   }
919 
920   return error;
921 }
922 
SetDisplayedContentSamplingEnabledVndService(bool enabled)923 HWC2::Error HWCDisplayBuiltIn::SetDisplayedContentSamplingEnabledVndService(bool enabled) {
924   std::unique_lock<decltype(sampling_mutex)> lk(sampling_mutex);
925   vndservice_sampling_vote = enabled;
926   if (api_sampling_vote || vndservice_sampling_vote) {
927     histogram.start();
928     display_intf_->colorSamplingOn();
929   } else {
930     display_intf_->colorSamplingOff();
931     histogram.stop();
932   }
933   return HWC2::Error::None;
934 }
935 
SetDisplayedContentSamplingEnabled(int32_t enabled,uint8_t component_mask,uint64_t max_frames)936 HWC2::Error HWCDisplayBuiltIn::SetDisplayedContentSamplingEnabled(int32_t enabled, uint8_t component_mask, uint64_t max_frames) {
937     if ((enabled != HWC2_DISPLAYED_CONTENT_SAMPLING_ENABLE) &&
938         (enabled != HWC2_DISPLAYED_CONTENT_SAMPLING_DISABLE))
939       return HWC2::Error::BadParameter;
940 
941     std::unique_lock<decltype(sampling_mutex)> lk(sampling_mutex);
942     if (enabled == HWC2_DISPLAYED_CONTENT_SAMPLING_ENABLE) {
943       api_sampling_vote = true;
944     } else {
945       api_sampling_vote = false;
946     }
947 
948     auto start = api_sampling_vote || vndservice_sampling_vote;
949     if (start && max_frames == 0) {
950       histogram.start();
951       display_intf_->colorSamplingOn();
952     } else if (start) {
953       histogram.start(max_frames);
954       display_intf_->colorSamplingOn();
955     } else {
956       display_intf_->colorSamplingOff();
957       histogram.stop();
958     }
959     return HWC2::Error::None;
960 }
961 
GetDisplayedContentSamplingAttributes(int32_t * format,int32_t * dataspace,uint8_t * supported_components)962 HWC2::Error HWCDisplayBuiltIn::GetDisplayedContentSamplingAttributes(int32_t* format,
963                                                                      int32_t* dataspace,
964                                                                      uint8_t* supported_components) {
965     return histogram.getAttributes(format, dataspace, supported_components);
966 }
967 
GetDisplayedContentSample(uint64_t max_frames,uint64_t timestamp,uint64_t * numFrames,int32_t samples_size[NUM_HISTOGRAM_COLOR_COMPONENTS],uint64_t * samples[NUM_HISTOGRAM_COLOR_COMPONENTS])968 HWC2::Error HWCDisplayBuiltIn::GetDisplayedContentSample(uint64_t max_frames,
969                                                          uint64_t timestamp,
970                                                          uint64_t* numFrames,
971                                                          int32_t samples_size[NUM_HISTOGRAM_COLOR_COMPONENTS],
972                                                          uint64_t* samples[NUM_HISTOGRAM_COLOR_COMPONENTS])
973 {
974     histogram.collect(max_frames, timestamp, samples_size, samples, numFrames);
975     return HWC2::Error::None;
976 }
977 
GetDisplayBrightnessSupport(bool * out_support)978 HWC2::Error HWCDisplayBuiltIn::GetDisplayBrightnessSupport(bool *out_support) {
979   if (display_intf_->IsSupportPanelBrightnessControl()) {
980     *out_support = true;
981   } else {
982     *out_support = false;
983   }
984 
985   return HWC2::Error::None;
986 }
987 
GetProtectedContentsSupport(bool * out_support)988 HWC2::Error HWCDisplayBuiltIn::GetProtectedContentsSupport(bool *out_support) {
989   *out_support = true;
990   return HWC2::Error::None;
991 }
992 
SetMixerResolution(uint32_t width,uint32_t height)993 DisplayError HWCDisplayBuiltIn::SetMixerResolution(uint32_t width, uint32_t height) {
994   DisplayError error = display_intf_->SetMixerResolution(width, height);
995   validated_ = false;
996   return error;
997 }
998 
GetMixerResolution(uint32_t * width,uint32_t * height)999 DisplayError HWCDisplayBuiltIn::GetMixerResolution(uint32_t *width, uint32_t *height) {
1000   return display_intf_->GetMixerResolution(width, height);
1001 }
1002 
SetQSyncMode(QSyncMode qsync_mode)1003 HWC2::Error HWCDisplayBuiltIn::SetQSyncMode(QSyncMode qsync_mode) {
1004   // Client needs to ensure that config change and qsync mode change
1005   // are not triggered in the same drawcycle.
1006   if (pending_config_) {
1007     DLOGE("Failed to set qsync mode. Pending active config transition");
1008     return HWC2::Error::Unsupported;
1009   }
1010 
1011   auto err = display_intf_->SetQSyncMode(qsync_mode);
1012   if (err != kErrorNone) {
1013     return HWC2::Error::Unsupported;
1014   }
1015 
1016   validated_ = false;
1017   return HWC2::Error::None;
1018 }
1019 
ControlIdlePowerCollapse(bool enable,bool synchronous)1020 DisplayError HWCDisplayBuiltIn::ControlIdlePowerCollapse(bool enable, bool synchronous) {
1021   DisplayError error = kErrorNone;
1022 
1023   if (display_intf_) {
1024     error = display_intf_->ControlIdlePowerCollapse(enable, synchronous);
1025     validated_ = false;
1026   }
1027   return error;
1028 }
1029 
SetDynamicDSIClock(uint64_t bitclk)1030 DisplayError HWCDisplayBuiltIn::SetDynamicDSIClock(uint64_t bitclk) {
1031   DisplayError error = display_intf_->SetDynamicDSIClock(bitclk);
1032   if (error != kErrorNone) {
1033     DLOGE(" failed: Clk: %llu Error: %d", bitclk, error);
1034     return error;
1035   }
1036 
1037   callbacks_->Refresh(id_);
1038   validated_ = false;
1039 
1040   return kErrorNone;
1041 }
1042 
GetDynamicDSIClock(uint64_t * bitclk)1043 DisplayError HWCDisplayBuiltIn::GetDynamicDSIClock(uint64_t *bitclk) {
1044   if (display_intf_) {
1045     return display_intf_->GetDynamicDSIClock(bitclk);
1046   }
1047 
1048   return kErrorNotSupported;
1049 }
1050 
GetSupportedDSIClock(std::vector<uint64_t> * bitclk_rates)1051 DisplayError HWCDisplayBuiltIn::GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates) {
1052   if (display_intf_) {
1053     return display_intf_->GetSupportedDSIClock(bitclk_rates);
1054   }
1055 
1056   return kErrorNotSupported;
1057 }
1058 
HistogramEvent(int fd,uint32_t blob_id)1059 DisplayError HWCDisplayBuiltIn::HistogramEvent(int fd, uint32_t blob_id) {
1060   histogram.notify_histogram_event(fd, blob_id);
1061   return kErrorNone;
1062 }
1063 
UpdateDisplayId(hwc2_display_t id)1064 HWC2::Error HWCDisplayBuiltIn::UpdateDisplayId(hwc2_display_t id) {
1065   id_ = id;
1066   return HWC2::Error::None;
1067 }
1068 
SetPendingRefresh()1069 HWC2::Error HWCDisplayBuiltIn::SetPendingRefresh() {
1070   pending_refresh_ = true;
1071   return HWC2::Error::None;
1072 }
1073 
SetPanelBrightness(int32_t level)1074 HWC2::Error HWCDisplayBuiltIn::SetPanelBrightness(int32_t level) {
1075   DisplayError ret = display_intf_->SetPanelBrightness(level);
1076   if (ret != kErrorNone) {
1077     return HWC2::Error::NoResources;
1078   }
1079 
1080   return HWC2::Error::None;
1081 }
1082 
GetPanelBrightness(int32_t & level) const1083 HWC2::Error HWCDisplayBuiltIn::GetPanelBrightness(int32_t &level) const {
1084   DisplayError ret = display_intf_->GetPanelBrightness(level);
1085   if (ret != kErrorNone) {
1086     return HWC2::Error::NoResources;
1087   }
1088 
1089   return HWC2::Error::None;
1090 }
1091 
GetPanelMaxBrightness(int32_t & max_brightness_level) const1092 HWC2::Error HWCDisplayBuiltIn::GetPanelMaxBrightness(int32_t &max_brightness_level) const {
1093   DisplayError ret = display_intf_->GetPanelMaxBrightness(max_brightness_level);
1094   if (ret != kErrorNone) {
1095     return HWC2::Error::NoResources;
1096   }
1097   return HWC2::Error::None;
1098 }
1099 
UpdatePowerMode(HWC2::PowerMode mode)1100 HWC2::Error HWCDisplayBuiltIn::UpdatePowerMode(HWC2::PowerMode mode) {
1101   current_power_mode_ = mode;
1102   validated_ = false;
1103   return HWC2::Error::None;
1104 }
1105 
PostCommitLayerStack(int32_t * out_retire_fence)1106 HWC2::Error HWCDisplayBuiltIn::PostCommitLayerStack(int32_t *out_retire_fence) {
1107   if (pmic_notification_pending_) {
1108     // Wait for current commit to complete
1109     if (*out_retire_fence >= 0) {
1110       int ret = sync_wait(*out_retire_fence, 1000);
1111       if (ret < 0) {
1112         DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
1113       }
1114     }
1115     pmic_intf_->Notify(kSecureDisplayEnd);
1116     pmic_notification_pending_ = false;
1117   }
1118   return HWCDisplay::PostCommitLayerStack(out_retire_fence);
1119 }
1120 
1121 }  // namespace sdm
1122