Chromium Code Reviews| Index: ui/ozone/platform/drm/gpu/drm_overlay_candidate.cc |
| diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_candidate.cc b/ui/ozone/platform/drm/gpu/drm_overlay_candidate.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..47c662f158c270223b126a9ad413cf6920f8866d |
| --- /dev/null |
| +++ b/ui/ozone/platform/drm/gpu/drm_overlay_candidate.cc |
| @@ -0,0 +1,231 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "ui/ozone/platform/drm/gpu/drm_overlay_candidate.h" |
| + |
| +#include <drm_fourcc.h> |
| + |
| +#include "ui/gfx/geometry/size_conversions.h" |
| +#include "ui/ozone/platform/drm/gpu/drm_device.h" |
| +#include "ui/ozone/platform/drm/gpu/drm_window.h" |
| +#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" |
| +#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" |
| + |
| +namespace ui { |
| + |
| +DrmOverlayCandidate::DrmOverlayCandidate(DrmWindow* window) : window_(window) {} |
| + |
| +DrmOverlayCandidate::~DrmOverlayCandidate() {} |
| + |
| +std::vector<OverlayCheck_Params> DrmOverlayCandidate::TestPageFlip( |
| + const std::vector<OverlayCheck_Params>& current_combination, |
| + const std::vector<OverlayCheck_Params>& new_combination, |
| + const OverlayPlaneList& last_used_planes, |
| + ScanoutBufferGenerator* buffer_generator) { |
| + std::vector<OverlayCheck_Params> validated_params; |
| + HardwareDisplayController* controller = window_->GetController(); |
| + if (!controller) { |
| + // Nothing much we can do here. |
| + return validated_params; |
| + } |
| + |
| + overlay_params_.clear(); |
| + OverlayPlaneList test_list; |
| + std::vector<scoped_refptr<ScanoutBuffer>> reusable_buffers; |
| + scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice(); |
| + const OverlayPlane& primary_plane = |
| + *OverlayPlane::GetPrimaryPlane(last_used_planes); |
| + |
| + for (const auto& plane : last_used_planes) |
| + reusable_buffers.push_back(plane.buffer); |
| + |
| + // We save the current in use configurations as we might have frames using |
| + // these configurations queued in SurfaceOzone. |
| + for (const auto& param : current_combination) |
| + overlay_params_.push_back(param); |
| + |
| + for (const auto& overlay : new_combination) { |
| + bool needs_flip_test = true; |
| + OverlayCheck_Params param(overlay); |
| + DCHECK(param.state != OverlayCheck_Params::kInvalid); |
| + OverlayPlane plane(nullptr, overlay.plane_z_order, overlay.transform, |
| + overlay.display_rect, overlay.crop_rect); |
| + |
| + if (param.state == OverlayCheck_Params::kTest) |
| + EvaluateBufferConfiguration(¶m, controller); |
| + |
| + // We expect this combination to always work. |
| + if (param.plane_z_order == 0 && |
| + param.required_buffer_size == primary_plane.buffer->GetSize() && |
| + param.optimal_format == gfx::BufferFormat::BGRX_8888) { |
| + param.state = OverlayCheck_Params::kOverlay; |
| + plane.buffer = primary_plane.buffer; |
| + overlay_params_.push_back(param); |
| + validated_params.push_back(param); |
| + test_list.push_back(plane); |
| + continue; |
| + } |
| + |
| + if (param.state != OverlayCheck_Params::kTest) { |
| + plane.buffer = GetBufferForPageFlipTest( |
| + buffer_generator, &reusable_buffers, param.required_buffer_size, |
| + param.optimal_format, drm); |
| + } else { |
| + ValidateConfiguration(buffer_generator, &plane, ¶m, &reusable_buffers, |
| + primary_plane, drm); |
| + // We can skip page flip test in case test_list size is less than 2 as the |
| + // result will be same as in ValidateConfiguration. |
| + needs_flip_test = test_list.size() > 1; |
| + } |
| + |
| + if (!plane.buffer) { |
| + param.state = OverlayCheck_Params::kInvalid; |
| + validated_params.push_back(param); |
| + continue; |
| + } |
| + |
| + test_list.push_back(plane); |
| + bool status = true; |
| + if (needs_flip_test) |
| + status = controller->TestPageFlip(test_list); |
| + |
| + if (status) { |
| + param.state = OverlayCheck_Params::kOverlay; |
| + overlay_params_.push_back(param); |
| + } else { |
| + // If test failed here, it means even though this configuration is |
| + // compatible, platform cannot support the current combination of layers. |
| + // This is usually the case when this plane has requested post processing |
| + // capability which needs additional hardware resources and they might |
| + // be already in use by other planes. For example this plane has requested |
| + // scaling capabilities and all available scalars are already in use by |
| + // other planes. |
| + DCHECK(test_list.size() > 1); |
| + param.state = OverlayCheck_Params::kCompatible; |
| + test_list.pop_back(); |
| + } |
| + |
| + validated_params.push_back(param); |
| + } |
| + |
| + return validated_params; |
| +} |
| + |
| +std::vector<OverlayCheck_Params> DrmOverlayCandidate::GetOverlayConfigurations() |
| + const { |
| + return overlay_params_; |
| +} |
| + |
| +scoped_refptr<ScanoutBuffer> DrmOverlayCandidate::GetBufferForPageFlipTest( |
| + ScanoutBufferGenerator* buffer_generator, |
| + std::vector<scoped_refptr<ScanoutBuffer>>* reusable_buffers, |
| + const gfx::Size& size, |
| + gfx::BufferFormat buffer_format, |
| + const scoped_refptr<DrmDevice>& drm_device) { |
| + scoped_refptr<ScanoutBuffer> scanout_buffer; |
| + uint32_t format = GetFourCCFormatFromBufferFormat(buffer_format); |
| + // Check if we can re-use existing buffers. |
| + for (const auto& buffer : *reusable_buffers) { |
| + if (buffer->GetFramebufferPixelFormat() == format && |
| + buffer->GetSize() == size) { |
| + scanout_buffer = buffer; |
| + break; |
| + } |
| + } |
| + |
| + if (!scanout_buffer) { |
| + scanout_buffer = buffer_generator->Create(drm_device, buffer_format, size); |
| + reusable_buffers->push_back(scanout_buffer); |
| + } |
| + |
| + return scanout_buffer; |
| +} |
| + |
| +void DrmOverlayCandidate::ValidateConfiguration( |
|
dnicoara
2015/11/23 19:22:54
Could you document what this does? My understandin
|
| + ScanoutBufferGenerator* buffer_generator, |
| + OverlayPlane* plane, |
| + OverlayCheck_Params* param, |
| + std::vector<scoped_refptr<ScanoutBuffer>>* reusable_buffers, |
| + const OverlayPlane& primary_plane, |
| + const scoped_refptr<DrmDevice>& drm) { |
| + OverlayPlaneList compatible_test_list; |
| + HardwareDisplayController* controller = window_->GetController(); |
| + |
| + plane->buffer = GetBufferForPageFlipTest(buffer_generator, reusable_buffers, |
| + param->required_buffer_size, |
| + param->optimal_format, drm); |
| + |
| + if (!plane->buffer) |
| + return; |
| + |
| + if (plane->z_order != 0) |
| + compatible_test_list.push_back(primary_plane); |
| + |
| + compatible_test_list.push_back(*plane); |
| + |
| + bool compatible = controller->TestPageFlip(compatible_test_list); |
| + |
| + if (!compatible) { |
| + plane->buffer = nullptr; |
| + if (param->optimal_format == param->format) |
| + return; |
| + |
| + // We tried to optimize the format and failed, check if original format |
| + // request can be supported. |
| + param->optimal_format = param->format; |
| + plane->buffer = GetBufferForPageFlipTest(buffer_generator, reusable_buffers, |
| + param->required_buffer_size, |
| + param->optimal_format, drm); |
| + |
| + if (!plane->buffer) |
| + return; |
| + |
| + compatible_test_list.back().buffer = plane->buffer; |
| + |
| + if (!controller->TestPageFlip(compatible_test_list)) |
| + plane->buffer = nullptr; |
| + } |
| +} |
| + |
| +void DrmOverlayCandidate::EvaluateBufferConfiguration( |
| + OverlayCheck_Params* param, |
| + HardwareDisplayController* controller) { |
| + uint32_t plane_z_order = param->plane_z_order; |
| + // TODO(kalyank): We always request scaling to be done by 3D engine, VPP etc. |
| + // We should only use them only if downscaling is needed and let display |
| + // controller handle up-scaling on platforms which support it. |
| + if (!param->crop_rect.IsEmpty()) { |
| + param->required_buffer_size = gfx::ToCeiledSize( |
| + gfx::SizeF(param->display_rect.width() / param->crop_rect.width(), |
| + param->display_rect.height() / param->crop_rect.height())); |
| + } |
| + |
| + gfx::BufferFormat format = param->format; |
| + // TODO(kalyank): We assume that it's always a Video buffer in case |
| + // plane_z_order > 0. This needs to be revisited when we add Overlay support |
| + // for other layers. |
| + if (param->plane_z_order > 0) { |
| + format = gfx::BufferFormat::BGRX_8888; |
|
dnicoara
2015/11/23 19:22:54
Shouldn't this be in the following if-statement? W
|
| + // Full screen is a special case, Plane manager will collapse Overlay plane |
| + // to primary. |
| + if (param->display_rect == window_->bounds()) |
| + plane_z_order = 0; |
| + |
| + // TODO(kalyank): In fullscreen case, we always fall back to BGRX format. |
| + // Currently, PlaneManager collapses planes to one only if format is BGRX. |
| + // This is due to the fact that page flip can fail on non-atomic kernels, |
| + // when trying to flip a buffer of format other than what was used during |
| + // Modeset with primary. However, with Atomic we can use test commit to |
| + // check if the actual commit will pass or not and make a decision. Remove |
| + // this restriction here and in plane manager once we are able to test it. |
| + if (plane_z_order && |
| + controller->IsFormatSupported(DRM_FORMAT_UYVY, plane_z_order)) { |
| + format = gfx::BufferFormat::UYVY_422; |
| + } |
| + } |
| + |
| + param->optimal_format = format; |
| +} |
| + |
| +} // namespace ui |