1 /*
2  * Copyright (c) 2019-2020, 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 <hwc_display_virtual_dpu.h>
31 
32 #define __CLASS__ "HWCDisplayVirtualDPU"
33 
34 namespace sdm {
35 
HWCDisplayVirtualDPU(CoreInterface * core_intf,HWCBufferAllocator * buffer_allocator,HWCCallbacks * callbacks,hwc2_display_t id,int32_t sdm_id,uint32_t width,uint32_t height,float min_lum,float max_lum)36 HWCDisplayVirtualDPU::HWCDisplayVirtualDPU(CoreInterface *core_intf, HWCBufferAllocator
37                                            *buffer_allocator, HWCCallbacks *callbacks,
38                                            hwc2_display_t id, int32_t sdm_id, uint32_t width,
39                                            uint32_t height, float min_lum, float max_lum)
40   : HWCDisplayVirtual(core_intf, buffer_allocator, callbacks, id, sdm_id, width, height),
41     min_lum_(min_lum), max_lum_(max_lum) {
42 }
43 
Init()44 int HWCDisplayVirtualDPU::Init() {
45   int status = HWCDisplay::Init();
46   if (status) {
47     DLOGE("Init failed: %d", status);
48     return status;
49   }
50 
51   if (max_lum_ != -1.0 || min_lum_ != -1.0) {
52     SetPanelLuminanceAttributes(min_lum_, max_lum_);
53   }
54 
55   status = SetConfig(width_, height_);
56   if (status) {
57     DLOGE("Failed to set width: %d height: %d", width_, height_);
58     return status;
59   }
60 
61   status = INT32(SetPowerMode(HWC2::PowerMode::On, false /* teardown */));
62   if (status) {
63     DLOGW("Failed to set power mode on virtual display");
64     return status;
65   }
66 
67   // TODO(user): Validate that we support this width/height
68   status = SetFrameBufferResolution(width_, height_);
69   if (status) {
70     DLOGW("Failed to set FrameBuffer resolution on virtual display");
71     return status;
72   }
73 
74   return HWCDisplayVirtual::Init();
75 }
76 
SetConfig(uint32_t width,uint32_t height)77 int HWCDisplayVirtualDPU::SetConfig(uint32_t width, uint32_t height) {
78   DisplayConfigVariableInfo variable_info;
79   variable_info.x_pixels = width;
80   variable_info.y_pixels = height;
81   // TODO(user): Need to get the framerate of primary display and update it.
82   variable_info.fps = 60;
83 
84   DisplayError err = display_intf_->SetActiveConfig(&variable_info);
85   if (err != kErrorNone) {
86     return -EINVAL;
87   }
88   return 0;
89 }
90 
SetOutputBuffer(buffer_handle_t buf,shared_ptr<Fence> release_fence)91 HWC2::Error HWCDisplayVirtualDPU::SetOutputBuffer(buffer_handle_t buf,
92                                                   shared_ptr<Fence> release_fence) {
93   HWC2::Error error = HWCDisplayVirtual::SetOutputBuffer(buf, release_fence);
94   if (error != HWC2::Error::None) {
95     return error;
96   }
97 
98   const private_handle_t *output_handle = static_cast<const private_handle_t *>(buf);
99   if (output_handle) {
100     int output_handle_format = output_handle->format;
101     int active_aligned_w, active_aligned_h;
102     int new_width, new_height;
103     int new_aligned_w, new_aligned_h;
104     uint32_t active_width, active_height;
105 
106     GetMixerResolution(&active_width, &active_height);
107     buffer_allocator_->GetCustomWidthAndHeight(output_handle, &new_width, &new_height);
108     buffer_allocator_->GetAlignedWidthAndHeight(INT(new_width), INT(new_height),
109                                                 output_handle_format, 0, &new_aligned_w,
110                                                 &new_aligned_h);
111     buffer_allocator_->GetAlignedWidthAndHeight(INT(active_width), INT(active_height),
112                                                 output_handle_format, 0, &active_aligned_w,
113                                                 &active_aligned_h);
114     if (new_aligned_w != active_aligned_w  || new_aligned_h != active_aligned_h) {
115       int status = SetConfig(UINT32(new_width), UINT32(new_height));
116       if (status) {
117         DLOGE("SetConfig failed custom WxH %dx%d", new_width, new_height);
118         return HWC2::Error::BadParameter;
119       }
120       validated_ = false;
121     }
122 
123     output_buffer_.width = UINT32(new_aligned_w);
124     output_buffer_.height = UINT32(new_aligned_h);
125     output_buffer_.unaligned_width = UINT32(new_width);
126     output_buffer_.unaligned_height = UINT32(new_height);
127   }
128 
129   return HWC2::Error::None;
130 }
131 
Validate(uint32_t * out_num_types,uint32_t * out_num_requests)132 HWC2::Error HWCDisplayVirtualDPU::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
133   if (NeedsGPUBypass()) {
134     MarkLayersForGPUBypass();
135     return HWC2::Error::None;
136   }
137 
138   BuildLayerStack();
139   layer_stack_.output_buffer = &output_buffer_;
140   // If Output buffer of Virtual Display is not secure, set SKIP flag on the secure layers.
141   if (!output_buffer_.flags.secure && layer_stack_.flags.secure_present) {
142     for (auto hwc_layer : layer_set_) {
143       Layer *layer = hwc_layer->GetSDMLayer();
144       if (layer->input_buffer.flags.secure) {
145         layer_stack_.flags.skip_present = true;
146         layer->flags.skip = true;
147       }
148     }
149   }
150 
151   return PrepareLayerStack(out_num_types, out_num_requests);
152 }
153 
Present(shared_ptr<Fence> * out_retire_fence)154 HWC2::Error HWCDisplayVirtualDPU::Present(shared_ptr<Fence> *out_retire_fence) {
155   auto status = HWC2::Error::None;
156 
157   if (!output_buffer_.buffer_id) {
158     return HWC2::Error::NoResources;
159   }
160 
161   if (active_secure_sessions_.any()) {
162     return status;
163   }
164 
165   layer_stack_.output_buffer = &output_buffer_;
166   if (display_paused_) {
167     validated_ = false;
168     flush_ = true;
169   }
170 
171   status = HWCDisplay::CommitLayerStack();
172   if (status != HWC2::Error::None) {
173     return status;
174   }
175 
176   DumpVDSBuffer();
177 
178   status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
179 
180   return status;
181 }
182 
SetPanelLuminanceAttributes(float min_lum,float max_lum)183 HWC2::Error HWCDisplayVirtualDPU::SetPanelLuminanceAttributes(float min_lum, float max_lum) {
184   DisplayError err = display_intf_->SetPanelLuminanceAttributes(min_lum, max_lum);
185   if (err != kErrorNone) {
186     return HWC2::Error::BadParameter;
187   }
188   return HWC2::Error::None;
189 }
190 
191 }  // namespace sdm
192 
193