[igt-dev] [PATCH i-g-t v8] tests/kms_async_flips: Add test to validate asynchronous flips

Karthik B S karthik.b.s at intel.com
Wed Sep 23 02:53:44 UTC 2020



On 9/18/2020 5:02 PM, Ville Syrjälä wrote:
> On Fri, Sep 18, 2020 at 12:13:18PM +0530, Karthik B S wrote:
>> Asynchronous flips are issued using the page flip IOCTL.
>> The test consists of two subtests. The first subtest waits for
>> the page flip event to be received before giving the next flip,
>> and the second subtest doesn't wait for page flip events.
>>
>> The test passes if the IOCTL is successful.
>>
>> v2: -Add authors in the test file. (Paulo)
>>      -Reduce the run time and timeouts to suit IGT needs. (Paulo)
>>      -Replace igt_debug's with igt_assert's to catch slow flips. (Paulo)
>>      -Follow IGT coding style regarding spaces. (Paulo)
>>      -Make set up code part of igt_fixture. (Paulo)
>>      -Skip the test if async flips are not supported. (Paulo)
>>      -Replace suggested-by. (Paulo)
>>      -Added description for test and subtests.
>>
>> v3: -Rename the test to kms_async_flips. (Paulo)
>>      -Modify the TODO comment. (Paulo)
>>      -Remove igt_debug in flip_handler. (Paulo)
>>      -Use drmIoctl() in has_async function. (Paulo)
>>      -Add more details in igt_assert in flip_handler. (Paulo)
>>      -Remove flag variable in flip_handler. (Paulo)
>>      -Call igt_assert in flip_handler after the warm up time.
>>
>> v4: -Calculate the time stamp in flip_handler from userspace, as the
>>       kernel will return vbl timestamps and this cannot be used
>>       for async flips.
>>      -Add a new subtest to verify that the async flip time stamp
>>       lies in between the previous and next vblank time stamp. (Daniel)
>>
>> v5: -Add test that alternates between sync and async flips. (Ville)
>>      -Add test to verify invalid async flips. (Ville)
>>      -Remove the subtest async-flip-without-page-flip-events. (Michel)
>>      -Remove the intel gpu restriction and make the test generic. (Michel)
>>
>> v6: -Change the THRESHOLD from 10 to 8 as failures are seen on CI
>>       on platforms <= gen10.
>>      -In older platforms(<= gen10), async address update bit in plane ctl
>>       is double buffered. Made changes in subtests to accomodate this.
>>      -Moved the igt_assert from flip_handler to individual subtest as we
>>       now have four subtests and adding conditions for the assert in
>>       flip handler is messy.
>>
>> v7: -Change flip_interval from int to float for more precision.
>>      -Remove the fb height change case in 'invalid' subtest as per the
>>       feedback received on the kernel patches.
>>      -Add subtest to verify legacy cursor IOCTL. (Ville)
>>
>> v8: -Add a cursor flip before async flip in cursor test. (Ville)
>>      -Make flip_interval double for more precision as failures are seen
>>       on older platforms on CI.
>>
>> Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
>> Signed-off-by: Karthik B S <karthik.b.s at intel.com>
>> ---
>>   tests/Makefile.sources  |   1 +
>>   tests/kms_async_flips.c | 428 ++++++++++++++++++++++++++++++++++++++++
>>   tests/meson.build       |   1 +
>>   3 files changed, 430 insertions(+)
>>   create mode 100644 tests/kms_async_flips.c
>>
>> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
>> index 6ae95155..f32ea9cf 100644
>> --- a/tests/Makefile.sources
>> +++ b/tests/Makefile.sources
>> @@ -32,6 +32,7 @@ TESTS_progs = \
>>   	feature_discovery \
>>   	kms_3d \
>>   	kms_addfb_basic \
>> +	kms_async_flips \
>>   	kms_atomic \
>>   	kms_atomic_interruptible \
>>   	kms_atomic_transition \
>> diff --git a/tests/kms_async_flips.c b/tests/kms_async_flips.c
>> new file mode 100644
>> index 00000000..ef63ec45
>> --- /dev/null
>> +++ b/tests/kms_async_flips.c
>> @@ -0,0 +1,428 @@
>> +/*
>> + * Copyright © 2020 Intel Corporation
>> + *
>> + * 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.
>> + *
>> + * Authors:
>> + *  Paulo Zanoni <paulo.r.zanoni at intel.com>
>> + *  Karthik B S <karthik.b.s at intel.com>
>> + */
>> +
>> +#include "igt.h"
>> +#include "igt_aux.h"
>> +#include <sys/ioctl.h>
>> +#include <sys/time.h>
>> +#include <poll.h>
>> +
>> +#define BUFS 4
> 
> I'd just truct igt_fb bufs[4], and replace all the other
> "BUFS" usages with ARRAY_SIZE(bufs).

