All of lore.kernel.org
 help / color / mirror / Atom feed
* [kms-test] [PATCH 00/10] Test plane alpha and zpos control
@ 2022-06-09 23:40 Laurent Pinchart
  2022-06-09 23:40 ` [kms-test] [PATCH 01/10] tests: Replace double quotes with single quotes Laurent Pinchart
                   ` (9 more replies)
  0 siblings, 10 replies; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Hello,

This patch series extends the kms-test scripts ([1]) with two tests, for
plane alpha and zpos control.

The first two patches are cleanups, and patch 03/10 improves logging in
the allplanes test. Patches 04/10 to 06/10 prepare the test library for
alpha support, and patch 07/10 adds the alpha test. Similarly, patches
08/10 and 09/10 respectively add zpos support to the library and in a
new test. Finally, patch 10/10 renames the planeposition test file to
match the naming scheme of other tests.

[1] https://git.ideasonboard.com/renesas/kms-tests.git

Laurent Pinchart (10):
  tests: Replace double quotes with single quotes
  tests: Convert to formatted string literals
  tests: allplanes: Log the plane IDs
  kmstest: Move props value formatting to AtomicRequest
  kmstest: Support specifying property values in percents
  kmstest: Support specifying alpha value for planes
  tests: Add plane alpha test
  kmstest: Support specifying zpos value for planes
  tests: Add plane zpos test
  tests: Rename kms-test-planeposition.py to kms-test-plane-position.py

 tests/kms-test-allplanes.py                   |  23 ++--
 tests/kms-test-brxalloc.py                    |  38 +++----
 tests/kms-test-connectors.py                  |   6 +-
 tests/kms-test-crc.py                         |  33 +++---
 tests/kms-test-formats.py                     |  18 +--
 tests/kms-test-legacy-modeset.py              |  20 ++--
 tests/kms-test-modes.py                       |  20 ++--
 tests/kms-test-modeset.py                     |  20 ++--
 tests/kms-test-pageflip.py                    |  28 ++---
 tests/kms-test-plane-alpha.py                 |  97 +++++++++++++++++
 ...position.py => kms-test-plane-position.py} |  32 +++---
 tests/kms-test-plane-zpos.py                  | 102 +++++++++++++++++
 tests/kms-test-routing.py                     |  16 +--
 tests/kmstest.py                              | 103 +++++++++++-------
 14 files changed, 388 insertions(+), 168 deletions(-)
 create mode 100755 tests/kms-test-plane-alpha.py
 rename tests/{kms-test-planeposition.py => kms-test-plane-position.py} (77%)
 create mode 100755 tests/kms-test-plane-zpos.py


base-commit: 322821a1381f81c4dd480d065bec13803c7e69dc
-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 01/10] tests: Replace double quotes with single quotes
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 13:22   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 02/10] tests: Convert to formatted string literals Laurent Pinchart
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

The code base mixes single and double quotes. Standardize on single
quotes except for triple-quoted strings (to match the PEP8 coding style)
and where the string contains single quotes to avoid the need to escape
them.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kms-test-allplanes.py      | 20 +++++------
 tests/kms-test-brxalloc.py       | 30 ++++++++--------
 tests/kms-test-connectors.py     |  6 ++--
 tests/kms-test-crc.py            | 30 ++++++++--------
 tests/kms-test-formats.py        | 16 ++++-----
 tests/kms-test-legacy-modeset.py | 18 +++++-----
 tests/kms-test-modes.py          | 18 +++++-----
 tests/kms-test-modeset.py        | 18 +++++-----
 tests/kms-test-pageflip.py       | 24 ++++++-------
 tests/kms-test-planeposition.py  | 30 ++++++++--------
 tests/kms-test-routing.py        | 14 ++++----
 tests/kmstest.py                 | 60 ++++++++++++++++----------------
 12 files changed, 142 insertions(+), 142 deletions(-)

diff --git a/tests/kms-test-allplanes.py b/tests/kms-test-allplanes.py
index d88326293782..710ae660f0ff 100755
--- a/tests/kms-test-allplanes.py
+++ b/tests/kms-test-allplanes.py
@@ -9,7 +9,7 @@ class AllPlanesTest(kmstest.KMSTest):
     """Test composition with all planes enabled on all CRTCs."""
 
     def handle_page_flip(self, frame, time):
-        self.logger.log("Page flip complete")
+        self.logger.log('Page flip complete')
 
     def main(self):
         # Create the connectors to CRTCs map
@@ -25,14 +25,14 @@ class AllPlanesTest(kmstest.KMSTest):
                     connectors[crtc] = connector
 
         for crtc in self.card.crtcs:
-            self.start("composition on CRTC %u" % crtc.id)
+            self.start('composition on CRTC %u' % crtc.id)
 
             # Get the connector and default mode
             try:
                 connector = connectors[crtc];
                 mode = connector.get_default_mode()
             except KeyError:
-                self.skip("no connector or mode available")
+                self.skip('no connector or mode available')
                 continue
 
             # List planes available for the CRTC
@@ -42,20 +42,20 @@ class AllPlanesTest(kmstest.KMSTest):
                     planes.append(plane)
 
             if len(planes) == 0:
-                self.skip("no plane available for CRTC")
+                self.skip('no plane available for CRTC')
                 continue
 
-            self.logger.log("Testing connector %s, CRTC %u, mode %s with %u planes" % \
+            self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
                   (connector.fullname, crtc.id, mode.name, len(planes)))
 
             # Create a frame buffer
-            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
+            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
             pykms.draw_test_pattern(fb)
 
             # Set the mode with a primary plane
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
             if ret < 0:
-                self.fail("atomic mode set failed with %d" % ret)
+                self.fail('atomic mode set failed with %d' % ret)
                 continue
 
             self.run(3)
@@ -67,14 +67,14 @@ class AllPlanesTest(kmstest.KMSTest):
                 destination = kmstest.Rect(offset, offset, fb.width, fb.height)
                 ret = self.atomic_plane_set(plane, crtc, source, destination, fb)
                 if ret < 0:
-                    self.fail("atomic plane set failed with %d" % ret)
+                    self.fail('atomic plane set failed with %d' % ret)
                     break
 
-                self.logger.log("Adding plane %u" % plane.id)
+                self.logger.log('Adding plane %u' % plane.id)
                 self.run(1)
 
                 if self.flips == 0:
-                    self.fail("No page flip registered")
+                    self.fail('No page flip registered')
                     break
 
                 offset += 50
diff --git a/tests/kms-test-brxalloc.py b/tests/kms-test-brxalloc.py
index dbdc78946b04..af6dd49f5c59 100755
--- a/tests/kms-test-brxalloc.py
+++ b/tests/kms-test-brxalloc.py
@@ -21,9 +21,9 @@ class BRxAllocTest(kmstest.KMSTest):
         # instance to test dynamic assignment of the BRU and BRS to pipelines.
         # This is only occurs on H3 ES2.0 and M3-N. Check the SoC model through
         # sysfs as we can't detected it through the DRM/KMS API.
-        soc = open("/sys/devices/soc0/soc_id", "rb").read().strip().decode()
-        if soc not in ["r8a7795", "r8a77965"]:
-            self.skip("VSPDL (BRU+BRS) not available")
+        soc = open('/sys/devices/soc0/soc_id', 'rb').read().strip().decode()
+        if soc not in ['r8a7795', 'r8a77965']:
+            self.skip('VSPDL (BRU+BRS) not available')
             return
 
         outputs = [Output(), Output()]
@@ -38,11 +38,11 @@ class BRxAllocTest(kmstest.KMSTest):
         # Verify that the two CRTCs share the same planes
         planes = outputs[0].crtc.possible_planes
         if planes != outputs[1].crtc.possible_planes:
