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 |