Thanks for the review.
Sure, I'll change this.
> 
>> +#define SYNC_FLIP 0
>> +#define ASYNC_FLIP 1
> 
> enum
> 

Will update this.

>> +#define CURSOR_RES 64
> 
> Should query that from the kernel so that test is driver agnostic.
> 

Sure. Will change this.
>> +#define CURSOR_POS 128
>> +
>> +/*
>> + * These constants can be tuned in case we start getting unexpected
>> + * results in CI.
>> + */
>> +
>> +#define WARM_UP_TIME 1
>> +#define RUN_TIME 2
>> +#define THRESHOLD 8
> 
> A rather non-descriptive name. I guess this is "min flips per frame" or
> something along those lines?
> 

Sure. I will change this to MIN_FLIPS_PER_FRAME.
>> +
>> +IGT_TEST_DESCRIPTION("Test asynchrous page flips.");
> 
> Check the spelling
> 

Will fix this.
>> +
>> +typedef struct {
>> +	int drm_fd;
>> +	uint32_t crtc_id;
>> +	struct igt_fb bufs[BUFS];
>> +	igt_display_t display;
>> +} data_t;
>> +
>> +uint32_t refresh_rate;
>> +unsigned long flip_timestamp_us;
>> +double flip_interval;
> 
> Hmm. I wonder why these are outside the data_t?
> 

Will move the refresh_rate variable inside data_t.
The other two are getting updated in flip_handler. Hence kept them 
global. Would you suggest making data_t global. Or any other way I can 
handle this better?
>> +
>> +static drmModeConnectorPtr find_connector_for_modeset(data_t *data)
>> +{
>> +	igt_output_t *output;
>> +	drmModeConnectorPtr ret = NULL;
>> +
>> +	for_each_connected_output(&data->display, output) {
>> +		if (output->config.connector->count_modes > 0) {
>> +			ret = output->config.connector;
>> +			break;
>> +		}
>> +	}
>> +
>> +	igt_assert_f(ret, "Connector NOT found\n");
>> +	return ret;
>> +}
>> +
>> +static void flip_handler(int fd_, unsigned int sequence, unsigned int tv_sec,
>> +			 unsigned int tv_usec, void *_data)
>> +{
>> +	static double last_ms;
>> +	double cur_ms;
>> +	struct timespec ts;
>> +
>> +	igt_assert(_data == NULL);
>> +
>> +	clock_gettime(CLOCK_MONOTONIC, &ts);
>> +
>> +	cur_ms =  ts.tv_sec * 1000.0 + ts.tv_nsec / 1000000.0;
>> +
>> +	flip_interval = cur_ms - last_ms;
>> +
>> +	last_ms = cur_ms;
>> +
>> +	flip_timestamp_us = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
>> +}
>> +
>> +static void wait_flip_event(data_t *data)
>> +{
>> +	int ret;
>> +	drmEventContext evctx;
>> +	struct pollfd pfd;
>> +
>> +	evctx.version = 2;
>> +	evctx.vblank_handler = NULL;
>> +	evctx.page_flip_handler = flip_handler;
>> +
>> +	pfd.fd = data->drm_fd;
>> +	pfd.events = POLLIN;
>> +	pfd.revents = 0;
>> +
>> +	ret = poll(&pfd, 1, 2000);
>> +
>> +	switch (ret) {
>> +	case 0:
>> +		igt_assert_f(0, "Flip Timeout\n");
>> +		break;
>> +	case 1:
>> +		ret = drmHandleEvent(data->drm_fd, &evctx);
>> +		igt_assert(ret == 0);
>> +		break;
>> +	default:
>> +		/* unexpected */
>> +		igt_assert(0);
>> +	}
>> +}
>> +
>> +static void make_fb(data_t *data, struct igt_fb *fb,
>> +		    drmModeConnectorPtr connector, int index)
>> +{
>> +	uint32_t width, height;
>> +	int rec_width;
>> +
>> +	width = connector->modes[0].hdisplay;
>> +	height = connector->modes[0].vdisplay;
>> +
>> +	rec_width = width / (BUFS * 2);
>> +
>> +	igt_create_fb(data->drm_fd, width, height, DRM_FORMAT_ARGB8888,
> 
> Make that XRGB8888. Otherwise some of our platforms won't support it.
> 

Sure, will update this.
>> +		      LOCAL_I915_FORMAT_MOD_X_TILED, fb);
>> +	igt_draw_fill_fb(data->drm_fd, fb, 0x88);
>> +	igt_draw_rect_fb(data->drm_fd, NULL, NULL, fb, IGT_DRAW_MMAP_CPU,
>> +			 rec_width * 2 + rec_width * index,
>> +			 height / 4, rec_width,
>> +			 height / 2, rand());
>> +}
>> +
>> +static void has_monotonic_timestamp(int fd)
> 
> Would expect has_foo() to return a boolean. I would call this
> require_monotonic_timestamp() or something. Or make this return
> the cap (like the has_async() thing) and move the igt_require() to
> the caller.
> 