-            self.skip("Planes differ for CRTCs %u and %u" % \
+            self.skip('Planes differ for CRTCs %u and %u' % \
                       (outputs[0].crtc.id, outputs[1].crtc.id))
             return
 
-        self.logger.log("Found %u planes for CRTCs %u and %u" % \
+        self.logger.log('Found %u planes for CRTCs %u and %u' % \
                         (len(planes), outputs[0].crtc.id, outputs[1].crtc.id))
 
         # Get one connector for each CRTC
@@ -58,11 +58,11 @@ class BRxAllocTest(kmstest.KMSTest):
                     outputs[1].connector = connector
 
         if not outputs[0].connector or not outputs[1].connector:
-            self.skip("No connected connectors for CRTCs %u and %u " % \
+            self.skip('No connected connectors for CRTCs %u and %u ' % \
                       (outputs[0].crtc.id, outputs[1].crtc.id))
             return
 
-        self.start("Moving %u planes from %s to %s" % \
+        self.start('Moving %u planes from %s to %s' % \
                    (len(planes), outputs[0].connector.fullname, outputs[1].connector.fullname))
 
         # Set the initial mode for both outputs and wait 5s for the monitors to
@@ -70,17 +70,17 @@ class BRxAllocTest(kmstest.KMSTest):
         for output in outputs:
             # Get the default mode and create a framebuffer
             mode = output.connector.get_default_mode()
-            output.fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
+            output.fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
             pykms.draw_test_pattern(output.fb)
 
             # Set the mode with no plane
             ret = self.atomic_crtc_mode_set(output.crtc, output.connector, mode, sync=True)
             if ret < 0:
-                self.fail("atomic mode set on %s failed with %d" % \
+                self.fail('atomic mode set on %s failed with %d' % \
                           (output.connector.fullname, ret))
                 return
 
-        self.logger.log("Initial atomic mode set completed")
+        self.logger.log('Initial atomic mode set completed')
         time.sleep(5)
 
         # Add all planes
@@ -88,13 +88,13 @@ class BRxAllocTest(kmstest.KMSTest):
         output = outputs[0]
 
         for plane in planes:
-            self.logger.log("Adding plane %u to %s" % (plane.id, output.connector.fullname))
+            self.logger.log('Adding plane %u to %s' % (plane.id, output.connector.fullname))
 
             source = kmstest.Rect(0, 0, output.fb.width, output.fb.height)
             destination = kmstest.Rect(offset, offset, output.fb.width, output.fb.height)
             ret = self.atomic_plane_set(plane, output.crtc, source, destination, output.fb, sync=True)
             if ret < 0:
-                self.fail("atomic plane set failed with %d" % ret)
+                self.fail('atomic plane set failed with %d' % ret)
                 return
 
             offset += 50
@@ -106,20 +106,20 @@ class BRxAllocTest(kmstest.KMSTest):
         output = outputs[1]
 
         for plane in planes:
-            self.logger.log("Moving plane %u to %s" % (plane.id, output.connector.fullname))
+            self.logger.log('Moving plane %u to %s' % (plane.id, output.connector.fullname))
 
             # Switching CRTC directly is not supported by DRM, start by
             # disabling the plane.
             ret = self.atomic_plane_disable(plane)
             if ret < 0:
-                self.fail("atomic plane disable failed with %d" % ret)
+                self.fail('atomic plane disable failed with %d' % ret)
                 return
 
             source = kmstest.Rect(0, 0, output.fb.width, output.fb.height)
             destination = kmstest.Rect(offset, offset, output.fb.width, output.fb.height)
             ret = self.atomic_plane_set(plane, output.crtc, source, destination, output.fb)
             if ret < 0:
-                self.fail("atomic plane set failed with %d" % ret)
+                self.fail('atomic plane set failed with %d' % ret)
                 return
 
             self.run(1)
diff --git a/tests/kms-test-connectors.py b/tests/kms-test-connectors.py
index 4c58b99f8fbf..54cc89ff308e 100755
--- a/tests/kms-test-connectors.py
+++ b/tests/kms-test-connectors.py
@@ -10,19 +10,19 @@ class ConnectorsTest(kmstest.KMSTest):
 
     def main(self):
         for connector in self.card.connectors:
-            self.start("connector %s" % connector.fullname)
+            self.start('connector %s' % connector.fullname)
 
             # Every connector should have at least one suitable CRTC
             crtcs = connector.get_possible_crtcs()
             if len(crtcs) == 0:
-                self.fail("no possible CRTC")
+                self.fail('no possible CRTC')
                 continue
 
             # Connected connectors should have at least one mode
             if connector.connected():
                 modes = connector.get_modes()
                 if len(modes) == 0:
-                    self.fail("no mode available")
+                    self.fail('no mode available')
                     continue
 
             self.success()
diff --git a/tests/kms-test-crc.py b/tests/kms-test-crc.py
index 60187eff1c48..5b8a679ffadc 100755
--- a/tests/kms-test-crc.py
+++ b/tests/kms-test-crc.py
@@ -105,7 +105,7 @@ class CRCTest(kmstest.KMSTest):
     """Test CRC calculation on pipeline output."""
 
     def handle_page_flip(self, frame, time):
-        self.logger.log("Page flip complete")
+        self.logger.log('Page flip complete')
 
     def main(self):
         # Create the connectors to CRTCs map
@@ -121,14 +121,14 @@ class CRCTest(kmstest.KMSTest):
                     connectors[crtc] = connector
 
         for crtc in self.card.crtcs:
-            self.start("CRC calculation on CRTC %u" % crtc.id)
+            self.start('CRC calculation on CRTC %u' % crtc.id)
 
             # Get the connector and default mode
             try:
                 connector = connectors[crtc];
                 mode = connector.get_default_mode()
             except KeyError:
-                self.skip("no connector or mode available")
+                self.skip('no connector or mode available')
                 continue
 
             # List planes available for the CRTC
@@ -138,14 +138,14 @@ class CRCTest(kmstest.KMSTest):
                     planes.append(plane)
 
             if len(planes) == 0:
-                self.skip("no plane available for CRTC")
+                self.skip('no plane available for CRTC')
                 continue
 
-            self.logger.log("Testing connector %s, CRTC %u, mode %s with %u planes" % \
+            self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
                   (connector.fullname, crtc.id, mode.name, len(planes)))
 
             # Create a frame buffer and draw a test pattern.
-            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
+            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
             pykms.draw_test_pattern(fb)
 
             # Create a composer. This will compute the reference CRCs.
@@ -154,7 +154,7 @@ class CRCTest(kmstest.KMSTest):
             # Set the mode and add all planes
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
             if ret < 0:
-                self.fail("atomic mode set failed with %d" % ret)
+                self.fail('atomic mode set failed with %d' % ret)
                 continue
 
             req = kmstest.AtomicRequest(self)
@@ -177,23 +177,23 @@ class CRCTest(kmstest.KMSTest):
 
             ret = req.commit(0)
             if ret < 0:
-                self.fail("atomic plane set failed with %d" % ret)
+                self.fail('atomic plane set failed with %d' % ret)
                 continue
 
             # Wait for one second and make sure the page flip has completed.
             self.run(1)
             if self.flips == 0:
-                self.fail("No page flip registered")
+                self.fail('No page flip registered')
                 continue
 
             sources = [crtc] + planes
             for source in sources:
                 if source == crtc:
-                    crc_source = "auto"
+                    crc_source = 'auto'
                 else:
-                    crc_source = "plane%u" % source.id
+                    crc_source = 'plane%u' % source.id
 
-                self.logger.log("Computing CRC from source %s" % crc_source)
+                self.logger.log('Computing CRC from source %s' % crc_source)
 
                 # Set the CRC source and acquire 10 CRC values. Discard the
                 # first value, as the device is running and the new source
@@ -204,7 +204,7 @@ class CRCTest(kmstest.KMSTest):
                 crc_reader.stop()
 
                 crcs = [c.crcs[0] for c in crcs[1:]]
-                self.logger.log("CRC value[0] 0x%08x" % crcs[0])
+                self.logger.log('CRC value[0] 0x%08x' % crcs[0])
 
                 failures = 0
                 ref_crc = composer.crc(source)
@@ -212,12 +212,12 @@ class CRCTest(kmstest.KMSTest):
                 for i in range(len(crcs)):
                     crc = crcs[i]
                     if crc != ref_crc:
-                        self.logger.log("CRC value[%u] 0x%08x does not match reference 0x%08x"
+                        self.logger.log('CRC value[%u] 0x%08x does not match reference 0x%08x'
                                         % (i, crc, ref_crc))
                         failures += 1
 
                 if failures:
-                    self.fail("Incorrect CRC values on source %s" % crc_source)
+                    self.fail('Incorrect CRC values on source %s' % crc_source)
                     break
 
             else:
diff --git a/tests/kms-test-formats.py b/tests/kms-test-formats.py
index 86f16511f1ea..ce849437b2fa 100755
--- a/tests/kms-test-formats.py
+++ b/tests/kms-test-formats.py
@@ -10,12 +10,12 @@ class FormatsTest(kmstest.KMSTest):
     """Test all available plane formats."""
 
     def main(self):
-        self.start("plane formats")
+        self.start('plane formats')
 
         # Find a CRTC with a connected connector and at least one plane
         for connector in self.output_connectors():
             if not connector.connected():
-                self.skip("unconnected connector")
+                self.skip('unconnected connector')
                 continue
 
             try:
@@ -34,10 +34,10 @@ class FormatsTest(kmstest.KMSTest):
                 break
 
         else:
-            self.skip("no CRTC available with connector")
+            self.skip('no CRTC available with connector')
             return
 
-        self.logger.log("Testing connector %s, CRTC %u, mode %s" % \
+        self.logger.log('Testing connector %s, CRTC %u, mode %s' % \
               (connector.fullname, crtc.id, mode.name))
 
         failed = 0
@@ -46,14 +46,14 @@ class FormatsTest(kmstest.KMSTest):
         for i in range(num_formats):
             format = crtc.primary_plane.formats[i]
 
-            self.logger.log("Testing format %s" % format)
+            self.logger.log('Testing format %s' % format)
             self.progress(i+1, num_formats)
 
             # Create a frame buffer
             try:
                 fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, format)
             except ValueError:
-                self.logger.log("Failed to create frame buffer")
+                self.logger.log('Failed to create frame buffer')
                 failed += 1
                 continue
 
@@ -62,7 +62,7 @@ class FormatsTest(kmstest.KMSTest):
             # Set the mode with a primary plane
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
             if ret < 0:
-                self.logger.log("atomic mode set failed with %d" % ret)
+                self.logger.log('atomic mode set failed with %d' % ret)
                 failed += 1
                 continue
 
@@ -71,7 +71,7 @@ class FormatsTest(kmstest.KMSTest):
         self.atomic_crtc_disable(crtc)
 
         if failed:
-            self.fail("%s/%s formats failed" % (failed, num_formats))
+            self.fail('%s/%s formats failed' % (failed, num_formats))
         else:
             self.success()
 
diff --git a/tests/kms-test-legacy-modeset.py b/tests/kms-test-legacy-modeset.py
index 4b5605345391..f856178172c0 100755
--- a/tests/kms-test-legacy-modeset.py
+++ b/tests/kms-test-legacy-modeset.py
@@ -9,15 +9,15 @@ class LegacyModeSetTest(kmstest.KMSTest):
     """Test mode setting on all connectors in sequence with the default mode through the legacy mode set API."""
 
     def handle_page_flip(self, frame, time):
-        self.logger.log("Page flip complete")
+        self.logger.log('Page flip complete')
 
     def main(self):
         for connector in self.output_connectors():
-            self.start("legacy mode set on connector %s" % connector.fullname)
+            self.start('legacy mode set on connector %s' % connector.fullname)
 
             # Skip disconnected connectors
             if not connector.connected():
-                self.skip("unconnected connector")
+                self.skip('unconnected connector')
                 continue
 
             # Find a CRTC suitable for the connector
@@ -33,28 +33,28 @@ class LegacyModeSetTest(kmstest.KMSTest):
             try:
                 mode = connector.get_default_mode()
             except ValueError:
-                self.skip("no mode available")
+                self.skip('no mode available')
                 continue
 
-            self.logger.log("Testing connector %s on CRTC %u with mode %s" % \
+            self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
                   (connector.fullname, crtc.id, mode.name))
 
             # Create a frame buffer
-            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
+            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
             pykms.draw_test_pattern(fb)
 
             # Perform a mode set
             ret = crtc.set_mode(connector, fb, mode)
             if ret < 0:
-                self.fail("legacy mode set failed with %d" % ret)
+                self.fail('legacy mode set failed with %d' % ret)
                 continue
 
-            self.logger.log("Legacy mode set complete")
+            self.logger.log('Legacy mode set complete')
             self.run(5)
 
             ret = crtc.disable_mode()
             if ret < 0:
-                self.fail("legacy mode set disable failed with %d" % ret)
+                self.fail('legacy mode set disable failed with %d' % ret)
                 continue
 
             self.success()
diff --git a/tests/kms-test-modes.py b/tests/kms-test-modes.py
index b298a19beedf..433bb0bdd157 100755
--- a/tests/kms-test-modes.py
+++ b/tests/kms-test-modes.py
@@ -9,35 +9,35 @@ class ModesTest(kmstest.KMSTest):
     """Test all available modes on all available connectors."""
 
     def handle_page_flip(self, frame, time):
-        self.logger.log("Page flip complete")
+        self.logger.log('Page flip complete')
 
     def test_mode(self, connector, crtc, mode):
-        self.logger.log("Testing connector %s on CRTC %u with mode %s" % \
+        self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
               (connector.fullname, crtc.id, mode.name))
 
         # Create a frame buffer
-        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
+        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
         pykms.draw_test_pattern(fb)
 
         # Perform the mode set
         ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
         if ret < 0:
-            raise RuntimeError("atomic mode set failed with %d" % ret)
+            raise RuntimeError('atomic mode set failed with %d' % ret)
 
-        self.logger.log("Atomic mode set complete")
+        self.logger.log('Atomic mode set complete')
         self.run(4)
         self.atomic_crtc_disable(crtc)
 
         if self.flips == 0:
-            raise RuntimeError("Page flip not registered")
+            raise RuntimeError('Page flip not registered')
 
     def main(self):
         for connector in self.output_connectors():
-            self.start("modes on connector %s" % connector.fullname)
+            self.start('modes on connector %s' % connector.fullname)
 
             # Skip disconnected connectors
             if not connector.connected():
-                self.skip("unconnected connector")
+                self.skip('unconnected connector')
                 continue
 
             # Find a CRTC suitable for the connector
@@ -52,7 +52,7 @@ class ModesTest(kmstest.KMSTest):
             # Test all available modes
             modes = connector.get_modes()
             if len(modes) == 0:
-                self.skip("no mode available")
+                self.skip('no mode available')
                 continue
 
             for i in range(len(modes)):
diff --git a/tests/kms-test-modeset.py b/tests/kms-test-modeset.py
index 0dbe67fb2a4f..a6ba61c920e5 100755
--- a/tests/kms-test-modeset.py
+++ b/tests/kms-test-modeset.py
@@ -9,15 +9,15 @@ class ModeSetTest(kmstest.KMSTest):
     """Test mode setting on all connectors in sequence with the default mode."""
 
     def handle_page_flip(self, frame, time):
-        self.logger.log("Page flip complete")
+        self.logger.log('Page flip complete')
 
     def main(self):
         for connector in self.output_connectors():
-            self.start("atomic mode set on connector %s" % connector.fullname)
+            self.start('atomic mode set on connector %s' % connector.fullname)
 
             # Skip disconnected connectors
             if not connector.connected():
-                self.skip("unconnected connector")
+                self.skip('unconnected connector')
                 continue
 
             # Find a CRTC suitable for the connector
@@ -33,28 +33,28 @@ class ModeSetTest(kmstest.KMSTest):
             try:
                 mode = connector.get_default_mode()
             except ValueError:
-                self.skip("no mode available")
+                self.skip('no mode available')
                 continue
 
-            self.logger.log("Testing connector %s on CRTC %u with mode %s" % \
+            self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
                   (connector.fullname, crtc.id, mode.name))
 
             # Create a frame buffer
-            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
+            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
             pykms.draw_test_pattern(fb)
 
             # Perform a mode set
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
             if ret < 0:
-                self.fail("atomic mode set failed with %d" % ret)
+                self.fail('atomic mode set failed with %d' % ret)
                 continue
 
-            self.logger.log("Atomic mode set complete")
+            self.logger.log('Atomic mode set complete')
             self.run(5)
             self.atomic_crtc_disable(crtc)
 
             if self.flips == 0:
-                self.fail("Page flip not registered")
+                self.fail('Page flip not registered')
             else:
                 self.success()
 
diff --git a/tests/kms-test-pageflip.py b/tests/kms-test-pageflip.py
index 19c3adaa601f..15dae6a23ab3 100755
--- a/tests/kms-test-pageflip.py
+++ b/tests/kms-test-pageflip.py
@@ -13,12 +13,12 @@ class PageFlipTest(kmstest.KMSTest):
 
     def handle_page_flip(self, frame, time):
         if self.flips == 1:
-            self.logger.log("first page flip frame %u time %f" % (frame, time))
+            self.logger.log('first page flip frame %u time %f' % (frame, time))
             self.frame_start = frame
             self.time_start = time
 
         if self.stop_requested:
-            self.logger.log("last page flip frame %u time %f" % (frame, time))
+            self.logger.log('last page flip frame %u time %f' % (frame, time))
             self.frame_end = frame
             self.time_end = time
             self.loop.stop()
@@ -43,11 +43,11 @@ class PageFlipTest(kmstest.KMSTest):
 
     def main(self):
         for connector in self.output_connectors():
-            self.start("page flip on connector %s" % connector.fullname)
+            self.start('page flip on connector %s' % connector.fullname)
 
             # Skip disconnected connectors
             if not connector.connected():
-                self.skip("unconnected connector")
+                self.skip('unconnected connector')
                 continue
 
             # Find a CRTC suitable for the connector
@@ -67,28 +67,28 @@ class PageFlipTest(kmstest.KMSTest):
                     self.plane = plane
                     break
             else:
-                self.skip("no plane available for CRTC %u" % crtc.id)
+                self.skip('no plane available for CRTC %u' % crtc.id)
                 continue
 
             # Get the default mode for the connector
             try:
                 mode = connector.get_default_mode()
             except ValueError:
-                self.skip("no mode available")
+                self.skip('no mode available')
                 continue
 
-            self.logger.log("Testing connector %s, CRTC %u, plane %u, mode %s" % \
+            self.logger.log('Testing connector %s, CRTC %u, plane %u, mode %s' % \
                   (connector.fullname, crtc.id, self.plane.id, mode.name))
 
             # Create two frame buffers
             self.fbs = []
             for i in range(2):
-                self.fbs.append(pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24"))
+                self.fbs.append(pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24'))
 
             # Set the mode and perform the initial page flip
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, self.fbs[0])
             if ret < 0:
-                self.fail("atomic mode set failed with %d" % ret)
+                self.fail('atomic mode set failed with %d' % ret)
                 continue
 
             # Flip pages for 10s
@@ -105,16 +105,16 @@ class PageFlipTest(kmstest.KMSTest):
             self.atomic_crtc_disable(crtc)
 
             if not self.flips:
-                self.fail("No page flip registered")
+                self.fail('No page flip registered')
                 continue
 
             if self.stop_requested:
-                self.fail("Last page flip not registered")
+                self.fail('Last page flip not registered')
                 continue
 
             frames = self.frame_end - self.frame_start + 1
             interval = self.time_end - self.time_start
-            self.logger.log("Frame rate: %f (%u/%u frames in %f s)" % \
+            self.logger.log('Frame rate: %f (%u/%u frames in %f s)' % \
                 (frames / interval, self.flips, frames, interval))
             self.success()
 
diff --git a/tests/kms-test-planeposition.py b/tests/kms-test-planeposition.py
index 0381896f1da8..e843ae13c50c 100755
--- a/tests/kms-test-planeposition.py
+++ b/tests/kms-test-planeposition.py
@@ -10,12 +10,12 @@ class PlanePositionTest(kmstest.KMSTest):
     """Test boundaries of plane positioning."""
 
     def main(self):
-        self.start("plane positioning boundaries")
+        self.start('plane positioning boundaries')
 
         # Find a CRTC with a connected connector and at least two planes
         for connector in self.output_connectors():
             if not connector.connected():
-                self.skip("unconnected connector")
+                self.skip('unconnected connector')
                 continue
 
             try:
@@ -39,23 +39,23 @@ class PlanePositionTest(kmstest.KMSTest):
                 break
 
         else:
-            self.skip("no CRTC available with connector and at least two planes")
+            self.skip('no CRTC available with connector and at least two planes')
             return
 
-        self.logger.log("Testing connector %s, CRTC %u, mode %s with %u planes" % \
+        self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
               (connector.fullname, crtc.id, mode.name, len(planes)))
 
         # Create a frame buffer
-        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
+        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
         pykms.draw_test_pattern(fb)
 
         # Set the mode with no plane, wait 5s for the monitor to wake up
         ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
         if ret < 0:
-            self.fail("atomic mode set failed with %d" % ret)
+            self.fail('atomic mode set failed with %d' % ret)
             return
 
-        self.logger.log("Initial atomic mode set completed")
+        self.logger.log('Initial atomic mode set completed')
         time.sleep(5)
 
         # Add the first plane to cover half of the CRTC
@@ -63,10 +63,10 @@ class PlanePositionTest(kmstest.KMSTest):
         destination = kmstest.Rect(0, 0, fb.width // 2, fb.height)
         ret = self.atomic_plane_set(planes[0], crtc, source, destination, fb, sync=True)
         if ret < 0:
-            self.fail("atomic plane set for first plane failed with %d" % ret)
+            self.fail('atomic plane set for first plane failed with %d' % ret)
             return
 
-        self.logger.log("Root plane enabled")
+        self.logger.log('Root plane enabled')
         time.sleep(3)
 
         # Add the second plane and move it around to cross all CRTC boundaries
@@ -79,10 +79,10 @@ class PlanePositionTest(kmstest.KMSTest):
 
             ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
             if ret < 0:
-                self.fail("atomic plane set with offset %d,%d" % offset)
+                self.fail('atomic plane set with offset %d,%d' % offset)
                 return
 
-            self.logger.log("Moved overlay plane to %d,%d" % offset)
+            self.logger.log('Moved overlay plane to %d,%d' % offset)
             time.sleep(3)
 
         # Try to move the plane completely off-screen. The device is expected
@@ -97,17 +97,17 @@ class PlanePositionTest(kmstest.KMSTest):
 
             ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
             if ret < 0:
-                self.fail("atomic plane set with offset %d,%d" % offset)
+                self.fail('atomic plane set with offset %d,%d' % offset)
                 return
 
-            self.logger.log("Moved overlay plane to %d,%d" % offset)
+            self.logger.log('Moved overlay plane to %d,%d' % offset)
             time.sleep(3)
 
         # Disable and re-enable the plane when it is off-screen. The device is
         # still expected to handle this gracefully.
         ret = self.atomic_plane_disable(planes[1])
         if ret < 0:
-            self.fail("off-screen atomic plane disable failed")
+            self.fail('off-screen atomic plane disable failed')
             return
 
         width = fb.width - 100
@@ -117,7 +117,7 @@ class PlanePositionTest(kmstest.KMSTest):
 
         ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
         if ret < 0:
-            self.fail("off-scrren atomic plane enable failed")
+            self.fail('off-scrren atomic plane enable failed')
             return
 
         self.atomic_crtc_disable(crtc)
diff --git a/tests/kms-test-routing.py b/tests/kms-test-routing.py
index 806adb8c68a8..69f8be127d2f 100755
--- a/tests/kms-test-routing.py
+++ b/tests/kms-test-routing.py
@@ -49,7 +49,7 @@ class RoutingTest(kmstest.KMSTest):
                 break
 
         if not shared_connector:
-            self.skip("No suitable connector")
+            self.skip('No suitable connector')
             return
 
         # Allocate planes for each CRTC.
@@ -61,13 +61,13 @@ class RoutingTest(kmstest.KMSTest):
             pool = [(elem[0], [p for p in elem[1] if p != pipe.plane]) for elem in pool[:-1]]
 
         # Create a framebuffer big enough for all connectors.
-        fb = pykms.DumbFramebuffer(self.card, max_hdisplay, max_vdisplay, "XR24")
+        fb = pykms.DumbFramebuffer(self.card, max_hdisplay, max_vdisplay, 'XR24')
         pykms.draw_test_pattern(fb)
 
-        self.start("Moving connector %s between CRTCs %s" % \
+        self.start('Moving connector %s between CRTCs %s' % \
                    (shared_connector.fullname, [pipe.crtc.id for pipe in pipes]))
 
-        self.logger.log("Highest display resolution: %ux%u" % (max_hdisplay, max_vdisplay))
+        self.logger.log('Highest display resolution: %ux%u' % (max_hdisplay, max_vdisplay))
 
         for master_pipe in pipes:
             req = kmstest.AtomicRequest(self)
@@ -97,13 +97,13 @@ class RoutingTest(kmstest.KMSTest):
                             'CRTC_H': mode.vdisplay,
                         })
 
-                route.append("CRTC %u to connector %s" % (pipe.crtc.id, pipe.connector.fullname))
+                route.append('CRTC %u to connector %s' % (pipe.crtc.id, pipe.connector.fullname))
 
-            self.logger.log("Routing " + ", ".join(route))
+            self.logger.log('Routing ' + ', '.join(route))
 
             ret = req.commit_sync(True)
             if ret < 0:
-                self.fail("atomic commit failed with %d" % ret)
+                self.fail('atomic commit failed with %d' % ret)
                 return
 
             time.sleep(5)
diff --git a/tests/kmstest.py b/tests/kmstest.py
index 949bb20b8b1a..708e6999d1f0 100755
--- a/tests/kmstest.py
+++ b/tests/kmstest.py
@@ -63,23 +63,23 @@ class EventLoop(selectors.DefaultSelector):
 
 class KernelLogMessage(object):
     def __init__(self, msg):
-        pos = msg.find(";")
+        pos = msg.find(';')
         header = msg[:pos]
         msg = msg[pos+1:]
 
-        facility, sequence, timestamp, *other = header.split(",")
+        facility, sequence, timestamp, *other = header.split(',')
         self.facility = int(facility)
         self.sequence = int(sequence)
         self.timestamp = int(timestamp) / 1000000.
 
-        msg = msg.split("\n")
+        msg = msg.split('\n')
         self.msg = msg[0]
         self.tags = {}
 
         try:
             tags = msg[1:-1]
             for tag in tags:
-                tag = tag.strip().split("=")
+                tag = tag.strip().split('=')
                 self.tags[tag[0]] = tag[1]
         except:
             pass
@@ -87,7 +87,7 @@ class KernelLogMessage(object):
 
 class KernelLogReader(object):
     def __init__(self):
-        self.kmsg = os.open("/dev/kmsg", 0)
+        self.kmsg = os.open('/dev/kmsg', 0)
         flags = fcntl.fcntl(self.kmsg, fcntl.F_GETFL)
         fcntl.fcntl(self.kmsg, fcntl.F_SETFL, flags | os.O_NONBLOCK)
         os.lseek(self.kmsg, 0, os.SEEK_END)
@@ -100,7 +100,7 @@ class KernelLogReader(object):
         while True:
             try:
                 msg = os.read(self.kmsg, 8191)
-                msg = msg.decode("utf-8")
+                msg = msg.decode('utf-8')
             except OSError as e:
                 if e.errno == errno.EAGAIN:
                     break
@@ -113,7 +113,7 @@ class KernelLogReader(object):
 
 class Logger(object):
     def __init__(self, name):
-        self.logfile = open("%s.log" % name, "w")
+        self.logfile = open('%s.log' % name, 'w')
         self._kmsg = KernelLogReader()
 
     def __del__(self):
@@ -129,7 +129,7 @@ class Logger(object):
     def event(self):
         kmsgs = self._kmsg.read()
         for msg in kmsgs:
-            self.logfile.write("K [%6f] %s\n" % (msg.timestamp, msg.msg))
+            self.logfile.write('K [%6f] %s\n' % (msg.timestamp, msg.msg))
         self.logfile.flush()
 
     @property
@@ -146,13 +146,13 @@ class Logger(object):
         self.event()
 
         now = time.clock_gettime(time.CLOCK_MONOTONIC)
-        self.logfile.write("U [%6f] %s\n" % (now, msg))
+        self.logfile.write('U [%6f] %s\n' % (now, msg))
         self.logfile.flush()
 
 
 class CRC(object):
     def __init__(self, crc):
-        if crc.startswith("XXXXXXXXXX"):
+        if crc.startswith('XXXXXXXXXX'):
             self.frame = None
         else:
             self.frame = int(crc[:10], 16)
@@ -171,8 +171,8 @@ class CRCReader(object):
 
         # Hardcode the device minor to 0 as the KMSTest constructor opens the
         # default card object.
-        self.dir = os.open("/sys/kernel/debug/dri/0/crtc-%u/crc" % self.pipe, 0)
-        self.ctrl = os.open("control", os.O_WRONLY, dir_fd = self.dir)
+        self.dir = os.open('/sys/kernel/debug/dri/0/crtc-%u/crc' % self.pipe, 0)
+        self.ctrl = os.open('control', os.O_WRONLY, dir_fd = self.dir)
         self.data = -1
 
     def __del__(self):
@@ -181,8 +181,8 @@ class CRCReader(object):
         os.close(self.dir)
 
     def start(self, source):
-        os.write(self.ctrl, source.encode("ascii"))
-        self.data = os.open("data", os.O_RDONLY, dir_fd = self.dir)
+        os.write(self.ctrl, source.encode('ascii'))
+        self.data = os.open('data', os.O_RDONLY, dir_fd = self.dir)
 
     def stop(self):
         if self.data != -1:
@@ -194,7 +194,7 @@ class CRCReader(object):
         while len(crcs) < num_entries:
             try:
                 crc = os.read(self.data, CRCReader.MAX_LINE_LEN)
-                crc = crc.decode("ascii")
+                crc = crc.decode('ascii')
             except OSError as e:
                 if e.errno == errno.EAGAIN:
                     break
@@ -211,7 +211,7 @@ class Dist(object):
         self.y = y
 
     def __repr__(self):
-        return "(%d,%d)" % (self.x, self.y)
+        return '(%d,%d)' % (self.x, self.y)
 
 
 class Point(object):
@@ -220,7 +220,7 @@ class Point(object):
         self.y = y
 
     def __repr__(self):
-        return "(%d,%d)" % (self.x, self.y)
+        return '(%d,%d)' % (self.x, self.y)
 
     def move(self, distance):
         self.x += distance.x
@@ -233,7 +233,7 @@ class Size(object):
         self.height = height
 
     def __repr__(self):
-        return "%ux%u" % (self.width, self.height)
+        return '%ux%u' % (self.width, self.height)
 
 
 class Rect(object):
@@ -244,7 +244,7 @@ class Rect(object):
         self.height = height
 
     def __repr__(self):
-        return "(%d,%d)/%ux%u" % (self.left, self.top, self.width, self.height)
+        return '(%d,%d)/%ux%u' % (self.left, self.top, self.width, self.height)
 
     def isEmpty(self):
         """Check if the rectangle has a zero width or height"""
@@ -387,7 +387,7 @@ class KMSTest(object):
 
     def atomic_plane_disable(self, plane, sync=True):
         req = AtomicRequest(self)
-        req.add(plane, { "FB_ID": 0, 'CRTC_ID': 0 })
+        req.add(plane, { 'FB_ID': 0, 'CRTC_ID': 0 })
 
         if sync:
             return req.commit_sync()
@@ -397,7 +397,7 @@ class KMSTest(object):
     def atomic_planes_disable(self, sync=True):
         req = AtomicRequest(self)
         for plane in self.card.planes:
-            req.add(plane, { "FB_ID": 0, 'CRTC_ID': 0 })
+            req.add(plane, { 'FB_ID': 0, 'CRTC_ID': 0 })
 
         if sync:
             return req.commit_sync()
@@ -462,32 +462,32 @@ class KMSTest(object):
     def start(self, name):
         """Start a test."""
         self.test_name = name
-        self.logger.log("Testing %s" % name)
-        sys.stdout.write("Testing %s: " % name)
+        self.logger.log('Testing %s' % name)
+        sys.stdout.write('Testing %s: ' % name)
         sys.stdout.flush()
 
     def progress(self, current, maximum):
-        sys.stdout.write("\rTesting %s: %u/%u" % (self.test_name, current, maximum))
+        sys.stdout.write('\rTesting %s: %u/%u' % (self.test_name, current, maximum))
         sys.stdout.flush()
 
     def fail(self, reason):
         """Complete a test with failure."""
-        self.logger.log("Test failed. Reason: %s" % reason)
+        self.logger.log('Test failed. Reason: %s' % reason)
         self.logger.flush()
-        sys.stdout.write("\rTesting %s: FAIL\n" % self.test_name)
+        sys.stdout.write('\rTesting %s: FAIL\n' % self.test_name)
         sys.stdout.flush()
 
     def skip(self, reason):
         """Complete a test with skip."""
-        self.logger.log("Test skipped. Reason: %s" % reason)
+        self.logger.log('Test skipped. Reason: %s' % reason)
         self.logger.flush()
-        sys.stdout.write("SKIP\n")
+        sys.stdout.write('SKIP\n')
         sys.stdout.flush()
 
     def success(self):
         """Complete a test with success."""
-        self.logger.log("Test completed successfully")
+        self.logger.log('Test completed successfully')
         self.logger.flush()
-        sys.stdout.write("\rTesting %s: SUCCESS\n" % self.test_name)
+        sys.stdout.write('\rTesting %s: SUCCESS\n' % self.test_name)
         sys.stdout.flush()
 
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 02/10] tests: Convert to formatted string literals
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
  2022-06-09 23:40 ` [kms-test] [PATCH 01/10] tests: Replace double quotes with single quotes Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:28   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 03/10] tests: allplanes: Log the plane IDs Laurent Pinchart
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Use formatted string literals to replace legacy printf-style string
formatting.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kms-test-allplanes.py      | 12 ++++++------
 tests/kms-test-brxalloc.py       | 28 +++++++++++++---------------
 tests/kms-test-connectors.py     |  2 +-
 tests/kms-test-crc.py            | 21 ++++++++++-----------
 tests/kms-test-formats.py        | 10 +++++-----
 tests/kms-test-legacy-modeset.py | 10 +++++-----
 tests/kms-test-modes.py          |  8 ++++----
 tests/kms-test-modeset.py        |  8 ++++----
 tests/kms-test-pageflip.py       | 18 +++++++++---------
 tests/kms-test-planeposition.py  | 16 ++++++++--------
 tests/kms-test-routing.py        | 10 +++++-----
 tests/kmstest.py                 | 30 +++++++++++++++---------------
 12 files changed, 85 insertions(+), 88 deletions(-)

diff --git a/tests/kms-test-allplanes.py b/tests/kms-test-allplanes.py
index 710ae660f0ff..0fe6cfab0a2d 100755
--- a/tests/kms-test-allplanes.py
+++ b/tests/kms-test-allplanes.py
@@ -25,7 +25,7 @@ class AllPlanesTest(kmstest.KMSTest):
                     connectors[crtc] = connector
 
         for crtc in self.card.crtcs:
-            self.start('composition on CRTC %u' % crtc.id)
+            self.start(f'composition on CRTC {crtc.id}')
 
             # Get the connector and default mode
             try:
@@ -45,8 +45,8 @@ class AllPlanesTest(kmstest.KMSTest):
                 self.skip('no plane available for CRTC')
                 continue
 
-            self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
-                  (connector.fullname, crtc.id, mode.name, len(planes)))
+            self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
+                            f'mode {mode.name} with {len(planes)} planes')
 
             # Create a frame buffer
             fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
@@ -55,7 +55,7 @@ class AllPlanesTest(kmstest.KMSTest):
             # Set the mode with a primary plane
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
             if ret < 0:
-                self.fail('atomic mode set failed with %d' % ret)
+                self.fail(f'atomic mode set failed with {ret}')
                 continue
 
             self.run(3)
@@ -67,10 +67,10 @@ class AllPlanesTest(kmstest.KMSTest):
                 destination = kmstest.Rect(offset, offset, fb.width, fb.height)
                 ret = self.atomic_plane_set(plane, crtc, source, destination, fb)
                 if ret < 0:
-                    self.fail('atomic plane set failed with %d' % ret)
+                    self.fail(f'atomic plane set failed with {ret}')
                     break
 
-                self.logger.log('Adding plane %u' % plane.id)
+                self.logger.log(f'Adding plane {plane.id}')
                 self.run(1)
 
                 if self.flips == 0:
diff --git a/tests/kms-test-brxalloc.py b/tests/kms-test-brxalloc.py
index af6dd49f5c59..7170ee6c7708 100755
--- a/tests/kms-test-brxalloc.py
+++ b/tests/kms-test-brxalloc.py
@@ -38,12 +38,11 @@ class BRxAllocTest(kmstest.KMSTest):
         # Verify that the two CRTCs share the same planes
         planes = outputs[0].crtc.possible_planes
         if planes != outputs[1].crtc.possible_planes:
-            self.skip('Planes differ for CRTCs %u and %u' % \
-                      (outputs[0].crtc.id, outputs[1].crtc.id))
+            self.skip(f'Planes differ for CRTCs {outputs[0].crtc.id} and {outputs[1].crtc.id}')
             return
 
-        self.logger.log('Found %u planes for CRTCs %u and %u' % \
-                        (len(planes), outputs[0].crtc.id, outputs[1].crtc.id))
+        self.logger.log(f'Found {len(planes)} planes for CRTCs {outputs[0].crtc.id} '
+                        f'and {outputs[1].crtc.id}')
 
         # Get one connector for each CRTC
         for connector in self.output_connectors():
@@ -58,12 +57,12 @@ class BRxAllocTest(kmstest.KMSTest):
                     outputs[1].connector = connector
 
         if not outputs[0].connector or not outputs[1].connector:
-            self.skip('No connected connectors for CRTCs %u and %u ' % \
-                      (outputs[0].crtc.id, outputs[1].crtc.id))
+            self.skip(f'No connected connectors for CRTCs {outputs[0].crtc.id} '
+                      f'and {outputs[1].crtc.id}')
             return
 
-        self.start('Moving %u planes from %s to %s' % \
-                   (len(planes), outputs[0].connector.fullname, outputs[1].connector.fullname))
+        self.start(f'Moving {len(planes)} planes from {outputs[0].connector.fullname} '
+                   f'to {outputs[0].connector.fullname}')
 
         # Set the initial mode for both outputs and wait 5s for the monitors to
         # wake up.
@@ -76,8 +75,7 @@ class BRxAllocTest(kmstest.KMSTest):
             # Set the mode with no plane
             ret = self.atomic_crtc_mode_set(output.crtc, output.connector, mode, sync=True)
             if ret < 0:
-                self.fail('atomic mode set on %s failed with %d' % \
-                          (output.connector.fullname, ret))
+                self.fail(f'atomic mode set on {output.connector.fullname} failed with {ret}')
                 return
 
         self.logger.log('Initial atomic mode set completed')
@@ -88,13 +86,13 @@ class BRxAllocTest(kmstest.KMSTest):
         output = outputs[0]
 
         for plane in planes:
-            self.logger.log('Adding plane %u to %s' % (plane.id, output.connector.fullname))
+            self.logger.log(f'Adding plane {plane.id} to {output.connector.fullname}')
 
             source = kmstest.Rect(0, 0, output.fb.width, output.fb.height)
             destination = kmstest.Rect(offset, offset, output.fb.width, output.fb.height)
             ret = self.atomic_plane_set(plane, output.crtc, source, destination, output.fb, sync=True)
             if ret < 0:
-                self.fail('atomic plane set failed with %d' % ret)
+                self.fail(f'atomic plane set failed with {ret}')
                 return
 
             offset += 50
@@ -106,20 +104,20 @@ class BRxAllocTest(kmstest.KMSTest):
         output = outputs[1]
 
         for plane in planes:
-            self.logger.log('Moving plane %u to %s' % (plane.id, output.connector.fullname))
+            self.logger.log(f'Moving plane {plane.id} to {output.connector.fullname}')
 
             # Switching CRTC directly is not supported by DRM, start by
             # disabling the plane.
             ret = self.atomic_plane_disable(plane)
             if ret < 0:
-                self.fail('atomic plane disable failed with %d' % ret)
+                self.fail(f'atomic plane disable failed with {ret}')
                 return
 
             source = kmstest.Rect(0, 0, output.fb.width, output.fb.height)
             destination = kmstest.Rect(offset, offset, output.fb.width, output.fb.height)
             ret = self.atomic_plane_set(plane, output.crtc, source, destination, output.fb)
             if ret < 0:
-                self.fail('atomic plane set failed with %d' % ret)
+                self.fail(f'atomic plane set failed with {ret}')
                 return
 
             self.run(1)
diff --git a/tests/kms-test-connectors.py b/tests/kms-test-connectors.py
index 54cc89ff308e..d2ca636eb2a0 100755
--- a/tests/kms-test-connectors.py
+++ b/tests/kms-test-connectors.py
@@ -10,7 +10,7 @@ class ConnectorsTest(kmstest.KMSTest):
 
     def main(self):
         for connector in self.card.connectors:
-            self.start('connector %s' % connector.fullname)
+            self.start(f'connector {connector.fullname}')
 
             # Every connector should have at least one suitable CRTC
             crtcs = connector.get_possible_crtcs()
diff --git a/tests/kms-test-crc.py b/tests/kms-test-crc.py
index 5b8a679ffadc..efb3cf0dbe41 100755
--- a/tests/kms-test-crc.py
+++ b/tests/kms-test-crc.py
@@ -121,7 +121,7 @@ class CRCTest(kmstest.KMSTest):
                     connectors[crtc] = connector
 
         for crtc in self.card.crtcs:
-            self.start('CRC calculation on CRTC %u' % crtc.id)
+            self.start(f'CRC calculation on CRTC {crtc.id}')
 
             # Get the connector and default mode
             try:
@@ -141,8 +141,8 @@ class CRCTest(kmstest.KMSTest):
                 self.skip('no plane available for CRTC')
                 continue
 
-            self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
-                  (connector.fullname, crtc.id, mode.name, len(planes)))
+            self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
+                            f'mode {mode.name} with {len(planes)} planes')
 
             # Create a frame buffer and draw a test pattern.
             fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
@@ -154,7 +154,7 @@ class CRCTest(kmstest.KMSTest):
             # Set the mode and add all planes
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
             if ret < 0:
-                self.fail('atomic mode set failed with %d' % ret)
+                self.fail(f'atomic mode set failed with {ret}')
                 continue
 
             req = kmstest.AtomicRequest(self)
@@ -177,7 +177,7 @@ class CRCTest(kmstest.KMSTest):
 
             ret = req.commit(0)
             if ret < 0:
-                self.fail('atomic plane set failed with %d' % ret)
+                self.fail(f'atomic plane set failed with {ret}')
                 continue
 
             # Wait for one second and make sure the page flip has completed.
@@ -191,9 +191,9 @@ class CRCTest(kmstest.KMSTest):
                 if source == crtc:
                     crc_source = 'auto'
                 else:
-                    crc_source = 'plane%u' % source.id
+                    crc_source = f'plane{source.id}'
 
-                self.logger.log('Computing CRC from source %s' % crc_source)
+                self.logger.log(f'Computing CRC from source {crc_source}')
 
                 # Set the CRC source and acquire 10 CRC values. Discard the
                 # first value, as the device is running and the new source
@@ -204,7 +204,7 @@ class CRCTest(kmstest.KMSTest):
                 crc_reader.stop()
 
                 crcs = [c.crcs[0] for c in crcs[1:]]
-                self.logger.log('CRC value[0] 0x%08x' % crcs[0])
+                self.logger.log(f'CRC value[0] 0x{crcs[0]:08x}')
 
                 failures = 0
                 ref_crc = composer.crc(source)
@@ -212,12 +212,11 @@ class CRCTest(kmstest.KMSTest):
                 for i in range(len(crcs)):
                     crc = crcs[i]
                     if crc != ref_crc:
-                        self.logger.log('CRC value[%u] 0x%08x does not match reference 0x%08x'
-                                        % (i, crc, ref_crc))
+                        self.logger.log(f'CRC value[{i}] 0x{crc:08x} does not match reference 0x{ref_crc:08x}')
                         failures += 1
 
                 if failures:
-                    self.fail('Incorrect CRC values on source %s' % crc_source)
+                    self.fail(f'Incorrect CRC values on source {crc_source}')
                     break
 
             else:
diff --git a/tests/kms-test-formats.py b/tests/kms-test-formats.py
index ce849437b2fa..5c3bfd441a38 100755
--- a/tests/kms-test-formats.py
+++ b/tests/kms-test-formats.py
@@ -37,8 +37,8 @@ class FormatsTest(kmstest.KMSTest):
             self.skip('no CRTC available with connector')
             return
 
-        self.logger.log('Testing connector %s, CRTC %u, mode %s' % \
-              (connector.fullname, crtc.id, mode.name))
+        self.logger.log(f'Testing connector {connector.fullname}, '
+                        f'CRTC {crtc.id}, mode {mode.name}')
 
         failed = 0
 
@@ -46,7 +46,7 @@ class FormatsTest(kmstest.KMSTest):
         for i in range(num_formats):
             format = crtc.primary_plane.formats[i]
 
-            self.logger.log('Testing format %s' % format)
+            self.logger.log(f'Testing format {format}')
             self.progress(i+1, num_formats)
 
             # Create a frame buffer
@@ -62,7 +62,7 @@ class FormatsTest(kmstest.KMSTest):
             # Set the mode with a primary plane
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
             if ret < 0:
-                self.logger.log('atomic mode set failed with %d' % ret)
+                self.logger.log(f'atomic mode set failed with {ret}')
                 failed += 1
                 continue
 
@@ -71,7 +71,7 @@ class FormatsTest(kmstest.KMSTest):
         self.atomic_crtc_disable(crtc)
 
         if failed:
-            self.fail('%s/%s formats failed' % (failed, num_formats))
+            self.fail(f'{failed}/{num_formats} formats failed')
         else:
             self.success()
 
diff --git a/tests/kms-test-legacy-modeset.py b/tests/kms-test-legacy-modeset.py
index f856178172c0..06eceade19c4 100755
--- a/tests/kms-test-legacy-modeset.py
+++ b/tests/kms-test-legacy-modeset.py
@@ -13,7 +13,7 @@ class LegacyModeSetTest(kmstest.KMSTest):
 
     def main(self):
         for connector in self.output_connectors():
-            self.start('legacy mode set on connector %s' % connector.fullname)
+            self.start(f'legacy mode set on connector {connector.fullname}')
 
             # Skip disconnected connectors
             if not connector.connected():
@@ -36,8 +36,8 @@ class LegacyModeSetTest(kmstest.KMSTest):
                 self.skip('no mode available')
                 continue
 
-            self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
-                  (connector.fullname, crtc.id, mode.name))
+            self.logger.log(f'Testing connector {connector.fullname} '
+                            f'on CRTC {crtc.id} with mode {mode.name}')
 
             # Create a frame buffer
             fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
@@ -46,7 +46,7 @@ class LegacyModeSetTest(kmstest.KMSTest):
             # Perform a mode set
             ret = crtc.set_mode(connector, fb, mode)
             if ret < 0:
-                self.fail('legacy mode set failed with %d' % ret)
+                self.fail(f'legacy mode set failed with {ret}')
                 continue
 
             self.logger.log('Legacy mode set complete')
@@ -54,7 +54,7 @@ class LegacyModeSetTest(kmstest.KMSTest):
 
             ret = crtc.disable_mode()
             if ret < 0:
-                self.fail('legacy mode set disable failed with %d' % ret)
+                self.fail(f'legacy mode set disable failed with {ret}')
                 continue
 
             self.success()
diff --git a/tests/kms-test-modes.py b/tests/kms-test-modes.py
index 433bb0bdd157..c47848904ec4 100755
--- a/tests/kms-test-modes.py
+++ b/tests/kms-test-modes.py
@@ -12,8 +12,8 @@ class ModesTest(kmstest.KMSTest):
         self.logger.log('Page flip complete')
 
     def test_mode(self, connector, crtc, mode):
-        self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
-              (connector.fullname, crtc.id, mode.name))
+        self.logger.log(f'Testing connector {connector.fullname} '
+                        f'on CRTC {crtc.id} with mode {mode.name}')
 
         # Create a frame buffer
         fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
@@ -22,7 +22,7 @@ class ModesTest(kmstest.KMSTest):
         # Perform the mode set
         ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
         if ret < 0:
-            raise RuntimeError('atomic mode set failed with %d' % ret)
+            raise RuntimeError(f'atomic mode set failed with {ret}')
 
         self.logger.log('Atomic mode set complete')
         self.run(4)
@@ -33,7 +33,7 @@ class ModesTest(kmstest.KMSTest):
 
     def main(self):
         for connector in self.output_connectors():
-            self.start('modes on connector %s' % connector.fullname)
+            self.start(f'modes on connector {connector.fullname}')
 
             # Skip disconnected connectors
             if not connector.connected():
diff --git a/tests/kms-test-modeset.py b/tests/kms-test-modeset.py
index a6ba61c920e5..e8b3d9ac37f9 100755
--- a/tests/kms-test-modeset.py
+++ b/tests/kms-test-modeset.py
@@ -13,7 +13,7 @@ class ModeSetTest(kmstest.KMSTest):
 
     def main(self):
         for connector in self.output_connectors():
-            self.start('atomic mode set on connector %s' % connector.fullname)
+            self.start(f'atomic mode set on connector {connector.fullname}')
 
             # Skip disconnected connectors
             if not connector.connected():
@@ -36,8 +36,8 @@ class ModeSetTest(kmstest.KMSTest):
                 self.skip('no mode available')
                 continue
 
-            self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
-                  (connector.fullname, crtc.id, mode.name))
+            self.logger.log(f'Testing connector {connector.fullname} '
+                            f'on CRTC {crtc.id} with mode {mode.name}')
 
             # Create a frame buffer
             fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
@@ -46,7 +46,7 @@ class ModeSetTest(kmstest.KMSTest):
             # Perform a mode set
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
             if ret < 0:
-                self.fail('atomic mode set failed with %d' % ret)
+                self.fail(f'atomic mode set failed with {ret}')
                 continue
 
             self.logger.log('Atomic mode set complete')
diff --git a/tests/kms-test-pageflip.py b/tests/kms-test-pageflip.py
index 15dae6a23ab3..14bea0a877a3 100755
--- a/tests/kms-test-pageflip.py
+++ b/tests/kms-test-pageflip.py
@@ -13,12 +13,12 @@ class PageFlipTest(kmstest.KMSTest):
 
     def handle_page_flip(self, frame, time):
         if self.flips == 1:
-            self.logger.log('first page flip frame %u time %f' % (frame, time))
+            self.logger.log(f'first page flip frame {frame} time {time}')
             self.frame_start = frame
             self.time_start = time
 
         if self.stop_requested:
-            self.logger.log('last page flip frame %u time %f' % (frame, time))
+            self.logger.log(f'last page flip frame {frame} time {time}')
             self.frame_end = frame
             self.time_end = time
             self.loop.stop()
@@ -43,7 +43,7 @@ class PageFlipTest(kmstest.KMSTest):
 
     def main(self):
         for connector in self.output_connectors():
-            self.start('page flip on connector %s' % connector.fullname)
+            self.start(f'page flip on connector {connector.fullname}')
 
             # Skip disconnected connectors
             if not connector.connected():
@@ -67,7 +67,7 @@ class PageFlipTest(kmstest.KMSTest):
                     self.plane = plane
                     break
             else:
-                self.skip('no plane available for CRTC %u' % crtc.id)
+                self.skip(f'no plane available for CRTC {crtc.id}')
                 continue
 
             # Get the default mode for the connector
@@ -77,8 +77,8 @@ class PageFlipTest(kmstest.KMSTest):
                 self.skip('no mode available')
                 continue
 
-            self.logger.log('Testing connector %s, CRTC %u, plane %u, mode %s' % \
-                  (connector.fullname, crtc.id, self.plane.id, mode.name))
+            self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
+                            f'plane {self.plane.id}, mode {mode.name}')
 
             # Create two frame buffers
             self.fbs = []
@@ -88,7 +88,7 @@ class PageFlipTest(kmstest.KMSTest):
             # Set the mode and perform the initial page flip
             ret = self.atomic_crtc_mode_set(crtc, connector, mode, self.fbs[0])
             if ret < 0:
-                self.fail('atomic mode set failed with %d' % ret)
+                self.fail(f'atomic mode set failed with {ret}')
                 continue
 
             # Flip pages for 10s
@@ -114,8 +114,8 @@ class PageFlipTest(kmstest.KMSTest):
 
             frames = self.frame_end - self.frame_start + 1
             interval = self.time_end - self.time_start
-            self.logger.log('Frame rate: %f (%u/%u frames in %f s)' % \
-                (frames / interval, self.flips, frames, interval))
+            self.logger.log(f'Frame rate: {frames / interval} '
+                            f'({self.flips}/{frames} frames in {interval} s)')
             self.success()
 
 PageFlipTest().execute()
diff --git a/tests/kms-test-planeposition.py b/tests/kms-test-planeposition.py
index e843ae13c50c..aceb849950a1 100755
--- a/tests/kms-test-planeposition.py
+++ b/tests/kms-test-planeposition.py
@@ -42,8 +42,8 @@ class PlanePositionTest(kmstest.KMSTest):
             self.skip('no CRTC available with connector and at least two planes')
             return
 
-        self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
-              (connector.fullname, crtc.id, mode.name, len(planes)))
+        self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
+                        f'mode {mode.name} with {len(planes)} planes')
 
         # Create a frame buffer
         fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
@@ -52,7 +52,7 @@ class PlanePositionTest(kmstest.KMSTest):
         # Set the mode with no plane, wait 5s for the monitor to wake up
         ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
         if ret < 0:
-            self.fail('atomic mode set failed with %d' % ret)
+            self.fail(f'atomic mode set failed with {ret}')
             return
 
         self.logger.log('Initial atomic mode set completed')
@@ -63,7 +63,7 @@ class PlanePositionTest(kmstest.KMSTest):
         destination = kmstest.Rect(0, 0, fb.width // 2, fb.height)
         ret = self.atomic_plane_set(planes[0], crtc, source, destination, fb, sync=True)
         if ret < 0:
-            self.fail('atomic plane set for first plane failed with %d' % ret)
+            self.fail(f'atomic plane set for first plane failed with {ret}')
             return
 
         self.logger.log('Root plane enabled')
@@ -79,10 +79,10 @@ class PlanePositionTest(kmstest.KMSTest):
 
             ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
             if ret < 0:
-                self.fail('atomic plane set with offset %d,%d' % offset)
+                self.fail(f'atomic plane set with offset {offset}')
                 return
 
-            self.logger.log('Moved overlay plane to %d,%d' % offset)
+            self.logger.log(f'Moved overlay plane to {offset}')
             time.sleep(3)
 
         # Try to move the plane completely off-screen. The device is expected
@@ -97,10 +97,10 @@ class PlanePositionTest(kmstest.KMSTest):
 
             ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
             if ret < 0:
-                self.fail('atomic plane set with offset %d,%d' % offset)
+                self.fail(f'atomic plane set with offset {offset}')
                 return
 
-            self.logger.log('Moved overlay plane to %d,%d' % offset)
+            self.logger.log(f'Moved overlay plane to {offset}')
             time.sleep(3)
 
         # Disable and re-enable the plane when it is off-screen. The device is
diff --git a/tests/kms-test-routing.py b/tests/kms-test-routing.py
index 69f8be127d2f..68aff9c11cff 100755
--- a/tests/kms-test-routing.py
+++ b/tests/kms-test-routing.py
@@ -64,10 +64,10 @@ class RoutingTest(kmstest.KMSTest):
         fb = pykms.DumbFramebuffer(self.card, max_hdisplay, max_vdisplay, 'XR24')
         pykms.draw_test_pattern(fb)
 
-        self.start('Moving connector %s between CRTCs %s' % \
-                   (shared_connector.fullname, [pipe.crtc.id for pipe in pipes]))
+        self.start(f'Moving connector {shared_connector.fullname} '
+                   f'between CRTCs {[pipe.crtc.id for pipe in pipes]}')
 
-        self.logger.log('Highest display resolution: %ux%u' % (max_hdisplay, max_vdisplay))
+        self.logger.log(f'Highest display resolution: {max_hdisplay}x{max_vdisplay}')
 
         for master_pipe in pipes:
             req = kmstest.AtomicRequest(self)
@@ -97,13 +97,13 @@ class RoutingTest(kmstest.KMSTest):
                             'CRTC_H': mode.vdisplay,
                         })
 
-                route.append('CRTC %u to connector %s' % (pipe.crtc.id, pipe.connector.fullname))
+                route.append(f'CRTC {pipe.crtc.id} to connector {pipe.connector.fullname}')
 
             self.logger.log('Routing ' + ', '.join(route))
 
             ret = req.commit_sync(True)
             if ret < 0:
-                self.fail('atomic commit failed with %d' % ret)
+                self.fail(f'atomic commit failed with {ret}')
                 return
 
             time.sleep(5)
diff --git a/tests/kmstest.py b/tests/kmstest.py
index 708e6999d1f0..14e28cd47fbd 100755
--- a/tests/kmstest.py
+++ b/tests/kmstest.py
@@ -113,7 +113,7 @@ class KernelLogReader(object):
 
 class Logger(object):
     def __init__(self, name):
-        self.logfile = open('%s.log' % name, 'w')
+        self.logfile = open(f'{name}.log', 'w')
         self._kmsg = KernelLogReader()
 
     def __del__(self):
@@ -129,7 +129,7 @@ class Logger(object):
     def event(self):
         kmsgs = self._kmsg.read()
         for msg in kmsgs:
-            self.logfile.write('K [%6f] %s\n' % (msg.timestamp, msg.msg))
+            self.logfile.write(f'K [{msg.timestamp:6f} {msg.msg}\n')
         self.logfile.flush()
 
     @property
@@ -146,7 +146,7 @@ class Logger(object):
         self.event()
 
         now = time.clock_gettime(time.CLOCK_MONOTONIC)
-        self.logfile.write('U [%6f] %s\n' % (now, msg))
+        self.logfile.write(f'U [{now:6f}] {msg}\n')
         self.logfile.flush()
 
 
@@ -171,7 +171,7 @@ class CRCReader(object):
 
         # Hardcode the device minor to 0 as the KMSTest constructor opens the
         # default card object.
-        self.dir = os.open('/sys/kernel/debug/dri/0/crtc-%u/crc' % self.pipe, 0)
+        self.dir = os.open('f/sys/kernel/debug/dri/0/crtc-{self.pipe}/crc', 0)
         self.ctrl = os.open('control', os.O_WRONLY, dir_fd = self.dir)
         self.data = -1
 
@@ -211,7 +211,7 @@ class Dist(object):
         self.y = y
 
     def __repr__(self):
-        return '(%d,%d)' % (self.x, self.y)
+        return f'({self.x},{self.y})'
 
 
 class Point(object):
@@ -220,7 +220,7 @@ class Point(object):
         self.y = y
 
     def __repr__(self):
-        return '(%d,%d)' % (self.x, self.y)
+        return f'({self.x},{self.y})'
 
     def move(self, distance):
         self.x += distance.x
@@ -233,7 +233,7 @@ class Size(object):
         self.height = height
 
     def __repr__(self):
-        return '%ux%u' % (self.width, self.height)
+        return f'{self.width}x{self.height}'
 
 
 class Rect(object):
@@ -244,7 +244,7 @@ class Rect(object):
         self.height = height
 
     def __repr__(self):
-        return '(%d,%d)/%ux%u' % (self.left, self.top, self.width, self.height)
+        return f'({self.left},{self.top})/{self.width}x{self.height}'
 
     def isEmpty(self):
         """Check if the rectangle has a zero width or height"""
@@ -462,24 +462,24 @@ class KMSTest(object):
     def start(self, name):
         """Start a test."""
         self.test_name = name
-        self.logger.log('Testing %s' % name)
-        sys.stdout.write('Testing %s: ' % name)
+        self.logger.log(f'Testing {name}')
+        sys.stdout.write(f'Testing {name}: ')
         sys.stdout.flush()
 
     def progress(self, current, maximum):
-        sys.stdout.write('\rTesting %s: %u/%u' % (self.test_name, current, maximum))
+        sys.stdout.write(f'\rTesting {self.test_name}: {current}/{maximum}')
         sys.stdout.flush()
 
     def fail(self, reason):
         """Complete a test with failure."""
-        self.logger.log('Test failed. Reason: %s' % reason)
+        self.logger.log(f'Test failed. Reason: {reason}')
         self.logger.flush()
-        sys.stdout.write('\rTesting %s: FAIL\n' % self.test_name)
+        sys.stdout.write(f'\rTesting {self.test_name}: FAIL\n')
         sys.stdout.flush()
 
     def skip(self, reason):
         """Complete a test with skip."""
-        self.logger.log('Test skipped. Reason: %s' % reason)
+        self.logger.log(f'Test skipped. Reason: {reason}')
         self.logger.flush()
         sys.stdout.write('SKIP\n')
         sys.stdout.flush()
@@ -488,6 +488,6 @@ class KMSTest(object):
         """Complete a test with success."""
         self.logger.log('Test completed successfully')
         self.logger.flush()
-        sys.stdout.write('\rTesting %s: SUCCESS\n' % self.test_name)
+        sys.stdout.write(f'\rTesting {self.test_name}: SUCCESS\n')
         sys.stdout.flush()
 
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 03/10] tests: allplanes: Log the plane IDs
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
  2022-06-09 23:40 ` [kms-test] [PATCH 01/10] tests: Replace double quotes with single quotes Laurent Pinchart
  2022-06-09 23:40 ` [kms-test] [PATCH 02/10] tests: Convert to formatted string literals Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:30   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 04/10] kmstest: Move props value formatting to AtomicRequest Laurent Pinchart
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Plane IDs are useful for debugging, log them.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kms-test-allplanes.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/kms-test-allplanes.py b/tests/kms-test-allplanes.py
index 0fe6cfab0a2d..96ac4f19f538 100755
--- a/tests/kms-test-allplanes.py
+++ b/tests/kms-test-allplanes.py
@@ -46,7 +46,8 @@ class AllPlanesTest(kmstest.KMSTest):
                 continue
 
             self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
-                            f'mode {mode.name} with {len(planes)} planes')
+                            f'mode {mode.name} with {len(planes)} planes '
+                            f'(P: {crtc.primary_plane.id}, O: {[plane.id for plane in planes]})')
 
             # Create a frame buffer
             fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 04/10] kmstest: Move props value formatting to AtomicRequest
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
                   ` (2 preceding siblings ...)
  2022-06-09 23:40 ` [kms-test] [PATCH 03/10] tests: allplanes: Log the plane IDs Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:36   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 05/10] kmstest: Support specifying property values in percents Laurent Pinchart
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Centralize props value formatting in the AtomicRequest.add() function to
avoid having to call it manually through the code base.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kmstest.py | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/tests/kmstest.py b/tests/kmstest.py
index 14e28cd47fbd..2afaa513aa4d 100755
--- a/tests/kmstest.py
+++ b/tests/kmstest.py
@@ -258,15 +258,20 @@ class AtomicRequest(pykms.AtomicReq):
         self.__test = test
         self.__props = {}
 
+    def __format_props(self, props):
+        return {k: v & ((1 << 64) - 1) for k, v in props.items()}
+
     def add(self, obj, *kwargs):
         if obj.id not in self.__props:
             self.__props[obj.id] = {}
-        props = self.__props[obj.id]
+        obj_props = self.__props[obj.id]
 
         if len(kwargs) == 1 and isinstance(kwargs[0], collections.abc.Mapping):
-            props.update(kwargs[0])
+            props = self.__format_props(kwargs[0])
         elif len(kwargs) == 2:
-            props[kwargs[0]] = kwargs[1]
+            props = self.__format_props({ kwargs[0]: = kwargs[1] })
+
+        obj_props.update(props)
 
         super().add(obj, *kwargs)
 
@@ -309,9 +314,6 @@ class KMSTest(object):
     def __del__(self):
         self.logger.close()
 
-    def __format_props(self, props):
-        return {k: v & ((1 << 64) - 1) for k, v in props.items()}
-
     def atomic_crtc_disable(self, crtc, sync=True):
         req = AtomicRequest(self)
         req.add(crtc, {'ACTIVE': 0, 'MODE_ID': 0})
@@ -368,7 +370,7 @@ class KMSTest(object):
 
     def atomic_plane_set(self, plane, crtc, source, destination, fb, sync=False):
         req = AtomicRequest(self)
-        req.add(plane, self.__format_props({
+        req.add(plane, {
                     'FB_ID': fb.id,
                     'CRTC_ID': crtc.id,
                     'SRC_X': int(source.left * 65536),
@@ -379,7 +381,7 @@ class KMSTest(object):
                     'CRTC_Y': destination.top,
                     'CRTC_W': destination.width,
                     'CRTC_H': destination.height,
-        }))
+        })
         if sync:
             return req.commit_sync()
         else:
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 05/10] kmstest: Support specifying property values in percents
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
                   ` (3 preceding siblings ...)
  2022-06-09 23:40 ` [kms-test] [PATCH 04/10] kmstest: Move props value formatting to AtomicRequest Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:39   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 06/10] kmstest: Support specifying alpha value for planes Laurent Pinchart
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

If the property is a string that ends with a '%' character, treat it as
a percentage of the range reported by the property and convert it to the
corresponding numerical value.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kmstest.py | 27 ++++++++++++++++++++++-----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/tests/kmstest.py b/tests/kmstest.py
index 2afaa513aa4d..a99bf3b89d34 100755
--- a/tests/kmstest.py
+++ b/tests/kmstest.py
@@ -258,8 +258,25 @@ class AtomicRequest(pykms.AtomicReq):
         self.__test = test
         self.__props = {}
 
-    def __format_props(self, props):
-        return {k: v & ((1 << 64) - 1) for k, v in props.items()}
+    def __format_props(self, obj, props):
+        out = {}
+        for k, v in props.items():
+            if isinstance(v, str):
+                if v.endswith('%'):
+                    prop = obj.get_prop(k)
+                    if prop.type not in (pykms.PropertyType.Range, pykms.PropertyType.SignedRange):
+                        raise RuntimeError(f'Unsupported property type {prop.type} for value {v}')
+
+                    min, max = prop.values
+                    v = min + int((max - min) * int(v[:-1]) / 100)
+                else:
+                    v = int(v)
+
+            if not isinstance(v, int):
+                raise RuntimeError(f'Unsupported value type {type(v)} for property {k}')
+
+            out[k] = v & ((1 << 64) - 1)
+        return out
 
     def add(self, obj, *kwargs):
         if obj.id not in self.__props:
@@ -267,13 +284,13 @@ class AtomicRequest(pykms.AtomicReq):
         obj_props = self.__props[obj.id]
 
         if len(kwargs) == 1 and isinstance(kwargs[0], collections.abc.Mapping):
-            props = self.__format_props(kwargs[0])
+            props = self.__format_props(obj, kwargs[0])
         elif len(kwargs) == 2:
-            props = self.__format_props({ kwargs[0]: = kwargs[1] })
+            props = self.__format_props(obj, { kwargs[0]: kwargs[1] })
 
         obj_props.update(props)
 
-        super().add(obj, *kwargs)
+        super().add(obj, props)
 
     def commit(self, data=0, allow_modeset=False):
         ret = super().commit(data, allow_modeset)
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 06/10] kmstest: Support specifying alpha value for planes
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
                   ` (4 preceding siblings ...)
  2022-06-09 23:40 ` [kms-test] [PATCH 05/10] kmstest: Support specifying property values in percents Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:45   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 07/10] tests: Add plane alpha test Laurent Pinchart
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Add an optional alpha argument to the atomic_plane_set() function to
specify the alpha value for the plane.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kmstest.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tests/kmstest.py b/tests/kmstest.py
index a99bf3b89d34..1c2a1b46ebe7 100755
--- a/tests/kmstest.py
+++ b/tests/kmstest.py
@@ -385,7 +385,7 @@ class KMSTest(object):
         else:
             return req.commit(0, True)
 
-    def atomic_plane_set(self, plane, crtc, source, destination, fb, sync=False):
+    def atomic_plane_set(self, plane, crtc, source, destination, fb, alpha=None, sync=False):
         req = AtomicRequest(self)
         req.add(plane, {
                     'FB_ID': fb.id,
@@ -399,6 +399,8 @@ class KMSTest(object):
                     'CRTC_W': destination.width,
                     'CRTC_H': destination.height,
         })
+        if alpha is not None:
+            req.add(plane, 'alpha', alpha)
         if sync:
             return req.commit_sync()
         else:
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 07/10] tests: Add plane alpha test
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
                   ` (5 preceding siblings ...)
  2022-06-09 23:40 ` [kms-test] [PATCH 06/10] kmstest: Support specifying alpha value for planes Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:48   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 08/10] kmstest: Support specifying zpos value for planes Laurent Pinchart
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Add a test that enables multiple planes with different alpha values.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kms-test-plane-alpha.py | 97 +++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100755 tests/kms-test-plane-alpha.py

diff --git a/tests/kms-test-plane-alpha.py b/tests/kms-test-plane-alpha.py
new file mode 100755
index 000000000000..8802bfeae40c
--- /dev/null
+++ b/tests/kms-test-plane-alpha.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Renesas Electronics Corporation
+
+import kmstest
+import pykms
+
+class PlaneAlphaTest(kmstest.KMSTest):
+    """Test composition with multiple planes and alpha channels."""
+
+    def handle_page_flip(self, frame, time):
+        self.logger.log('Page flip complete')
+
+    def find_pipeline(self):
+        # Find a CRTC that has multiple planes with a connected connector
+        for connector in self.output_connectors():
+            # Skip disconnected connectors
+            if not connector.connected():
+                continue
+
+            # Add the connector to the map
+            for crtc in connector.get_possible_crtcs():
+                planes = []
+                for plane in self.card.planes:
+                    if plane.supports_crtc(crtc) and plane != crtc.primary_plane:
+                        planes.append(plane)
+
+                if len(planes):
+                    return crtc, connector, planes
+
+        return None, None, None
+
+    def main(self):
+        self.start('composition with alpha control')
+
+        crtc, connector, planes = self.find_pipeline()
+        if crtc is None:
+            self.skip('no suitable pipeline')
+            return
+
+        # Get the default mode
+        try:
+            mode = connector.get_default_mode()
+        except KeyError:
+            self.skip('no mode available')
+            return
+
+        self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
+                        f'mode {mode.name} with {len(planes)} planes '
+                        f'(P: {crtc.primary_plane.id}, O: {[plane.id for plane in planes]})')
+
+        # Create a frame buffer
+        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
+        pykms.draw_test_pattern(fb)
+
+        # Set the mode with a primary plane
+        ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
+        if ret < 0:
+            self.fail(f'atomic mode set failed with {ret}')
+            return
+
+        req = kmstest.AtomicRequest(self)
+        req.add(crtc.primary_plane, 'alpha', '50%')
+        ret = req.commit_sync(True)
+        if ret < 0:
+            self.fail(f'failed to set alpha for primary plane: {ret}')
+            return
+
+        self.run(3)
+
+        # Add all other planes one by one
+        alpha = 20
+        offset = 100
+        for plane in planes:
+            source = kmstest.Rect(0, 0, fb.width, fb.height)
+            destination = kmstest.Rect(offset, offset, fb.width, fb.height)
+            ret = self.atomic_plane_set(plane, crtc, source, destination, fb, alpha=f'{alpha}%')
+            if ret < 0:
+                self.fail(f'atomic plane set failed with {ret}')
+                break
+
+            self.logger.log(f'Adding plane {plane.id}')
+            self.run(1)
+
+            if self.flips == 0:
+                self.fail('No page flip registered')
+                break
+
+            alpha = min(alpha + 20, 100)
+            offset += 50
+
+        else:
+            self.success()
+
+        self.atomic_crtc_disable(crtc)
+
+PlaneAlphaTest().execute()
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 08/10] kmstest: Support specifying zpos value for planes
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
                   ` (6 preceding siblings ...)
  2022-06-09 23:40 ` [kms-test] [PATCH 07/10] tests: Add plane alpha test Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:48   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 09/10] tests: Add plane zpos test Laurent Pinchart
  2022-06-09 23:40 ` [kms-test] [PATCH 10/10] tests: Rename kms-test-planeposition.py to kms-test-plane-position.py Laurent Pinchart
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Add an optional zpos argument to the atomic_plane_set() function to
allow controlling the zpos of a plane.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kmstest.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tests/kmstest.py b/tests/kmstest.py
index 1c2a1b46ebe7..11cc328b5b32 100755
--- a/tests/kmstest.py
+++ b/tests/kmstest.py
@@ -385,7 +385,7 @@ class KMSTest(object):
         else:
             return req.commit(0, True)
 
-    def atomic_plane_set(self, plane, crtc, source, destination, fb, alpha=None, sync=False):
+    def atomic_plane_set(self, plane, crtc, source, destination, fb, alpha=None, zpos=None, sync=False):
         req = AtomicRequest(self)
         req.add(plane, {
                     'FB_ID': fb.id,
@@ -401,6 +401,8 @@ class KMSTest(object):
         })
         if alpha is not None:
             req.add(plane, 'alpha', alpha)
+        if zpos is not None:
+            req.add(plane, 'zpos', zpos)
         if sync:
             return req.commit_sync()
         else:
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 09/10] tests: Add plane zpos test
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
                   ` (7 preceding siblings ...)
  2022-06-09 23:40 ` [kms-test] [PATCH 08/10] kmstest: Support specifying zpos value for planes Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:52   ` Kieran Bingham
  2022-06-09 23:40 ` [kms-test] [PATCH 10/10] tests: Rename kms-test-planeposition.py to kms-test-plane-position.py Laurent Pinchart
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Add a test that enables multiple planes with different zpos values.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/kms-test-plane-zpos.py | 102 +++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100755 tests/kms-test-plane-zpos.py

diff --git a/tests/kms-test-plane-zpos.py b/tests/kms-test-plane-zpos.py
new file mode 100755
index 000000000000..052eea542ec0
--- /dev/null
+++ b/tests/kms-test-plane-zpos.py
@@ -0,0 +1,102 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Renesas Electronics Corporation
+
+import kmstest
+import pykms
+
+class PlaneZPosTest(kmstest.KMSTest):
+    """Test composition with multiple planes and custom z-pos."""
+
+    def handle_page_flip(self, frame, time):
+        self.logger.log('Page flip complete')
+
+    def find_pipeline(self):
+        # Find a CRTC that has multiple planes with a connected connector
+        for connector in self.output_connectors():
+            # Skip disconnected connectors
+            if not connector.connected():
+                continue
+
+            # Add the connector to the map
+            for crtc in connector.get_possible_crtcs():
+                planes = []
+                for plane in self.card.planes:
+                    if plane.supports_crtc(crtc) and plane != crtc.primary_plane:
+                        planes.append(plane)
+
+                if len(planes):
+                    return crtc, connector, planes
+
+        return None, None, None
+
+    def main(self):
+        self.start('composition with z-pos control')
+
+        crtc, connector, planes = self.find_pipeline()
+        if crtc is None:
+            self.skip('no suitable pipeline')
+            return
+
+        # Get the default mode
+        try:
+            mode = connector.get_default_mode()
+        except KeyError:
+            self.skip('no mode available')
+            return
+
+        self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
+                        f'mode {mode.name} with {len(planes)} planes '
+                        f'(P: {crtc.primary_plane.id}, O: {[plane.id for plane in planes]})')
+
+        # Create a frame buffer
+        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
+        pykms.draw_test_pattern(fb)
+
+        # Set the mode with a primary plane, and position it on top of the
+        # stack. Make it transparent to visualize the overlay planes that will
+        # be positioned underneath.
+        zpos = len(planes)
+        ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
+        if ret < 0:
+            self.fail(f'atomic mode set failed with {ret}')
+            return
+
+        req = kmstest.AtomicRequest(self)
+        req.add(crtc.primary_plane, 'alpha', '50%')
+        req.add(crtc.primary_plane, 'zpos', zpos)
+        ret = req.commit_sync(True)
+        if ret < 0:
+            self.fail(f'failed to set properties for primary plane: {ret}')
+            return
+
+        self.run(3)
+
+        # Add all other planes one by one
+        offset = 100 + 50 * (len(planes) - 1)
+
+        for plane in planes:
+            zpos -= 1
+
+            source = kmstest.Rect(0, 0, fb.width, fb.height)
+            destination = kmstest.Rect(offset, offset, fb.width, fb.height)
+            ret = self.atomic_plane_set(plane, crtc, source, destination, fb, alpha='100%', zpos=zpos)
+            if ret < 0:
+                self.fail(f'atomic plane set failed with {ret}')
+                break
+
+            self.logger.log(f'Adding plane {plane.id}')
+            self.run(1)
+
+            if self.flips == 0:
+                self.fail('No page flip registered')
+                break
+
+            offset -= 50
+
+        else:
+            self.success()
+
+        self.atomic_crtc_disable(crtc)
+
+PlaneZPosTest().execute()
-- 
Regards,

Laurent Pinchart


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [kms-test] [PATCH 10/10] tests: Rename kms-test-planeposition.py to kms-test-plane-position.py
  2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
                   ` (8 preceding siblings ...)
  2022-06-09 23:40 ` [kms-test] [PATCH 09/10] tests: Add plane zpos test Laurent Pinchart
@ 2022-06-09 23:40 ` Laurent Pinchart
  2022-06-29 15:44   ` Kieran Bingham
  9 siblings, 1 reply; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-09 23:40 UTC (permalink / raw)
  To: linux-renesas-soc; +Cc: Kieran Bingham

Match the name scheme of other tests by renaming
kms-test-planeposition.py to kms-test-plane-position.py.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 tests/{kms-test-planeposition.py => kms-test-plane-position.py} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename tests/{kms-test-planeposition.py => kms-test-plane-position.py} (100%)

diff --git a/tests/kms-test-planeposition.py b/tests/kms-test-plane-position.py
similarity index 100%
rename from tests/kms-test-planeposition.py
rename to tests/kms-test-plane-position.py
-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 01/10] tests: Replace double quotes with single quotes
  2022-06-09 23:40 ` [kms-test] [PATCH 01/10] tests: Replace double quotes with single quotes Laurent Pinchart
@ 2022-06-29 13:22   ` Kieran Bingham
  0 siblings, 0 replies; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 13:22 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:22)
> The code base mixes single and double quotes. Standardize on single
> quotes except for triple-quoted strings (to match the PEP8 coding style)
> and where the string contains single quotes to avoid the need to escape
> them.
> 

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kms-test-allplanes.py      | 20 +++++------
>  tests/kms-test-brxalloc.py       | 30 ++++++++--------
>  tests/kms-test-connectors.py     |  6 ++--
>  tests/kms-test-crc.py            | 30 ++++++++--------
>  tests/kms-test-formats.py        | 16 ++++-----
>  tests/kms-test-legacy-modeset.py | 18 +++++-----
>  tests/kms-test-modes.py          | 18 +++++-----
>  tests/kms-test-modeset.py        | 18 +++++-----
>  tests/kms-test-pageflip.py       | 24 ++++++-------
>  tests/kms-test-planeposition.py  | 30 ++++++++--------
>  tests/kms-test-routing.py        | 14 ++++----
>  tests/kmstest.py                 | 60 ++++++++++++++++----------------
>  12 files changed, 142 insertions(+), 142 deletions(-)
> 
> diff --git a/tests/kms-test-allplanes.py b/tests/kms-test-allplanes.py
> index d88326293782..710ae660f0ff 100755
> --- a/tests/kms-test-allplanes.py
> +++ b/tests/kms-test-allplanes.py
> @@ -9,7 +9,7 @@ class AllPlanesTest(kmstest.KMSTest):
>      """Test composition with all planes enabled on all CRTCs."""
>  
>      def handle_page_flip(self, frame, time):
> -        self.logger.log("Page flip complete")
> +        self.logger.log('Page flip complete')
>  
>      def main(self):
>          # Create the connectors to CRTCs map
> @@ -25,14 +25,14 @@ class AllPlanesTest(kmstest.KMSTest):
>                      connectors[crtc] = connector
>  
>          for crtc in self.card.crtcs:
> -            self.start("composition on CRTC %u" % crtc.id)
> +            self.start('composition on CRTC %u' % crtc.id)
>  
>              # Get the connector and default mode
>              try:
>                  connector = connectors[crtc];
>                  mode = connector.get_default_mode()
>              except KeyError:
> -                self.skip("no connector or mode available")
> +                self.skip('no connector or mode available')
>                  continue
>  
>              # List planes available for the CRTC
> @@ -42,20 +42,20 @@ class AllPlanesTest(kmstest.KMSTest):
>                      planes.append(plane)
>  
>              if len(planes) == 0:
> -                self.skip("no plane available for CRTC")
> +                self.skip('no plane available for CRTC')
>                  continue
>  
> -            self.logger.log("Testing connector %s, CRTC %u, mode %s with %u planes" % \
> +            self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
>                    (connector.fullname, crtc.id, mode.name, len(planes)))
>  
>              # Create a frame buffer
> -            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
> +            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
>              pykms.draw_test_pattern(fb)
>  
>              # Set the mode with a primary plane
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
>              if ret < 0:
> -                self.fail("atomic mode set failed with %d" % ret)
> +                self.fail('atomic mode set failed with %d' % ret)
>                  continue
>  
>              self.run(3)
> @@ -67,14 +67,14 @@ class AllPlanesTest(kmstest.KMSTest):
>                  destination = kmstest.Rect(offset, offset, fb.width, fb.height)
>                  ret = self.atomic_plane_set(plane, crtc, source, destination, fb)
>                  if ret < 0:
> -                    self.fail("atomic plane set failed with %d" % ret)
> +                    self.fail('atomic plane set failed with %d' % ret)
>                      break
>  
> -                self.logger.log("Adding plane %u" % plane.id)
> +                self.logger.log('Adding plane %u' % plane.id)
>                  self.run(1)
>  
>                  if self.flips == 0:
> -                    self.fail("No page flip registered")
> +                    self.fail('No page flip registered')
>                      break
>  
>                  offset += 50
> diff --git a/tests/kms-test-brxalloc.py b/tests/kms-test-brxalloc.py
> index dbdc78946b04..af6dd49f5c59 100755
> --- a/tests/kms-test-brxalloc.py
> +++ b/tests/kms-test-brxalloc.py
> @@ -21,9 +21,9 @@ class BRxAllocTest(kmstest.KMSTest):
>          # instance to test dynamic assignment of the BRU and BRS to pipelines.
>          # This is only occurs on H3 ES2.0 and M3-N. Check the SoC model through
>          # sysfs as we can't detected it through the DRM/KMS API.
> -        soc = open("/sys/devices/soc0/soc_id", "rb").read().strip().decode()
> -        if soc not in ["r8a7795", "r8a77965"]:
> -            self.skip("VSPDL (BRU+BRS) not available")
> +        soc = open('/sys/devices/soc0/soc_id', 'rb').read().strip().decode()
> +        if soc not in ['r8a7795', 'r8a77965']:
> +            self.skip('VSPDL (BRU+BRS) not available')
>              return
>  
>          outputs = [Output(), Output()]
> @@ -38,11 +38,11 @@ class BRxAllocTest(kmstest.KMSTest):
>          # Verify that the two CRTCs share the same planes
>          planes = outputs[0].crtc.possible_planes
>          if planes != outputs[1].crtc.possible_planes:
> -            self.skip("Planes differ for CRTCs %u and %u" % \
> +            self.skip('Planes differ for CRTCs %u and %u' % \
>                        (outputs[0].crtc.id, outputs[1].crtc.id))
>              return
>  
> -        self.logger.log("Found %u planes for CRTCs %u and %u" % \
> +        self.logger.log('Found %u planes for CRTCs %u and %u' % \
>                          (len(planes), outputs[0].crtc.id, outputs[1].crtc.id))
>  
>          # Get one connector for each CRTC
> @@ -58,11 +58,11 @@ class BRxAllocTest(kmstest.KMSTest):
>                      outputs[1].connector = connector
>  
>          if not outputs[0].connector or not outputs[1].connector:
> -            self.skip("No connected connectors for CRTCs %u and %u " % \
> +            self.skip('No connected connectors for CRTCs %u and %u ' % \
>                        (outputs[0].crtc.id, outputs[1].crtc.id))
>              return
>  
> -        self.start("Moving %u planes from %s to %s" % \
> +        self.start('Moving %u planes from %s to %s' % \
>                     (len(planes), outputs[0].connector.fullname, outputs[1].connector.fullname))
>  
>          # Set the initial mode for both outputs and wait 5s for the monitors to
> @@ -70,17 +70,17 @@ class BRxAllocTest(kmstest.KMSTest):
>          for output in outputs:
>              # Get the default mode and create a framebuffer
>              mode = output.connector.get_default_mode()
> -            output.fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
> +            output.fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
>              pykms.draw_test_pattern(output.fb)
>  
>              # Set the mode with no plane
>              ret = self.atomic_crtc_mode_set(output.crtc, output.connector, mode, sync=True)
>              if ret < 0:
> -                self.fail("atomic mode set on %s failed with %d" % \
> +                self.fail('atomic mode set on %s failed with %d' % \
>                            (output.connector.fullname, ret))
>                  return
>  
> -        self.logger.log("Initial atomic mode set completed")
> +        self.logger.log('Initial atomic mode set completed')
>          time.sleep(5)
>  
>          # Add all planes
> @@ -88,13 +88,13 @@ class BRxAllocTest(kmstest.KMSTest):
>          output = outputs[0]
>  
>          for plane in planes:
> -            self.logger.log("Adding plane %u to %s" % (plane.id, output.connector.fullname))
> +            self.logger.log('Adding plane %u to %s' % (plane.id, output.connector.fullname))
>  
>              source = kmstest.Rect(0, 0, output.fb.width, output.fb.height)
>              destination = kmstest.Rect(offset, offset, output.fb.width, output.fb.height)
>              ret = self.atomic_plane_set(plane, output.crtc, source, destination, output.fb, sync=True)
>              if ret < 0:
> -                self.fail("atomic plane set failed with %d" % ret)
> +                self.fail('atomic plane set failed with %d' % ret)
>                  return
>  
>              offset += 50
> @@ -106,20 +106,20 @@ class BRxAllocTest(kmstest.KMSTest):
>          output = outputs[1]
>  
>          for plane in planes:
> -            self.logger.log("Moving plane %u to %s" % (plane.id, output.connector.fullname))
> +            self.logger.log('Moving plane %u to %s' % (plane.id, output.connector.fullname))
>  
>              # Switching CRTC directly is not supported by DRM, start by
>              # disabling the plane.
>              ret = self.atomic_plane_disable(plane)
>              if ret < 0:
> -                self.fail("atomic plane disable failed with %d" % ret)
> +                self.fail('atomic plane disable failed with %d' % ret)
>                  return
>  
>              source = kmstest.Rect(0, 0, output.fb.width, output.fb.height)
>              destination = kmstest.Rect(offset, offset, output.fb.width, output.fb.height)
>              ret = self.atomic_plane_set(plane, output.crtc, source, destination, output.fb)
>              if ret < 0:
> -                self.fail("atomic plane set failed with %d" % ret)
> +                self.fail('atomic plane set failed with %d' % ret)
>                  return
>  
>              self.run(1)
> diff --git a/tests/kms-test-connectors.py b/tests/kms-test-connectors.py
> index 4c58b99f8fbf..54cc89ff308e 100755
> --- a/tests/kms-test-connectors.py
> +++ b/tests/kms-test-connectors.py
> @@ -10,19 +10,19 @@ class ConnectorsTest(kmstest.KMSTest):
>  
>      def main(self):
>          for connector in self.card.connectors:
> -            self.start("connector %s" % connector.fullname)
> +            self.start('connector %s' % connector.fullname)
>  
>              # Every connector should have at least one suitable CRTC
>              crtcs = connector.get_possible_crtcs()
>              if len(crtcs) == 0:
> -                self.fail("no possible CRTC")
> +                self.fail('no possible CRTC')
>                  continue
>  
>              # Connected connectors should have at least one mode
>              if connector.connected():
>                  modes = connector.get_modes()
>                  if len(modes) == 0:
> -                    self.fail("no mode available")
> +                    self.fail('no mode available')
>                      continue
>  
>              self.success()
> diff --git a/tests/kms-test-crc.py b/tests/kms-test-crc.py
> index 60187eff1c48..5b8a679ffadc 100755
> --- a/tests/kms-test-crc.py
> +++ b/tests/kms-test-crc.py
> @@ -105,7 +105,7 @@ class CRCTest(kmstest.KMSTest):
>      """Test CRC calculation on pipeline output."""
>  
>      def handle_page_flip(self, frame, time):
> -        self.logger.log("Page flip complete")
> +        self.logger.log('Page flip complete')
>  
>      def main(self):
>          # Create the connectors to CRTCs map
> @@ -121,14 +121,14 @@ class CRCTest(kmstest.KMSTest):
>                      connectors[crtc] = connector
>  
>          for crtc in self.card.crtcs:
> -            self.start("CRC calculation on CRTC %u" % crtc.id)
> +            self.start('CRC calculation on CRTC %u' % crtc.id)
>  
>              # Get the connector and default mode
>              try:
>                  connector = connectors[crtc];
>                  mode = connector.get_default_mode()
>              except KeyError:
> -                self.skip("no connector or mode available")
> +                self.skip('no connector or mode available')
>                  continue
>  
>              # List planes available for the CRTC
> @@ -138,14 +138,14 @@ class CRCTest(kmstest.KMSTest):
>                      planes.append(plane)
>  
>              if len(planes) == 0:
> -                self.skip("no plane available for CRTC")
> +                self.skip('no plane available for CRTC')
>                  continue
>  
> -            self.logger.log("Testing connector %s, CRTC %u, mode %s with %u planes" % \
> +            self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
>                    (connector.fullname, crtc.id, mode.name, len(planes)))
>  
>              # Create a frame buffer and draw a test pattern.
> -            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
> +            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
>              pykms.draw_test_pattern(fb)
>  
>              # Create a composer. This will compute the reference CRCs.
> @@ -154,7 +154,7 @@ class CRCTest(kmstest.KMSTest):
>              # Set the mode and add all planes
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
>              if ret < 0:
> -                self.fail("atomic mode set failed with %d" % ret)
> +                self.fail('atomic mode set failed with %d' % ret)
>                  continue
>  
>              req = kmstest.AtomicRequest(self)
> @@ -177,23 +177,23 @@ class CRCTest(kmstest.KMSTest):
>  
>              ret = req.commit(0)
>              if ret < 0:
> -                self.fail("atomic plane set failed with %d" % ret)
> +                self.fail('atomic plane set failed with %d' % ret)
>                  continue
>  
>              # Wait for one second and make sure the page flip has completed.
>              self.run(1)
>              if self.flips == 0:
> -                self.fail("No page flip registered")
> +                self.fail('No page flip registered')
>                  continue
>  
>              sources = [crtc] + planes
>              for source in sources:
>                  if source == crtc:
> -                    crc_source = "auto"
> +                    crc_source = 'auto'
>                  else:
> -                    crc_source = "plane%u" % source.id
> +                    crc_source = 'plane%u' % source.id
>  
> -                self.logger.log("Computing CRC from source %s" % crc_source)
> +                self.logger.log('Computing CRC from source %s' % crc_source)
>  
>                  # Set the CRC source and acquire 10 CRC values. Discard the
>                  # first value, as the device is running and the new source
> @@ -204,7 +204,7 @@ class CRCTest(kmstest.KMSTest):
>                  crc_reader.stop()
>  
>                  crcs = [c.crcs[0] for c in crcs[1:]]
> -                self.logger.log("CRC value[0] 0x%08x" % crcs[0])
> +                self.logger.log('CRC value[0] 0x%08x' % crcs[0])
>  
>                  failures = 0
>                  ref_crc = composer.crc(source)
> @@ -212,12 +212,12 @@ class CRCTest(kmstest.KMSTest):
>                  for i in range(len(crcs)):
>                      crc = crcs[i]
>                      if crc != ref_crc:
> -                        self.logger.log("CRC value[%u] 0x%08x does not match reference 0x%08x"
> +                        self.logger.log('CRC value[%u] 0x%08x does not match reference 0x%08x'
>                                          % (i, crc, ref_crc))
>                          failures += 1
>  
>                  if failures:
> -                    self.fail("Incorrect CRC values on source %s" % crc_source)
> +                    self.fail('Incorrect CRC values on source %s' % crc_source)
>                      break
>  
>              else:
> diff --git a/tests/kms-test-formats.py b/tests/kms-test-formats.py
> index 86f16511f1ea..ce849437b2fa 100755
> --- a/tests/kms-test-formats.py
> +++ b/tests/kms-test-formats.py
> @@ -10,12 +10,12 @@ class FormatsTest(kmstest.KMSTest):
>      """Test all available plane formats."""
>  
>      def main(self):
> -        self.start("plane formats")
> +        self.start('plane formats')
>  
>          # Find a CRTC with a connected connector and at least one plane
>          for connector in self.output_connectors():
>              if not connector.connected():
> -                self.skip("unconnected connector")
> +                self.skip('unconnected connector')
>                  continue
>  
>              try:
> @@ -34,10 +34,10 @@ class FormatsTest(kmstest.KMSTest):
>                  break
>  
>          else:
> -            self.skip("no CRTC available with connector")
> +            self.skip('no CRTC available with connector')
>              return
>  
> -        self.logger.log("Testing connector %s, CRTC %u, mode %s" % \
> +        self.logger.log('Testing connector %s, CRTC %u, mode %s' % \
>                (connector.fullname, crtc.id, mode.name))
>  
>          failed = 0
> @@ -46,14 +46,14 @@ class FormatsTest(kmstest.KMSTest):
>          for i in range(num_formats):
>              format = crtc.primary_plane.formats[i]
>  
> -            self.logger.log("Testing format %s" % format)
> +            self.logger.log('Testing format %s' % format)
>              self.progress(i+1, num_formats)
>  
>              # Create a frame buffer
>              try:
>                  fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, format)
>              except ValueError:
> -                self.logger.log("Failed to create frame buffer")
> +                self.logger.log('Failed to create frame buffer')
>                  failed += 1
>                  continue
>  
> @@ -62,7 +62,7 @@ class FormatsTest(kmstest.KMSTest):
>              # Set the mode with a primary plane
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
>              if ret < 0:
> -                self.logger.log("atomic mode set failed with %d" % ret)
> +                self.logger.log('atomic mode set failed with %d' % ret)
>                  failed += 1
>                  continue
>  
> @@ -71,7 +71,7 @@ class FormatsTest(kmstest.KMSTest):
>          self.atomic_crtc_disable(crtc)
>  
>          if failed:
> -            self.fail("%s/%s formats failed" % (failed, num_formats))
> +            self.fail('%s/%s formats failed' % (failed, num_formats))
>          else:
>              self.success()
>  
> diff --git a/tests/kms-test-legacy-modeset.py b/tests/kms-test-legacy-modeset.py
> index 4b5605345391..f856178172c0 100755
> --- a/tests/kms-test-legacy-modeset.py
> +++ b/tests/kms-test-legacy-modeset.py
> @@ -9,15 +9,15 @@ class LegacyModeSetTest(kmstest.KMSTest):
>      """Test mode setting on all connectors in sequence with the default mode through the legacy mode set API."""
>  
>      def handle_page_flip(self, frame, time):
> -        self.logger.log("Page flip complete")
> +        self.logger.log('Page flip complete')
>  
>      def main(self):
>          for connector in self.output_connectors():
> -            self.start("legacy mode set on connector %s" % connector.fullname)
> +            self.start('legacy mode set on connector %s' % connector.fullname)
>  
>              # Skip disconnected connectors
>              if not connector.connected():
> -                self.skip("unconnected connector")
> +                self.skip('unconnected connector')
>                  continue
>  
>              # Find a CRTC suitable for the connector
> @@ -33,28 +33,28 @@ class LegacyModeSetTest(kmstest.KMSTest):
>              try:
>                  mode = connector.get_default_mode()
>              except ValueError:
> -                self.skip("no mode available")
> +                self.skip('no mode available')
>                  continue
>  
> -            self.logger.log("Testing connector %s on CRTC %u with mode %s" % \
> +            self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
>                    (connector.fullname, crtc.id, mode.name))
>  
>              # Create a frame buffer
> -            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
> +            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
>              pykms.draw_test_pattern(fb)
>  
>              # Perform a mode set
>              ret = crtc.set_mode(connector, fb, mode)
>              if ret < 0:
> -                self.fail("legacy mode set failed with %d" % ret)
> +                self.fail('legacy mode set failed with %d' % ret)
>                  continue
>  
> -            self.logger.log("Legacy mode set complete")
> +            self.logger.log('Legacy mode set complete')
>              self.run(5)
>  
>              ret = crtc.disable_mode()
>              if ret < 0:
> -                self.fail("legacy mode set disable failed with %d" % ret)
> +                self.fail('legacy mode set disable failed with %d' % ret)
>                  continue
>  
>              self.success()
> diff --git a/tests/kms-test-modes.py b/tests/kms-test-modes.py
> index b298a19beedf..433bb0bdd157 100755
> --- a/tests/kms-test-modes.py
> +++ b/tests/kms-test-modes.py
> @@ -9,35 +9,35 @@ class ModesTest(kmstest.KMSTest):
>      """Test all available modes on all available connectors."""
>  
>      def handle_page_flip(self, frame, time):
> -        self.logger.log("Page flip complete")
> +        self.logger.log('Page flip complete')
>  
>      def test_mode(self, connector, crtc, mode):
> -        self.logger.log("Testing connector %s on CRTC %u with mode %s" % \
> +        self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
>                (connector.fullname, crtc.id, mode.name))
>  
>          # Create a frame buffer
> -        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
> +        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
>          pykms.draw_test_pattern(fb)
>  
>          # Perform the mode set
>          ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
>          if ret < 0:
> -            raise RuntimeError("atomic mode set failed with %d" % ret)
> +            raise RuntimeError('atomic mode set failed with %d' % ret)
>  
> -        self.logger.log("Atomic mode set complete")
> +        self.logger.log('Atomic mode set complete')
>          self.run(4)
>          self.atomic_crtc_disable(crtc)
>  
>          if self.flips == 0:
> -            raise RuntimeError("Page flip not registered")
> +            raise RuntimeError('Page flip not registered')
>  
>      def main(self):
>          for connector in self.output_connectors():
> -            self.start("modes on connector %s" % connector.fullname)
> +            self.start('modes on connector %s' % connector.fullname)
>  
>              # Skip disconnected connectors
>              if not connector.connected():
> -                self.skip("unconnected connector")
> +                self.skip('unconnected connector')
>                  continue
>  
>              # Find a CRTC suitable for the connector
> @@ -52,7 +52,7 @@ class ModesTest(kmstest.KMSTest):
>              # Test all available modes
>              modes = connector.get_modes()
>              if len(modes) == 0:
> -                self.skip("no mode available")
> +                self.skip('no mode available')
>                  continue
>  
>              for i in range(len(modes)):
> diff --git a/tests/kms-test-modeset.py b/tests/kms-test-modeset.py
> index 0dbe67fb2a4f..a6ba61c920e5 100755
> --- a/tests/kms-test-modeset.py
> +++ b/tests/kms-test-modeset.py
> @@ -9,15 +9,15 @@ class ModeSetTest(kmstest.KMSTest):
>      """Test mode setting on all connectors in sequence with the default mode."""
>  
>      def handle_page_flip(self, frame, time):
> -        self.logger.log("Page flip complete")
> +        self.logger.log('Page flip complete')
>  
>      def main(self):
>          for connector in self.output_connectors():
> -            self.start("atomic mode set on connector %s" % connector.fullname)
> +            self.start('atomic mode set on connector %s' % connector.fullname)
>  
>              # Skip disconnected connectors
>              if not connector.connected():
> -                self.skip("unconnected connector")
> +                self.skip('unconnected connector')
>                  continue
>  
>              # Find a CRTC suitable for the connector
> @@ -33,28 +33,28 @@ class ModeSetTest(kmstest.KMSTest):
>              try:
>                  mode = connector.get_default_mode()
>              except ValueError:
> -                self.skip("no mode available")
> +                self.skip('no mode available')
>                  continue
>  
> -            self.logger.log("Testing connector %s on CRTC %u with mode %s" % \
> +            self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
>                    (connector.fullname, crtc.id, mode.name))
>  
>              # Create a frame buffer
> -            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
> +            fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
>              pykms.draw_test_pattern(fb)
>  
>              # Perform a mode set
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
>              if ret < 0:
> -                self.fail("atomic mode set failed with %d" % ret)
> +                self.fail('atomic mode set failed with %d' % ret)
>                  continue
>  
> -            self.logger.log("Atomic mode set complete")
> +            self.logger.log('Atomic mode set complete')
>              self.run(5)
>              self.atomic_crtc_disable(crtc)
>  
>              if self.flips == 0:
> -                self.fail("Page flip not registered")
> +                self.fail('Page flip not registered')
>              else:
>                  self.success()
>  
> diff --git a/tests/kms-test-pageflip.py b/tests/kms-test-pageflip.py
> index 19c3adaa601f..15dae6a23ab3 100755
> --- a/tests/kms-test-pageflip.py
> +++ b/tests/kms-test-pageflip.py
> @@ -13,12 +13,12 @@ class PageFlipTest(kmstest.KMSTest):
>  
>      def handle_page_flip(self, frame, time):
>          if self.flips == 1:
> -            self.logger.log("first page flip frame %u time %f" % (frame, time))
> +            self.logger.log('first page flip frame %u time %f' % (frame, time))
>              self.frame_start = frame
>              self.time_start = time
>  
>          if self.stop_requested:
> -            self.logger.log("last page flip frame %u time %f" % (frame, time))
> +            self.logger.log('last page flip frame %u time %f' % (frame, time))
>              self.frame_end = frame
>              self.time_end = time
>              self.loop.stop()
> @@ -43,11 +43,11 @@ class PageFlipTest(kmstest.KMSTest):
>  
>      def main(self):
>          for connector in self.output_connectors():
> -            self.start("page flip on connector %s" % connector.fullname)
> +            self.start('page flip on connector %s' % connector.fullname)
>  
>              # Skip disconnected connectors
>              if not connector.connected():
> -                self.skip("unconnected connector")
> +                self.skip('unconnected connector')
>                  continue
>  
>              # Find a CRTC suitable for the connector
> @@ -67,28 +67,28 @@ class PageFlipTest(kmstest.KMSTest):
>                      self.plane = plane
>                      break
>              else:
> -                self.skip("no plane available for CRTC %u" % crtc.id)
> +                self.skip('no plane available for CRTC %u' % crtc.id)
>                  continue
>  
>              # Get the default mode for the connector
>              try:
>                  mode = connector.get_default_mode()
>              except ValueError:
> -                self.skip("no mode available")
> +                self.skip('no mode available')
>                  continue
>  
> -            self.logger.log("Testing connector %s, CRTC %u, plane %u, mode %s" % \
> +            self.logger.log('Testing connector %s, CRTC %u, plane %u, mode %s' % \
>                    (connector.fullname, crtc.id, self.plane.id, mode.name))
>  
>              # Create two frame buffers
>              self.fbs = []
>              for i in range(2):
> -                self.fbs.append(pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24"))
> +                self.fbs.append(pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24'))
>  
>              # Set the mode and perform the initial page flip
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, self.fbs[0])
>              if ret < 0:
> -                self.fail("atomic mode set failed with %d" % ret)
> +                self.fail('atomic mode set failed with %d' % ret)
>                  continue
>  
>              # Flip pages for 10s
> @@ -105,16 +105,16 @@ class PageFlipTest(kmstest.KMSTest):
>              self.atomic_crtc_disable(crtc)
>  
>              if not self.flips:
> -                self.fail("No page flip registered")
> +                self.fail('No page flip registered')
>                  continue
>  
>              if self.stop_requested:
> -                self.fail("Last page flip not registered")
> +                self.fail('Last page flip not registered')
>                  continue
>  
>              frames = self.frame_end - self.frame_start + 1
>              interval = self.time_end - self.time_start
> -            self.logger.log("Frame rate: %f (%u/%u frames in %f s)" % \
> +            self.logger.log('Frame rate: %f (%u/%u frames in %f s)' % \
>                  (frames / interval, self.flips, frames, interval))
>              self.success()
>  
> diff --git a/tests/kms-test-planeposition.py b/tests/kms-test-planeposition.py
> index 0381896f1da8..e843ae13c50c 100755
> --- a/tests/kms-test-planeposition.py
> +++ b/tests/kms-test-planeposition.py
> @@ -10,12 +10,12 @@ class PlanePositionTest(kmstest.KMSTest):
>      """Test boundaries of plane positioning."""
>  
>      def main(self):
> -        self.start("plane positioning boundaries")
> +        self.start('plane positioning boundaries')
>  
>          # Find a CRTC with a connected connector and at least two planes
>          for connector in self.output_connectors():
>              if not connector.connected():
> -                self.skip("unconnected connector")
> +                self.skip('unconnected connector')
>                  continue
>  
>              try:
> @@ -39,23 +39,23 @@ class PlanePositionTest(kmstest.KMSTest):
>                  break
>  
>          else:
> -            self.skip("no CRTC available with connector and at least two planes")
> +            self.skip('no CRTC available with connector and at least two planes')
>              return
>  
> -        self.logger.log("Testing connector %s, CRTC %u, mode %s with %u planes" % \
> +        self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
>                (connector.fullname, crtc.id, mode.name, len(planes)))
>  
>          # Create a frame buffer
> -        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
> +        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
>          pykms.draw_test_pattern(fb)
>  
>          # Set the mode with no plane, wait 5s for the monitor to wake up
>          ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
>          if ret < 0:
> -            self.fail("atomic mode set failed with %d" % ret)
> +            self.fail('atomic mode set failed with %d' % ret)
>              return
>  
> -        self.logger.log("Initial atomic mode set completed")
> +        self.logger.log('Initial atomic mode set completed')
>          time.sleep(5)
>  
>          # Add the first plane to cover half of the CRTC
> @@ -63,10 +63,10 @@ class PlanePositionTest(kmstest.KMSTest):
>          destination = kmstest.Rect(0, 0, fb.width // 2, fb.height)
>          ret = self.atomic_plane_set(planes[0], crtc, source, destination, fb, sync=True)
>          if ret < 0:
> -            self.fail("atomic plane set for first plane failed with %d" % ret)
> +            self.fail('atomic plane set for first plane failed with %d' % ret)
>              return
>  
> -        self.logger.log("Root plane enabled")
> +        self.logger.log('Root plane enabled')
>          time.sleep(3)
>  
>          # Add the second plane and move it around to cross all CRTC boundaries
> @@ -79,10 +79,10 @@ class PlanePositionTest(kmstest.KMSTest):
>  
>              ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
>              if ret < 0:
> -                self.fail("atomic plane set with offset %d,%d" % offset)
> +                self.fail('atomic plane set with offset %d,%d' % offset)
>                  return
>  
> -            self.logger.log("Moved overlay plane to %d,%d" % offset)
> +            self.logger.log('Moved overlay plane to %d,%d' % offset)
>              time.sleep(3)
>  
>          # Try to move the plane completely off-screen. The device is expected
> @@ -97,17 +97,17 @@ class PlanePositionTest(kmstest.KMSTest):
>  
>              ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
>              if ret < 0:
> -                self.fail("atomic plane set with offset %d,%d" % offset)
> +                self.fail('atomic plane set with offset %d,%d' % offset)
>                  return
>  
> -            self.logger.log("Moved overlay plane to %d,%d" % offset)
> +            self.logger.log('Moved overlay plane to %d,%d' % offset)
>              time.sleep(3)
>  
>          # Disable and re-enable the plane when it is off-screen. The device is
>          # still expected to handle this gracefully.
>          ret = self.atomic_plane_disable(planes[1])
>          if ret < 0:
> -            self.fail("off-screen atomic plane disable failed")
> +            self.fail('off-screen atomic plane disable failed')
>              return
>  
>          width = fb.width - 100
> @@ -117,7 +117,7 @@ class PlanePositionTest(kmstest.KMSTest):
>  
>          ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
>          if ret < 0:
> -            self.fail("off-scrren atomic plane enable failed")
> +            self.fail('off-scrren atomic plane enable failed')
>              return
>  
>          self.atomic_crtc_disable(crtc)
> diff --git a/tests/kms-test-routing.py b/tests/kms-test-routing.py
> index 806adb8c68a8..69f8be127d2f 100755
> --- a/tests/kms-test-routing.py
> +++ b/tests/kms-test-routing.py
> @@ -49,7 +49,7 @@ class RoutingTest(kmstest.KMSTest):
>                  break
>  
>          if not shared_connector:
> -            self.skip("No suitable connector")
> +            self.skip('No suitable connector')
>              return
>  
>          # Allocate planes for each CRTC.
> @@ -61,13 +61,13 @@ class RoutingTest(kmstest.KMSTest):
>              pool = [(elem[0], [p for p in elem[1] if p != pipe.plane]) for elem in pool[:-1]]
>  
>          # Create a framebuffer big enough for all connectors.
> -        fb = pykms.DumbFramebuffer(self.card, max_hdisplay, max_vdisplay, "XR24")
> +        fb = pykms.DumbFramebuffer(self.card, max_hdisplay, max_vdisplay, 'XR24')
>          pykms.draw_test_pattern(fb)
>  
> -        self.start("Moving connector %s between CRTCs %s" % \
> +        self.start('Moving connector %s between CRTCs %s' % \
>                     (shared_connector.fullname, [pipe.crtc.id for pipe in pipes]))
>  
> -        self.logger.log("Highest display resolution: %ux%u" % (max_hdisplay, max_vdisplay))
> +        self.logger.log('Highest display resolution: %ux%u' % (max_hdisplay, max_vdisplay))
>  
>          for master_pipe in pipes:
>              req = kmstest.AtomicRequest(self)
> @@ -97,13 +97,13 @@ class RoutingTest(kmstest.KMSTest):
>                              'CRTC_H': mode.vdisplay,
>                          })
>  
> -                route.append("CRTC %u to connector %s" % (pipe.crtc.id, pipe.connector.fullname))
> +                route.append('CRTC %u to connector %s' % (pipe.crtc.id, pipe.connector.fullname))
>  
> -            self.logger.log("Routing " + ", ".join(route))
> +            self.logger.log('Routing ' + ', '.join(route))
>  
>              ret = req.commit_sync(True)
>              if ret < 0:
> -                self.fail("atomic commit failed with %d" % ret)
> +                self.fail('atomic commit failed with %d' % ret)
>                  return
>  
>              time.sleep(5)
> diff --git a/tests/kmstest.py b/tests/kmstest.py
> index 949bb20b8b1a..708e6999d1f0 100755
> --- a/tests/kmstest.py
> +++ b/tests/kmstest.py
> @@ -63,23 +63,23 @@ class EventLoop(selectors.DefaultSelector):
>  
>  class KernelLogMessage(object):
>      def __init__(self, msg):
> -        pos = msg.find(";")
> +        pos = msg.find(';')
>          header = msg[:pos]
>          msg = msg[pos+1:]
>  
> -        facility, sequence, timestamp, *other = header.split(",")
> +        facility, sequence, timestamp, *other = header.split(',')
>          self.facility = int(facility)
>          self.sequence = int(sequence)
>          self.timestamp = int(timestamp) / 1000000.
>  
> -        msg = msg.split("\n")
> +        msg = msg.split('\n')
>          self.msg = msg[0]
>          self.tags = {}
>  
>          try:
>              tags = msg[1:-1]
>              for tag in tags:
> -                tag = tag.strip().split("=")
> +                tag = tag.strip().split('=')
>                  self.tags[tag[0]] = tag[1]
>          except:
>              pass
> @@ -87,7 +87,7 @@ class KernelLogMessage(object):
>  
>  class KernelLogReader(object):
>      def __init__(self):
> -        self.kmsg = os.open("/dev/kmsg", 0)
> +        self.kmsg = os.open('/dev/kmsg', 0)
>          flags = fcntl.fcntl(self.kmsg, fcntl.F_GETFL)
>          fcntl.fcntl(self.kmsg, fcntl.F_SETFL, flags | os.O_NONBLOCK)
>          os.lseek(self.kmsg, 0, os.SEEK_END)
> @@ -100,7 +100,7 @@ class KernelLogReader(object):
>          while True:
>              try:
>                  msg = os.read(self.kmsg, 8191)
> -                msg = msg.decode("utf-8")
> +                msg = msg.decode('utf-8')
>              except OSError as e:
>                  if e.errno == errno.EAGAIN:
>                      break
> @@ -113,7 +113,7 @@ class KernelLogReader(object):
>  
>  class Logger(object):
>      def __init__(self, name):
> -        self.logfile = open("%s.log" % name, "w")
> +        self.logfile = open('%s.log' % name, 'w')
>          self._kmsg = KernelLogReader()
>  
>      def __del__(self):
> @@ -129,7 +129,7 @@ class Logger(object):
>      def event(self):
>          kmsgs = self._kmsg.read()
>          for msg in kmsgs:
> -            self.logfile.write("K [%6f] %s\n" % (msg.timestamp, msg.msg))
> +            self.logfile.write('K [%6f] %s\n' % (msg.timestamp, msg.msg))
>          self.logfile.flush()
>  
>      @property
> @@ -146,13 +146,13 @@ class Logger(object):
>          self.event()
>  
>          now = time.clock_gettime(time.CLOCK_MONOTONIC)
> -        self.logfile.write("U [%6f] %s\n" % (now, msg))
> +        self.logfile.write('U [%6f] %s\n' % (now, msg))
>          self.logfile.flush()
>  
>  
>  class CRC(object):
>      def __init__(self, crc):
> -        if crc.startswith("XXXXXXXXXX"):
> +        if crc.startswith('XXXXXXXXXX'):
>              self.frame = None
>          else:
>              self.frame = int(crc[:10], 16)
> @@ -171,8 +171,8 @@ class CRCReader(object):
>  
>          # Hardcode the device minor to 0 as the KMSTest constructor opens the
>          # default card object.
> -        self.dir = os.open("/sys/kernel/debug/dri/0/crtc-%u/crc" % self.pipe, 0)
> -        self.ctrl = os.open("control", os.O_WRONLY, dir_fd = self.dir)
> +        self.dir = os.open('/sys/kernel/debug/dri/0/crtc-%u/crc' % self.pipe, 0)
> +        self.ctrl = os.open('control', os.O_WRONLY, dir_fd = self.dir)
>          self.data = -1
>  
>      def __del__(self):
> @@ -181,8 +181,8 @@ class CRCReader(object):
>          os.close(self.dir)
>  
>      def start(self, source):
> -        os.write(self.ctrl, source.encode("ascii"))
> -        self.data = os.open("data", os.O_RDONLY, dir_fd = self.dir)
> +        os.write(self.ctrl, source.encode('ascii'))
> +        self.data = os.open('data', os.O_RDONLY, dir_fd = self.dir)
>  
>      def stop(self):
>          if self.data != -1:
> @@ -194,7 +194,7 @@ class CRCReader(object):
>          while len(crcs) < num_entries:
>              try:
>                  crc = os.read(self.data, CRCReader.MAX_LINE_LEN)
> -                crc = crc.decode("ascii")
> +                crc = crc.decode('ascii')
>              except OSError as e:
>                  if e.errno == errno.EAGAIN:
>                      break
> @@ -211,7 +211,7 @@ class Dist(object):
>          self.y = y
>  
>      def __repr__(self):
> -        return "(%d,%d)" % (self.x, self.y)
> +        return '(%d,%d)' % (self.x, self.y)
>  
>  
>  class Point(object):
> @@ -220,7 +220,7 @@ class Point(object):
>          self.y = y
>  
>      def __repr__(self):
> -        return "(%d,%d)" % (self.x, self.y)
> +        return '(%d,%d)' % (self.x, self.y)
>  
>      def move(self, distance):
>          self.x += distance.x
> @@ -233,7 +233,7 @@ class Size(object):
>          self.height = height
>  
>      def __repr__(self):
> -        return "%ux%u" % (self.width, self.height)
> +        return '%ux%u' % (self.width, self.height)
>  
>  
>  class Rect(object):
> @@ -244,7 +244,7 @@ class Rect(object):
>          self.height = height
>  
>      def __repr__(self):
> -        return "(%d,%d)/%ux%u" % (self.left, self.top, self.width, self.height)
> +        return '(%d,%d)/%ux%u' % (self.left, self.top, self.width, self.height)
>  
>      def isEmpty(self):
>          """Check if the rectangle has a zero width or height"""
> @@ -387,7 +387,7 @@ class KMSTest(object):
>  
>      def atomic_plane_disable(self, plane, sync=True):
>          req = AtomicRequest(self)
> -        req.add(plane, { "FB_ID": 0, 'CRTC_ID': 0 })
> +        req.add(plane, { 'FB_ID': 0, 'CRTC_ID': 0 })
>  
>          if sync:
>              return req.commit_sync()
> @@ -397,7 +397,7 @@ class KMSTest(object):
>      def atomic_planes_disable(self, sync=True):
>          req = AtomicRequest(self)
>          for plane in self.card.planes:
> -            req.add(plane, { "FB_ID": 0, 'CRTC_ID': 0 })
> +            req.add(plane, { 'FB_ID': 0, 'CRTC_ID': 0 })
>  
>          if sync:
>              return req.commit_sync()
> @@ -462,32 +462,32 @@ class KMSTest(object):
>      def start(self, name):
>          """Start a test."""
>          self.test_name = name
> -        self.logger.log("Testing %s" % name)
> -        sys.stdout.write("Testing %s: " % name)
> +        self.logger.log('Testing %s' % name)
> +        sys.stdout.write('Testing %s: ' % name)
>          sys.stdout.flush()
>  
>      def progress(self, current, maximum):
> -        sys.stdout.write("\rTesting %s: %u/%u" % (self.test_name, current, maximum))
> +        sys.stdout.write('\rTesting %s: %u/%u' % (self.test_name, current, maximum))
>          sys.stdout.flush()
>  
>      def fail(self, reason):
>          """Complete a test with failure."""
> -        self.logger.log("Test failed. Reason: %s" % reason)
> +        self.logger.log('Test failed. Reason: %s' % reason)
>          self.logger.flush()
> -        sys.stdout.write("\rTesting %s: FAIL\n" % self.test_name)
> +        sys.stdout.write('\rTesting %s: FAIL\n' % self.test_name)
>          sys.stdout.flush()
>  
>      def skip(self, reason):
>          """Complete a test with skip."""
> -        self.logger.log("Test skipped. Reason: %s" % reason)
> +        self.logger.log('Test skipped. Reason: %s' % reason)
>          self.logger.flush()
> -        sys.stdout.write("SKIP\n")
> +        sys.stdout.write('SKIP\n')
>          sys.stdout.flush()
>  
>      def success(self):
>          """Complete a test with success."""
> -        self.logger.log("Test completed successfully")
> +        self.logger.log('Test completed successfully')
>          self.logger.flush()
> -        sys.stdout.write("\rTesting %s: SUCCESS\n" % self.test_name)
> +        sys.stdout.write('\rTesting %s: SUCCESS\n' % self.test_name)
>          sys.stdout.flush()
>  
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 02/10] tests: Convert to formatted string literals
  2022-06-09 23:40 ` [kms-test] [PATCH 02/10] tests: Convert to formatted string literals Laurent Pinchart
@ 2022-06-29 15:28   ` Kieran Bingham
  0 siblings, 0 replies; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:28 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:23)
> Use formatted string literals to replace legacy printf-style string
> formatting.
> 

This is nice. Putting the parameter directly in the place makes it much
easier to parse.


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kms-test-allplanes.py      | 12 ++++++------
>  tests/kms-test-brxalloc.py       | 28 +++++++++++++---------------
>  tests/kms-test-connectors.py     |  2 +-
>  tests/kms-test-crc.py            | 21 ++++++++++-----------
>  tests/kms-test-formats.py        | 10 +++++-----
>  tests/kms-test-legacy-modeset.py | 10 +++++-----
>  tests/kms-test-modes.py          |  8 ++++----
>  tests/kms-test-modeset.py        |  8 ++++----
>  tests/kms-test-pageflip.py       | 18 +++++++++---------
>  tests/kms-test-planeposition.py  | 16 ++++++++--------
>  tests/kms-test-routing.py        | 10 +++++-----
>  tests/kmstest.py                 | 30 +++++++++++++++---------------
>  12 files changed, 85 insertions(+), 88 deletions(-)
> 
> diff --git a/tests/kms-test-allplanes.py b/tests/kms-test-allplanes.py
> index 710ae660f0ff..0fe6cfab0a2d 100755
> --- a/tests/kms-test-allplanes.py
> +++ b/tests/kms-test-allplanes.py
> @@ -25,7 +25,7 @@ class AllPlanesTest(kmstest.KMSTest):
>                      connectors[crtc] = connector
>  
>          for crtc in self.card.crtcs:
> -            self.start('composition on CRTC %u' % crtc.id)
> +            self.start(f'composition on CRTC {crtc.id}')
>  
>              # Get the connector and default mode
>              try:
> @@ -45,8 +45,8 @@ class AllPlanesTest(kmstest.KMSTest):
>                  self.skip('no plane available for CRTC')
>                  continue
>  
> -            self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
> -                  (connector.fullname, crtc.id, mode.name, len(planes)))
> +            self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> +                            f'mode {mode.name} with {len(planes)} planes')
>  
>              # Create a frame buffer
>              fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> @@ -55,7 +55,7 @@ class AllPlanesTest(kmstest.KMSTest):
>              # Set the mode with a primary plane
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
>              if ret < 0:
> -                self.fail('atomic mode set failed with %d' % ret)
> +                self.fail(f'atomic mode set failed with {ret}')
>                  continue
>  
>              self.run(3)
> @@ -67,10 +67,10 @@ class AllPlanesTest(kmstest.KMSTest):
>                  destination = kmstest.Rect(offset, offset, fb.width, fb.height)
>                  ret = self.atomic_plane_set(plane, crtc, source, destination, fb)
>                  if ret < 0:
> -                    self.fail('atomic plane set failed with %d' % ret)
> +                    self.fail(f'atomic plane set failed with {ret}')
>                      break
>  
> -                self.logger.log('Adding plane %u' % plane.id)
> +                self.logger.log(f'Adding plane {plane.id}')
>                  self.run(1)
>  
>                  if self.flips == 0:
> diff --git a/tests/kms-test-brxalloc.py b/tests/kms-test-brxalloc.py
> index af6dd49f5c59..7170ee6c7708 100755
> --- a/tests/kms-test-brxalloc.py
> +++ b/tests/kms-test-brxalloc.py
> @@ -38,12 +38,11 @@ class BRxAllocTest(kmstest.KMSTest):
>          # Verify that the two CRTCs share the same planes
>          planes = outputs[0].crtc.possible_planes
>          if planes != outputs[1].crtc.possible_planes:
> -            self.skip('Planes differ for CRTCs %u and %u' % \
> -                      (outputs[0].crtc.id, outputs[1].crtc.id))
> +            self.skip(f'Planes differ for CRTCs {outputs[0].crtc.id} and {outputs[1].crtc.id}')
>              return
>  
> -        self.logger.log('Found %u planes for CRTCs %u and %u' % \
> -                        (len(planes), outputs[0].crtc.id, outputs[1].crtc.id))
> +        self.logger.log(f'Found {len(planes)} planes for CRTCs {outputs[0].crtc.id} '
> +                        f'and {outputs[1].crtc.id}')
>  
>          # Get one connector for each CRTC
>          for connector in self.output_connectors():
> @@ -58,12 +57,12 @@ class BRxAllocTest(kmstest.KMSTest):
>                      outputs[1].connector = connector
>  
>          if not outputs[0].connector or not outputs[1].connector:
> -            self.skip('No connected connectors for CRTCs %u and %u ' % \
> -                      (outputs[0].crtc.id, outputs[1].crtc.id))
> +            self.skip(f'No connected connectors for CRTCs {outputs[0].crtc.id} '
> +                      f'and {outputs[1].crtc.id}')
>              return
>  
> -        self.start('Moving %u planes from %s to %s' % \
> -                   (len(planes), outputs[0].connector.fullname, outputs[1].connector.fullname))
> +        self.start(f'Moving {len(planes)} planes from {outputs[0].connector.fullname} '
> +                   f'to {outputs[0].connector.fullname}')
>  
>          # Set the initial mode for both outputs and wait 5s for the monitors to
>          # wake up.
> @@ -76,8 +75,7 @@ class BRxAllocTest(kmstest.KMSTest):
>              # Set the mode with no plane
>              ret = self.atomic_crtc_mode_set(output.crtc, output.connector, mode, sync=True)
>              if ret < 0:
> -                self.fail('atomic mode set on %s failed with %d' % \
> -                          (output.connector.fullname, ret))
> +                self.fail(f'atomic mode set on {output.connector.fullname} failed with {ret}')
>                  return
>  
>          self.logger.log('Initial atomic mode set completed')
> @@ -88,13 +86,13 @@ class BRxAllocTest(kmstest.KMSTest):
>          output = outputs[0]
>  
>          for plane in planes:
> -            self.logger.log('Adding plane %u to %s' % (plane.id, output.connector.fullname))
> +            self.logger.log(f'Adding plane {plane.id} to {output.connector.fullname}')
>  
>              source = kmstest.Rect(0, 0, output.fb.width, output.fb.height)
>              destination = kmstest.Rect(offset, offset, output.fb.width, output.fb.height)
>              ret = self.atomic_plane_set(plane, output.crtc, source, destination, output.fb, sync=True)
>              if ret < 0:
> -                self.fail('atomic plane set failed with %d' % ret)
> +                self.fail(f'atomic plane set failed with {ret}')
>                  return
>  
>              offset += 50
> @@ -106,20 +104,20 @@ class BRxAllocTest(kmstest.KMSTest):
>          output = outputs[1]
>  
>          for plane in planes:
> -            self.logger.log('Moving plane %u to %s' % (plane.id, output.connector.fullname))
> +            self.logger.log(f'Moving plane {plane.id} to {output.connector.fullname}')
>  
>              # Switching CRTC directly is not supported by DRM, start by
>              # disabling the plane.
>              ret = self.atomic_plane_disable(plane)
>              if ret < 0:
> -                self.fail('atomic plane disable failed with %d' % ret)
> +                self.fail(f'atomic plane disable failed with {ret}')
>                  return
>  
>              source = kmstest.Rect(0, 0, output.fb.width, output.fb.height)
>              destination = kmstest.Rect(offset, offset, output.fb.width, output.fb.height)
>              ret = self.atomic_plane_set(plane, output.crtc, source, destination, output.fb)
>              if ret < 0:
> -                self.fail('atomic plane set failed with %d' % ret)
> +                self.fail(f'atomic plane set failed with {ret}')
>                  return
>  
>              self.run(1)
> diff --git a/tests/kms-test-connectors.py b/tests/kms-test-connectors.py
> index 54cc89ff308e..d2ca636eb2a0 100755
> --- a/tests/kms-test-connectors.py
> +++ b/tests/kms-test-connectors.py
> @@ -10,7 +10,7 @@ class ConnectorsTest(kmstest.KMSTest):
>  
>      def main(self):
>          for connector in self.card.connectors:
> -            self.start('connector %s' % connector.fullname)
> +            self.start(f'connector {connector.fullname}')
>  
>              # Every connector should have at least one suitable CRTC
>              crtcs = connector.get_possible_crtcs()
> diff --git a/tests/kms-test-crc.py b/tests/kms-test-crc.py
> index 5b8a679ffadc..efb3cf0dbe41 100755
> --- a/tests/kms-test-crc.py
> +++ b/tests/kms-test-crc.py
> @@ -121,7 +121,7 @@ class CRCTest(kmstest.KMSTest):
>                      connectors[crtc] = connector
>  
>          for crtc in self.card.crtcs:
> -            self.start('CRC calculation on CRTC %u' % crtc.id)
> +            self.start(f'CRC calculation on CRTC {crtc.id}')
>  
>              # Get the connector and default mode
>              try:
> @@ -141,8 +141,8 @@ class CRCTest(kmstest.KMSTest):
>                  self.skip('no plane available for CRTC')
>                  continue
>  
> -            self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
> -                  (connector.fullname, crtc.id, mode.name, len(planes)))
> +            self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> +                            f'mode {mode.name} with {len(planes)} planes')
>  
>              # Create a frame buffer and draw a test pattern.
>              fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> @@ -154,7 +154,7 @@ class CRCTest(kmstest.KMSTest):
>              # Set the mode and add all planes
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
>              if ret < 0:
> -                self.fail('atomic mode set failed with %d' % ret)
> +                self.fail(f'atomic mode set failed with {ret}')
>                  continue
>  
>              req = kmstest.AtomicRequest(self)
> @@ -177,7 +177,7 @@ class CRCTest(kmstest.KMSTest):
>  
>              ret = req.commit(0)
>              if ret < 0:
> -                self.fail('atomic plane set failed with %d' % ret)
> +                self.fail(f'atomic plane set failed with {ret}')
>                  continue
>  
>              # Wait for one second and make sure the page flip has completed.
> @@ -191,9 +191,9 @@ class CRCTest(kmstest.KMSTest):
>                  if source == crtc:
>                      crc_source = 'auto'
>                  else:
> -                    crc_source = 'plane%u' % source.id
> +                    crc_source = f'plane{source.id}'
>  
> -                self.logger.log('Computing CRC from source %s' % crc_source)
> +                self.logger.log(f'Computing CRC from source {crc_source}')
>  
>                  # Set the CRC source and acquire 10 CRC values. Discard the
>                  # first value, as the device is running and the new source
> @@ -204,7 +204,7 @@ class CRCTest(kmstest.KMSTest):
>                  crc_reader.stop()
>  
>                  crcs = [c.crcs[0] for c in crcs[1:]]
> -                self.logger.log('CRC value[0] 0x%08x' % crcs[0])
> +                self.logger.log(f'CRC value[0] 0x{crcs[0]:08x}')
>  
>                  failures = 0
>                  ref_crc = composer.crc(source)
> @@ -212,12 +212,11 @@ class CRCTest(kmstest.KMSTest):
>                  for i in range(len(crcs)):
>                      crc = crcs[i]
>                      if crc != ref_crc:
> -                        self.logger.log('CRC value[%u] 0x%08x does not match reference 0x%08x'
> -                                        % (i, crc, ref_crc))
> +                        self.logger.log(f'CRC value[{i}] 0x{crc:08x} does not match reference 0x{ref_crc:08x}')
>                          failures += 1
>  
>                  if failures:
> -                    self.fail('Incorrect CRC values on source %s' % crc_source)
> +                    self.fail(f'Incorrect CRC values on source {crc_source}')
>                      break
>  
>              else:
> diff --git a/tests/kms-test-formats.py b/tests/kms-test-formats.py
> index ce849437b2fa..5c3bfd441a38 100755
> --- a/tests/kms-test-formats.py
> +++ b/tests/kms-test-formats.py
> @@ -37,8 +37,8 @@ class FormatsTest(kmstest.KMSTest):
>              self.skip('no CRTC available with connector')
>              return
>  
> -        self.logger.log('Testing connector %s, CRTC %u, mode %s' % \
> -              (connector.fullname, crtc.id, mode.name))
> +        self.logger.log(f'Testing connector {connector.fullname}, '
> +                        f'CRTC {crtc.id}, mode {mode.name}')
>  
>          failed = 0
>  
> @@ -46,7 +46,7 @@ class FormatsTest(kmstest.KMSTest):
>          for i in range(num_formats):
>              format = crtc.primary_plane.formats[i]
>  
> -            self.logger.log('Testing format %s' % format)
> +            self.logger.log(f'Testing format {format}')
>              self.progress(i+1, num_formats)
>  
>              # Create a frame buffer
> @@ -62,7 +62,7 @@ class FormatsTest(kmstest.KMSTest):
>              # Set the mode with a primary plane
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
>              if ret < 0:
> -                self.logger.log('atomic mode set failed with %d' % ret)
> +                self.logger.log(f'atomic mode set failed with {ret}')
>                  failed += 1
>                  continue
>  
> @@ -71,7 +71,7 @@ class FormatsTest(kmstest.KMSTest):
>          self.atomic_crtc_disable(crtc)
>  
>          if failed:
> -            self.fail('%s/%s formats failed' % (failed, num_formats))
> +            self.fail(f'{failed}/{num_formats} formats failed')
>          else:
>              self.success()
>  
> diff --git a/tests/kms-test-legacy-modeset.py b/tests/kms-test-legacy-modeset.py
> index f856178172c0..06eceade19c4 100755
> --- a/tests/kms-test-legacy-modeset.py
> +++ b/tests/kms-test-legacy-modeset.py
> @@ -13,7 +13,7 @@ class LegacyModeSetTest(kmstest.KMSTest):
>  
>      def main(self):
>          for connector in self.output_connectors():
> -            self.start('legacy mode set on connector %s' % connector.fullname)
> +            self.start(f'legacy mode set on connector {connector.fullname}')
>  
>              # Skip disconnected connectors
>              if not connector.connected():
> @@ -36,8 +36,8 @@ class LegacyModeSetTest(kmstest.KMSTest):
>                  self.skip('no mode available')
>                  continue
>  
> -            self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
> -                  (connector.fullname, crtc.id, mode.name))
> +            self.logger.log(f'Testing connector {connector.fullname} '
> +                            f'on CRTC {crtc.id} with mode {mode.name}')
>  
>              # Create a frame buffer
>              fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> @@ -46,7 +46,7 @@ class LegacyModeSetTest(kmstest.KMSTest):
>              # Perform a mode set
>              ret = crtc.set_mode(connector, fb, mode)
>              if ret < 0:
> -                self.fail('legacy mode set failed with %d' % ret)
> +                self.fail(f'legacy mode set failed with {ret}')
>                  continue
>  
>              self.logger.log('Legacy mode set complete')
> @@ -54,7 +54,7 @@ class LegacyModeSetTest(kmstest.KMSTest):
>  
>              ret = crtc.disable_mode()
>              if ret < 0:
> -                self.fail('legacy mode set disable failed with %d' % ret)
> +                self.fail(f'legacy mode set disable failed with {ret}')
>                  continue
>  
>              self.success()
> diff --git a/tests/kms-test-modes.py b/tests/kms-test-modes.py
> index 433bb0bdd157..c47848904ec4 100755
> --- a/tests/kms-test-modes.py
> +++ b/tests/kms-test-modes.py
> @@ -12,8 +12,8 @@ class ModesTest(kmstest.KMSTest):
>          self.logger.log('Page flip complete')
>  
>      def test_mode(self, connector, crtc, mode):
> -        self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
> -              (connector.fullname, crtc.id, mode.name))
> +        self.logger.log(f'Testing connector {connector.fullname} '
> +                        f'on CRTC {crtc.id} with mode {mode.name}')
>  
>          # Create a frame buffer
>          fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> @@ -22,7 +22,7 @@ class ModesTest(kmstest.KMSTest):
>          # Perform the mode set
>          ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
>          if ret < 0:
> -            raise RuntimeError('atomic mode set failed with %d' % ret)
> +            raise RuntimeError(f'atomic mode set failed with {ret}')
>  
>          self.logger.log('Atomic mode set complete')
>          self.run(4)
> @@ -33,7 +33,7 @@ class ModesTest(kmstest.KMSTest):
>  
>      def main(self):
>          for connector in self.output_connectors():
> -            self.start('modes on connector %s' % connector.fullname)
> +            self.start(f'modes on connector {connector.fullname}')
>  
>              # Skip disconnected connectors
>              if not connector.connected():
> diff --git a/tests/kms-test-modeset.py b/tests/kms-test-modeset.py
> index a6ba61c920e5..e8b3d9ac37f9 100755
> --- a/tests/kms-test-modeset.py
> +++ b/tests/kms-test-modeset.py
> @@ -13,7 +13,7 @@ class ModeSetTest(kmstest.KMSTest):
>  
>      def main(self):
>          for connector in self.output_connectors():
> -            self.start('atomic mode set on connector %s' % connector.fullname)
> +            self.start(f'atomic mode set on connector {connector.fullname}')
>  
>              # Skip disconnected connectors
>              if not connector.connected():
> @@ -36,8 +36,8 @@ class ModeSetTest(kmstest.KMSTest):
>                  self.skip('no mode available')
>                  continue
>  
> -            self.logger.log('Testing connector %s on CRTC %u with mode %s' % \
> -                  (connector.fullname, crtc.id, mode.name))
> +            self.logger.log(f'Testing connector {connector.fullname} '
> +                            f'on CRTC {crtc.id} with mode {mode.name}')
>  
>              # Create a frame buffer
>              fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> @@ -46,7 +46,7 @@ class ModeSetTest(kmstest.KMSTest):
>              # Perform a mode set
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
>              if ret < 0:
> -                self.fail('atomic mode set failed with %d' % ret)
> +                self.fail(f'atomic mode set failed with {ret}')
>                  continue
>  
>              self.logger.log('Atomic mode set complete')
> diff --git a/tests/kms-test-pageflip.py b/tests/kms-test-pageflip.py
> index 15dae6a23ab3..14bea0a877a3 100755
> --- a/tests/kms-test-pageflip.py
> +++ b/tests/kms-test-pageflip.py
> @@ -13,12 +13,12 @@ class PageFlipTest(kmstest.KMSTest):
>  
>      def handle_page_flip(self, frame, time):
>          if self.flips == 1:
> -            self.logger.log('first page flip frame %u time %f' % (frame, time))
> +            self.logger.log(f'first page flip frame {frame} time {time}')
>              self.frame_start = frame
>              self.time_start = time
>  
>          if self.stop_requested:
> -            self.logger.log('last page flip frame %u time %f' % (frame, time))
> +            self.logger.log(f'last page flip frame {frame} time {time}')
>              self.frame_end = frame
>              self.time_end = time
>              self.loop.stop()
> @@ -43,7 +43,7 @@ class PageFlipTest(kmstest.KMSTest):
>  
>      def main(self):
>          for connector in self.output_connectors():
> -            self.start('page flip on connector %s' % connector.fullname)
> +            self.start(f'page flip on connector {connector.fullname}')
>  
>              # Skip disconnected connectors
>              if not connector.connected():
> @@ -67,7 +67,7 @@ class PageFlipTest(kmstest.KMSTest):
>                      self.plane = plane
>                      break
>              else:
> -                self.skip('no plane available for CRTC %u' % crtc.id)
> +                self.skip(f'no plane available for CRTC {crtc.id}')
>                  continue
>  
>              # Get the default mode for the connector
> @@ -77,8 +77,8 @@ class PageFlipTest(kmstest.KMSTest):
>                  self.skip('no mode available')
>                  continue
>  
> -            self.logger.log('Testing connector %s, CRTC %u, plane %u, mode %s' % \
> -                  (connector.fullname, crtc.id, self.plane.id, mode.name))
> +            self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> +                            f'plane {self.plane.id}, mode {mode.name}')
>  
>              # Create two frame buffers
>              self.fbs = []
> @@ -88,7 +88,7 @@ class PageFlipTest(kmstest.KMSTest):
>              # Set the mode and perform the initial page flip
>              ret = self.atomic_crtc_mode_set(crtc, connector, mode, self.fbs[0])
>              if ret < 0:
> -                self.fail('atomic mode set failed with %d' % ret)
> +                self.fail(f'atomic mode set failed with {ret}')
>                  continue
>  
>              # Flip pages for 10s
> @@ -114,8 +114,8 @@ class PageFlipTest(kmstest.KMSTest):
>  
>              frames = self.frame_end - self.frame_start + 1
>              interval = self.time_end - self.time_start
> -            self.logger.log('Frame rate: %f (%u/%u frames in %f s)' % \
> -                (frames / interval, self.flips, frames, interval))
> +            self.logger.log(f'Frame rate: {frames / interval} '
> +                            f'({self.flips}/{frames} frames in {interval} s)')
>              self.success()
>  
>  PageFlipTest().execute()
> diff --git a/tests/kms-test-planeposition.py b/tests/kms-test-planeposition.py
> index e843ae13c50c..aceb849950a1 100755
> --- a/tests/kms-test-planeposition.py
> +++ b/tests/kms-test-planeposition.py
> @@ -42,8 +42,8 @@ class PlanePositionTest(kmstest.KMSTest):
>              self.skip('no CRTC available with connector and at least two planes')
>              return
>  
> -        self.logger.log('Testing connector %s, CRTC %u, mode %s with %u planes' % \
> -              (connector.fullname, crtc.id, mode.name, len(planes)))
> +        self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> +                        f'mode {mode.name} with {len(planes)} planes')
>  
>          # Create a frame buffer
>          fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> @@ -52,7 +52,7 @@ class PlanePositionTest(kmstest.KMSTest):
>          # Set the mode with no plane, wait 5s for the monitor to wake up
>          ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
>          if ret < 0:
> -            self.fail('atomic mode set failed with %d' % ret)
> +            self.fail(f'atomic mode set failed with {ret}')
>              return
>  
>          self.logger.log('Initial atomic mode set completed')
> @@ -63,7 +63,7 @@ class PlanePositionTest(kmstest.KMSTest):
>          destination = kmstest.Rect(0, 0, fb.width // 2, fb.height)
>          ret = self.atomic_plane_set(planes[0], crtc, source, destination, fb, sync=True)
>          if ret < 0:
> -            self.fail('atomic plane set for first plane failed with %d' % ret)
> +            self.fail(f'atomic plane set for first plane failed with {ret}')
>              return
>  
>          self.logger.log('Root plane enabled')
> @@ -79,10 +79,10 @@ class PlanePositionTest(kmstest.KMSTest):
>  
>              ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
>              if ret < 0:
> -                self.fail('atomic plane set with offset %d,%d' % offset)
> +                self.fail(f'atomic plane set with offset {offset}')
>                  return
>  
> -            self.logger.log('Moved overlay plane to %d,%d' % offset)
> +            self.logger.log(f'Moved overlay plane to {offset}')
>              time.sleep(3)
>  
>          # Try to move the plane completely off-screen. The device is expected
> @@ -97,10 +97,10 @@ class PlanePositionTest(kmstest.KMSTest):
>  
>              ret = self.atomic_plane_set(planes[1], crtc, source, destination, fb, sync=True)
>              if ret < 0:
> -                self.fail('atomic plane set with offset %d,%d' % offset)
> +                self.fail(f'atomic plane set with offset {offset}')
>                  return
>  
> -            self.logger.log('Moved overlay plane to %d,%d' % offset)
> +            self.logger.log(f'Moved overlay plane to {offset}')
>              time.sleep(3)
>  
>          # Disable and re-enable the plane when it is off-screen. The device is
> diff --git a/tests/kms-test-routing.py b/tests/kms-test-routing.py
> index 69f8be127d2f..68aff9c11cff 100755
> --- a/tests/kms-test-routing.py
> +++ b/tests/kms-test-routing.py
> @@ -64,10 +64,10 @@ class RoutingTest(kmstest.KMSTest):
>          fb = pykms.DumbFramebuffer(self.card, max_hdisplay, max_vdisplay, 'XR24')
>          pykms.draw_test_pattern(fb)
>  
> -        self.start('Moving connector %s between CRTCs %s' % \
> -                   (shared_connector.fullname, [pipe.crtc.id for pipe in pipes]))
> +        self.start(f'Moving connector {shared_connector.fullname} '
> +                   f'between CRTCs {[pipe.crtc.id for pipe in pipes]}')
>  
> -        self.logger.log('Highest display resolution: %ux%u' % (max_hdisplay, max_vdisplay))
> +        self.logger.log(f'Highest display resolution: {max_hdisplay}x{max_vdisplay}')
>  
>          for master_pipe in pipes:
>              req = kmstest.AtomicRequest(self)
> @@ -97,13 +97,13 @@ class RoutingTest(kmstest.KMSTest):
>                              'CRTC_H': mode.vdisplay,
>                          })
>  
> -                route.append('CRTC %u to connector %s' % (pipe.crtc.id, pipe.connector.fullname))
> +                route.append(f'CRTC {pipe.crtc.id} to connector {pipe.connector.fullname}')
>  
>              self.logger.log('Routing ' + ', '.join(route))
>  
>              ret = req.commit_sync(True)
>              if ret < 0:
> -                self.fail('atomic commit failed with %d' % ret)
> +                self.fail(f'atomic commit failed with {ret}')
>                  return
>  
>              time.sleep(5)
> diff --git a/tests/kmstest.py b/tests/kmstest.py
> index 708e6999d1f0..14e28cd47fbd 100755
> --- a/tests/kmstest.py
> +++ b/tests/kmstest.py
> @@ -113,7 +113,7 @@ class KernelLogReader(object):
>  
>  class Logger(object):
>      def __init__(self, name):
> -        self.logfile = open('%s.log' % name, 'w')
> +        self.logfile = open(f'{name}.log', 'w')
>          self._kmsg = KernelLogReader()
>  
>      def __del__(self):
> @@ -129,7 +129,7 @@ class Logger(object):
>      def event(self):
>          kmsgs = self._kmsg.read()
>          for msg in kmsgs:
> -            self.logfile.write('K [%6f] %s\n' % (msg.timestamp, msg.msg))
> +            self.logfile.write(f'K [{msg.timestamp:6f} {msg.msg}\n')
>          self.logfile.flush()
>  
>      @property
> @@ -146,7 +146,7 @@ class Logger(object):
>          self.event()
>  
>          now = time.clock_gettime(time.CLOCK_MONOTONIC)
> -        self.logfile.write('U [%6f] %s\n' % (now, msg))
> +        self.logfile.write(f'U [{now:6f}] {msg}\n')
>          self.logfile.flush()
>  
>  
> @@ -171,7 +171,7 @@ class CRCReader(object):
>  
>          # Hardcode the device minor to 0 as the KMSTest constructor opens the
>          # default card object.
> -        self.dir = os.open('/sys/kernel/debug/dri/0/crtc-%u/crc' % self.pipe, 0)
> +        self.dir = os.open('f/sys/kernel/debug/dri/0/crtc-{self.pipe}/crc', 0)
>          self.ctrl = os.open('control', os.O_WRONLY, dir_fd = self.dir)
>          self.data = -1
>  
> @@ -211,7 +211,7 @@ class Dist(object):
>          self.y = y
>  
>      def __repr__(self):
> -        return '(%d,%d)' % (self.x, self.y)
> +        return f'({self.x},{self.y})'
>  
>  
>  class Point(object):
> @@ -220,7 +220,7 @@ class Point(object):
>          self.y = y
>  
>      def __repr__(self):
> -        return '(%d,%d)' % (self.x, self.y)
> +        return f'({self.x},{self.y})'
>  
>      def move(self, distance):
>          self.x += distance.x
> @@ -233,7 +233,7 @@ class Size(object):
>          self.height = height
>  
>      def __repr__(self):
> -        return '%ux%u' % (self.width, self.height)
> +        return f'{self.width}x{self.height}'
>  
>  
>  class Rect(object):
> @@ -244,7 +244,7 @@ class Rect(object):
>          self.height = height
>  
>      def __repr__(self):
> -        return '(%d,%d)/%ux%u' % (self.left, self.top, self.width, self.height)
> +        return f'({self.left},{self.top})/{self.width}x{self.height}'
>  
>      def isEmpty(self):
>          """Check if the rectangle has a zero width or height"""
> @@ -462,24 +462,24 @@ class KMSTest(object):
>      def start(self, name):
>          """Start a test."""
>          self.test_name = name
> -        self.logger.log('Testing %s' % name)
> -        sys.stdout.write('Testing %s: ' % name)
> +        self.logger.log(f'Testing {name}')
> +        sys.stdout.write(f'Testing {name}: ')
>          sys.stdout.flush()
>  
>      def progress(self, current, maximum):
> -        sys.stdout.write('\rTesting %s: %u/%u' % (self.test_name, current, maximum))
> +        sys.stdout.write(f'\rTesting {self.test_name}: {current}/{maximum}')
>          sys.stdout.flush()
>  
>      def fail(self, reason):
>          """Complete a test with failure."""
> -        self.logger.log('Test failed. Reason: %s' % reason)
> +        self.logger.log(f'Test failed. Reason: {reason}')
>          self.logger.flush()
> -        sys.stdout.write('\rTesting %s: FAIL\n' % self.test_name)
> +        sys.stdout.write(f'\rTesting {self.test_name}: FAIL\n')
>          sys.stdout.flush()
>  
>      def skip(self, reason):
>          """Complete a test with skip."""
> -        self.logger.log('Test skipped. Reason: %s' % reason)
> +        self.logger.log(f'Test skipped. Reason: {reason}')
>          self.logger.flush()
>          sys.stdout.write('SKIP\n')
>          sys.stdout.flush()
> @@ -488,6 +488,6 @@ class KMSTest(object):
>          """Complete a test with success."""
>          self.logger.log('Test completed successfully')
>          self.logger.flush()
> -        sys.stdout.write('\rTesting %s: SUCCESS\n' % self.test_name)
> +        sys.stdout.write(f'\rTesting {self.test_name}: SUCCESS\n')
>          sys.stdout.flush()
>  
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 03/10] tests: allplanes: Log the plane IDs
  2022-06-09 23:40 ` [kms-test] [PATCH 03/10] tests: allplanes: Log the plane IDs Laurent Pinchart
@ 2022-06-29 15:30   ` Kieran Bingham
  2022-06-29 18:06     ` Laurent Pinchart
  0 siblings, 1 reply; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:30 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:24)
> Plane IDs are useful for debugging, log them.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kms-test-allplanes.py | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/kms-test-allplanes.py b/tests/kms-test-allplanes.py
> index 0fe6cfab0a2d..96ac4f19f538 100755
> --- a/tests/kms-test-allplanes.py
> +++ b/tests/kms-test-allplanes.py
> @@ -46,7 +46,8 @@ class AllPlanesTest(kmstest.KMSTest):
>                  continue
>  
>              self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> -                            f'mode {mode.name} with {len(planes)} planes')
> +                            f'mode {mode.name} with {len(planes)} planes '
> +                            f'(P: {crtc.primary_plane.id}, O: {[plane.id for plane in planes]})')

Is P plane / Primary ? And O ... Other ?

either way, it's debug info that's helpful (and I hope more obvious) to
the reader at runtime.


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

>  
>              # Create a frame buffer
>              fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 04/10] kmstest: Move props value formatting to AtomicRequest
  2022-06-09 23:40 ` [kms-test] [PATCH 04/10] kmstest: Move props value formatting to AtomicRequest Laurent Pinchart
@ 2022-06-29 15:36   ` Kieran Bingham
  2022-06-29 18:13     ` Laurent Pinchart
  0 siblings, 1 reply; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:36 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:25)
