@@ -33,6 +33,7 @@ The tests scripts require the following dependencies to be installed on the
target.
* Python 3
+* The Python module 'crcmod'
* kmsxx Python bindings (https://github.com/tomba/kmsxx.git)
kmsxx hasn't released any stable version yet, it is recommended to use the
@@ -3,8 +3,10 @@
# SPDX-FileCopyrightText: 2017-2019 Renesas Electronics Corporation
import copy
+import crcmod
import kmstest
import pykms
+import tempfile
class Composer(object):
@@ -17,15 +19,31 @@ class Composer(object):
START_POINT = kmstest.Point(0, 0)
INCREMENT = kmstest.Dist(50, 50)
- def __init__(self, crtc, planes, fb):
+ # The CRC initial value is XORed with the final XOR value, so we need to
+ # pass 0 to get the desired 0xffffffff initial value.
+ CRC = crcmod.Crc(0x104c11db7, 0x00000000, True, 0xffffffff)
+
+ def __init__(self, mode, crtc, planes, fb):
+ self.__screen_size = kmstest.Size(mode.hdisplay, mode.vdisplay)
self.__fb_size = kmstest.Size(fb.width, fb.height)
self.__planes_positions = {}
+ self.__crcs = {}
+
+ # Dump the contents of the frame buffer to compute the CRCs.
+ file = tempfile.TemporaryFile()
+ pykms.dump_framebuffer(fb, file.fileno())
+ file.seek(0)
+ image = file.read()
+ file.close()
position = copy.copy(Composer.START_POINT)
for plane in planes:
self.__planes_positions[plane] = copy.copy(position)
+ self.__crcs[plane] = self.__plane_crc(plane, image)
position.move(Composer.INCREMENT)
+ self.__crcs[crtc] = self.__crtc_crc(planes, image)
+
def source(self, plane):
pos = self.__planes_positions[plane]
return kmstest.Rect(0, 0,
@@ -39,6 +57,50 @@ class Composer(object):
max(0, self.__fb_size.height - pos.y))
+ def crc(self, obj):
+ return self.__crcs[obj]
+
+ def __plane_crc(self, plane, image):
+ # Compute the reference CRC for a plane. Only the visible part of the
+ # plane is used by the hardware.
+
+ crcg = Composer.CRC.new()
+
+ src = self.source(plane)
+ if src.isEmpty():
+ return 0
+
+ for y in range(src.height):
+ src_offset = ((src.top + y) * self.__fb_size.width + src.left) * 4
+ crcg.update(image[src_offset:src_offset+src.width*4])
+
+ return crcg.crcValue
+
+ def __crtc_crc(self, planes, image):
+ # Compute the reference CRC for the composed display output. Start with
+ # a black background and compose the planes.
+
+ crcg = Composer.CRC.new()
+
+ # The background is set to black, with and alpha value of 255 (opaque)
+ # to match the BRx configuration.
+ output = [0, 0, 0, 255] * (self.__screen_size.width * self.__screen_size.height)
+
+ # Compose planes on top.
+ for plane in planes:
+ src = self.source(plane)
+ dst = self.destination(plane)
+
+ for y in range(src.height):
+ src_offset = ((src.top + y) * self.__fb_size.width + src.left) * 4
+ dst_offset = ((dst.top + y) * self.__screen_size.width + dst.left) * 4
+ output[dst_offset:dst_offset+src.width*4] = image[src_offset:src_offset+src.width*4]
+
+ crcg.update(bytes(output))
+
+ return crcg.crcValue
+
+
class CRCTest(kmstest.KMSTest):
"""Test CRC calculation on pipeline output."""
@@ -86,8 +148,8 @@ class CRCTest(kmstest.KMSTest):
fb = pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, "XR24")
pykms.draw_test_pattern(fb)
- # Create a composer.
- composer = Composer(crtc, planes, fb)
+ # Create a composer. This will compute the reference CRCs.
+ composer = Composer(mode, crtc, planes, fb)
# Set the mode and add all planes
ret = self.atomic_crtc_mode_set(crtc, connector, mode, sync=True)
@@ -124,21 +186,40 @@ class CRCTest(kmstest.KMSTest):
self.fail("No page flip registered")
continue
- sources = ["auto"] + ["plane%u" % plane.id for plane in planes]
- for src in sources:
- self.logger.log("Computing CRC in source %s" % src)
+ sources = [crtc] + planes
+ for source in sources:
+ if source == crtc:
+ crc_source = "auto"
+ else:
+ crc_source = "plane%u" % source.id
+ 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
+ # needs one frame to take effect.
crc_reader = kmstest.CRCReader(crtc)
- crc_reader.start(src)
+ crc_reader.start(crc_source)
crcs = crc_reader.read(10)
crc_reader.stop()
- crcs = [c.crcs[0] for c in crcs]
- if len(set(crcs)) != 1:
- self.fail("CRC values not constant on source %s" % src)
+ crcs = [c.crcs[0] for c in crcs[1:]]
+ self.logger.log("CRC value[0] 0x%08x" % crcs[0])
+
+ failures = 0
+ ref_crc = composer.crc(source)
+
+ 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))
+ failures += 1
+
+ if failures:
+ self.fail("Incorrect CRC values on source %s" % crc_source)
break
- self.logger.log("CRC value 0x%08x" % crcs[0])
else:
self.success()
Instead of only checking that the CRC value is constant, compute the expected CRC value, and compare it to the hardware-generated CRC. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- README | 1 + tests/kms-test-crc.py | 103 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 93 insertions(+), 11 deletions(-)