blob: 854e442c4646a3ecb5b7787dc99c1c878d4509b2 [file] [log] [blame]
/*
* 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 "hwc_display_virtual_gpu.h"
#include "hwc_session.h"
#include <qdMetaData.h>
#define __CLASS__ "HWCDisplayVirtualGPU"
namespace sdm {
int HWCDisplayVirtualGPU::Init() {
// Create client target.
client_target_ = new HWCLayer(id_, buffer_allocator_);
// Calls into SDM need to be dropped. Create Null Display interface.
display_intf_ = new DisplayNull();
disable_animation_ = Debug::IsExtAnimDisabled();
return HWCDisplayVirtual::Init();
}
int HWCDisplayVirtualGPU::Deinit() {
// Destory color convert instance. This destroys thread and underlying GL resources.
if (gl_color_convert_) {
color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeDestroyInstance, nullptr);
}
delete static_cast<DisplayNull *>(display_intf_);
delete client_target_;
for (auto hwc_layer : layer_set_) {
delete hwc_layer;
}
return 0;
}
HWCDisplayVirtualGPU::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) :
HWCDisplayVirtual(core_intf, buffer_allocator, callbacks, id, sdm_id, width, height),
color_convert_task_(*this) {
}
HWC2::Error HWCDisplayVirtualGPU::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
DTRACE_SCOPED();
// Reset previous changes.
layer_changes_.clear();
layer_requests_.clear();
// Mark all layers to GPU if there is no need to bypass.
bool needs_gpu_bypass = NeedsGPUBypass() || FreezeScreen();
for (auto hwc_layer : layer_set_) {
auto layer = hwc_layer->GetSDMLayer();
layer->composition = needs_gpu_bypass ? kCompositionSDE : kCompositionGPU;
if (needs_gpu_bypass) {
if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::Client) {
layer_changes_[hwc_layer->GetId()] = HWC2::Composition::Device;
layer_requests_[hwc_layer->GetId()] = HWC2::LayerRequest::ClearClientTarget;
}
} else {
if (hwc_layer->GetClientRequestedCompositionType() != HWC2::Composition::Client) {
layer_changes_[hwc_layer->GetId()] = HWC2::Composition::Client;
}
}
}
// Derive client target dataspace based on the color mode - bug/115482728
int32_t client_target_dataspace = GetDataspaceFromColorMode(GetCurrentColorMode());
SetClientTargetDataSpace(client_target_dataspace);
*out_num_types = UINT32(layer_changes_.size());
*out_num_requests = UINT32(layer_requests_.size());;
has_client_composition_ = !needs_gpu_bypass;
client_target_->ResetValidation();
validated_ = true;
return ((*out_num_types > 0) ? HWC2::Error::HasChanges : HWC2::Error::None);
}
HWC2::Error HWCDisplayVirtualGPU::SetOutputBuffer(buffer_handle_t buf,
shared_ptr<Fence> release_fence) {
HWC2::Error error = HWCDisplayVirtual::SetOutputBuffer(buf, release_fence);
if (error != HWC2::Error::None) {
return error;
}
const private_handle_t *hnd = static_cast<const private_handle_t *>(buf);
output_buffer_.width = hnd->width;
output_buffer_.height = hnd->height;
output_buffer_.unaligned_width = width_;
output_buffer_.unaligned_height = height_;
// Update active dimensions.
BufferDim_t buffer_dim;
if (getMetaData(const_cast<private_handle_t *>(hnd), GET_BUFFER_GEOMETRY, &buffer_dim) == 0) {
output_buffer_.unaligned_width = buffer_dim.sliceWidth;
output_buffer_.unaligned_height = buffer_dim.sliceHeight;
color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeReset, nullptr);
}
return HWC2::Error::None;
}
HWC2::Error HWCDisplayVirtualGPU::Present(shared_ptr<Fence> *out_retire_fence) {
DTRACE_SCOPED();
auto status = HWC2::Error::None;
if (!validated_) {
return HWC2::Error::NotValidated;
}
if (!output_buffer_.buffer_id) {
return HWC2::Error::NoResources;
}
if (active_secure_sessions_.any() || layer_set_.empty()) {
return status;
}
layer_stack_.output_buffer = &output_buffer_;
if (display_paused_) {
validated_ = false;
}
// Ensure that blit is initialized.
// GPU context gets in secure or non-secure mode depending on output buffer provided.
if (!gl_color_convert_) {
// Get instance.
color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeGetInstance, nullptr);
if (gl_color_convert_ == nullptr) {
DLOGE("Failed to get Color Convert Instance");
return HWC2::Error::NoResources;
} else {
DLOGI("Created ColorConvert instance: %p", gl_color_convert_);
}
}
ColorConvertBlitContext ctx = {};
Layer *sdm_layer = client_target_->GetSDMLayer();
LayerBuffer &input_buffer = sdm_layer->input_buffer;
ctx.src_hnd = reinterpret_cast<const private_handle_t *>(input_buffer.buffer_id);
ctx.dst_hnd = reinterpret_cast<const private_handle_t *>(output_handle_);
ctx.dst_rect = {0, 0, FLOAT(output_buffer_.unaligned_width),
FLOAT(output_buffer_.unaligned_height)};
ctx.src_acquire_fence = input_buffer.acquire_fence;
ctx.dst_acquire_fence = output_buffer_.acquire_fence;
color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeBlit, &ctx);
// todo blit
DumpVDSBuffer();
*out_retire_fence = ctx.release_fence;
return status;
}
void HWCDisplayVirtualGPU::OnTask(const ColorConvertTaskCode &task_code,
SyncTask<ColorConvertTaskCode>::TaskContext *task_context) {
switch (task_code) {
case ColorConvertTaskCode::kCodeGetInstance: {
gl_color_convert_ = GLColorConvert::GetInstance(kTargetYUV, output_buffer_.flags.secure);
}
break;
case ColorConvertTaskCode::kCodeBlit: {
DTRACE_SCOPED();
ColorConvertBlitContext* ctx = reinterpret_cast<ColorConvertBlitContext*>(task_context);
gl_color_convert_->Blit(ctx->src_hnd, ctx->dst_hnd, ctx->src_rect, ctx->dst_rect,
ctx->src_acquire_fence, ctx->dst_acquire_fence,
&(ctx->release_fence));
}
break;
case ColorConvertTaskCode::kCodeReset: {
DTRACE_SCOPED();
if (gl_color_convert_) {
gl_color_convert_->Reset();
}
}
break;
case ColorConvertTaskCode::kCodeDestroyInstance: {
if (gl_color_convert_) {
GLColorConvert::Destroy(gl_color_convert_);
}
}
break;
}
}
bool HWCDisplayVirtualGPU::FreezeScreen() {
if (!disable_animation_) {
return false;
}
bool freeze_screen = false;
if (animating_ && !animation_in_progress_) {
// Start of animation. GPU comp is needed.
animation_in_progress_ = true;
} else if (!animating_ && animation_in_progress_) {
// End of animation. Start composing.
animation_in_progress_ = false;
} else if (animating_ && animation_in_progress_) {
// Animation in progress...
freeze_screen = true;
}
return freeze_screen;
}
} // namespace sdm