> Centralize props value formatting in the AtomicRequest.add() function to
> avoid having to call it manually through the code base.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kmstest.py | 18 ++++++++++--------
>  1 file changed, 10 insertions(+), 8 deletions(-)
> 
> diff --git a/tests/kmstest.py b/tests/kmstest.py
> index 14e28cd47fbd..2afaa513aa4d 100755
> --- a/tests/kmstest.py
> +++ b/tests/kmstest.py
> @@ -258,15 +258,20 @@ class AtomicRequest(pykms.AtomicReq):
>          self.__test = test
>          self.__props = {}
>  
> +    def __format_props(self, props):

This is only validating the value arguements right, to ensure they are
limited to 64 bit...

> +        return {k: v & ((1 << 64) - 1) for k, v in props.items()}
> +

Not this patch, but seems like 'add()' would benefit from some
documentation here to show how to use it, what to pass etc.

It's complex to read from just this context, but I can just about see
that this patch is cleaning things up.

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

>      def add(self, obj, *kwargs):
>          if obj.id not in self.__props:
>              self.__props[obj.id] = {}
> -        props = self.__props[obj.id]
> +        obj_props = self.__props[obj.id]
>  
>          if len(kwargs) == 1 and isinstance(kwargs[0], collections.abc.Mapping):
> -            props.update(kwargs[0])
> +            props = self.__format_props(kwargs[0])
>          elif len(kwargs) == 2:
> -            props[kwargs[0]] = kwargs[1]
> +            props = self.__format_props({ kwargs[0]: = kwargs[1] })
> +
> +        obj_props.update(props)
>  
>          super().add(obj, *kwargs)
>  
> @@ -309,9 +314,6 @@ class KMSTest(object):
>      def __del__(self):
>          self.logger.close()
>  
> -    def __format_props(self, props):
> -        return {k: v & ((1 << 64) - 1) for k, v in props.items()}
> -
>      def atomic_crtc_disable(self, crtc, sync=True):
>          req = AtomicRequest(self)
>          req.add(crtc, {'ACTIVE': 0, 'MODE_ID': 0})
> @@ -368,7 +370,7 @@ class KMSTest(object):
>  
>      def atomic_plane_set(self, plane, crtc, source, destination, fb, sync=False):
>          req = AtomicRequest(self)
> -        req.add(plane, self.__format_props({
> +        req.add(plane, {
>                      'FB_ID': fb.id,
>                      'CRTC_ID': crtc.id,
>                      'SRC_X': int(source.left * 65536),
> @@ -379,7 +381,7 @@ class KMSTest(object):
>                      'CRTC_Y': destination.top,
>                      'CRTC_W': destination.width,
>                      'CRTC_H': destination.height,
> -        }))
> +        })
>          if sync:
>              return req.commit_sync()
>          else:
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 05/10] kmstest: Support specifying property values in percents
  2022-06-09 23:40 ` [kms-test] [PATCH 05/10] kmstest: Support specifying property values in percents Laurent Pinchart
@ 2022-06-29 15:39   ` Kieran Bingham
  0 siblings, 0 replies; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:39 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:26)
