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