/* * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of The Linux Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define __CLASS__ "HWCDisplayVirtualDPU" namespace sdm { HWCDisplayVirtualDPU::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) : HWCDisplayVirtual(core_intf, buffer_allocator, callbacks, id, sdm_id, width, height), min_lum_(min_lum), max_lum_(max_lum) { } int HWCDisplayVirtualDPU::Init() { int status = HWCDisplay::Init(); if (status) { DLOGE("Init failed: %d", status); return status; } if (max_lum_ != -1.0 || min_lum_ != -1.0) { SetPanelLuminanceAttributes(min_lum_, max_lum_); } status = SetConfig(width_, height_); if (status) { DLOGE("Failed to set width: %d height: %d", width_, height_); return status; } status = INT32(SetPowerMode(HWC2::PowerMode::On, false /* teardown */)); if (status) { DLOGW("Failed to set power mode on virtual display"); return status; } // TODO(user): Validate that we support this width/height status = SetFrameBufferResolution(width_, height_); if (status) { DLOGW("Failed to set FrameBuffer resolution on virtual display"); return status; } return HWCDisplayVirtual::Init(); } int HWCDisplayVirtualDPU::SetConfig(uint32_t width, uint32_t height) { DisplayConfigVariableInfo variable_info; variable_info.x_pixels = width; variable_info.y_pixels = height; // TODO(user): Need to get the framerate of primary display and update it. variable_info.fps = 60; DisplayError err = display_intf_->SetActiveConfig(&variable_info); if (err != kErrorNone) { return -EINVAL; } return 0; } HWC2::Error HWCDisplayVirtualDPU::SetOutputBuffer(buffer_handle_t buf, shared_ptr release_fence) { HWC2::Error error = HWCDisplayVirtual::SetOutputBuffer(buf, release_fence); if (error != HWC2::Error::None) { return error; } const private_handle_t *output_handle = static_cast(buf); if (output_handle) { int output_handle_format = output_handle->format; int active_aligned_w, active_aligned_h; int new_width, new_height; int new_aligned_w, new_aligned_h; uint32_t active_width, active_height; GetMixerResolution(&active_width, &active_height); buffer_allocator_->GetCustomWidthAndHeight(output_handle, &new_width, &new_height); buffer_allocator_->GetAlignedWidthAndHeight(INT(new_width), INT(new_height), output_handle_format, 0, &new_aligned_w, &new_aligned_h); buffer_allocator_->GetAlignedWidthAndHeight(INT(active_width), INT(active_height), output_handle_format, 0, &active_aligned_w, &active_aligned_h); if (new_aligned_w != active_aligned_w || new_aligned_h != active_aligned_h) { int status = SetConfig(UINT32(new_width), UINT32(new_height)); if (status) { DLOGE("SetConfig failed custom WxH %dx%d", new_width, new_height); return HWC2::Error::BadParameter; } validated_ = false; } output_buffer_.width = UINT32(new_aligned_w); output_buffer_.height = UINT32(new_aligned_h); output_buffer_.unaligned_width = UINT32(new_width); output_buffer_.unaligned_height = UINT32(new_height); } return HWC2::Error::None; } HWC2::Error HWCDisplayVirtualDPU::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) { if (NeedsGPUBypass()) { MarkLayersForGPUBypass(); return HWC2::Error::None; } BuildLayerStack(); layer_stack_.output_buffer = &output_buffer_; // If Output buffer of Virtual Display is not secure, set SKIP flag on the secure layers. if (!output_buffer_.flags.secure && layer_stack_.flags.secure_present) { for (auto hwc_layer : layer_set_) { Layer *layer = hwc_layer->GetSDMLayer(); if (layer->input_buffer.flags.secure) { layer_stack_.flags.skip_present = true; layer->flags.skip = true; } } } return PrepareLayerStack(out_num_types, out_num_requests); } HWC2::Error HWCDisplayVirtualDPU::Present(shared_ptr *out_retire_fence) { auto status = HWC2::Error::None; if (!output_buffer_.buffer_id) { return HWC2::Error::NoResources; } if (active_secure_sessions_.any()) { return status; } layer_stack_.output_buffer = &output_buffer_; if (display_paused_) { validated_ = false; flush_ = true; } status = HWCDisplay::CommitLayerStack(); if (status != HWC2::Error::None) { return status; } DumpVDSBuffer(); status = HWCDisplay::PostCommitLayerStack(out_retire_fence); return status; } HWC2::Error HWCDisplayVirtualDPU::SetPanelLuminanceAttributes(float min_lum, float max_lum) { DisplayError err = display_intf_->SetPanelLuminanceAttributes(min_lum, max_lum); if (err != kErrorNone) { return HWC2::Error::BadParameter; } return HWC2::Error::None; } } // namespace sdm