> If the property is a string that ends with a '%' character, treat it as
> a percentage of the range reported by the property and convert it to the
> corresponding numerical value.
> 

This seems neat, I'm guessing that following patches are about to show
me the use case, so I'll just throw this in now:


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kmstest.py | 27 ++++++++++++++++++++++-----
>  1 file changed, 22 insertions(+), 5 deletions(-)
> 
> diff --git a/tests/kmstest.py b/tests/kmstest.py
> index 2afaa513aa4d..a99bf3b89d34 100755
> --- a/tests/kmstest.py
> +++ b/tests/kmstest.py
> @@ -258,8 +258,25 @@ class AtomicRequest(pykms.AtomicReq):
>          self.__test = test
>          self.__props = {}
>  
> -    def __format_props(self, props):
> -        return {k: v & ((1 << 64) - 1) for k, v in props.items()}
> +    def __format_props(self, obj, props):
> +        out = {}
> +        for k, v in props.items():
> +            if isinstance(v, str):
> +                if v.endswith('%'):
> +                    prop = obj.get_prop(k)
> +                    if prop.type not in (pykms.PropertyType.Range, pykms.PropertyType.SignedRange):
> +                        raise RuntimeError(f'Unsupported property type {prop.type} for value {v}')
> +
> +                    min, max = prop.values
> +                    v = min + int((max - min) * int(v[:-1]) / 100)
> +                else:
> +                    v = int(v)
> +
> +            if not isinstance(v, int):
> +                raise RuntimeError(f'Unsupported value type {type(v)} for property {k}')
> +
> +            out[k] = v & ((1 << 64) - 1)
> +        return out
>  
>      def add(self, obj, *kwargs):
>          if obj.id not in self.__props:
> @@ -267,13 +284,13 @@ class AtomicRequest(pykms.AtomicReq):
>          obj_props = self.__props[obj.id]
>  
>          if len(kwargs) == 1 and isinstance(kwargs[0], collections.abc.Mapping):
> -            props = self.__format_props(kwargs[0])
> +            props = self.__format_props(obj, kwargs[0])
>          elif len(kwargs) == 2:
> -            props = self.__format_props({ kwargs[0]: = kwargs[1] })
> +            props = self.__format_props(obj, { kwargs[0]: kwargs[1] })
>  
>          obj_props.update(props)
>  
> -        super().add(obj, *kwargs)
> +        super().add(obj, props)
>  
>      def commit(self, data=0, allow_modeset=False):
>          ret = super().commit(data, allow_modeset)
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 10/10] tests: Rename kms-test-planeposition.py to kms-test-plane-position.py
  2022-06-09 23:40 ` [kms-test] [PATCH 10/10] tests: Rename kms-test-planeposition.py to kms-test-plane-position.py Laurent Pinchart
@ 2022-06-29 15:44   ` Kieran Bingham
  0 siblings, 0 replies; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:44 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:31)