Will change the name to require_monotonic_timestamp().
>> +{
>> +	struct drm_get_cap cap = { .capability = DRM_CAP_TIMESTAMP_MONOTONIC };
>> +
>> +	igt_assert(drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap) == 0);
>> +
>> +	igt_require_f(cap.value, "Monotonic timestamps not supported\n");
>> +}
>> +
>> +static void test_async_flip(data_t *data, bool alternate_sync_async)
>> +{
>> +	int ret, frame, warm_end_frame, count = 0;
>> +	long long int fps;
>> +	struct timeval start, end, diff;
>> +	bool toggle = SYNC_FLIP;
>> +	bool test_flip_interval = true;
>> +	bool warming_up = true;
>> +
>> +	has_monotonic_timestamp(data->drm_fd);
>> +
>> +	gettimeofday(&start, NULL);
>> +	frame = 1;
>> +	do {
>> +		int flags = DRM_MODE_PAGE_FLIP_ASYNC | DRM_MODE_PAGE_FLIP_EVENT;
>> +
>> +		if (alternate_sync_async) {
>> +			if (toggle == SYNC_FLIP) {
>> +				flags &= ~DRM_MODE_PAGE_FLIP_ASYNC;
>> +				test_flip_interval = false;
>> +				toggle = ASYNC_FLIP;
>> +			} else {
>> +				/* In older platforms (<= Gen10), async address update bit is double buffered.
>> +				 * So flip timestamp can be verified only from the second flip.
>> +				 * The first async flip just enables the async address update.
>> +				 */
> 
> We may want to limit this stuff to just those specific platforms.
> That will make sure new platforms coming in would fail the test
> if this mechanism ever broke again in hw.
> 

Sure, I'll add a check for Gen 9 and Gen 10 for this.

> The logic might be easier to understand if we just did an explciit
> extra async flip for the bad hw:
> 
> do {
> 	if (sync) {
> 		...
> 	} else {
> 		/* blah */
> 		if (bad_hw) {
> 			drmModePAgeflip(async);
> 			wait();
> 		}
> 		...
> 	}
> 	drmModePageflip(async or sync);
> 	...
> }
> 
> Actually I might even suggest replacing this toggle stuff
> with two explicit drmModePageflip() calls. One would be async,
> the other would be sync. That way you don't have to keep
> more than one iteration of the loop in your mind when
> reading the code.
> 
> But I guess we can massage this later as well.
> 

I will update this to remove the toggle logic and have explicit async 
and sync flip calls.
>> +				if (count == 0) {
>> +					count++;
>> +					test_flip_interval = false;
>> +				} else {
>> +					count = 0;
>> +					toggle = SYNC_FLIP;
>> +					test_flip_interval = true;
>> +				}
>> +			}
>> +		}
>> +
>> +		ret = drmModePageFlip(data->drm_fd, data->crtc_id,
>> +				      data->bufs[frame % 4].fb_id,
>> +				      flags, NULL);
>> +
>> +		igt_assert(ret == 0);
>> +
>> +		wait_flip_event(data);
>> +
>> +		gettimeofday(&end, NULL);
>> +		timersub(&end, &start, &diff);
>> +
>> +		/* 1s of warm-up time for the freq to stabilize */
>> +		if (warming_up && diff.tv_sec >= WARM_UP_TIME) {
>> +			warming_up = false;
>> +			warm_end_frame = frame;
>> +			start = end;
>> +		}
> 
> What's this warming thing?
> 

Will remove this as it is not relevant any more.
>> +
>> +		if (test_flip_interval && !warming_up) {
>> +			igt_assert_f(flip_interval < 1000.0 / (refresh_rate * THRESHOLD),
>> +				     "Flip interval not significantly smaller than vblank interval\n"
>> +				     "Flip interval: %lfms, Refresh Rate = %dHz, Threshold = %d\n",
>> +				     flip_interval, refresh_rate, THRESHOLD);
>> +
>> +		}
>> +
>> +		frame++;
>> +	} while (diff.tv_sec < RUN_TIME);
>> +
>> +	if (!alternate_sync_async) {
>> +		fps = (frame - warm_end_frame) * 1000 / RUN_TIME;
>> +		igt_assert_f((fps / 1000) > (refresh_rate * THRESHOLD),
>> +			     "FPS should be significantly higher than the refresh rate\n");
>> +	}
>> +}
>> +
>> +static void get_vbl_timestamp_us(data_t *data, unsigned long *vbl_time, unsigned int *seq)
>> +{
>> +	drmVBlank wait_vbl;
>> +	uint32_t pipe_id_flag;
>> +	int pipe;
>> +
>> +	memset(&wait_vbl, 0, sizeof(wait_vbl));
>> +	pipe = kmstest_get_pipe_from_crtc_id(data->drm_fd, data->crtc_id);
>> +	pipe_id_flag = kmstest_get_vbl_flag(pipe);
>> +
>> +	wait_vbl.request.type = DRM_VBLANK_RELATIVE | pipe_id_flag;
>> +	wait_vbl.request.sequence = 1;
> 
> Looks like this is actually doing a vblank wait. So the function
> name is a bit poor.
> 

Will rename it to wait_for_vblank.
>> +
>> +	igt_assert(drmIoctl(data->drm_fd, DRM_IOCTL_WAIT_VBLANK, &wait_vbl) == 0);
>> +	*vbl_time = wait_vbl.reply.tval_sec * 1000000 + wait_vbl.reply.tval_usec;
>> +	*seq = wait_vbl.reply.sequence;
>> +}
>> +
>> +static void test_timestamp(data_t *data)
>> +{
>> +	int flags = DRM_MODE_PAGE_FLIP_ASYNC | DRM_MODE_PAGE_FLIP_EVENT;
>> +	unsigned long vbl_time, vbl_time1;
>> +	unsigned int seq, seq1;
>> +	int ret;
>> +
>> +	has_monotonic_timestamp(data->drm_fd);
>> +
>> +	/* In older platforms(<= gen10), async address update bit is double buffered.
>> +	 * So flip timestamp can be verified only from the second flip.
>> +	 * The first async flip just enables the async address update.
>> +	 */
>> +	ret = drmModePageFlip(data->drm_fd, data->crtc_id,
>> +			      data->bufs[0].fb_id,
>> +			      flags, NULL);
>> +
>> +	igt_assert(ret == 0);
>> +
>> +	wait_flip_event(data);
>> +
>> +	get_vbl_timestamp_us(data, &vbl_time, &seq);
>> +
>> +	ret = drmModePageFlip(data->drm_fd, data->crtc_id,
>> +			      data->bufs[0].fb_id,
>> +			      flags, NULL);
>> +
>> +	igt_assert(ret == 0);
>> +
>> +	wait_flip_event(data);
>> +
>> +	get_vbl_timestamp_us(data, &vbl_time1, &seq1);
> 
> This one we could just replace with a query of the current vblank
> count. Would speed up the test by one frame. I guess we still want
> to keep the vblank wait before this one so that we know we have enough
> time during the frame to perform the async flip.
> 
> Dunno if we might want to do more than one async flip here actually.
> Potentially we might want to just do as many as possible until the
> vblank count changes. And then assert that we did at least a few.
> The timestamps should then be identical for all the flips except the
> last one.
> 
> Nothing critical I guess. Could think about these as followup.
> 

Sure. Will add a TODO here and add these changes as a followup.
>> +
>> +	igt_assert_f(seq1 == seq + 1,
>> +		     "Vblank sequence is expected to be incremented by one(%d != (%d + 1)\n", seq1, seq);
>> +
>> +	igt_info("vbl1_timestamp = %ldus\nflip_timestamp = %ldus\nvbl2_timestamp = %ldus\n",
>> +		 vbl_time, flip_timestamp_us, vbl_time1);
>> +
>> +	igt_assert_f(vbl_time < flip_timestamp_us && vbl_time1 > flip_timestamp_us,
>> +		     "Async flip time stamp is expected to be in between 2 vblank time stamps\n");
>> +}
>> +
>> +static void test_cursor(data_t *data)
>> +{
>> +	int flags = DRM_MODE_PAGE_FLIP_ASYNC | DRM_MODE_PAGE_FLIP_EVENT;
>> +	int ret;
>> +	struct igt_fb cursor_fb;
>> +	struct drm_mode_cursor cur;
>> +
>> +	igt_create_color_fb(data->drm_fd, CURSOR_RES, CURSOR_RES, DRM_FORMAT_ARGB8888,
>> +			    LOCAL_DRM_FORMAT_MOD_NONE, 1., 1., 1., &cursor_fb);
>> +
>> +	cur.flags = DRM_MODE_CURSOR_BO;
>> +	cur.crtc_id = data->crtc_id;
>> +	cur.width = CURSOR_RES;
>> +	cur.height = CURSOR_RES;
>> +	cur.handle = cursor_fb.gem_handle;
>> +
>> +	do_ioctl(data->drm_fd, DRM_IOCTL_MODE_CURSOR, &cur);
>> +
>> +	ret = drmModePageFlip(data->drm_fd, data->crtc_id,
>> +			      data->bufs[0].fb_id,
>> +			      flags, NULL);
>> +
>> +	igt_assert(ret == 0);
>> +
>> +	cur.flags = DRM_MODE_CURSOR_MOVE;
>> +	cur.x = CURSOR_POS;
>> +	cur.y = CURSOR_POS;
>> +
>> +	do_ioctl(data->drm_fd, DRM_IOCTL_MODE_CURSOR, &cur);
> 
> Did we manage to get the anticipated oops?
> 

Yes, after enabling the cursor before doing the async flip,
we were seeing the oops as you had pointed out.
Added a change accordingly in the kernel for that.
>> +}
>> +
>> +static void test_invalid(data_t *data, drmModeConnectorPtr connector)
>> +{
>> +	int flags = DRM_MODE_PAGE_FLIP_ASYNC | DRM_MODE_PAGE_FLIP_EVENT;
>> +	int ret;
>> +	uint32_t width, height;
>> +	struct igt_fb fb1, fb2;
>> +
>> +	width = connector->modes[0].hdisplay;
>> +	height = connector->modes[0].vdisplay;
>> +
>> +	igt_create_fb(data->drm_fd, width, height, DRM_FORMAT_ARGB8888,
> 
> XRGB8888
>

Noted.

>> +		      LOCAL_I915_FORMAT_MOD_X_TILED, &fb1);
>> +
>> +	igt_create_fb(data->drm_fd, width, height, DRM_FORMAT_ARGB8888,
> 
> And since we just want to check the X->Y transition this too should be
> XRGB8888.
> 

Noted.
> I guess we might want a few more of these to test the different
> things; stride and pixelformat at least. Could add those as a
> followup.
> 

Sure. Will add a TODO here and add these changes as a follow up.
>> +		      LOCAL_I915_FORMAT_MOD_Y_TILED, &fb2);
>> +
>> +	ret = drmModePageFlip(data->drm_fd, data->crtc_id,
>> +			      fb1.fb_id, flags, NULL);
>> +
>> +	igt_assert(ret == 0);
> 
> Not quite sure why we have this first page flip here?
> 

First to have an async flip with xtiled buffer and then follow it up 
with an async flip with a y-tiled buffer, so the second one is expected 
to fail. Could this be done in one flip? Am I missing something here?
>> +
>> +	wait_flip_event(data);
>> +
>> +	/* Flip with a different fb modifier which is expected to be rejected */
>> +	ret = drmModePageFlip(data->drm_fd, data->crtc_id,
>> +			      fb2.fb_id, flags, NULL);
>> +
>> +	igt_assert(ret == -EINVAL);
> 
> We're leaking the fbs here.
> 

Sure, will fix this.
>> +}
>> +
>> +static bool has_async(int fd)
> 
> has_async_flip() or has_async_page_flip() would be more descriptive.
> 

