[igt-dev] [PATCH i-g-t 2/6] kms_writeback: Add initial writeback tests

Maarten Lankhorst maarten.lankhorst at linux.intel.com
Tue Jun 26 12:44:08 UTC 2018


Op 26-06-18 om 10:38 schreef Liviu Dudau:
> On Mon, Jun 25, 2018 at 02:48:47PM +0200, Maarten Lankhorst wrote:
>> Op 01-03-18 om 18:38 schreef Liviu Dudau:
>>> From: Brian Starkey <brian.starkey at arm.com>
>>>
>>> Add tests for the WRITEBACK_PIXEL_FORMATS, WRITEBACK_OUT_FENCE_PTR and
>>> WRITEBACK_FB_ID properties on writeback connectors, ensuring their
>>> behaviour is correct.
>>>
>>> Signed-off-by: Brian Starkey <brian.starkey at arm.com>
>>> ---
>>>  lib/igt_kms.c          |   7 +-
>>>  lib/igt_kms.h          |   8 ++
>>>  tests/Makefile.sources |   1 +
>>>  tests/kms_writeback.c  | 352 +++++++++++++++++++++++++++++++++++++++++++++++++
>>>  tests/meson.build      |   1 +
>>>  5 files changed, 365 insertions(+), 4 deletions(-)
>>>  create mode 100644 tests/kms_writeback.c
>>>
>>> diff --git a/lib/igt_kms.c b/lib/igt_kms.c
>>> index 00d9d2e2..d558c1b8 100644
>>> --- a/lib/igt_kms.c
>>> +++ b/lib/igt_kms.c
>>> @@ -2267,8 +2267,7 @@ static uint32_t igt_plane_get_fb_id(igt_plane_t *plane)
>>>  /*
>>>   * Add position and fb changes of a plane to the atomic property set
>>>   */
>>> -static void
>>> -igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe,
>>> +void igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe,
>>>  	drmModeAtomicReq *req)
>>>  {
>>>  	igt_display_t *display = pipe->display;
>>> @@ -2878,7 +2877,7 @@ igt_pipe_obj_replace_prop_blob(igt_pipe_t *pipe, enum igt_atomic_crtc_properties
>>>  /*
>>>   * Add crtc property changes to the atomic property set
>>>   */
>>> -static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req)
>>> +void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req)
>>>  {
>>>  	int i;
>>>  
>>> @@ -2902,7 +2901,7 @@ static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicRe
>>>  /*
>>>   * Add connector property changes to the atomic property set
>>>   */
>>> -static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req)
>>> +void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req)
>>>  {
>>>  
>>>  	int i;
>>> diff --git a/lib/igt_kms.h b/lib/igt_kms.h
>>> index 59ccc4c6..f38fd0a0 100644
>>> --- a/lib/igt_kms.h
>>> +++ b/lib/igt_kms.h
>>> @@ -581,6 +581,12 @@ extern void igt_output_replace_prop_blob(igt_output_t *output,
>>>  					 enum igt_atomic_connector_properties prop,
>>>  					 const void *ptr, size_t length);
>>>  
>>> +void igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe,
>>> +	drmModeAtomicReq *req);
>>> +
>>> +
>>> +void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req);
>>> +
>>>  /**
>>>   * igt_pipe_obj_has_prop:
>>>   * @pipe: Pipe to check.
>>> @@ -670,6 +676,8 @@ extern void igt_pipe_obj_replace_prop_blob(igt_pipe_t *pipe,
>>>  
>>>  void igt_pipe_refresh(igt_display_t *display, enum pipe pipe, bool force);
>>>  
>>> +void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req);
>>> +
>>>  void igt_enable_connectors(void);
>>>  void igt_reset_connectors(void);
>> Please don't..
> More context on what I should not do/say/write would be helpful.
>
>>> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
>>> index 23f859be..9cfa474d 100644
>>> --- a/tests/Makefile.sources
>>> +++ b/tests/Makefile.sources
>>> @@ -212,6 +212,7 @@ TESTS_progs = \
>>>  	kms_tv_load_detect \
>>>  	kms_universal_plane \
>>>  	kms_vblank \
>>> +	kms_writeback \
>>>  	meta_test \
>>>  	perf \
>>>  	perf_pmu \
>>> diff --git a/tests/kms_writeback.c b/tests/kms_writeback.c
>>> new file mode 100644
>>> index 00000000..d922213d
>>> --- /dev/null
>>> +++ b/tests/kms_writeback.c
>>> @@ -0,0 +1,352 @@
>>> +/*
>>> + * (C) COPYRIGHT 2017 ARM Limited. All rights reserved.
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining a
>>> + * copy of this software and associated documentation files (the "Software"),
>>> + * to deal in the Software without restriction, including without limitation
>>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>>> + * and/or sell copies of the Software, and to permit persons to whom the
>>> + * Software is furnished to do so, subject to the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice (including the next
>>> + * paragraph) shall be included in all copies or substantial portions of the
>>> + * Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>>> + * IN THE SOFTWARE.
>>> + *
>>> + */
>>> +
>>> +#include <errno.h>
>>> +#include <stdbool.h>
>>> +#include <stdio.h>
>>> +#include <string.h>
>>> +
>>> +#include "igt.h"
>>> +#include "igt_core.h"
>>> +#include "igt_fb.h"
>>> +
>>> +/* We need to define these ourselves until we get an updated libdrm */
>>> +#ifndef DRM_MODE_CONNECTOR_WRITEBACK
>>> +#define DRM_MODE_CONNECTOR_WRITEBACK   18
>>> +#endif
>>> +
>>> +static drmModePropertyBlobRes *get_writeback_formats_blob(igt_output_t *output)
>>> +{
>>> +	drmModePropertyBlobRes *blob = NULL;
>>> +	uint64_t blob_id;
>>> +	int ret;
>>> +
>>> +	ret = kmstest_get_property(output->display->drm_fd,
>>> +				   output->config.connector->connector_id,
>>> +				   DRM_MODE_OBJECT_CONNECTOR,
>>> +				   igt_connector_prop_names[IGT_CONNECTOR_WRITEBACK_PIXEL_FORMATS],
>>> +				   NULL, &blob_id, NULL);
>>> +	if (ret)
>>> +		blob = drmModeGetPropertyBlob(output->display->drm_fd, blob_id);
>>> +
>>> +	igt_assert(blob);
>>> +
>>> +	return blob;
>>> +}
>>> +
>>> +static bool check_writeback_config(igt_display_t *display, igt_output_t *output)
>>> +{
>>> +	igt_fb_t input_fb, output_fb;
>>> +	igt_plane_t *plane;
>>> +	uint32_t writeback_format = DRM_FORMAT_XRGB8888;
>>> +	uint64_t tiling = igt_fb_mod_to_tiling(0);
>>> +	int width, height, ret;
>>> +	drmModeModeInfo override_mode = {
>>> +		.clock = 25175,
>>> +		.hdisplay = 640,
>>> +		.hsync_start = 656,
>>> +		.hsync_end = 752,
>>> +		.htotal = 800,
>>> +		.hskew = 0,
>>> +		.vdisplay = 480,
>>> +		.vsync_start = 490,
>>> +		.vsync_end = 492,
>>> +		.vtotal = 525,
>>> +		.vscan = 0,
>>> +		.vrefresh = 60,
>>> +		.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
>>> +		.name = {"640x480-60"},
>>> +	};
>>> +	igt_output_override_mode(output, &override_mode);
>> Could we perhaps update igt_output_is_connected to always return true when mode override
>> is set, so we don't have to force enable the connector?
> Yes, that is now obsolete as we have a client cap as well that will hide
> the connector unless set, so this patch needs updating as well.
>
>>> +	width = override_mode.hdisplay;
>>> +	height = override_mode.vdisplay;
>>> +
>>> +	ret = igt_create_fb(display->drm_fd, width, height, DRM_FORMAT_XRGB8888,
>>> +			    tiling, &input_fb);
>>> +	igt_assert(ret >= 0);
>>> +
>>> +	ret = igt_create_fb(display->drm_fd, width, height, writeback_format,
>>> +			    tiling, &output_fb);
>>> +	igt_assert(ret >= 0);
>>> +
>>> +	plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
>>> +	igt_plane_set_fb(plane, &input_fb);
>>> +	igt_output_set_writeback_fb(output, &output_fb);
>>> +
>>> +	ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY |
>>> +					    DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
>>> +	igt_plane_set_fb(plane, NULL);
>>> +	igt_remove_fb(display->drm_fd, &input_fb);
>>> +	igt_remove_fb(display->drm_fd, &output_fb);
>>> +
>>> +	return !ret;
>>> +}
>>> +
>>> +static igt_output_t *kms_writeback_get_output(igt_display_t *display)
>>> +{
>>> +	int i;
>>> +
>>> +	for (i = 0; i < display->n_outputs; i++) {
>>> +		igt_output_t *output = &display->outputs[i];
>>> +		int j;
>>> +
>>> +		if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
>>> +			continue;
>>> +
>>> +		kmstest_force_connector(display->drm_fd, output->config.connector, FORCE_CONNECTOR_ON);
>>> +
>>> +		for (j = 0; j < igt_display_get_n_pipes(display); j++) {
>>> +			igt_output_set_pipe(output, j);
>>> +
>>> +			if (check_writeback_config(display, output)) {
>>> +				igt_debug("Using connector %u:%s on pipe %d\n",
>>> +					  output->config.connector->connector_id,
>>> +					  output->name, j);
>>> +				return output;
>>> +			}
>>> +		}
>>> +
>>> +		/* Restore any connectors we don't use, so we don't trip on them later */
>>> +		kmstest_force_connector(display->drm_fd, output->config.connector, FORCE_CONNECTOR_UNSPECIFIED);
>>> +	}
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +static void check_writeback_fb_id(igt_output_t *output)
>>> +{
>>> +	bool found;
>>> +	uint64_t check_fb_id;
>>> +
>>> +	found = kmstest_get_property(output->display->drm_fd, output->id,
>>> +				     DRM_MODE_OBJECT_CONNECTOR,
>>> +				     igt_connector_prop_names[IGT_CONNECTOR_WRITEBACK_FB_ID],
>>> +				     NULL, &check_fb_id, NULL);
>>> +	igt_assert(found && (check_fb_id == 0));
>>> +}
>>> +
>>> +static int do_writeback_test(igt_output_t *output, uint32_t flags,
>>> +			      uint32_t fb_id, int32_t *out_fence_ptr,
>>> +			      bool ptr_valid)
>>> +{
>>> +	int ret;
>>> +	enum pipe pipe;
>>> +	drmModeAtomicReq *req;
>>> +	igt_display_t *display = output->display;
>>> +	struct kmstest_connector_config *config = &output->config;
>>> +
>>> +	req = drmModeAtomicAlloc();
>>> +	drmModeAtomicSetCursor(req, 0);
>>> +
>>> +	for_each_pipe(display, pipe) {
>>> +		igt_pipe_t *pipe_obj = &display->pipes[pipe];
>>> +		igt_plane_t *plane;
>>> +
>>> +		/*
>>> +		 * Add CRTC Properties to the property set
>>> +		 */
>>> +		igt_atomic_prepare_crtc_commit(pipe_obj, req);
>>> +
>>> +		for_each_plane_on_pipe(display, pipe, plane) {
>>> +			igt_atomic_prepare_plane_commit(plane, pipe_obj, req);
>>> +		}
>>> +	}
>>> +
>>> +	igt_assert_lt(0, drmModeAtomicAddProperty(req, output->config.connector->connector_id,
>>> +						  output->props[IGT_CONNECTOR_CRTC_ID],
>>> +						  config->crtc->crtc_id));
>> igt_output_set_pipe() ?
>> Or failing that, igt_output_set_property(output, IGT_CONNECTOR_CRTC_ID);
> Thanks for the hint, will update the patch.
>
>>> +	igt_assert_lt(0, drmModeAtomicAddProperty(req, output->config.connector->connector_id,
>>> +						  output->props[IGT_CONNECTOR_WRITEBACK_FB_ID],
>>> +						  fb_id));
>> igt_output_set_property(output, IGT_CONNECTOR_FB_ID); or the convenience function from v1.. which also saves you from having to do the call below.
>>
>> I would really keep all the logic for the atomic properties internal, please don't override igt_display_commit_atomic.. we've made it too easy to set properties to anything you want.
> Understood. On the other hand, some flexibility in the test framework
> for whacky values in order to do adversarial testing could be useful.
We do allow this explicitly, see kms_atomic, crtc_invalid_params tries setting an invalid mode:

	/* Pass a series of invalid object IDs for the mode ID. */
	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, plane->drm_plane->plane_id);
	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);

	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, pipe->crtc_id);
	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);

	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, output->id);
	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);

	igt_pipe_obj_set_prop_value(pipe, IGT_CRTC_MODE_ID, fb->fb_id);
	crtc_commit_atomic_err(pipe, plane, ATOMIC_RELAX_NONE, EINVAL);

I couldn't put in a pointer to the kitchen sink, else I would have. O:)
Same works for plane and connector too, this is why you don't need to
override atomic commit(). 

You can put together an atomic test without ever using anything but
igt_plane_set_prop_value, igt_output_set_prop_value and igt_pipe(,_obj)_set_prop_value.

The convenience functions are just for allowing legacy support to continue working.

~Maarten



More information about the igt-dev mailing list