xref: /aosp_15_r20/external/autotest/client/site_tests/graphics_HwOverlays/graphics_HwOverlays.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright 2018 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import logging
7import os
8
9from autotest_lib.client.bin import utils
10from autotest_lib.client.common_lib import error
11from autotest_lib.client.cros.graphics import graphics_utils
12from autotest_lib.client.common_lib.cros import chrome
13from autotest_lib.client.cros import constants
14from autotest_lib.client.cros.multimedia import display_facade as display_facade_lib
15from autotest_lib.client.cros.multimedia import facade_resource
16
17EXTRA_BROWSER_ARGS = ['--enable-experimental-web-platform-features',
18                      '--force-tablet-mode=clamshell']
19
20
21class graphics_HwOverlays(graphics_utils.GraphicsTest):
22    """Runs a given html and measures stuff."""
23    version = 1
24
25    # The tests are essentially composed of a preamble and an epilog, in between
26    # which we count the amount of overlays. Each of those essentially waits
27    # until either a total number of items is drawn, or there's a timeout.
28    PREAMBLE_TOTAL_NUMBER_OF_DRAW_PASSES = 5
29    PREAMBLE_TIMEOUT_SECONDS = 10
30    EPILOG_TOTAL_NUMBER_OF_DRAW_PASSES = 10
31    EPILOG_TIMEOUT_SECONDS = 10
32
33    POLLING_INTERVAL_SECONDS = 1
34
35    def initialize(self):
36        super(graphics_HwOverlays, self).initialize()
37
38    def cleanup(self):
39        super(graphics_HwOverlays, self).cleanup()
40
41    def set_rotation_to_zero(self, display_facade):
42        # Set rotation to 0 (portrait) otherwise tablet platforms might not get
43        # overlays.
44        internal_display_id = display_facade.get_internal_display_id()
45
46        logging.info("Internal display ID is %s", internal_display_id)
47        display_facade.set_display_rotation(internal_display_id, rotation=0)
48
49    def run_once(self, html_file, data_file_url = None,
50                 use_skia_renderer = False):
51        """Normalizes the environment, starts a Chrome environment, and
52        executes the test in `html_file`.
53        """
54        if not graphics_utils.is_drm_atomic_supported():
55            raise error.TestNAError(
56                    'Skipping test: platform does not support DRM atomic')
57
58        if graphics_utils.get_max_num_available_drm_planes() <= 2:
59            raise error.TestNAError(
60                    'Skipping test: platform supports 2 or less planes')
61
62        is_video = "video" in html_file
63        if is_video and not graphics_utils.is_nv12_supported_by_drm_planes():
64            raise error.TestNAError(
65                    'Skipping test: platform does not support NV12 planes')
66
67        extra_browser_args = EXTRA_BROWSER_ARGS
68        if use_skia_renderer:
69            # TODO(andrescj): remove when SkiaRenderer is enabled by default.
70            extra_browser_args.append('--enable-features=UseSkiaRenderer')
71
72        logging.info('Starting test, navigating to %s', html_file)
73
74        with chrome.Chrome(extra_browser_args=extra_browser_args,
75                           extension_paths=[constants.DISPLAY_TEST_EXTENSION],
76                           autotest_ext=True,
77                           init_network_controller=True) as cr:
78            facade = facade_resource.FacadeResource(cr)
79            display_facade = display_facade_lib.DisplayFacadeLocal(facade)
80            # TODO(crbug.com/927103): Run on an external monitor if one is
81            # present.
82            if not display_facade.has_internal_display():
83                raise error.TestNAError(
84                        'Skipping test: platform has no internal display')
85
86            self.set_rotation_to_zero(display_facade)
87
88            cr.browser.platform.SetHTTPServerDirectories(self.bindir)
89
90            tab = cr.browser.tabs[0]
91            tab.Navigate(cr.browser.platform.http_server.UrlOf(
92                    os.path.join(self.bindir, html_file)))
93            tab.WaitForDocumentReadyStateToBeComplete()
94
95            if data_file_url:
96                tab.EvaluateJavaScript('load_data_url("%s")' % data_file_url)
97
98            # Draw something; this also triggers JS parsing and execution.
99            tab.EvaluateJavaScript('draw_pass()')
100
101            # Wait until a few passes have been drawn, then read the amount of
102            # overlays.
103            utils.poll_for_condition(
104                    lambda: tab.EvaluateJavaScript('get_draw_passes_count()') >
105                            self.PREAMBLE_TOTAL_NUMBER_OF_DRAW_PASSES,
106                    exception=error.TestFail('JS is not drawing (preamble)'),
107                    timeout=self.PREAMBLE_TIMEOUT_SECONDS,
108                    sleep_interval=self.POLLING_INTERVAL_SECONDS)
109
110            num_overlays = 0;
111            try:
112                num_overlays = graphics_utils.get_num_hardware_overlays()
113                logging.debug('Found %s overlays', num_overlays)
114            except Exception as e:
115                logging.error(e)
116                raise error.TestFail('Error: %s' % str(e))
117
118            utils.poll_for_condition(
119                    lambda: tab.EvaluateJavaScript('get_draw_passes_count()') >
120                            self.EPILOG_TOTAL_NUMBER_OF_DRAW_PASSES,
121                    exception=error.TestFail('JS is not drawing (epilog)'),
122                    timeout=self.EPILOG_TIMEOUT_SECONDS,
123                    sleep_interval=self.POLLING_INTERVAL_SECONDS)
124
125            if (num_overlays <= 1):
126                raise error.TestFail('%s failed, number of overlays is %d' %
127                        (html_file, num_overlays))
128