Sure. Will update this.
>> +{
>> +	struct drm_get_cap cap = { .capability = DRM_CAP_ASYNC_PAGE_FLIP };
>> +
>> +	igt_assert(drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap) == 0);
>> +	return cap.value;
>> +}
>> +
>> +igt_main
>> +{
>> +	data_t data;
> 
> I think better make that static. IIRC there are issues with longjmp
> magic otherwise.
> 

Sure, will update this.
>> +	drmModeResPtr res;
>> +	drmModeConnectorPtr connector;
>> +	int i, ret;
>> +	bool async_capable;
> 
> Pointless variable.
> 

Will remove this variable.
>> +
>> +	igt_fixture {
>> +		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
>> +		kmstest_set_vt_graphics_mode();
>> +		igt_display_require(&data.display, data.drm_fd);
>> +		igt_display_require_output(&data.display);
>> +
>> +		async_capable = has_async(data.drm_fd);
>> +		igt_require_f(async_capable, "Async Flip is not supported\n");
>> +	}
>> +
>> +	igt_describe("Verify the async flip functionality and the fps during async flips");
>> +	igt_subtest_group {
>> +		igt_fixture {
>> +			res = drmModeGetResources(data.drm_fd);
>> +			igt_assert(res);
>> +
>> +			kmstest_unset_all_crtcs(data.drm_fd, res);
>> +
>> +			connector = find_connector_for_modeset(&data);
>> +			data.crtc_id = kmstest_find_crtc_for_connector(data.drm_fd,
>> +								       res, connector, 0);
>> +
>> +			refresh_rate = connector->modes[0].vrefresh;
>> +
>> +			for (i = 0; i < BUFS; i++)
>> +				make_fb(&data, &data.bufs[i], connector, i);
>> +
>> +			ret = drmModeSetCrtc(data.drm_fd, data.crtc_id, data.bufs[0].fb_id, 0, 0,
>> +					     &connector->connector_id, 1, &connector->modes[0]);
>> +			igt_assert(ret == 0);
> 
> All of that stuff could be in a function AFAICS.
> 

Sure, I'll move it to a test_init() function.
> Also leaking 'res' AFAICS.
> 

Will fix this.

Thanks,
Karthik.B.S
>> +		}
>> +
>> +		igt_describe("Wait for page flip events in between successive asynchronous flips");
>> +		igt_subtest("async-flip-with-page-flip-events")
>> +			test_async_flip(&data, false);
>> +
>> +		igt_describe("Alternate between sync and async flips");
>> +		igt_subtest("alternate-sync-async-flip")
>> +			test_async_flip(&data, true);
>> +
>> +		igt_describe("Verify that the async flip timestamp does not coincide with either previous or next vblank");
>> +		igt_subtest("test-time-stamp")
>> +			test_timestamp(&data);
>> +
>> +		igt_describe("Verify that the DRM_IOCTL_MODE_CURSOR passes after async flip");
>> +		igt_subtest("test-cursor")
>> +			test_cursor(&data);
>> +
>> +		igt_describe("Negative case to verify if changes in fb are rejected from kernel as expected");
>> +		igt_subtest("invalid-async-flip")
>> +			test_invalid(&data, connector);
>> +
>> +		igt_fixture {
>> +			for (i = 0; i < BUFS; i++)
>> +				igt_remove_fb(data.drm_fd, &data.bufs[i]);
>> +		}
>> +	}
>> +
>> +	igt_fixture
>> +		igt_display_fini(&data.display);
>> +}
>> diff --git a/tests/meson.build b/tests/meson.build
>> index 5eb2d2fc..515f7528 100644
>> --- a/tests/meson.build
>> +++ b/tests/meson.build
>> @@ -16,6 +16,7 @@ test_progs = [
>>   	'feature_discovery',
>>   	'kms_3d',
>>   	'kms_addfb_basic',
>> +	'kms_async_flips',
>>   	'kms_atomic',
>>   	'kms_atomic_interruptible',
>>   	'kms_atomic_transition',
>> -- 
>> 2.22.0
> 


More information about the igt-dev mailing list