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