> Match the name scheme of other tests by renaming
> kms-test-planeposition.py to kms-test-plane-position.py.
> 

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/{kms-test-planeposition.py => kms-test-plane-position.py} | 0
>  1 file changed, 0 insertions(+), 0 deletions(-)
>  rename tests/{kms-test-planeposition.py => kms-test-plane-position.py} (100%)
> 
> diff --git a/tests/kms-test-planeposition.py b/tests/kms-test-plane-position.py
> similarity index 100%
> rename from tests/kms-test-planeposition.py
> rename to tests/kms-test-plane-position.py
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 06/10] kmstest: Support specifying alpha value for planes
  2022-06-09 23:40 ` [kms-test] [PATCH 06/10] kmstest: Support specifying alpha value for planes Laurent Pinchart
@ 2022-06-29 15:45   ` Kieran Bingham
  0 siblings, 0 replies; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:45 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:27)
> Add an optional alpha argument to the atomic_plane_set() function to
> specify the alpha value for the plane.
> 


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kmstest.py | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/kmstest.py b/tests/kmstest.py
> index a99bf3b89d34..1c2a1b46ebe7 100755
> --- a/tests/kmstest.py
> +++ b/tests/kmstest.py
> @@ -385,7 +385,7 @@ class KMSTest(object):
>          else:
>              return req.commit(0, True)
>  
> -    def atomic_plane_set(self, plane, crtc, source, destination, fb, sync=False):
> +    def atomic_plane_set(self, plane, crtc, source, destination, fb, alpha=None, sync=False):
>          req = AtomicRequest(self)
>          req.add(plane, {
>                      'FB_ID': fb.id,
> @@ -399,6 +399,8 @@ class KMSTest(object):
>                      'CRTC_W': destination.width,
>                      'CRTC_H': destination.height,
>          })
> +        if alpha is not None:
> +            req.add(plane, 'alpha', alpha)
>          if sync:
>              return req.commit_sync()
>          else:
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 07/10] tests: Add plane alpha test
  2022-06-09 23:40 ` [kms-test] [PATCH 07/10] tests: Add plane alpha test Laurent Pinchart
@ 2022-06-29 15:48   ` Kieran Bingham
  0 siblings, 0 replies; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:48 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:28)
