* [PATCH] tests: Add an output routing test
@ 2019-06-17 20:25 Laurent Pinchart
2019-06-18 21:25 ` Kieran Bingham
0 siblings, 1 reply; 2+ messages in thread
From: Laurent Pinchart @ 2019-06-17 20:25 UTC (permalink / raw)
To: linux-renesas-soc; +Cc: Kieran Bingham
Add a test that moves an output connector between multiple CRTCs with a
single mode set operation at each step, without going through disable
and reenable cycles. This helps testing the routing configuration code
paths in the commit tail handler.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
tests/kms-test-routing.py | 148 ++++++++++++++++++++++++++++++++++++++
1 file changed, 148 insertions(+)
create mode 100755 tests/kms-test-routing.py
diff --git a/tests/kms-test-routing.py b/tests/kms-test-routing.py
new file mode 100755
index 000000000000..2cf02ddcc6b5
--- /dev/null
+++ b/tests/kms-test-routing.py
@@ -0,0 +1,148 @@
+#!/usr/bin/python3
+
+import kmstest
+import pykms
+import time
+
+class Pipeline(object):
+ def __init__(self, crtc):
+ self.crtc = crtc
+ self.connector = None
+ self.plane = None
+ self.mode_blob = None
+
+
+class RoutingTest(kmstest.KMSTest):
+ """Test output routing."""
+
+ def main(self):
+
+ # Create the reverse map from CRTC to possible connectors and calculate
+ # the largest resolution.
+ self.crtc_to_connectors = {}
+ max_hdisplay = 0
+ max_vdisplay = 0
+
+ for connector in self.card.connectors:
+ if connector.fullname.startswith('writeback-'):
+ continue
+
+ mode = connector.get_default_mode()
+ max_hdisplay = max(mode.hdisplay, max_hdisplay)
+ max_vdisplay = max(mode.vdisplay, max_vdisplay)
+
+ for crtc in connector.get_possible_crtcs():
+ if not crtc in self.crtc_to_connectors:
+ self.crtc_to_connectors[crtc] = []
+ self.crtc_to_connectors[crtc].append(connector)
+
+ # Find a connector that can be routed to at least two CRTCs that have
+ # at least two output routes each.
+ shared_connector = None
+ for connector in self.card.connectors:
+ if connector.fullname.startswith('writeback-'):
+ continue
+
+ pipes = []
+ for crtc in connector.get_possible_crtcs():
+ if len(self.crtc_to_connectors[crtc]) >= 2:
+ pipes.append(Pipeline(crtc))
+
+ if len(pipes) >= 2:
+ shared_connector = connector
+ break
+
+ if not shared_connector:
+ self.skip("No suitable connector")
+ return
+
+ # Allocate planes for each CRTC.
+ pool = [(pipe, list(pipe.crtc.possible_planes)) for pipe in pipes]
+ while len(pool):
+ pool.sort(key=lambda elem: len(elem[1]), reverse=True)
+ pipe, planes = pool[-1]
+ pipe.plane = planes[0]
+ 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")
+ pykms.draw_test_pattern(fb)
+
+ 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))
+
+ for master_pipe in pipes:
+ req = kmstest.AtomicRequest(self)
+ connectors = self.allocate_connectors(pipes, master_pipe, shared_connector)
+ route = []
+
+ for pipe in pipes:
+ if pipe.connector and not pipe.connector in connectors.values():
+ req.add(pipe.connector, 'CRTC_ID', 0)
+
+ pipe.connector = connectors[pipe.crtc]
+ mode = pipe.connector.get_default_mode()
+ pipe.mode_blob = mode.to_blob(self.card)
+
+ req.add(pipe.connector, 'CRTC_ID', pipe.crtc.id)
+ req.add(pipe.crtc, {'ACTIVE': 1, 'MODE_ID': pipe.mode_blob.id})
+ req.add(pipe.plane, {
+ 'FB_ID': fb.id,
+ 'CRTC_ID': pipe.crtc.id,
+ 'SRC_X': 0,
+ 'SRC_Y': 0,
+ 'SRC_W': int(mode.hdisplay * 65536),
+ 'SRC_H': int(mode.vdisplay * 65536),
+ 'CRTC_X': 0,
+ 'CRTC_Y': 0,
+ 'CRTC_W': mode.hdisplay,
+ 'CRTC_H': mode.vdisplay,
+ })
+
+ route.append("CRTC %u to connector %s" % (pipe.crtc.id, 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)
+ return
+
+ time.sleep(5)
+
+ self.success()
+
+ for pipe in pipes:
+ self.atomic_crtc_disable(pipe.crtc)
+
+
+ def allocate_connectors(self, pipes, master_pipe, shared_connector):
+ # Allocate one connector for each CRTC. Create a pool of available
+ # connectors for each CRTC, sorted by the number of connectors, and
+ # allocate started with the CRTC that has the least number of options.
+ # The master CRTC is always given the shared connector.
+ pool = []
+ for pipe in pipes:
+ if pipe == master_pipe:
+ pool.append((pipe.crtc, [shared_connector]))
+ continue
+
+ pool.append((pipe.crtc, list(self.crtc_to_connectors[pipe.crtc])))
+
+ allocated = {}
+ while len(pool):
+ pool.sort(key=lambda elem: len(elem[1]), reverse=True)
+ crtc, connectors = pool[-1]
+
+ connector = connectors[0]
+ allocated[crtc] = connector
+
+ # Remove the selected connector from all elements in the pool
+ pool = [(elem[0], [c for c in elem[1] if c != connector]) for elem in pool[:-1]]
+
+ return allocated
+
+
+RoutingTest().execute()
--
Regards,
Laurent Pinchart
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] tests: Add an output routing test
2019-06-17 20:25 [PATCH] tests: Add an output routing test Laurent Pinchart
@ 2019-06-18 21:25 ` Kieran Bingham
0 siblings, 0 replies; 2+ messages in thread
From: Kieran Bingham @ 2019-06-18 21:25 UTC (permalink / raw)
To: Laurent Pinchart, linux-renesas-soc
Hi Laurent,
On 17/06/2019 21:25, Laurent Pinchart wrote:
> Add a test that moves an output connector between multiple CRTCs with a
> single mode set operation at each step, without going through disable
> and reenable cycles. This helps testing the routing configuration code
> paths in the commit tail handler.
>
Small concern about the duplication of skipping writeback connectors
which we may likely need across other tests, but that is probably a
separate patch on it's own right.
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> tests/kms-test-routing.py | 148 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 148 insertions(+)
> create mode 100755 tests/kms-test-routing.py
>
> diff --git a/tests/kms-test-routing.py b/tests/kms-test-routing.py
> new file mode 100755
> index 000000000000..2cf02ddcc6b5
> --- /dev/null
> +++ b/tests/kms-test-routing.py
> @@ -0,0 +1,148 @@
> +#!/usr/bin/python3
> +
> +import kmstest
> +import pykms
> +import time
> +
> +class Pipeline(object):
> + def __init__(self, crtc):
> + self.crtc = crtc
> + self.connector = None
> + self.plane = None
> + self.mode_blob = None
> +
> +
> +class RoutingTest(kmstest.KMSTest):
> + """Test output routing."""
> +
> + def main(self):
> +
> + # Create the reverse map from CRTC to possible connectors and calculate
> + # the largest resolution.
> + self.crtc_to_connectors = {}
> + max_hdisplay = 0
> + max_vdisplay = 0
> +
> + for connector in self.card.connectors:
> + if connector.fullname.startswith('writeback-'):
> + continue
Will this need to be added to other existing tests to deal with
writeback? And if so - should it be some sort of common library generator?
> +
> + mode = connector.get_default_mode()
> + max_hdisplay = max(mode.hdisplay, max_hdisplay)
> + max_vdisplay = max(mode.vdisplay, max_vdisplay)
> +
> + for crtc in connector.get_possible_crtcs():
> + if not crtc in self.crtc_to_connectors:
> + self.crtc_to_connectors[crtc] = []
> + self.crtc_to_connectors[crtc].append(connector)
> +
> + # Find a connector that can be routed to at least two CRTCs that have
> + # at least two output routes each.
> + shared_connector = None
> + for connector in self.card.connectors:
> + if connector.fullname.startswith('writeback-'):
> + continue
> +
Oh - especially now it's already been duplicated!
> + pipes = []
> + for crtc in connector.get_possible_crtcs():
> + if len(self.crtc_to_connectors[crtc]) >= 2:
> + pipes.append(Pipeline(crtc))
> +
> + if len(pipes) >= 2:
> + shared_connector = connector
> + break
> +
> + if not shared_connector:
> + self.skip("No suitable connector")
> + return
> +
> + # Allocate planes for each CRTC.
> + pool = [(pipe, list(pipe.crtc.possible_planes)) for pipe in pipes]
> + while len(pool):
> + pool.sort(key=lambda elem: len(elem[1]), reverse=True)
> + pipe, planes = pool[-1]
> + pipe.plane = planes[0]
> + 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")
> + pykms.draw_test_pattern(fb)
> +
> + 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))
> +
> + for master_pipe in pipes:
> + req = kmstest.AtomicRequest(self)
> + connectors = self.allocate_connectors(pipes, master_pipe, shared_connector)
> + route = []
> +
> + for pipe in pipes:
> + if pipe.connector and not pipe.connector in connectors.values():
> + req.add(pipe.connector, 'CRTC_ID', 0)
> +
> + pipe.connector = connectors[pipe.crtc]
> + mode = pipe.connector.get_default_mode()
> + pipe.mode_blob = mode.to_blob(self.card)
> +
> + req.add(pipe.connector, 'CRTC_ID', pipe.crtc.id)
> + req.add(pipe.crtc, {'ACTIVE': 1, 'MODE_ID': pipe.mode_blob.id})
> + req.add(pipe.plane, {
> + 'FB_ID': fb.id,
> + 'CRTC_ID': pipe.crtc.id,
> + 'SRC_X': 0,
> + 'SRC_Y': 0,
> + 'SRC_W': int(mode.hdisplay * 65536),
> + 'SRC_H': int(mode.vdisplay * 65536),
> + 'CRTC_X': 0,
> + 'CRTC_Y': 0,
> + 'CRTC_W': mode.hdisplay,
> + 'CRTC_H': mode.vdisplay,
> + })
> +
> + route.append("CRTC %u to connector %s" % (pipe.crtc.id, 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)
> + return
> +
> + time.sleep(5)
> +
> + self.success()
> +
> + for pipe in pipes:
> + self.atomic_crtc_disable(pipe.crtc)
> +
> +
> + def allocate_connectors(self, pipes, master_pipe, shared_connector):
> + # Allocate one connector for each CRTC. Create a pool of available
> + # connectors for each CRTC, sorted by the number of connectors, and
> + # allocate started with the CRTC that has the least number of options.
> + # The master CRTC is always given the shared connector.
> + pool = []
> + for pipe in pipes:
> + if pipe == master_pipe:
> + pool.append((pipe.crtc, [shared_connector]))
> + continue
> +
> + pool.append((pipe.crtc, list(self.crtc_to_connectors[pipe.crtc])))
> +
> + allocated = {}
> + while len(pool):
> + pool.sort(key=lambda elem: len(elem[1]), reverse=True)
> + crtc, connectors = pool[-1]
> +
> + connector = connectors[0]
> + allocated[crtc] = connector
> +
> + # Remove the selected connector from all elements in the pool
> + pool = [(elem[0], [c for c in elem[1] if c != connector]) for elem in pool[:-1]]
> +
> + return allocated
> +
> +
> +RoutingTest().execute()
>
--
Regards
--
Kieran
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2019-06-18 21:26 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-17 20:25 [PATCH] tests: Add an output routing test Laurent Pinchart
2019-06-18 21:25 ` Kieran Bingham
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).