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_gpu.h"
31 #include "hwc_session.h"
32
33 #include <qdMetaData.h>
34
35 #define __CLASS__ "HWCDisplayVirtualGPU"
36
37 namespace sdm {
38
Init()39 int HWCDisplayVirtualGPU::Init() {
40 // Create client target.
41 client_target_ = new HWCLayer(id_, buffer_allocator_);
42
43 // Calls into SDM need to be dropped. Create Null Display interface.
44 display_intf_ = new DisplayNull();
45
46 disable_animation_ = Debug::IsExtAnimDisabled();
47
48 return HWCDisplayVirtual::Init();
49 }
50
Deinit()51 int HWCDisplayVirtualGPU::Deinit() {
52 // Destory color convert instance. This destroys thread and underlying GL resources.
53 if (gl_color_convert_) {
54 color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeDestroyInstance, nullptr);
55 }
56
57 delete static_cast<DisplayNull *>(display_intf_);
58 delete client_target_;
59
60 for (auto hwc_layer : layer_set_) {
61 delete hwc_layer;
62 }
63
64 return 0;
65 }
66
HWCDisplayVirtualGPU(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)67 HWCDisplayVirtualGPU::HWCDisplayVirtualGPU(CoreInterface *core_intf, HWCBufferAllocator
68 *buffer_allocator, HWCCallbacks *callbacks,
69 hwc2_display_t id, int32_t sdm_id, uint32_t width,
70 uint32_t height, float min_lum, float max_lum) :
71 HWCDisplayVirtual(core_intf, buffer_allocator, callbacks, id, sdm_id, width, height),
72 color_convert_task_(*this) {
73 }
74
Validate(uint32_t * out_num_types,uint32_t * out_num_requests)75 HWC2::Error HWCDisplayVirtualGPU::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
76 DTRACE_SCOPED();
77
78 // Reset previous changes.
79 layer_changes_.clear();
80 layer_requests_.clear();
81
82 // Mark all layers to GPU if there is no need to bypass.
83 bool needs_gpu_bypass = NeedsGPUBypass() || FreezeScreen();
84 for (auto hwc_layer : layer_set_) {
85 auto layer = hwc_layer->GetSDMLayer();
86 layer->composition = needs_gpu_bypass ? kCompositionSDE : kCompositionGPU;
87
88 if (needs_gpu_bypass) {
89 if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::Client) {
90 layer_changes_[hwc_layer->GetId()] = HWC2::Composition::Device;
91 layer_requests_[hwc_layer->GetId()] = HWC2::LayerRequest::ClearClientTarget;
92 }
93 } else {
94 if (hwc_layer->GetClientRequestedCompositionType() != HWC2::Composition::Client) {
95 layer_changes_[hwc_layer->GetId()] = HWC2::Composition::Client;
96 }
97 }
98 }
99
100 // Derive client target dataspace based on the color mode - bug/115482728
101 int32_t client_target_dataspace = GetDataspaceFromColorMode(GetCurrentColorMode());
102 SetClientTargetDataSpace(client_target_dataspace);
103
104 *out_num_types = UINT32(layer_changes_.size());
105 *out_num_requests = UINT32(layer_requests_.size());;
106 has_client_composition_ = !needs_gpu_bypass;
107 client_target_->ResetValidation();
108
109 validated_ = true;
110
111 return ((*out_num_types > 0) ? HWC2::Error::HasChanges : HWC2::Error::None);
112 }
113
SetOutputBuffer(buffer_handle_t buf,shared_ptr<Fence> release_fence)114 HWC2::Error HWCDisplayVirtualGPU::SetOutputBuffer(buffer_handle_t buf,
115 shared_ptr<Fence> release_fence) {
116 HWC2::Error error = HWCDisplayVirtual::SetOutputBuffer(buf, release_fence);
117 if (error != HWC2::Error::None) {
118 return error;
119 }
120
121 const private_handle_t *hnd = static_cast<const private_handle_t *>(buf);
122 output_buffer_.width = hnd->width;
123 output_buffer_.height = hnd->height;
124 output_buffer_.unaligned_width = width_;
125 output_buffer_.unaligned_height = height_;
126
127 // Update active dimensions.
128 BufferDim_t buffer_dim;
129 if (getMetaData(const_cast<private_handle_t *>(hnd), GET_BUFFER_GEOMETRY, &buffer_dim) == 0) {
130 output_buffer_.unaligned_width = buffer_dim.sliceWidth;
131 output_buffer_.unaligned_height = buffer_dim.sliceHeight;
132 color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeReset, nullptr);
133 }
134
135 return HWC2::Error::None;
136 }
137
Present(shared_ptr<Fence> * out_retire_fence)138 HWC2::Error HWCDisplayVirtualGPU::Present(shared_ptr<Fence> *out_retire_fence) {
139 DTRACE_SCOPED();
140
141 auto status = HWC2::Error::None;
142
143 if (!validated_) {
144 return HWC2::Error::NotValidated;
145 }
146
147 if (!output_buffer_.buffer_id) {
148 return HWC2::Error::NoResources;
149 }
150
151 if (active_secure_sessions_.any() || layer_set_.empty()) {
152 return status;
153 }
154
155 layer_stack_.output_buffer = &output_buffer_;
156 if (display_paused_) {
157 validated_ = false;
158 }
159
160 // Ensure that blit is initialized.
161 // GPU context gets in secure or non-secure mode depending on output buffer provided.
162 if (!gl_color_convert_) {
163 // Get instance.
164 color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeGetInstance, nullptr);
165 if (gl_color_convert_ == nullptr) {
166 DLOGE("Failed to get Color Convert Instance");
167 return HWC2::Error::NoResources;
168 } else {
169 DLOGI("Created ColorConvert instance: %p", gl_color_convert_);
170 }
171 }
172
173 ColorConvertBlitContext ctx = {};
174
175 Layer *sdm_layer = client_target_->GetSDMLayer();
176 LayerBuffer &input_buffer = sdm_layer->input_buffer;
177 ctx.src_hnd = reinterpret_cast<const private_handle_t *>(input_buffer.buffer_id);
178 ctx.dst_hnd = reinterpret_cast<const private_handle_t *>(output_handle_);
179 ctx.dst_rect = {0, 0, FLOAT(output_buffer_.unaligned_width),
180 FLOAT(output_buffer_.unaligned_height)};
181 ctx.src_acquire_fence = input_buffer.acquire_fence;
182 ctx.dst_acquire_fence = output_buffer_.acquire_fence;
183
184 color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeBlit, &ctx);
185
186 // todo blit
187 DumpVDSBuffer();
188
189 *out_retire_fence = ctx.release_fence;
190
191 return status;
192 }
193
OnTask(const ColorConvertTaskCode & task_code,SyncTask<ColorConvertTaskCode>::TaskContext * task_context)194 void HWCDisplayVirtualGPU::OnTask(const ColorConvertTaskCode &task_code,
195 SyncTask<ColorConvertTaskCode>::TaskContext *task_context) {
196 switch (task_code) {
197 case ColorConvertTaskCode::kCodeGetInstance: {
198 gl_color_convert_ = GLColorConvert::GetInstance(kTargetYUV, output_buffer_.flags.secure);
199 }
200 break;
201 case ColorConvertTaskCode::kCodeBlit: {
202 DTRACE_SCOPED();
203 ColorConvertBlitContext* ctx = reinterpret_cast<ColorConvertBlitContext*>(task_context);
204 gl_color_convert_->Blit(ctx->src_hnd, ctx->dst_hnd, ctx->src_rect, ctx->dst_rect,
205 ctx->src_acquire_fence, ctx->dst_acquire_fence,
206 &(ctx->release_fence));
207 }
208 break;
209 case ColorConvertTaskCode::kCodeReset: {
210 DTRACE_SCOPED();
211 if (gl_color_convert_) {
212 gl_color_convert_->Reset();
213 }
214 }
215 break;
216 case ColorConvertTaskCode::kCodeDestroyInstance: {
217 if (gl_color_convert_) {
218 GLColorConvert::Destroy(gl_color_convert_);
219 }
220 }
221 break;
222 }
223 }
224
FreezeScreen()225 bool HWCDisplayVirtualGPU::FreezeScreen() {
226 if (!disable_animation_) {
227 return false;
228 }
229
230 bool freeze_screen = false;
231 if (animating_ && !animation_in_progress_) {
232 // Start of animation. GPU comp is needed.
233 animation_in_progress_ = true;
234 } else if (!animating_ && animation_in_progress_) {
235 // End of animation. Start composing.
236 animation_in_progress_ = false;
237 } else if (animating_ && animation_in_progress_) {
238 // Animation in progress...
239 freeze_screen = true;
240 }
241
242 return freeze_screen;
243 }
244
245 } // namespace sdm
246
247