> Add a test that enables multiple planes with different alpha values.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kms-test-plane-alpha.py | 97 +++++++++++++++++++++++++++++++++++
>  1 file changed, 97 insertions(+)
>  create mode 100755 tests/kms-test-plane-alpha.py
> 
> diff --git a/tests/kms-test-plane-alpha.py b/tests/kms-test-plane-alpha.py
> new file mode 100755
> index 000000000000..8802bfeae40c
> --- /dev/null
> +++ b/tests/kms-test-plane-alpha.py
> @@ -0,0 +1,97 @@
> +#!/usr/bin/python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Renesas Electronics Corporation
> +
> +import kmstest
> +import pykms
> +
> +class PlaneAlphaTest(kmstest.KMSTest):
> +    """Test composition with multiple planes and alpha channels."""
> +
> +    def handle_page_flip(self, frame, time):
> +        self.logger.log('Page flip complete')
> +
> +    def find_pipeline(self):
> +        # Find a CRTC that has multiple planes with a connected connector
> +        for connector in self.output_connectors():
> +            # Skip disconnected connectors
> +            if not connector.connected():
> +                continue
> +
> +            # Add the connector to the map
> +            for crtc in connector.get_possible_crtcs():
> +                planes = []
> +                for plane in self.card.planes:
> +                    if plane.supports_crtc(crtc) and plane != crtc.primary_plane:
> +                        planes.append(plane)
> +
> +                if len(planes):
> +                    return crtc, connector, planes
> +
> +        return None, None, None
> +
> +    def main(self):
> +        self.start('composition with alpha control')
> +
> +        crtc, connector, planes = self.find_pipeline()
> +        if crtc is None:
> +            self.skip('no suitable pipeline')
> +            return
> +
> +        # Get the default mode
> +        try:
> +            mode = connector.get_default_mode()
> +        except KeyError:
> +            self.skip('no mode available')
> +            return
> +
> +        self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> +                        f'mode {mode.name} with {len(planes)} planes '
> +                        f'(P: {crtc.primary_plane.id}, O: {[plane.id for plane in planes]})')
> +
> +        # Create a frame buffer
> +        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> +        pykms.draw_test_pattern(fb)
> +
> +        # Set the mode with a primary plane
> +        ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
> +        if ret < 0:
> +            self.fail(f'atomic mode set failed with {ret}')
> +            return
> +
> +        req = kmstest.AtomicRequest(self)
> +        req.add(crtc.primary_plane, 'alpha', '50%')

Nice. That's better than having to identify the range and set it
explicitly.


> +        ret = req.commit_sync(True)
> +        if ret < 0:
> +            self.fail(f'failed to set alpha for primary plane: {ret}')
> +            return
> +
> +        self.run(3)
> +
> +        # Add all other planes one by one
> +        alpha = 20
> +        offset = 100
> +        for plane in planes:
> +            source = kmstest.Rect(0, 0, fb.width, fb.height)
> +            destination = kmstest.Rect(offset, offset, fb.width, fb.height)
> +            ret = self.atomic_plane_set(plane, crtc, source, destination, fb, alpha=f'{alpha}%')
> +            if ret < 0:
> +                self.fail(f'atomic plane set failed with {ret}')
> +                break
> +
> +            self.logger.log(f'Adding plane {plane.id}')
> +            self.run(1)
> +
> +            if self.flips == 0:
> +                self.fail('No page flip registered')
> +                break
> +
> +            alpha = min(alpha + 20, 100)

Curious to see this. I'll have to spin up a board and display.


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> +            offset += 50
> +
> +        else:
> +            self.success()
> +
> +        self.atomic_crtc_disable(crtc)
> +
> +PlaneAlphaTest().execute()
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 08/10] kmstest: Support specifying zpos value for planes
  2022-06-09 23:40 ` [kms-test] [PATCH 08/10] kmstest: Support specifying zpos value for planes Laurent Pinchart
@ 2022-06-29 15:48   ` Kieran Bingham
  0 siblings, 0 replies; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:48 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:29)
> Add an optional zpos argument to the atomic_plane_set() function to
> allow controlling the zpos of a plane.

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kmstest.py | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/kmstest.py b/tests/kmstest.py
> index 1c2a1b46ebe7..11cc328b5b32 100755
> --- a/tests/kmstest.py
> +++ b/tests/kmstest.py
> @@ -385,7 +385,7 @@ class KMSTest(object):
>          else:
>              return req.commit(0, True)
>  
> -    def atomic_plane_set(self, plane, crtc, source, destination, fb, alpha=None, sync=False):
> +    def atomic_plane_set(self, plane, crtc, source, destination, fb, alpha=None, zpos=None, sync=False):
>          req = AtomicRequest(self)
>          req.add(plane, {
>                      'FB_ID': fb.id,
> @@ -401,6 +401,8 @@ class KMSTest(object):
>          })
>          if alpha is not None:
>              req.add(plane, 'alpha', alpha)
> +        if zpos is not None:
> +            req.add(plane, 'zpos', zpos)
>          if sync:
>              return req.commit_sync()
>          else:
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 09/10] tests: Add plane zpos test
  2022-06-09 23:40 ` [kms-test] [PATCH 09/10] tests: Add plane zpos test Laurent Pinchart
@ 2022-06-29 15:52   ` Kieran Bingham
  2022-06-29 18:08     ` Laurent Pinchart
  0 siblings, 1 reply; 24+ messages in thread
From: Kieran Bingham @ 2022-06-29 15:52 UTC (permalink / raw)
  To: Laurent Pinchart, linux-renesas-soc

Quoting Laurent Pinchart (2022-06-10 00:40:30)
> Add a test that enables multiple planes with different zpos values.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  tests/kms-test-plane-zpos.py | 102 +++++++++++++++++++++++++++++++++++
>  1 file changed, 102 insertions(+)
>  create mode 100755 tests/kms-test-plane-zpos.py
> 
> diff --git a/tests/kms-test-plane-zpos.py b/tests/kms-test-plane-zpos.py
> new file mode 100755
> index 000000000000..052eea542ec0
> --- /dev/null
> +++ b/tests/kms-test-plane-zpos.py
> @@ -0,0 +1,102 @@
> +#!/usr/bin/python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# SPDX-FileCopyrightText: 2022 Renesas Electronics Corporation
> +
> +import kmstest
> +import pykms
> +
> +class PlaneZPosTest(kmstest.KMSTest):
> +    """Test composition with multiple planes and custom z-pos."""
> +
> +    def handle_page_flip(self, frame, time):
> +        self.logger.log('Page flip complete')
> +
> +    def find_pipeline(self):
> +        # Find a CRTC that has multiple planes with a connected connector
> +        for connector in self.output_connectors():
> +            # Skip disconnected connectors
> +            if not connector.connected():
> +                continue
> +
> +            # Add the connector to the map
> +            for crtc in connector.get_possible_crtcs():
> +                planes = []
> +                for plane in self.card.planes:
> +                    if plane.supports_crtc(crtc) and plane != crtc.primary_plane:
> +                        planes.append(plane)
> +
> +                if len(planes):
> +                    return crtc, connector, planes
> +
> +        return None, None, None
> +
> +    def main(self):
> +        self.start('composition with z-pos control')
> +
> +        crtc, connector, planes = self.find_pipeline()
> +        if crtc is None:
> +            self.skip('no suitable pipeline')
> +            return
> +
> +        # Get the default mode
> +        try:
> +            mode = connector.get_default_mode()
> +        except KeyError:
> +            self.skip('no mode available')
> +            return
> +
> +        self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> +                        f'mode {mode.name} with {len(planes)} planes '
> +                        f'(P: {crtc.primary_plane.id}, O: {[plane.id for plane in planes]})')
> +
> +        # Create a frame buffer
> +        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> +        pykms.draw_test_pattern(fb)
> +
> +        # Set the mode with a primary plane, and position it on top of the
> +        # stack. Make it transparent to visualize the overlay planes that will

How handy that there's now transparency ;-)

> +        # be positioned underneath.
> +        zpos = len(planes)
> +        ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
> +        if ret < 0:
> +            self.fail(f'atomic mode set failed with {ret}')
> +            return
> +
> +        req = kmstest.AtomicRequest(self)
> +        req.add(crtc.primary_plane, 'alpha', '50%')
> +        req.add(crtc.primary_plane, 'zpos', zpos)

Not that it matters, but those could both be added in a single statement
right?

(not needed, just understanding the API of .add() )


> +        ret = req.commit_sync(True)
> +        if ret < 0:
> +            self.fail(f'failed to set properties for primary plane: {ret}')
> +            return
> +
> +        self.run(3)
> +
> +        # Add all other planes one by one
> +        offset = 100 + 50 * (len(planes) - 1)
> +
> +        for plane in planes:
> +            zpos -= 1
> +
> +            source = kmstest.Rect(0, 0, fb.width, fb.height)
> +            destination = kmstest.Rect(offset, offset, fb.width, fb.height)
> +            ret = self.atomic_plane_set(plane, crtc, source, destination, fb, alpha='100%', zpos=zpos)

Seems pretty good to me.


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> +            if ret < 0:
> +                self.fail(f'atomic plane set failed with {ret}')
> +                break
> +
> +            self.logger.log(f'Adding plane {plane.id}')
> +            self.run(1)
> +
> +            if self.flips == 0:
> +                self.fail('No page flip registered')
> +                break
> +
> +            offset -= 50
> +
> +        else:
> +            self.success()
> +
> +        self.atomic_crtc_disable(crtc)
> +
> +PlaneZPosTest().execute()
> -- 
> Regards,
> 
> Laurent Pinchart
>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 03/10] tests: allplanes: Log the plane IDs
  2022-06-29 15:30   ` Kieran Bingham
@ 2022-06-29 18:06     ` Laurent Pinchart
  0 siblings, 0 replies; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-29 18:06 UTC (permalink / raw)
  To: Kieran Bingham; +Cc: linux-renesas-soc

On Wed, Jun 29, 2022 at 04:30:26PM +0100, Kieran Bingham wrote:
> Quoting Laurent Pinchart (2022-06-10 00:40:24)
> > Plane IDs are useful for debugging, log them.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  tests/kms-test-allplanes.py | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> > 
> > diff --git a/tests/kms-test-allplanes.py b/tests/kms-test-allplanes.py
> > index 0fe6cfab0a2d..96ac4f19f538 100755
> > --- a/tests/kms-test-allplanes.py
> > +++ b/tests/kms-test-allplanes.py
> > @@ -46,7 +46,8 @@ class AllPlanesTest(kmstest.KMSTest):
> >                  continue
> >  
> >              self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> > -                            f'mode {mode.name} with {len(planes)} planes')
> > +                            f'mode {mode.name} with {len(planes)} planes '
> > +                            f'(P: {crtc.primary_plane.id}, O: {[plane.id for plane in planes]})')
> 
> Is P plane / Primary ? And O ... Other ?

It's Primary and Overlay.

> either way, it's debug info that's helpful (and I hope more obvious) to
> the reader at runtime.
> 
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> >  
> >              # Create a frame buffer
> >              fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 09/10] tests: Add plane zpos test
  2022-06-29 15:52   ` Kieran Bingham
@ 2022-06-29 18:08     ` Laurent Pinchart
  0 siblings, 0 replies; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-29 18:08 UTC (permalink / raw)
  To: Kieran Bingham; +Cc: linux-renesas-soc

On Wed, Jun 29, 2022 at 04:52:10PM +0100, Kieran Bingham wrote:
> Quoting Laurent Pinchart (2022-06-10 00:40:30)
> > Add a test that enables multiple planes with different zpos values.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  tests/kms-test-plane-zpos.py | 102 +++++++++++++++++++++++++++++++++++
> >  1 file changed, 102 insertions(+)
> >  create mode 100755 tests/kms-test-plane-zpos.py
> > 
> > diff --git a/tests/kms-test-plane-zpos.py b/tests/kms-test-plane-zpos.py
> > new file mode 100755
> > index 000000000000..052eea542ec0
> > --- /dev/null
> > +++ b/tests/kms-test-plane-zpos.py
> > @@ -0,0 +1,102 @@
> > +#!/usr/bin/python3
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +# SPDX-FileCopyrightText: 2022 Renesas Electronics Corporation
> > +
> > +import kmstest
> > +import pykms
> > +
> > +class PlaneZPosTest(kmstest.KMSTest):
> > +    """Test composition with multiple planes and custom z-pos."""
> > +
> > +    def handle_page_flip(self, frame, time):
> > +        self.logger.log('Page flip complete')
> > +
> > +    def find_pipeline(self):
> > +        # Find a CRTC that has multiple planes with a connected connector
> > +        for connector in self.output_connectors():
> > +            # Skip disconnected connectors
> > +            if not connector.connected():
> > +                continue
> > +
> > +            # Add the connector to the map
> > +            for crtc in connector.get_possible_crtcs():
> > +                planes = []
> > +                for plane in self.card.planes:
> > +                    if plane.supports_crtc(crtc) and plane != crtc.primary_plane:
> > +                        planes.append(plane)
> > +
> > +                if len(planes):
> > +                    return crtc, connector, planes
> > +
> > +        return None, None, None
> > +
> > +    def main(self):
> > +        self.start('composition with z-pos control')
> > +
> > +        crtc, connector, planes = self.find_pipeline()
> > +        if crtc is None:
> > +            self.skip('no suitable pipeline')
> > +            return
> > +
> > +        # Get the default mode
> > +        try:
> > +            mode = connector.get_default_mode()
> > +        except KeyError:
> > +            self.skip('no mode available')
> > +            return
> > +
> > +        self.logger.log(f'Testing connector {connector.fullname}, CRTC {crtc.id}, '
> > +                        f'mode {mode.name} with {len(planes)} planes '
> > +                        f'(P: {crtc.primary_plane.id}, O: {[plane.id for plane in planes]})')
> > +
> > +        # Create a frame buffer
> > +        fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, 'XR24')
> > +        pykms.draw_test_pattern(fb)
> > +
> > +        # Set the mode with a primary plane, and position it on top of the
> > +        # stack. Make it transparent to visualize the overlay planes that will
> 
> How handy that there's now transparency ;-)
> 
> > +        # be positioned underneath.
> > +        zpos = len(planes)
> > +        ret = self.atomic_crtc_mode_set(crtc, connector, mode, fb)
> > +        if ret < 0:
> > +            self.fail(f'atomic mode set failed with {ret}')
> > +            return
> > +
> > +        req = kmstest.AtomicRequest(self)
> > +        req.add(crtc.primary_plane, 'alpha', '50%')
> > +        req.add(crtc.primary_plane, 'zpos', zpos)
> 
> Not that it matters, but those could both be added in a single statement
> right?

Yes, that's right.

> (not needed, just understanding the API of .add() )
> 
> > +        ret = req.commit_sync(True)
> > +        if ret < 0:
> > +            self.fail(f'failed to set properties for primary plane: {ret}')
> > +            return
> > +
> > +        self.run(3)
> > +
> > +        # Add all other planes one by one
> > +        offset = 100 + 50 * (len(planes) - 1)
> > +
> > +        for plane in planes:
> > +            zpos -= 1
> > +
> > +            source = kmstest.Rect(0, 0, fb.width, fb.height)
> > +            destination = kmstest.Rect(offset, offset, fb.width, fb.height)
> > +            ret = self.atomic_plane_set(plane, crtc, source, destination, fb, alpha='100%', zpos=zpos)
> 
> Seems pretty good to me.
> 
> 
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> > +            if ret < 0:
> > +                self.fail(f'atomic plane set failed with {ret}')
> > +                break
> > +
> > +            self.logger.log(f'Adding plane {plane.id}')
> > +            self.run(1)
> > +
> > +            if self.flips == 0:
> > +                self.fail('No page flip registered')
> > +                break
> > +
> > +            offset -= 50
> > +
> > +        else:
> > +            self.success()
> > +
> > +        self.atomic_crtc_disable(crtc)
> > +
> > +PlaneZPosTest().execute()

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [kms-test] [PATCH 04/10] kmstest: Move props value formatting to AtomicRequest
  2022-06-29 15:36   ` Kieran Bingham
@ 2022-06-29 18:13     ` Laurent Pinchart
  0 siblings, 0 replies; 24+ messages in thread
From: Laurent Pinchart @ 2022-06-29 18:13 UTC (permalink / raw)
  To: Kieran Bingham; +Cc: linux-renesas-soc

On Wed, Jun 29, 2022 at 04:36:49PM +0100, Kieran Bingham wrote:
> Quoting Laurent Pinchart (2022-06-10 00:40:25)
> > Centralize props value formatting in the AtomicRequest.add() function to
> > avoid having to call it manually through the code base.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  tests/kmstest.py | 18 ++++++++++--------
> >  1 file changed, 10 insertions(+), 8 deletions(-)
> > 
> > diff --git a/tests/kmstest.py b/tests/kmstest.py
> > index 14e28cd47fbd..2afaa513aa4d 100755
> > --- a/tests/kmstest.py
> > +++ b/tests/kmstest.py
> > @@ -258,15 +258,20 @@ class AtomicRequest(pykms.AtomicReq):
> >          self.__test = test
> >          self.__props = {}
> >  
> > +    def __format_props(self, props):
> 
> This is only validating the value arguements right, to ensure they are
> limited to 64 bit...

That's right, and it's mostly for negative values, that Python would
otherwise handle incorrectly (if I recall correctly that's due to the
bindings for the add() method mapping to the uint64_t, without automatic
conversion for negative values).

> > +        return {k: v & ((1 << 64) - 1) for k, v in props.items()}
> > +
> 
> Not this patch, but seems like 'add()' would benefit from some
> documentation here to show how to use it, what to pass etc.

Good point.

> It's complex to read from just this context, but I can just about see
> that this patch is cleaning things up.
> 
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> >      def add(self, obj, *kwargs):
> >          if obj.id not in self.__props:
> >              self.__props[obj.id] = {}
> > -        props = self.__props[obj.id]
> > +        obj_props = self.__props[obj.id]
> >  
> >          if len(kwargs) == 1 and isinstance(kwargs[0], collections.abc.Mapping):
> > -            props.update(kwargs[0])
> > +            props = self.__format_props(kwargs[0])
> >          elif len(kwargs) == 2:
> > -            props[kwargs[0]] = kwargs[1]
> > +            props = self.__format_props({ kwargs[0]: = kwargs[1] })
> > +
> > +        obj_props.update(props)
> >  
> >          super().add(obj, *kwargs)
> >  
> > @@ -309,9 +314,6 @@ class KMSTest(object):
> >      def __del__(self):
> >          self.logger.close()
> >  
> > -    def __format_props(self, props):
> > -        return {k: v & ((1 << 64) - 1) for k, v in props.items()}
> > -
> >      def atomic_crtc_disable(self, crtc, sync=True):
> >          req = AtomicRequest(self)
> >          req.add(crtc, {'ACTIVE': 0, 'MODE_ID': 0})
> > @@ -368,7 +370,7 @@ class KMSTest(object):
> >  
> >      def atomic_plane_set(self, plane, crtc, source, destination, fb, sync=False):
> >          req = AtomicRequest(self)
> > -        req.add(plane, self.__format_props({
> > +        req.add(plane, {
> >                      'FB_ID': fb.id,
> >                      'CRTC_ID': crtc.id,
> >                      'SRC_X': int(source.left * 65536),
> > @@ -379,7 +381,7 @@ class KMSTest(object):
> >                      'CRTC_Y': destination.top,
> >                      'CRTC_W': destination.width,
> >                      'CRTC_H': destination.height,
> > -        }))
> > +        })
> >          if sync:
> >              return req.commit_sync()
> >          else:

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2022-06-29 18:13 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-09 23:40 [kms-test] [PATCH 00/10] Test plane alpha and zpos control Laurent Pinchart
2022-06-09 23:40 ` [kms-test] [PATCH 01/10] tests: Replace double quotes with single quotes Laurent Pinchart
2022-06-29 13:22   ` Kieran Bingham
2022-06-09 23:40 ` [kms-test] [PATCH 02/10] tests: Convert to formatted string literals Laurent Pinchart
2022-06-29 15:28   ` Kieran Bingham
2022-06-09 23:40 ` [kms-test] [PATCH 03/10] tests: allplanes: Log the plane IDs Laurent Pinchart
2022-06-29 15:30   ` Kieran Bingham
2022-06-29 18:06     ` Laurent Pinchart
2022-06-09 23:40 ` [kms-test] [PATCH 04/10] kmstest: Move props value formatting to AtomicRequest Laurent Pinchart
2022-06-29 15:36   ` Kieran Bingham
2022-06-29 18:13     ` Laurent Pinchart
2022-06-09 23:40 ` [kms-test] [PATCH 05/10] kmstest: Support specifying property values in percents Laurent Pinchart
2022-06-29 15:39   ` Kieran Bingham
2022-06-09 23:40 ` [kms-test] [PATCH 06/10] kmstest: Support specifying alpha value for planes Laurent Pinchart
2022-06-29 15:45   ` Kieran Bingham
2022-06-09 23:40 ` [kms-test] [PATCH 07/10] tests: Add plane alpha test Laurent Pinchart
2022-06-29 15:48   ` Kieran Bingham
2022-06-09 23:40 ` [kms-test] [PATCH 08/10] kmstest: Support specifying zpos value for planes Laurent Pinchart
2022-06-29 15:48   ` Kieran Bingham
2022-06-09 23:40 ` [kms-test] [PATCH 09/10] tests: Add plane zpos test Laurent Pinchart
2022-06-29 15:52   ` Kieran Bingham
2022-06-29 18:08     ` Laurent Pinchart
2022-06-09 23:40 ` [kms-test] [PATCH 10/10] tests: Rename kms-test-planeposition.py to kms-test-plane-position.py Laurent Pinchart
2022-06-29 15:44   ` Kieran Bingham

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.