tests: add kms_frontbuffer_tracking
PATCH 1/1 tests: add kms_frontbuffer_tracking
From: Paulo Zanoni <[email protected]>
This is a new test that should exercise the frontbuffer tracking feature of the Kernel in a number of different ways. We use different drawing methods, we use the primary, cursor and sprite planes, we can test both on single and dual pipes, also on buffers not associated with any CRTCs, etc.
We currently have assertions for both FBC and PSR, and we also have a "nop" test mode that should disable both FBC and PSR, and can be used for debugging.
This test is also capable of testing both FBC and PSR even if they are disabled by default on the Kernel: the test knows how to change the i915.ko parameters and then set them back after testing.
I am getting a small number of failures when I run this test, which means we have some work to do on the Kernel.
I also still have a small list of additional subtests that I plan to add to this test, and those tests are documented on the main function.
--- tests/.gitignore | 1 + tests/Makefile.sources | 1 + tests/kms_frontbuffer_tracking.c | 1825 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1827 insertions(+) create mode 100644 tests/kms_frontbuffer_tracking.c
Some interesting details:
On a tree from 2015, May 06, I get 18 failures and 357 successes. The only FBC failures I get are from the MMAP_WC draw method, which is maybe lacking proper frontbuffer tracking support on the Kernel. The other 16 failures are for PSR, most of them with GTT MMAPs.
But if I use a tree from 2015, May 25, every single PSR test fails. We need to investigate that. Maybe if I had finished this earlier we would have an automated bisect. This also highlights the importance of testing stuff even when they are disabled by default! I plan to patch the other tests to do the same thing.
I am also seeing some FBC failures that happen right after booting. It seems that the very first tests fail until I run a test that uses the render ring. I'll have to investigate this.
I am also seeing some occasional corruptions on my eDP panel, but on these cases both the pipe and sink CRC tests succeed! Maybe this is some weird panel malfunction caused by the fact that we're doing tons and tons of modesets on the panel.
tests/.gitignore +1 -0
@@ -134,6 +134,7 @@ kms_flip kms_flip_event_leak kms_flip_tiling kms_force_connector +kms_frontbuffer_tracking kms_legacy_colorkey kms_mmio_vs_cs_flip kms_pipe_b_c_ivb
tests/Makefile.sources +1 -0
@@ -66,6 +66,7 @@ TESTS_progs_M = \ kms_flip \ kms_flip_event_leak \ kms_flip_tiling \ + kms_frontbuffer_tracking \ kms_legacy_colorkey \ kms_mmio_vs_cs_flip \ kms_pipe_b_c_ivb \
tests/kms_frontbuffer_tracking.c new file +1825 -0
1,825 lines not on this page · raw message
Signature · 6 lines
2.1.4 _______________________________________________ Intel-gfx mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Quoted 11 lines · Paulo Zanoni
From: Paulo Zanoni <[email protected]>
This is a new test that should exercise the frontbuffer tracking feature of the Kernel in a number of different ways. We use different drawing methods, we use the primary, cursor and sprite planes, we can test both on single and dual pipes, also on buffers not associated with any CRTCs, etc.
We currently have assertions for both FBC and PSR, and we also have a "nop" test mode that should disable both FBC and PSR, and can be used for debugging.
It would be good to have this information in the test as a comment somewhere as well as adding a short description for the IGT_TEST_DESCRIPTION macro.
Also, there are a few suggestions from lib/igt.cocci that might be worth implementing.
Quoted 281 lines
This test is also capable of testing both FBC and PSR even if they are disabled by default on the Kernel: the test knows how to change the i915.ko parameters and then set them back after testing.
I am getting a small number of failures when I run this test, which means we have some work to do on the Kernel.
I also still have a small list of additional subtests that I plan to add to this test, and those tests are documented on the main function.
Signed-off-by Paulo Zanoni <[email protected]>--- tests/.gitignore | 1 + tests/Makefile.sources | 1 + tests/kms_frontbuffer_tracking.c | 1825 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1827 insertions(+) create mode 100644 tests/kms_frontbuffer_tracking.cSome interesting details:
On a tree from 2015, May 06, I get 18 failures and 357 successes. The only FBC failures I get are from the
MMAP_WCdraw method, which is maybe lacking proper frontbuffer tracking support on the Kernel. The other 16 failures are for PSR, most of them with GTT MMAPs.But if I use a tree from 2015, May 25, every single PSR test fails. We need to investigate that. Maybe if I had finished this earlier we would have an automated bisect. This also highlights the importance of testing stuff even when they are disabled by default! I plan to patch the other tests to do the same thing.
I am also seeing some FBC failures that happen right after booting. It seems that the very first tests fail until I run a test that uses the render ring. I'll have to investigate this.
I am also seeing some occasional corruptions on my eDP panel, but on these cases both the pipe and sink CRC tests succeed! Maybe this is some weird panel malfunction caused by the fact that we're doing tons and tons of modesets on the panel.
tests/.gitignore +1
-0@@ -134,6 +134,7 @@ kms_flip kms_flip_event_leak kms_flip_tiling kms_force_connector +kms_frontbuffer_tracking kms_legacy_colorkey kms_mmio_vs_cs_flip kms_pipe_b_c_ivbtests/Makefile.sources +1
-0@@ -66,6 +66,7 @@ TESTS_progs_M = \ kms_flip \ kms_flip_event_leak \ kms_flip_tiling \ + kms_frontbuffer_tracking \ kms_legacy_colorkey \ kms_mmio_vs_cs_flip \ kms_pipe_b_c_ivb \tests/kms_frontbuffer_tracking.c new file +210
-0@@ -0,0 +1,1825 @@ +/* +* Copyright © 2015 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 <[email protected]> +* +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "drmtest.h" +#include "igt_aux.h" +#include "igt_draw.h" +#include "igt_kms.h" +#include "igt_debugfs.h" +#include "intel_chipset.h" +#include "ioctl_wrappers.h" + +#define FBC_PARAM_PATH "/sys/module/i915/parameters/enable_fbc" +#define PSR_PARAM_PATH "/sys/module/i915/parameters/enable_psr" + +struct test_mode { +enum { +PIPE_SINGLE =0 , +PIPE_DUAL , +PIPE_COUNT , + } pipes; + +enum { +SCREEN_PRIM =0 , +SCREEN_SCND , +SCREEN_OFFSCREEN , +SCREEN_COUNT , + } screen; + +enum { +PLANE_PRI =0 , +PLANE_CUR , +PLANE_SPR , +PLANE_COUNT , + } plane; + +enum { +FEATURE_NONE =0 , +FEATURE_FBC , +FEATURE_PSR , +FEATURE_COUNT , + } feature; + +enum igt_draw_method method; +}; + +enum feature_status { +ENABLED , +DISABLED , +}; + +struct rect { +int x; +int y; +int w; +int h; +uint32_t color; +}; + +#define MAX_CONNECTORS 32 +struct { +int fd; +drmModeResPtr res; +drmModeConnectorPtr connectors[MAX_CONNECTORS ]; +drmModePlaneResPtr planes; +drm_intel_bufmgr *bufmgr; +} drm; + +struct { +int fd; + +char param_original_value[16 ]; + +bool supports_compressing; +bool supports_last_action; + +struct timespec last_action; +} fbc = { + .fd =-1 , + .supports_last_action = false, + .supports_compressing = false, +}; + +struct { +int fd; +bool can_test; + +char param_original_value[16 ]; +} psr = { + .fd =-1 , + .can_test = false, +}; + + +#define SINK_CRC_SIZE 12 +typedef struct { +char data[SINK_CRC_SIZE ]; +}sink_crc_t ; + +struct both_crcs { +igt_crc_t pipe; +sink_crc_t sink; +}; + +igt_pipe_crc_t *pipe_crc; +struct both_crcs blue_crc; +struct both_crcs *wanted_crc; + +struct { +int fd; +} sink_crc; + +struct draw_pattern_info { +bool initialized; +bool frames_stack; +int n_rects; +struct both_crcs *crcs; +struct rect (*get_rect)(struct igt_fb *fb,int r); +}; + +/* Draw big rectangles on the screen. */ +struct draw_pattern_info pattern1; +/* 64x64 rectangles at x:0,y:0, just so we can draw on the cursor and sprite. */ +struct draw_pattern_info pattern2; +/* 64x64 rectangles at different positions, same color, for the move test. */ +struct draw_pattern_info pattern3; +/* Just a fullscreen green square. */ +struct draw_pattern_info pattern4; + +/* Command line parameters. */ +struct { +bool check_status; +bool check_crc; +bool fbc_check_compression; +bool fbc_check_last_action; +bool no_edp; +bool small_modes; +int step; +int only_feature; +int only_pipes; +} opt = { + .check_status = true, + .check_crc = true, + .fbc_check_compression = true, + .fbc_check_last_action = true, + .no_edp = false, + .small_modes = false, + .step =0 , + .only_feature =FEATURE_COUNT , + .only_pipes =PIPE_COUNT , +}; + +struct modeset_params { +uint32_t crtc_id; +uint32_t connector_id; +uint32_t sprite_id; +drmModeModeInfoPtr mode; +struct igt_fb fb; +struct igt_fb cursor; +struct igt_fb sprite; +}; + +struct modeset_params prim_mode_params; +struct modeset_params scnd_mode_params; +struct igt_fb offscreen_fb; + +static drmModeModeInfoPtr get_connector_smallest_mode (drmModeConnectorPtr c) +{ +int i; +drmModeModeInfoPtr smallest =NULL ; + +for (i =0 ; i < c->count_modes; i++) { +drmModeModeInfoPtr mode = &c->modes[i]; + +if (!smallest) + smallest = mode; + +if (mode->hdisplay * mode->vdisplay < + smallest->hdisplay * smallest->vdisplay) + smallest = mode; + } + +return smallest; +}
tests/kms_frontbuffer_tracking.c line 220
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ +static drmModeConnectorPtr get_connector (uint32_t id) +{ +int i; + +for (i =0 ; i < drm.res->count_connectors; i++) +if (drm.res->connectors[i] == id) +return drm.connectors[i]; + +igt_assert (false);
igt_assert_f() could be used here to provide a more descriptive error message.
Quoted 375 lines
tests/kms_frontbuffer_tracking.c new file +375
-0+} + +static void print_mode_info (const char *screen,struct modeset_params *params) +{ +drmModeConnectorPtr c =get_connector (params->connector_id); + +igt_info ("%s screen: %s %s\n" , + screen, +kmstest_connector_type_str (c->connector_type), + params->mode->name); +} + +static void init_mode_params (struct modeset_params *params,uint32_t crtc_id, +int crtc_index,uint32_t connector_id, +drmModeModeInfoPtr mode) +{ +uint32_t plane_id =0 ; +int i; + +igt_create_fb (drm.fd, mode->hdisplay, mode->vdisplay, +DRM_FORMAT_XRGB8888 ,LOCAL_I915_FORMAT_MOD_X_TILED , + ¶ms->fb); +igt_create_fb (drm.fd,64 ,64 ,DRM_FORMAT_ARGB8888 , +LOCAL_DRM_FORMAT_MOD_NONE , ¶ms->cursor); +igt_create_fb (drm.fd,64 ,64 ,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , ¶ms->sprite); + +for (i =0 ; i < drm.planes->count_planes && plane_id ==0 ; i++) { +drmModePlanePtr plane; + + plane =drmModeGetPlane (drm.fd, drm.planes->planes[i]); +igt_assert (plane); + +if (plane->possible_crtcs & (1 << crtc_index)) + plane_id = plane->plane_id; + +drmModeFreePlane (plane); + } +igt_assert (plane_id); + + params->crtc_id = crtc_id; + params->connector_id = connector_id; + params->mode = mode; + params->sprite_id = plane_id; +} + +drmModeModeInfo std_1024_mode = { + .clock =65000 , + .hdisplay =1024 , + .hsync_start =1048 , + .hsync_end =1184 , + .htotal =1344 , + .vtotal =806 , + .hskew =0 , + .vdisplay =768 , + .vsync_start =771 , + .vsync_end =777 , + .vtotal =806 , + .vscan =0 , + .vrefresh =60 , + .flags =0xA , + .type =0x40 , + .name ="Custom 1024x768" , +}; + +static bool connector_get_mode (drmModeConnectorPtr c,drmModeModeInfoPtr *mode) +{ + *mode =NULL ; + +if (c->connection !=DRM_MODE_CONNECTED || !c->count_modes) +return false; + +if (c->connector_type == DRM_MODE_CONNECTOR_eDP && opt.no_edp) +return false; + +if (opt.small_modes) + *mode =get_connector_smallest_mode (c); +else + *mode = &c->modes[0 ]; + +/* Because on some machines we don't have enough stolen memory to fit in +* those 3k panels. And on HSW the CRC WA is so awful that it makes you +* think everything is bugged. */ +if (c->connector_type == DRM_MODE_CONNECTOR_eDP) + *mode = &std_1024_mode; + +return true; +} + +static bool init_modeset_cached_params (void ) +{ +int i; +uint32_t prim_connector_id =0 , scnd_connector_id =0 ; +drmModeModeInfoPtr prim_mode =NULL , scnd_mode =NULL ; +drmModeModeInfoPtr tmp_mode; + +/* First, try to find an eDP monitor since it's the only possible type +* for PSR. */ +for (i =0 ; i < drm.res->count_connectors; i++) { +if (drm.connectors[i]->connector_type != DRM_MODE_CONNECTOR_eDP) +continue ; + +if (connector_get_mode (drm.connectors[i], &tmp_mode)) { + prim_connector_id = drm.res->connectors[i]; + prim_mode = tmp_mode; + } + } +for (i =0 ; i < drm.res->count_connectors; i++) { +/* Don't pick again what we just selected on the above loop. */ +if (drm.res->connectors[i] == prim_connector_id) +continue ; + +if (connector_get_mode (drm.connectors[i], &tmp_mode)) { +if (!prim_connector_id) { + prim_connector_id = drm.res->connectors[i]; + prim_mode = tmp_mode; + }else if (!scnd_connector_id) { + scnd_connector_id = drm.res->connectors[i]; + scnd_mode = tmp_mode; +break ; + } + } + } + +if (!prim_connector_id) +return false; + +init_mode_params (&prim_mode_params, drm.res->crtcs[0 ],0 , + prim_connector_id, prim_mode); +print_mode_info ("Primary" , &prim_mode_params); + +if (!scnd_connector_id) { + scnd_mode_params.connector_id =0 ; +return true; + } + +igt_assert (drm.res->count_crtcs >=2 ); +init_mode_params (&scnd_mode_params, drm.res->crtcs[1 ],1 , + scnd_connector_id, scnd_mode); +print_mode_info ("Secondary" , &scnd_mode_params); + +return true; +} + +static bool set_mode_for_params (struct modeset_params *params) +{ +int rc; + + rc =drmModeSetCrtc (drm.fd, params->crtc_id, params->fb.fb_id,0 ,0 , + ¶ms->connector_id,1 , params->mode); +return (rc ==0 ); +} + +#define DEBUGFS_MSG_SIZE 256 + +static void get_debugfs_string (int fd,char *buf) +{ +ssize_t n_read; + +lseek (fd,0 ,SEEK_SET ); + + n_read =read (fd, buf,DEBUGFS_MSG_SIZE -1 ); +igt_assert (n_read >=0 ); + buf[n_read] ='\0' ; +} + +static enum feature_status fbc_get_status (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); + +if (strstr (buf,"FBC enabled\n" )) +return ENABLED ; +else +return DISABLED ; +} + +static enum feature_status psr_get_status (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (psr.fd, buf); + +if (strstr (buf,"\nActive: yes\n" )) +return ENABLED ; +else +return DISABLED ; +} + +static struct timespec fbc_get_last_action (void ) +{ +struct timespec ret = {0 ,0 }; +char buf[DEBUGFS_MSG_SIZE ]; +char *action; +ssize_t n_read; + +get_debugfs_string (fbc.fd, buf); + + action =strstr (buf,"\nLast action:" ); +igt_assert (action); + + n_read =sscanf (action,"Last action: %ld.%ld" , + &ret.tv_sec, &ret.tv_nsec); +igt_assert (n_read ==2 ); + +return ret; +} + +static bool fbc_last_action_changed (void ) +{ +struct timespec t_new, t_old; + + t_old = fbc.last_action; + t_new =fbc_get_last_action (); + + fbc.last_action = t_new; + +#if 0 +igt_info ("old: %ld.%ld\n" , t_old.tv_sec, t_old.tv_nsec); +igt_info ("new: %ld.%ld\n" , t_new.tv_sec, t_new.tv_nsec); +#endif + +return t_old.tv_sec != t_new.tv_sec || + t_old.tv_nsec != t_new.tv_nsec; +} + +static void fbc_update_last_action (void ) +{ +if (!fbc.supports_last_action) +return ; + + fbc.last_action =fbc_get_last_action (); + +#if 0 +igt_info ("Last action: %ld.%ld\n" , + fbc.last_action.tv_sec, fbc.last_action.tv_nsec); +#endif +} + +static void fbc_setup_last_action (void ) +{ +ssize_t n_read; +char buf[DEBUGFS_MSG_SIZE ]; +char *action; + +get_debugfs_string (fbc.fd, buf); + + action =strstr (buf,"\nLast action:" ); +if (!action) { +igt_info ("FBC last action not supported\n" ); +return ; + } + + fbc.supports_last_action = true; + + n_read =sscanf (action,"Last action: %ld.%ld" , + &fbc.last_action.tv_sec, &fbc.last_action.tv_nsec); +igt_assert (n_read ==2 ); +} + +static bool fbc_is_compressing (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); +return strstr (buf,"\nCompressing: yes\n" ) !=NULL ; +} + +static bool fbc_wait_for_compression (void ) +{ +return igt_wait (fbc_is_compressing (),5000 ,1 ); +} + +static void fbc_setup_compressing (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); + +if (strstr (buf,"\nCompressing:" )) + fbc.supports_compressing = true; +else +igt_info ("FBC compression information not supported\n" ); +} + +static bool fbc_wait_for_status (enum feature_status status) +{ +return igt_wait (fbc_get_status () == status,5000 ,1 ); +} + +static bool psr_wait_for_status (enum feature_status status) +{ +return igt_wait (psr_get_status () == status,5000 ,1 ); +} + +static void set_param (const char *path,bool enable) +{ +int fd; +const char *str; + + fd =open (path,O_RDWR ); +igt_assert (fd >=0 ); + + str = enable ?"1\n" :"0\n" ; +igt_assert (write (fd, str,2 ) ==2 ); + +igt_assert (close (fd) ==0 ); +} +#define fbc_enable () set_param(FBC_PARAM_PATH, true) +#define fbc_disable () set_param(FBC_PARAM_PATH, false) +#define psr_enable () set_param(PSR_PARAM_PATH, true) +#define psr_disable () set_param(PSR_PARAM_PATH, false) + +static void save_param (const char *file_path,char *param_value) +{ +int fd; +ssize_t n; + + fd =open (file_path,O_RDWR ); +igt_assert (fd >=0 ); + + n =read (fd, param_value,15 ); +igt_assert (n >0 ); + param_value[n] ='\0' ; +igt_assert (close (fd) ==0 ); +} + +static void get_sink_crc (sink_crc_t *crc) +{ +lseek (sink_crc.fd,0 ,SEEK_SET ); + +igt_assert (read (sink_crc.fd, crc->data,SINK_CRC_SIZE ) == +SINK_CRC_SIZE ); +} + +static bool sink_crc_equal (sink_crc_t *a,sink_crc_t *b) +{ +return (memcmp (a->data, b->data,SINK_CRC_SIZE ) ==0 ); +} + +#define assert_sink_crc_equal (a, b) igt_assert(sink_crc_equal(a, b)) + +static struct rect pat1_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + +switch (r) { +case 0 : + rect.x =0 ; + rect.y =0 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0x00FF00 ; +break ; +case 1 : + rect.x = fb->width /8 ; + rect.y = fb->height /8 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0xFF0000 ; +break ; +case 2 : + rect.x = fb->width /8 *4 ; + rect.y = fb->height /8 *4 ; + rect.w = fb->width /8 *2 ; + rect.h = fb->height /8 *2 ; + rect.color =0xFF00FF ; +break ; +case 3 : + rect.x = fb->width /16 ; + rect.y = fb->height /16 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0x00FFFF ;
tests/kms_frontbuffer_tracking.c line 605
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+break ; +case 4 : + rect.x = fb->width -64 ; + rect.y = fb->height -64 ; + rect.w =64 ; + rect.h =64 ; + rect.color =0xFFFFFF ; +break ; +default : +igt_assert (0 );
It might be worth adding an igt_assert_not_reached function (or similar) for these, which could print a better error message.
Quoted 233 lines
tests/kms_frontbuffer_tracking.c new file +233
-0+ } + +return rect; +} + +static struct rect pat2_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + + rect.x =0 ; + rect.y =0 ; + rect.w =64 ; + rect.h =64 ; + +switch (r) { +case 0 : + rect.color =0xFF00FF00 ; +break ; +case 1 : + rect.w =32 ; + rect.h =32 ; + rect.color =0xFFFF0000 ; +break ; +case 2 : + rect.x =32 ; + rect.y =32 ; + rect.w =32 ; + rect.h =32 ; + rect.color =0xFFFF00FF ; +break ; +case 3 : + rect.x =16 ; + rect.y =16 ; + rect.w =32 ; + rect.h =32 ; + rect.color =0xFF00FFFF ; +break ; +case 4 : + rect.color =0xFFFFFF00 ; +break ; +default : +igt_assert (0 ); + } + +return rect; +} + +static struct rect pat3_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + + rect.w =64 ; + rect.h =64 ; + rect.color =0xFF00FF00 ; + +switch (r) { +case 0 : + rect.x =0 ; + rect.y =0 ; +break ; +case 1 : + rect.x =64 ; + rect.y =64 ; +break ; +case 2 : + rect.x =1 ; + rect.y =1 ; +break ; +case 3 : + rect.x = fb->width -64 ; + rect.y = fb->height -64 ; +break ; +case 4 : + rect.x = fb->width /2 -32 ; + rect.y = fb->height /2 -32 ; +break ; +default : +igt_assert (0 ); + } + +return rect; +} + +static struct rect pat4_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + +igt_assert (r ==0 ); + + rect.x =0 ; + rect.y =0 ; + rect.w = fb->width; + rect.h = fb->height; + rect.color =0xFF00FF00 ; + +return rect; +} + +static void draw_rect (struct draw_pattern_info *pattern,struct igt_fb *fb, +enum igt_draw_method method,int r) +{ +struct rect rect = pattern->get_rect (fb, r); + +igt_draw_rect_fb (drm.fd, drm.bufmgr,NULL , fb, method, rect.x, rect.y, + rect.w, rect.h, rect.color); +} + +static void unset_all_crtcs (void ) +{ +int i, rc; + +for (i =0 ; i < drm.res->count_crtcs; i++) { + rc =drmModeSetCrtc (drm.fd, drm.res->crtcs[i],-1 ,0 ,0 ,NULL , +0 ,NULL ); +igt_assert (rc ==0 ); + + rc =drmModeSetCursor (drm.fd, drm.res->crtcs[i],0 ,0 ,0 ); +igt_assert (rc ==0 ); + } + +for (i =0 ; i < drm.planes->count_planes; i++) { + rc =drmModeSetPlane (drm.fd, drm.planes->planes[i],0 ,0 ,0 ,0 , +0 ,0 ,0 ,0 ,0 ,0 ,0 ); +igt_assert (rc ==0 ); + } +} + +static void disable_features (void ) +{ +fbc_disable (); +psr_disable (); +} + +static void print_crc (const char *str,struct both_crcs *crc) +{ +int i; +char *pipe_str; + + pipe_str =igt_crc_to_string (&crc->pipe); + +igt_debug ("%s pipe:[%s] sink:[" , str, pipe_str); +for (i =0 ; i <SINK_CRC_SIZE ; i++) +igt_debug ("%c" , crc->sink.data[i]); +igt_debug ("]\n" ); + +free (pipe_str); +} + +static void collect_crcs (struct both_crcs *crcs) +{ +drmModeConnectorPtr c; + +igt_pipe_crc_collect_crc (pipe_crc, &crcs->pipe); + + c =get_connector (prim_mode_params.connector_id); +if (c->connector_type == DRM_MODE_CONNECTOR_eDP) +get_sink_crc (&crcs->sink); +else +memcpy (&crcs->sink,"unsupported!" ,SINK_CRC_SIZE ); +} + +static void init_blue_crc (void ) +{ +struct igt_fb blue; +int rc; + +disable_features (); +unset_all_crtcs (); + +igt_create_fb (drm.fd, prim_mode_params.mode->hdisplay, + prim_mode_params.mode->vdisplay,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &blue); + +igt_draw_fill_fb (drm.fd, &blue,0xFF ); + + rc =drmModeSetCrtc (drm.fd, prim_mode_params.crtc_id, + blue.fb_id,0 ,0 , &prim_mode_params.connector_id,1 , + prim_mode_params.mode); +igt_assert (rc ==0 ); +collect_crcs (&blue_crc); + +print_crc ("Blue CRC: " , &blue_crc); + +igt_remove_fb (drm.fd, &blue); +} + +static void init_crcs (struct draw_pattern_info *pattern) +{ +int r, r_, rc; +struct igt_fb fbs[pattern->n_rects]; + +if (pattern->initialized) +return ; + + pattern->crcs =calloc (pattern->n_rects,sizeof (*(pattern->crcs))); + +for (r =0 ; r < pattern->n_rects; r++) +igt_create_fb (drm.fd, prim_mode_params.mode->hdisplay, + prim_mode_params.mode->vdisplay, +DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &fbs[r]); + +for (r =0 ; r < pattern->n_rects; r++) +igt_draw_fill_fb (drm.fd, &fbs[r],0xFF ); + +if (pattern->frames_stack) { +for (r =0 ; r < pattern->n_rects; r++) +for (r_ =0 ; r_ <= r; r_++) +draw_rect (pattern, &fbs[r],IGT_DRAW_PWRITE , + r_); + }else { +for (r =0 ; r < pattern->n_rects; r++) +draw_rect (pattern, &fbs[r],IGT_DRAW_PWRITE , r); + } + +for (r =0 ; r < pattern->n_rects; r++) { + rc =drmModeSetCrtc (drm.fd, prim_mode_params.crtc_id, + fbs[r].fb_id,0 ,0 , + &prim_mode_params.connector_id,1 , + prim_mode_params.mode); +igt_assert (rc ==0 ); +collect_crcs (&pattern->crcs[r]); + } + +for (r =0 ; r < pattern->n_rects; r++) { +igt_debug ("Rect %d CRC:" , r); +print_crc ("" , &pattern->crcs[r]); + } + +unset_all_crtcs (); + +for (r =0 ; r < pattern->n_rects; r++) +igt_remove_fb (drm.fd, &fbs[r]);
tests/kms_frontbuffer_tracking.c line 848
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ + pattern->initialized = true; +} + +static void setup_drm (void ) +{ +int i; + + drm.fd =drm_open_any_master (); +igt_require (drm.fd >=0 );
The file descriptor check is done inside drm_open_any_master.
Quoted 49 lines
tests/kms_frontbuffer_tracking.c new file +49
-0+ + drm.res =drmModeGetResources (drm.fd); +igt_assert (drm.res->count_connectors <=MAX_CONNECTORS ); + +for (i =0 ; i < drm.res->count_connectors; i++) + drm.connectors[i] =drmModeGetConnector (drm.fd, + drm.res->connectors[i]); + + drm.planes =drmModeGetPlaneResources (drm.fd); + + drm.bufmgr =drm_intel_bufmgr_gem_init (drm.fd,4096 ); +igt_assert (drm.bufmgr); +drm_intel_bufmgr_gem_enable_reuse (drm.bufmgr); +} + +static void teardown_drm (void ) +{ +int i; + +drm_intel_bufmgr_destroy (drm.bufmgr); + +drmModeFreePlaneResources (drm.planes); + +for (i =0 ; i < drm.res->count_connectors; i++) +drmModeFreeConnector (drm.connectors[i]); + +drmModeFreeResources (drm.res); +close (drm.fd); +} + +static void setup_modeset (void ) +{ +igt_require (init_modeset_cached_params ()); + +kmstest_set_vt_graphics_mode (); + +igt_create_fb (drm.fd,1024 ,1024 ,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &offscreen_fb); +} + +static void teardown_modeset (void ) +{ +if (scnd_mode_params.connector_id) { +igt_remove_fb (drm.fd, &scnd_mode_params.fb); +igt_remove_fb (drm.fd, &scnd_mode_params.cursor); +igt_remove_fb (drm.fd, &scnd_mode_params.sprite); + } +igt_remove_fb (drm.fd, &prim_mode_params.fb); +igt_remove_fb (drm.fd, &prim_mode_params.cursor);
tests/kms_frontbuffer_tracking.c line 907
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+igt_remove_fb (drm.fd, &prim_mode_params.sprite); +igt_remove_fb (drm.fd, &offscreen_fb); +} + +static void setup_crcs (void ) +{ + pipe_crc =igt_pipe_crc_new (0 ,INTEL_PIPE_CRC_SOURCE_AUTO ); + + sink_crc.fd =open ("/sys/kernel/debug/dri/0/i915_sink_crc_eDP1" , +O_RDONLY );
igt_debugfs_open would take care of ensuring debugfs is mounted and the path is correct.
Quoted 130 lines
tests/kms_frontbuffer_tracking.c new file +130
-0+igt_assert (sink_crc.fd >=0 ); + +init_blue_crc (); + + pattern1.initialized = false; + pattern1.frames_stack = true; + pattern1.n_rects =5 ; + pattern1.crcs =NULL ; + pattern1.get_rect = pat1_get_rect; + + pattern2.initialized = false; + pattern2.frames_stack = true; + pattern2.n_rects =5 ; + pattern2.crcs =NULL ; + pattern2.get_rect = pat2_get_rect; + + pattern3.initialized = false; + pattern3.frames_stack = false; + pattern3.n_rects =5 ; + pattern3.crcs =NULL ; + pattern3.get_rect = pat3_get_rect; + + pattern4.initialized = false; + pattern4.frames_stack = false; + pattern4.n_rects =1 ; + pattern4.crcs =NULL ; + pattern4.get_rect = pat4_get_rect; +} + +static void teardown_crcs (void ) +{ +if (pattern1.crcs) +free (pattern1.crcs); +if (pattern2.crcs) +free (pattern2.crcs); +if (pattern3.crcs) +free (pattern3.crcs); +if (pattern4.crcs) +free (pattern4.crcs); + +close (sink_crc.fd); + +igt_pipe_crc_free (pipe_crc); +} + +static void restore_param (const char *file_path,char *param_value) +{ +int fd; + + fd =open (file_path,O_RDWR ); +if (fd >=0 ) { +write (fd, param_value,strlen (param_value)); +close (fd); + } +} + +static void exit_handler (int sig) +{ +restore_param (FBC_PARAM_PATH , fbc.param_original_value); +restore_param (PSR_PARAM_PATH , psr.param_original_value); +} + +static void setup_fbc (void ) +{ + fbc.fd =open ("/sys/kernel/debug/dri/0/i915_fbc_status" ,O_RDONLY ); +igt_assert (fbc.fd >=0 ); + +save_param (FBC_PARAM_PATH , fbc.param_original_value); + +fbc_setup_last_action (); +fbc_setup_compressing (); +} + +static void teardown_fbc (void ) +{ +if (fbc.fd !=-1 ) +close (fbc.fd); +} + +static bool psr_sink_has_support (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (psr.fd, buf); + +return strstr (buf,"Sink_Support: yes\n" ); +} + +static void setup_psr (void ) +{ +if (get_connector (prim_mode_params.connector_id)->connector_type != + DRM_MODE_CONNECTOR_eDP) { +igt_info ("Can't test PSR: no usable eDP screen.\n" ); +return ; + } + + psr.fd =open ("/sys/kernel/debug/dri/0/i915_edp_psr_status" ,O_RDONLY ); +igt_assert (psr.fd >=0 ); + +if (!psr_sink_has_support ()) { +igt_info ("Can't test PSR: not supported by sink.\n" ); +return ; + } + psr.can_test = true; + +save_param (PSR_PARAM_PATH , psr.param_original_value); +} + +static void teardown_psr (void ) +{ +if (psr.fd !=-1 ) +close (psr.fd); +} + +static void setup_environment (void ) +{ +setup_drm (); +setup_modeset (); + +igt_install_exit_handler (exit_handler); +setup_fbc (); +setup_psr (); + +setup_crcs (); +} + +static void teardown_environment (void ) +{ +teardown_crcs (); +teardown_psr ();
tests/kms_frontbuffer_tracking.c line 1047
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+teardown_fbc (); +teardown_modeset (); +teardown_drm (); +} + +static void wait_user (void ) +{ +igt_info ("Press enter...\n" ); +while (getchar () !='\n' ) + ;
Could this be done with the interactive debug option? (i.e. using igt_debug_wait_for_keypress)
Quoted 75 lines
tests/kms_frontbuffer_tracking.c new file +75
-0+} + +static struct modeset_params *pick_params (const struct test_mode *t) +{ +switch (t->screen) { +case SCREEN_PRIM : +return &prim_mode_params; +case SCREEN_SCND : +return &scnd_mode_params; +case SCREEN_OFFSCREEN : +return NULL ; +default : +igt_assert (false); + } +} + +static struct igt_fb *pick_target (const struct test_mode *t, +struct modeset_params *params) +{ +if (!params) +return &offscreen_fb; + +switch (t->plane) { +case PLANE_PRI : +return ¶ms->fb; +case PLANE_CUR : +return ¶ms->cursor; +case PLANE_SPR : +return ¶ms->sprite; +default : +igt_assert (false); + } +} + +static void do_flush (const struct test_mode *t) +{ +struct modeset_params *params =pick_params (t); +struct igt_fb *target =pick_target (t, params); + +gem_set_domain (drm.fd, target->gem_handle,I915_GEM_DOMAIN_GTT ,0 ); +} + +#define DONT_ASSERT_CRC (1 << 0) + +#define FBC_ASSERT_FLAGS (0xF << 1) +#define ASSERT_FBC_ENABLED (1 << 1) +#define ASSERT_FBC_DISABLED (1 << 2) +#define ASSERT_LAST_ACTION_CHANGED (1 << 3) +#define ASSERT_NO_ACTION_CHANGE (1 << 4) + +#define PSR_ASSERT_FLAGS (3 << 5) +#define ASSERT_PSR_ENABLED (1 << 5) +#define ASSERT_PSR_DISABLED (1 << 6) + +static int adjust_assertion_flags (const struct test_mode *t,int flags) +{ +if (!(flags &ASSERT_FBC_DISABLED )) + flags |=ASSERT_FBC_ENABLED ; +if (!(flags &ASSERT_PSR_DISABLED )) + flags |=ASSERT_PSR_ENABLED ; + +if (t->feature !=FEATURE_FBC ) + flags &= ~FBC_ASSERT_FLAGS ; +if (t->feature !=FEATURE_PSR ) + flags &= ~PSR_ASSERT_FLAGS ; + +return flags; +} + +#define do_crc_assertions (flags) do { \ + int flags__ = (flags); \ + struct both_crcs crc_; \ + \ + if (!opt.check_crc || (flags__ & DONT_ASSERT_CRC)) \ + break; \
tests/kms_frontbuffer_tracking.c line 1132
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ \ +collect_crcs (&crc_); \ +print_crc ("Calculated CRC:" , &crc_); \ + \ +igt_assert (wanted_crc); \ +igt_assert_crc_equal (&crc_.pipe, &wanted_crc->pipe); \ +assert_sink_crc_equal (&crc_.sink, &wanted_crc->sink); \ +} while (0) + +#define do_assertions (flags) do { \
Could this be a function rather than a macro to make debugging easier?
Quoted 109 lines
tests/kms_frontbuffer_tracking.c new file +109
-0+int flags_ =adjust_assertion_flags (t, (flags)); \ + \ +if (opt.step >1 ) \ +wait_user (); \ + \ +/* Check the CRC to make sure the drawing operations work \ +* immediately, independently of the features being enabled */ \ +do_crc_assertions (flags_); \ + \ +/* Now we can flush things to make the test faster. */ \ +do_flush (t); \ + \ +if (opt.check_status) { \ +if (flags_ &ASSERT_FBC_ENABLED ) { \ +igt_assert (fbc_wait_for_status (ENABLED )); \ + \ +if (fbc.supports_compressing && \ + opt.fbc_check_compression) \ +igt_assert (fbc_wait_for_compression ()); \ + }else if (flags_ &ASSERT_FBC_DISABLED ) { \ +igt_assert (fbc_wait_for_status (DISABLED )); \ + } \ + \ +if (flags_ &ASSERT_PSR_ENABLED ) \ +igt_assert (psr_wait_for_status (ENABLED )); \ +else if (flags_ &ASSERT_PSR_DISABLED ) \ +igt_assert (psr_wait_for_status (DISABLED )); \ + }else { \ +/* Make sure we settle before continuing. */ \ +sleep (1 ); \ + } \ + \ +/* Check CRC again to make sure the compressed screen is ok. */ \ +do_crc_assertions (flags_); \ + \ +if (fbc.supports_last_action && opt.fbc_check_last_action) { \ +if (flags_ &ASSERT_LAST_ACTION_CHANGED ) \ +igt_assert (fbc_last_action_changed ()); \ +else if (flags_ &ASSERT_NO_ACTION_CHANGE ) \ +igt_assert (!fbc_last_action_changed ()); \ + } \ + \ +if (opt.step) \ +wait_user (); \ +}while (0 ) + +static void enable_prim_screen_and_wait(const struct test_mode *t) +{ +igt_draw_fill_fb (drm.fd, &prim_mode_params.fb,0xFF ); +set_mode_for_params (&prim_mode_params); + + wanted_crc = &blue_crc; +fbc_update_last_action (); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void enable_scnd_screen_and_wait (const struct test_mode *t) +{ +igt_draw_fill_fb (drm.fd, &scnd_mode_params.fb,0x80 ); +set_mode_for_params (&scnd_mode_params); +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void set_cursor_for_test (const struct test_mode *t, +struct modeset_params *params) +{ +int rc; + +igt_draw_fill_fb (drm.fd, ¶ms->cursor,0xFF0000FF ); + + rc =drmModeMoveCursor (drm.fd, params->crtc_id,0 ,0 ); +igt_assert (rc ==0 ); + + rc =drmModeSetCursor (drm.fd, params->crtc_id, + params->cursor.gem_handle, params->cursor.width, + params->cursor.height); +igt_assert (rc ==0 ); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void set_sprite_for_test (const struct test_mode *t, +struct modeset_params *params) +{ +int rc; + +igt_draw_fill_fb (drm.fd, ¶ms->sprite,0xFF0000FF ); + + rc =drmModeSetPlane (drm.fd, params->sprite_id, params->crtc_id, + params->sprite.fb_id,0 ,0 ,0 , + params->sprite.width, params->sprite.height, +0 ,0 , params->sprite.width <<16 , + params->sprite.height <<16 ); +igt_assert (rc ==0 ); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void enable_features_for_test (const struct test_mode *t) +{ +switch (t->feature) { +case FEATURE_NONE : +break ; +case FEATURE_FBC : +fbc_enable (); +break ; +case FEATURE_PSR : +psr_enable ();
tests/kms_frontbuffer_tracking.c line 1251
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+break ; +default : +igt_assert (false); + } +} + +static void check_test_requirements (const struct test_mode *t) +{ +if (t->pipes ==PIPE_DUAL ) +igt_require (scnd_mode_params.connector_id);
It might be nice to use igt_require_f on these checks, so that a better message is printed if the test skips.
Quoted 464 lines
tests/kms_frontbuffer_tracking.c new file +464
-0+ +if (t->feature ==FEATURE_PSR ) +igt_require (psr.can_test); + +if (opt.only_feature !=FEATURE_COUNT ) +igt_require (t->feature == opt.only_feature); + +if (opt.only_pipes !=PIPE_COUNT ) +igt_require (t->pipes == opt.only_pipes); +} + +static void set_screens_for_test (const struct test_mode *t, +struct draw_pattern_info *pattern) +{ +check_test_requirements (t); + +if (t->screen ==SCREEN_OFFSCREEN ) +igt_draw_fill_fb (drm.fd, &offscreen_fb,0x80 ); + +disable_features (); +unset_all_crtcs (); +init_crcs (pattern); +enable_features_for_test (t); + +enable_prim_screen_and_wait (t); +if (t->screen ==SCREEN_PRIM ) { +if (t->plane ==PLANE_CUR ) +set_cursor_for_test (t, &prim_mode_params); +if (t->plane ==PLANE_SPR ) +set_sprite_for_test (t, &prim_mode_params); + } + +if (t->pipes ==PIPE_SINGLE ) +return ; + +enable_scnd_screen_and_wait (t); +if (t->screen ==SCREEN_SCND ) { +if (t->plane ==PLANE_CUR ) +set_cursor_for_test (t, &scnd_mode_params); +if (t->plane ==PLANE_SPR ) +set_sprite_for_test (t, &scnd_mode_params); + } +} + +static void rte_subtest (const struct test_mode *t) +{ +check_test_requirements (t); + +disable_features (); +enable_features_for_test (t); +unset_all_crtcs (); +do_assertions (ASSERT_FBC_DISABLED |ASSERT_PSR_DISABLED | +DONT_ASSERT_CRC ); + +enable_prim_screen_and_wait (t); +set_cursor_for_test (t, &prim_mode_params); +set_sprite_for_test (t, &prim_mode_params); + +if (t->pipes ==PIPE_SINGLE ) +return ; + +enable_scnd_screen_and_wait (t); +set_cursor_for_test (t, &scnd_mode_params); +set_sprite_for_test (t, &scnd_mode_params); +} + +static void update_wanted_crc (const struct test_mode *t,struct both_crcs *crc) +{ +if (t->screen ==SCREEN_PRIM ) + wanted_crc = crc; +} + +static void draw_subtest (const struct test_mode *t) +{ +int r; +int assertions =0 ; +struct draw_pattern_info *pattern; +struct modeset_params *params =pick_params (t); +struct igt_fb *target =pick_target (t, params); + +switch (t->screen) { +case SCREEN_PRIM : +if (t->method !=IGT_DRAW_MMAP_GTT && t->plane ==PLANE_PRI ) + assertions |=ASSERT_LAST_ACTION_CHANGED ; +break ; +case SCREEN_SCND : +case SCREEN_OFFSCREEN : + assertions |=ASSERT_NO_ACTION_CHANGE ; +break ; +default : +igt_assert (false); + } + +switch (t->plane) { +case PLANE_PRI : + pattern = &pattern1; +break ; +case PLANE_CUR : +case PLANE_SPR : + pattern = &pattern2; +break ; +default : +igt_assert (false); + } + +set_screens_for_test (t, pattern); + +for (r =0 ; r < pattern->n_rects; r++) { +draw_rect (pattern, target, t->method, r); +update_wanted_crc (t, &pattern->crcs[r]); +do_assertions (assertions); + } +} + +static void flip_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =0 ; +struct igt_fb fb2, *target; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern1; +uint32_t bg_color; + +switch (t->screen) { +case SCREEN_PRIM : + assertions |=ASSERT_LAST_ACTION_CHANGED ; + bg_color =0xFF ; +break ; +case SCREEN_SCND : + assertions |=ASSERT_NO_ACTION_CHANGE ; + bg_color =0x80 ; +break ; +default : +igt_assert (false); + } + +set_screens_for_test (t, pattern); + +igt_create_fb (drm.fd, params->mode->hdisplay, params->mode->vdisplay, +DRM_FORMAT_XRGB8888 ,LOCAL_I915_FORMAT_MOD_X_TILED , &fb2); +igt_draw_fill_fb (drm.fd, &fb2, bg_color); + +for (r =0 ; r < pattern->n_rects; r++) { + target = (r %2 ==0 ) ? &fb2 : ¶ms->fb; + +if (r !=0 ) +draw_rect (pattern, target, t->method, r -1 ); +draw_rect (pattern, target, t->method, r); +update_wanted_crc (t, &pattern->crcs[r]); + + rc =drmModePageFlip (drm.fd, params->crtc_id, target->fb_id,0 , +NULL ); +igt_assert (rc ==0 ); + +do_assertions (assertions); + } + +igt_remove_fb (drm.fd, &fb2); +} + +static void move_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =ASSERT_NO_ACTION_CHANGE ; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern3; +bool repeat = false; + +set_screens_for_test (t, pattern); + +/* Just paint the right color since we start at 0x0. */ +draw_rect (pattern,pick_target (t, params), t->method,0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); + +do_assertions (assertions); + +for (r =1 ; r < pattern->n_rects; r++) { +struct rect rect = pattern->get_rect (¶ms->fb, r); + +switch (t->plane) { +case PLANE_CUR : + rc =drmModeMoveCursor (drm.fd, params->crtc_id, rect.x, + rect.y); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, + params->crtc_id, + params->sprite.fb_id,0 , + rect.x, rect.y, rect.w, + rect.h,0 ,0 , rect.w <<16 , + rect.h <<16 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &pattern->crcs[r]); + +do_assertions (assertions); + +/* "Move" the last rect to the same position just to make sure +* this works too. */ +if (r+1 == pattern->n_rects && !repeat) { + repeat = true; + r--; + } + } +} + +static void onoff_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =ASSERT_NO_ACTION_CHANGE ; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern3; + +set_screens_for_test (t, pattern); + +/* Just paint the right color since we start at 0x0. */ +draw_rect (pattern,pick_target (t, params), t->method,0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); +do_assertions (assertions); + +for (r =0 ; r <4 ; r++) { +if (r %2 ==0 ) { +switch (t->plane) { +case PLANE_CUR : + rc =drmModeSetCursor (drm.fd, params->crtc_id, +0 ,0 ,0 ); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, +0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +0 ,0 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &blue_crc); + + }else { +switch (t->plane) { +case PLANE_CUR : + rc =drmModeSetCursor (drm.fd, params->crtc_id, + params->cursor.gem_handle, + params->cursor.width, + params->cursor.height); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, + params->crtc_id, + params->sprite.fb_id,0 , +0 ,0 , params->sprite.width, + params->sprite.height,0 , +0 , + params->sprite.width <<16 , + params->sprite.height <<16 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &pattern->crcs[0 ]); + + } + +do_assertions (assertions); + } +} + +static void fullscreen_plane_subtest (const struct test_mode *t) +{ +struct draw_pattern_info *pattern = &pattern4; +struct igt_fb fullscreen_fb; +struct rect rect; +struct modeset_params *params =pick_params (t); +int assertions; +int rc; + +set_screens_for_test (t, pattern); + + rect = pattern->get_rect (¶ms->fb,0 ); +igt_create_fb (drm.fd, rect.w, rect.h,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &fullscreen_fb); +igt_draw_fill_fb (drm.fd, &fullscreen_fb, rect.color); + + rc =drmModeSetPlane (drm.fd, params->sprite_id, params->crtc_id, + fullscreen_fb.fb_id,0 ,0 ,0 , fullscreen_fb.width, + fullscreen_fb.height,0 ,0 , + fullscreen_fb.width <<16 , + fullscreen_fb.height <<16 ); +igt_assert (rc ==0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); + +switch (t->screen) { +case SCREEN_PRIM : + assertions =ASSERT_FBC_DISABLED | +ASSERT_LAST_ACTION_CHANGED ; +break ; +case SCREEN_SCND : + assertions =ASSERT_NO_ACTION_CHANGE ; +break ; +default : +igt_assert (false); + } +do_assertions (assertions); + + rc =drmModeSetPlane (drm.fd, params->sprite_id,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +0 ,0 ,0 ); +igt_assert (rc ==0 ); + +if (t->screen ==SCREEN_PRIM ) + assertions =ASSERT_LAST_ACTION_CHANGED ; +update_wanted_crc (t, &blue_crc); +do_assertions (assertions); + +igt_remove_fb (drm.fd, &fullscreen_fb); +} + +static int opt_handler (int option,int option_index) +{ +switch (option) { +case 's' : + opt.check_status = false; +break ; +case 'c' : + opt.check_crc = false; +break ; +case 'o' : + opt.fbc_check_compression = false; +break ; +case 'a' : + opt.fbc_check_last_action = false; +break ; +case 'e' : + opt.no_edp = true; +break ; +case 'm' : + opt.small_modes = true; +break ; +case 't' : + opt.step++; +break ; +case 'n' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_NONE ; +break ; +case 'f' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_FBC ; +break ; +case 'p' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_PSR ; +break ; +case '1' : +igt_assert (opt.only_pipes ==PIPE_COUNT ); + opt.only_pipes =PIPE_SINGLE ; +break ; +case '2' : +igt_assert (opt.only_pipes ==PIPE_COUNT ); + opt.only_pipes =PIPE_DUAL ; +break ; +default : +igt_assert (false); + } + +return 0 ; +} + +const char *help_str = +" --no-status-check Don't check for enable/disable status\n" +" --no-crc-check Don't check for CRC values\n" +" --no-fbc-compression-check Don't check for the FBC compression status\n" +" --no-fbc-action-check Don't check for the FBC last action\n" +" --no-edp Don't use eDP monitors\n" +" --use-small-modes Use smaller resolutions for the modes\n" +" --step Stop on each step so you can check the screen\n" +" --nop-only Only run the \"nop\" feature subtests\n" +" --fbc-only Only run the \"fbc\" feature subtests\n" +" --psr-only Only run the \"psr\" feature subtests\n" +" --1p-only Only run subtests that use 1 pipe\n" +" --2p-only Only run subtests that use 2 pipes\n" ; + +static const char *pipes_str (int pipes) +{ +switch (pipes) { +case PIPE_SINGLE : +return "1p" ; +case PIPE_DUAL : +return "2p" ; +default : +igt_assert (false); + } +} + +static const char *screen_str (int screen) +{ +switch (screen) { +case SCREEN_PRIM : +return "primscrn" ; +case SCREEN_SCND : +return "scndscrn" ; +case SCREEN_OFFSCREEN : +return "offscren" ; +default : +igt_assert (false); + } +} + +static const char *plane_str (int plane) +{ +switch (plane) { +case PLANE_PRI : +return "pri" ; +case PLANE_CUR : +return "cur" ; +case PLANE_SPR : +return "spr" ; +default : +igt_assert (false); + } +} + +static const char *feature_str (int feature) +{ +switch (feature) { +case FEATURE_NONE : +return "nop" ; +case FEATURE_FBC : +return "fbc" ; +case FEATURE_PSR : +return "psr" ; +default : +igt_assert (false); + } +} + +#define TEST_MODE_ITER_BEGIN (t) \ + for (t.pipes = 0; t.pipes < PIPE_COUNT; t.pipes++) { \ + for (t.screen = 0; t.screen < SCREEN_COUNT; t.screen++) { \ + for (t.plane = 0; t.plane < PLANE_COUNT; t.plane++) { \ + for (t.method = 0; t.method < IGT_DRAW_METHOD_COUNT; t.method++) { \ + for (t.feature = 0; t.feature < FEATURE_COUNT; t.feature++) { \ + if (t.pipes == PIPE_SINGLE && t.screen == SCREEN_SCND) \ + continue; + +#define TEST_MODE_ITER_END } } } } } + +int main (int argc,char *argv[]) +{ +struct test_mode t; +struct option long_options[] = { + {"no-status-check" ,0 ,0 ,'s' }, + {"no-crc-check" ,0 ,0 ,'c' }, + {"no-fbc-compression-check" ,0 ,0 ,'o' }, + {"no-fbc-action-check" ,0 ,0 ,'a' }, + {"no-edp" ,0 ,0 ,'e' }, + {"use-small-modes" ,0 ,0 ,'m' }, + {"step" ,0 ,0 ,'t' },
tests/kms_frontbuffer_tracking.c line 1725
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ { "nop-only", 0, 0, 'n'}, + { "fbc-only", 0, 0, 'f'}, + { "psr-only", 0, 0, 'p'}, + { "1p-only", 0, 0, '1'}, + { "2p-only", 0, 0, '2'}, + { 0, 0, 0, 0 } + }; + +igt_subtest_init_parse_opts (&argc, argv,"" , long_options, help_str, + opt_handler);
This needs updating for the latest changes as this function and the option handler now have a user data pointer.
Quoted 103 lines
tests/kms_frontbuffer_tracking.c new file +100
-1+ +igt_fixture +setup_environment (); + +for (t.pipes =0 ; t.pipes <PIPE_COUNT ; t.pipes++) { +for (t.feature =0 ; t.feature <FEATURE_COUNT ; t.feature++) { + t.screen =SCREEN_PRIM ; + t.plane =PLANE_PRI ; +/* Make sure nothing is using this value. */ + t.method =-1 ; + +igt_subtest_f ("%s-rte-%s" , +pipes_str (t.pipes), + feature_str(t.feature)) +rte_subtest (&t); + } + } + + TEST_MODE_ITER_BEGIN(t) + igt_subtest_f("%s-%s-%s-draw-%s-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + igt_draw_get_method_name(t.method), + feature_str(t.feature)) +draw_subtest (&t); + TEST_MODE_ITER_END + + + TEST_MODE_ITER_BEGIN(t) + if (t.plane != PLANE_PRI) + continue; + + if (t.screen == SCREEN_OFFSCREEN) + continue; + + igt_subtest_f("%s-%s-flip-%s-%s", + pipes_str(t.pipes), + screen_str(t.screen), + igt_draw_get_method_name(t.method), + feature_str(t.feature)) +flip_subtest (&t); + TEST_MODE_ITER_END + + TEST_MODE_ITER_BEGIN(t) + if (t.screen == SCREEN_OFFSCREEN) + continue; + if (t.method != IGT_DRAW_BLT) + continue; + if (t.plane == PLANE_PRI) + continue; + + igt_subtest_f("%s-%s-%s-move-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + feature_str(t.feature)) +move_subtest (&t); + +igt_subtest_f ("%s-%s-%s-onoff-%s" , +pipes_str (t.pipes), +screen_str (t.screen), +plane_str (t.plane), + feature_str(t.feature)) +onoff_subtest (&t); + TEST_MODE_ITER_END + + TEST_MODE_ITER_BEGIN(t) + if (t.screen == SCREEN_OFFSCREEN) + continue; + if (t.method != IGT_DRAW_BLT) + continue; + if (t.plane != PLANE_SPR) + continue; + + igt_subtest_f("%s-%s-%s-fullscreen-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + feature_str(t.feature)) +fullscreen_plane_subtest (&t); +TEST_MODE_ITER_END + +/* +* TODO: ideas for subtests: +* - Add a new pipe configuration where both pipes can share a big +* framebuffer (instead of each pipe having its own FB). This will +* possibly require some wrapping of struct igt_fb to make the +* implementation easier. +* - Add a test that alternates between different writing methods. Don't +* forget to add the proper domain handling. +* - Add a new enum to struct test_mode that allows us to specify the +* BPP/depth configuration. +*/ + + igt_fixture +teardown_environment (); + +igt_exit (); +} --2.1.4
Quoted 4 lines
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
2015-05-26 8:13 GMT-03:00 Thomas Wood <[email protected]>:
Quoted 9 lines · Paulo Zanoni
Quoted 8 lines
From: Paulo Zanoni <[email protected]>
This is a new test that should exercise the frontbuffer tracking feature of the Kernel in a number of different ways. We use different drawing methods, we use the primary, cursor and sprite planes, we can test both on single and dual pipes, also on buffers not associated with any CRTCs, etc.
Quoted 7 lines
Quoted 3 lines
We currently have assertions for both FBC and PSR, and we also have a "nop" test mode that should disable both FBC and PSR, and can be used for debugging.
It would be good to have this information in the test as a comment somewhere as well as adding a short description for the
IGT_TEST_DESCRIPTIONmacro.
Will do.
Quoted 3 lines
Also, there are a few suggestions from
lib/igt.coccithat might be worth implementing.
I'll take a look.
Quoted 287 lines
Quoted 287 lines
This test is also capable of testing both FBC and PSR even if they are disabled by default on the Kernel: the test knows how to change the i915.ko parameters and then set them back after testing.
I am getting a small number of failures when I run this test, which means we have some work to do on the Kernel.
I also still have a small list of additional subtests that I plan to add to this test, and those tests are documented on the main function.
Signed-off-by Paulo Zanoni <[email protected]>--- tests/.gitignore | 1 + tests/Makefile.sources | 1 + tests/kms_frontbuffer_tracking.c | 1825 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1827 insertions(+) create mode 100644 tests/kms_frontbuffer_tracking.cSome interesting details:
On a tree from 2015, May 06, I get 18 failures and 357 successes. The only FBC failures I get are from the
MMAP_WCdraw method, which is maybe lacking proper frontbuffer tracking support on the Kernel. The other 16 failures are for PSR, most of them with GTT MMAPs.But if I use a tree from 2015, May 25, every single PSR test fails. We need to investigate that. Maybe if I had finished this earlier we would have an automated bisect. This also highlights the importance of testing stuff even when they are disabled by default! I plan to patch the other tests to do the same thing.
I am also seeing some FBC failures that happen right after booting. It seems that the very first tests fail until I run a test that uses the render ring. I'll have to investigate this.
I am also seeing some occasional corruptions on my eDP panel, but on these cases both the pipe and sink CRC tests succeed! Maybe this is some weird panel malfunction caused by the fact that we're doing tons and tons of modesets on the panel.
tests/.gitignore +1
-0@@ -134,6 +134,7 @@ kms_flip kms_flip_event_leak kms_flip_tiling kms_force_connector +kms_frontbuffer_tracking kms_legacy_colorkey kms_mmio_vs_cs_flip kms_pipe_b_c_ivbtests/Makefile.sources +1
-0@@ -66,6 +66,7 @@ TESTS_progs_M = \ kms_flip \ kms_flip_event_leak \ kms_flip_tiling \ + kms_frontbuffer_tracking \ kms_legacy_colorkey \ kms_mmio_vs_cs_flip \ kms_pipe_b_c_ivb \tests/kms_frontbuffer_tracking.c new file +214
-0@@ -0,0 +1,1825 @@ +/* +* Copyright © 2015 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 <[email protected]> +* +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "drmtest.h" +#include "igt_aux.h" +#include "igt_draw.h" +#include "igt_kms.h" +#include "igt_debugfs.h" +#include "intel_chipset.h" +#include "ioctl_wrappers.h" + +#define FBC_PARAM_PATH "/sys/module/i915/parameters/enable_fbc" +#define PSR_PARAM_PATH "/sys/module/i915/parameters/enable_psr" + +struct test_mode { +enum { +PIPE_SINGLE =0 , +PIPE_DUAL , +PIPE_COUNT , + } pipes; + +enum { +SCREEN_PRIM =0 , +SCREEN_SCND , +SCREEN_OFFSCREEN , +SCREEN_COUNT , + } screen; + +enum { +PLANE_PRI =0 , +PLANE_CUR , +PLANE_SPR , +PLANE_COUNT , + } plane; + +enum { +FEATURE_NONE =0 , +FEATURE_FBC , +FEATURE_PSR , +FEATURE_COUNT , + } feature; + +enum igt_draw_method method; +}; + +enum feature_status { +ENABLED , +DISABLED , +}; + +struct rect { +int x; +int y; +int w; +int h; +uint32_t color; +}; + +#define MAX_CONNECTORS 32 +struct { +int fd; +drmModeResPtr res; +drmModeConnectorPtr connectors[MAX_CONNECTORS ]; +drmModePlaneResPtr planes; +drm_intel_bufmgr *bufmgr; +} drm; + +struct { +int fd; + +char param_original_value[16 ]; + +bool supports_compressing; +bool supports_last_action; + +struct timespec last_action; +} fbc = { + .fd =-1 , + .supports_last_action = false, + .supports_compressing = false, +}; + +struct { +int fd; +bool can_test; + +char param_original_value[16 ]; +} psr = { + .fd =-1 , + .can_test = false, +}; + + +#define SINK_CRC_SIZE 12 +typedef struct { +char data[SINK_CRC_SIZE ]; +}sink_crc_t ; + +struct both_crcs { +igt_crc_t pipe; +sink_crc_t sink; +}; + +igt_pipe_crc_t *pipe_crc; +struct both_crcs blue_crc; +struct both_crcs *wanted_crc; + +struct { +int fd; +} sink_crc; + +struct draw_pattern_info { +bool initialized; +bool frames_stack; +int n_rects; +struct both_crcs *crcs; +struct rect (*get_rect)(struct igt_fb *fb,int r); +}; + +/* Draw big rectangles on the screen. */ +struct draw_pattern_info pattern1; +/* 64x64 rectangles at x:0,y:0, just so we can draw on the cursor and sprite. */ +struct draw_pattern_info pattern2; +/* 64x64 rectangles at different positions, same color, for the move test. */ +struct draw_pattern_info pattern3; +/* Just a fullscreen green square. */ +struct draw_pattern_info pattern4; + +/* Command line parameters. */ +struct { +bool check_status; +bool check_crc; +bool fbc_check_compression; +bool fbc_check_last_action; +bool no_edp; +bool small_modes; +int step; +int only_feature; +int only_pipes; +} opt = { + .check_status = true, + .check_crc = true, + .fbc_check_compression = true, + .fbc_check_last_action = true, + .no_edp = false, + .small_modes = false, + .step =0 , + .only_feature =FEATURE_COUNT , + .only_pipes =PIPE_COUNT , +}; + +struct modeset_params { +uint32_t crtc_id; +uint32_t connector_id; +uint32_t sprite_id; +drmModeModeInfoPtr mode; +struct igt_fb fb; +struct igt_fb cursor; +struct igt_fb sprite; +}; + +struct modeset_params prim_mode_params; +struct modeset_params scnd_mode_params; +struct igt_fb offscreen_fb; + +static drmModeModeInfoPtr get_connector_smallest_mode (drmModeConnectorPtr c) +{ +int i; +drmModeModeInfoPtr smallest =NULL ; + +for (i =0 ; i < c->count_modes; i++) { +drmModeModeInfoPtr mode = &c->modes[i]; + +if (!smallest) + smallest = mode; + +if (mode->hdisplay * mode->vdisplay < + smallest->hdisplay * smallest->vdisplay) + smallest = mode; + } + +return smallest; +} + +static drmModeConnectorPtr get_connector (uint32_t id) +{ +int i;
Quoted 8 lines
tests/kms_frontbuffer_tracking.c line 220
Quoted 6 lines
tests/kms_frontbuffer_tracking.c new file +6
-0+ +for (i =0 ; i < drm.res->count_connectors; i++) +if (drm.res->connectors[i] == id) +return drm.connectors[i]; + +igt_assert (false);
igt_assert_f()could be used here to provide a more descriptive error message.
This would be a user of the igt_assert_not_reached() you mentioned below. We should really never reach this assertion.
Quoted 382 lines
Quoted 382 lines
tests/kms_frontbuffer_tracking.c new file +380
-0+} + +static void print_mode_info (const char *screen,struct modeset_params *params) +{ +drmModeConnectorPtr c =get_connector (params->connector_id); + +igt_info ("%s screen: %s %s\n" , + screen, +kmstest_connector_type_str (c->connector_type), + params->mode->name); +} + +static void init_mode_params (struct modeset_params *params,uint32_t crtc_id, +int crtc_index,uint32_t connector_id, +drmModeModeInfoPtr mode) +{ +uint32_t plane_id =0 ; +int i; + +igt_create_fb (drm.fd, mode->hdisplay, mode->vdisplay, +DRM_FORMAT_XRGB8888 ,LOCAL_I915_FORMAT_MOD_X_TILED , + ¶ms->fb); +igt_create_fb (drm.fd,64 ,64 ,DRM_FORMAT_ARGB8888 , +LOCAL_DRM_FORMAT_MOD_NONE , ¶ms->cursor); +igt_create_fb (drm.fd,64 ,64 ,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , ¶ms->sprite); + +for (i =0 ; i < drm.planes->count_planes && plane_id ==0 ; i++) { +drmModePlanePtr plane; + + plane =drmModeGetPlane (drm.fd, drm.planes->planes[i]); +igt_assert (plane); + +if (plane->possible_crtcs & (1 << crtc_index)) + plane_id = plane->plane_id; + +drmModeFreePlane (plane); + } +igt_assert (plane_id); + + params->crtc_id = crtc_id; + params->connector_id = connector_id; + params->mode = mode; + params->sprite_id = plane_id; +} + +drmModeModeInfo std_1024_mode = { + .clock =65000 , + .hdisplay =1024 , + .hsync_start =1048 , + .hsync_end =1184 , + .htotal =1344 , + .vtotal =806 , + .hskew =0 , + .vdisplay =768 , + .vsync_start =771 , + .vsync_end =777 , + .vtotal =806 , + .vscan =0 , + .vrefresh =60 , + .flags =0xA , + .type =0x40 , + .name ="Custom 1024x768" , +}; + +static bool connector_get_mode (drmModeConnectorPtr c,drmModeModeInfoPtr *mode) +{ + *mode =NULL ; + +if (c->connection !=DRM_MODE_CONNECTED || !c->count_modes) +return false; + +if (c->connector_type == DRM_MODE_CONNECTOR_eDP && opt.no_edp) +return false; + +if (opt.small_modes) + *mode =get_connector_smallest_mode (c); +else + *mode = &c->modes[0 ]; + +/* Because on some machines we don't have enough stolen memory to fit in +* those 3k panels. And on HSW the CRC WA is so awful that it makes you +* think everything is bugged. */ +if (c->connector_type == DRM_MODE_CONNECTOR_eDP) + *mode = &std_1024_mode; + +return true; +} + +static bool init_modeset_cached_params (void ) +{ +int i; +uint32_t prim_connector_id =0 , scnd_connector_id =0 ; +drmModeModeInfoPtr prim_mode =NULL , scnd_mode =NULL ; +drmModeModeInfoPtr tmp_mode; + +/* First, try to find an eDP monitor since it's the only possible type +* for PSR. */ +for (i =0 ; i < drm.res->count_connectors; i++) { +if (drm.connectors[i]->connector_type != DRM_MODE_CONNECTOR_eDP) +continue ; + +if (connector_get_mode (drm.connectors[i], &tmp_mode)) { + prim_connector_id = drm.res->connectors[i]; + prim_mode = tmp_mode; + } + } +for (i =0 ; i < drm.res->count_connectors; i++) { +/* Don't pick again what we just selected on the above loop. */ +if (drm.res->connectors[i] == prim_connector_id) +continue ; + +if (connector_get_mode (drm.connectors[i], &tmp_mode)) { +if (!prim_connector_id) { + prim_connector_id = drm.res->connectors[i]; + prim_mode = tmp_mode; + }else if (!scnd_connector_id) { + scnd_connector_id = drm.res->connectors[i]; + scnd_mode = tmp_mode; +break ; + } + } + } + +if (!prim_connector_id) +return false; + +init_mode_params (&prim_mode_params, drm.res->crtcs[0 ],0 , + prim_connector_id, prim_mode); +print_mode_info ("Primary" , &prim_mode_params); + +if (!scnd_connector_id) { + scnd_mode_params.connector_id =0 ; +return true; + } + +igt_assert (drm.res->count_crtcs >=2 ); +init_mode_params (&scnd_mode_params, drm.res->crtcs[1 ],1 , + scnd_connector_id, scnd_mode); +print_mode_info ("Secondary" , &scnd_mode_params); + +return true; +} + +static bool set_mode_for_params (struct modeset_params *params) +{ +int rc; + + rc =drmModeSetCrtc (drm.fd, params->crtc_id, params->fb.fb_id,0 ,0 , + ¶ms->connector_id,1 , params->mode); +return (rc ==0 ); +} + +#define DEBUGFS_MSG_SIZE 256 + +static void get_debugfs_string (int fd,char *buf) +{ +ssize_t n_read; + +lseek (fd,0 ,SEEK_SET ); + + n_read =read (fd, buf,DEBUGFS_MSG_SIZE -1 ); +igt_assert (n_read >=0 ); + buf[n_read] ='\0' ; +} + +static enum feature_status fbc_get_status (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); + +if (strstr (buf,"FBC enabled\n" )) +return ENABLED ; +else +return DISABLED ; +} + +static enum feature_status psr_get_status (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (psr.fd, buf); + +if (strstr (buf,"\nActive: yes\n" )) +return ENABLED ; +else +return DISABLED ; +} + +static struct timespec fbc_get_last_action (void ) +{ +struct timespec ret = {0 ,0 }; +char buf[DEBUGFS_MSG_SIZE ]; +char *action; +ssize_t n_read; + +get_debugfs_string (fbc.fd, buf); + + action =strstr (buf,"\nLast action:" ); +igt_assert (action); + + n_read =sscanf (action,"Last action: %ld.%ld" , + &ret.tv_sec, &ret.tv_nsec); +igt_assert (n_read ==2 ); + +return ret; +} + +static bool fbc_last_action_changed (void ) +{ +struct timespec t_new, t_old; + + t_old = fbc.last_action; + t_new =fbc_get_last_action (); + + fbc.last_action = t_new; + +#if 0 +igt_info ("old: %ld.%ld\n" , t_old.tv_sec, t_old.tv_nsec); +igt_info ("new: %ld.%ld\n" , t_new.tv_sec, t_new.tv_nsec); +#endif + +return t_old.tv_sec != t_new.tv_sec || + t_old.tv_nsec != t_new.tv_nsec; +} + +static void fbc_update_last_action (void ) +{ +if (!fbc.supports_last_action) +return ; + + fbc.last_action =fbc_get_last_action (); + +#if 0 +igt_info ("Last action: %ld.%ld\n" , + fbc.last_action.tv_sec, fbc.last_action.tv_nsec); +#endif +} + +static void fbc_setup_last_action (void ) +{ +ssize_t n_read; +char buf[DEBUGFS_MSG_SIZE ]; +char *action; + +get_debugfs_string (fbc.fd, buf); + + action =strstr (buf,"\nLast action:" ); +if (!action) { +igt_info ("FBC last action not supported\n" ); +return ; + } + + fbc.supports_last_action = true; + + n_read =sscanf (action,"Last action: %ld.%ld" , + &fbc.last_action.tv_sec, &fbc.last_action.tv_nsec); +igt_assert (n_read ==2 ); +} + +static bool fbc_is_compressing (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); +return strstr (buf,"\nCompressing: yes\n" ) !=NULL ; +} + +static bool fbc_wait_for_compression (void ) +{ +return igt_wait (fbc_is_compressing (),5000 ,1 ); +} + +static void fbc_setup_compressing (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); + +if (strstr (buf,"\nCompressing:" )) + fbc.supports_compressing = true; +else +igt_info ("FBC compression information not supported\n" ); +} + +static bool fbc_wait_for_status (enum feature_status status) +{ +return igt_wait (fbc_get_status () == status,5000 ,1 ); +} + +static bool psr_wait_for_status (enum feature_status status) +{ +return igt_wait (psr_get_status () == status,5000 ,1 ); +} + +static void set_param (const char *path,bool enable) +{ +int fd; +const char *str; + + fd =open (path,O_RDWR ); +igt_assert (fd >=0 ); + + str = enable ?"1\n" :"0\n" ; +igt_assert (write (fd, str,2 ) ==2 ); + +igt_assert (close (fd) ==0 ); +} +#define fbc_enable () set_param(FBC_PARAM_PATH, true) +#define fbc_disable () set_param(FBC_PARAM_PATH, false) +#define psr_enable () set_param(PSR_PARAM_PATH, true) +#define psr_disable () set_param(PSR_PARAM_PATH, false) + +static void save_param (const char *file_path,char *param_value) +{ +int fd; +ssize_t n; + + fd =open (file_path,O_RDWR ); +igt_assert (fd >=0 ); + + n =read (fd, param_value,15 ); +igt_assert (n >0 ); + param_value[n] ='\0' ; +igt_assert (close (fd) ==0 ); +} + +static void get_sink_crc (sink_crc_t *crc) +{ +lseek (sink_crc.fd,0 ,SEEK_SET ); + +igt_assert (read (sink_crc.fd, crc->data,SINK_CRC_SIZE ) == +SINK_CRC_SIZE ); +} + +static bool sink_crc_equal (sink_crc_t *a,sink_crc_t *b) +{ +return (memcmp (a->data, b->data,SINK_CRC_SIZE ) ==0 ); +} + +#define assert_sink_crc_equal (a, b) igt_assert(sink_crc_equal(a, b)) + +static struct rect pat1_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + +switch (r) { +case 0 : + rect.x =0 ; + rect.y =0 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0x00FF00 ; +break ; +case 1 : + rect.x = fb->width /8 ; + rect.y = fb->height /8 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0xFF0000 ; +break ; +case 2 : + rect.x = fb->width /8 *4 ; + rect.y = fb->height /8 *4 ; + rect.w = fb->width /8 *2 ; + rect.h = fb->height /8 *2 ; + rect.color =0xFF00FF ; +break ; +case 3 : + rect.x = fb->width /16 ; + rect.y = fb->height /16 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0x00FFFF ; +break ; +case 4 : + rect.x = fb->width -64 ; + rect.y = fb->height -64 ; + rect.w =64 ;
Quoted 8 lines
tests/kms_frontbuffer_tracking.c line 605
Quoted 5 lines
tests/kms_frontbuffer_tracking.c new file +5
-0+ rect.h =64 ; + rect.color =0xFFFFFF ; +break ; +default : +igt_assert (0 );It might be worth adding an
igt_assert_not_reachedfunction (or similar) for these, which could print a better error message.
Agree. I'd totally use that for my tests.
Quoted 302 lines
Quoted 235 lines
tests/kms_frontbuffer_tracking.c new file +233
-0+ } + +return rect; +} + +static struct rect pat2_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + + rect.x =0 ; + rect.y =0 ; + rect.w =64 ; + rect.h =64 ; + +switch (r) { +case 0 : + rect.color =0xFF00FF00 ; +break ; +case 1 : + rect.w =32 ; + rect.h =32 ; + rect.color =0xFFFF0000 ; +break ; +case 2 : + rect.x =32 ; + rect.y =32 ; + rect.w =32 ; + rect.h =32 ; + rect.color =0xFFFF00FF ; +break ; +case 3 : + rect.x =16 ; + rect.y =16 ; + rect.w =32 ; + rect.h =32 ; + rect.color =0xFF00FFFF ; +break ; +case 4 : + rect.color =0xFFFFFF00 ; +break ; +default : +igt_assert (0 ); + } + +return rect; +} + +static struct rect pat3_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + + rect.w =64 ; + rect.h =64 ; + rect.color =0xFF00FF00 ; + +switch (r) { +case 0 : + rect.x =0 ; + rect.y =0 ; +break ; +case 1 : + rect.x =64 ; + rect.y =64 ; +break ; +case 2 : + rect.x =1 ; + rect.y =1 ; +break ; +case 3 : + rect.x = fb->width -64 ; + rect.y = fb->height -64 ; +break ; +case 4 : + rect.x = fb->width /2 -32 ; + rect.y = fb->height /2 -32 ; +break ; +default : +igt_assert (0 ); + } + +return rect; +} + +static struct rect pat4_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + +igt_assert (r ==0 ); + + rect.x =0 ; + rect.y =0 ; + rect.w = fb->width; + rect.h = fb->height; + rect.color =0xFF00FF00 ; + +return rect; +} + +static void draw_rect (struct draw_pattern_info *pattern,struct igt_fb *fb, +enum igt_draw_method method,int r) +{ +struct rect rect = pattern->get_rect (fb, r); + +igt_draw_rect_fb (drm.fd, drm.bufmgr,NULL , fb, method, rect.x, rect.y, + rect.w, rect.h, rect.color); +} + +static void unset_all_crtcs (void ) +{ +int i, rc; + +for (i =0 ; i < drm.res->count_crtcs; i++) { + rc =drmModeSetCrtc (drm.fd, drm.res->crtcs[i],-1 ,0 ,0 ,NULL , +0 ,NULL ); +igt_assert (rc ==0 ); + + rc =drmModeSetCursor (drm.fd, drm.res->crtcs[i],0 ,0 ,0 ); +igt_assert (rc ==0 ); + } + +for (i =0 ; i < drm.planes->count_planes; i++) { + rc =drmModeSetPlane (drm.fd, drm.planes->planes[i],0 ,0 ,0 ,0 , +0 ,0 ,0 ,0 ,0 ,0 ,0 ); +igt_assert (rc ==0 ); + } +} + +static void disable_features (void ) +{ +fbc_disable (); +psr_disable (); +} + +static void print_crc (const char *str,struct both_crcs *crc) +{ +int i; +char *pipe_str; + + pipe_str =igt_crc_to_string (&crc->pipe); + +igt_debug ("%s pipe:[%s] sink:[" , str, pipe_str); +for (i =0 ; i <SINK_CRC_SIZE ; i++) +igt_debug ("%c" , crc->sink.data[i]); +igt_debug ("]\n" ); + +free (pipe_str); +} + +static void collect_crcs (struct both_crcs *crcs) +{ +drmModeConnectorPtr c; + +igt_pipe_crc_collect_crc (pipe_crc, &crcs->pipe); + + c =get_connector (prim_mode_params.connector_id); +if (c->connector_type == DRM_MODE_CONNECTOR_eDP) +get_sink_crc (&crcs->sink); +else +memcpy (&crcs->sink,"unsupported!" ,SINK_CRC_SIZE ); +} + +static void init_blue_crc (void ) +{ +struct igt_fb blue; +int rc; + +disable_features (); +unset_all_crtcs (); + +igt_create_fb (drm.fd, prim_mode_params.mode->hdisplay, + prim_mode_params.mode->vdisplay,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &blue); + +igt_draw_fill_fb (drm.fd, &blue,0xFF ); + + rc =drmModeSetCrtc (drm.fd, prim_mode_params.crtc_id, + blue.fb_id,0 ,0 , &prim_mode_params.connector_id,1 , + prim_mode_params.mode); +igt_assert (rc ==0 ); +collect_crcs (&blue_crc); + +print_crc ("Blue CRC: " , &blue_crc); + +igt_remove_fb (drm.fd, &blue); +} + +static void init_crcs (struct draw_pattern_info *pattern) +{ +int r, r_, rc; +struct igt_fb fbs[pattern->n_rects]; + +if (pattern->initialized) +return ; + + pattern->crcs =calloc (pattern->n_rects,sizeof (*(pattern->crcs))); + +for (r =0 ; r < pattern->n_rects; r++) +igt_create_fb (drm.fd, prim_mode_params.mode->hdisplay, + prim_mode_params.mode->vdisplay, +DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &fbs[r]); + +for (r =0 ; r < pattern->n_rects; r++) +igt_draw_fill_fb (drm.fd, &fbs[r],0xFF ); + +if (pattern->frames_stack) { +for (r =0 ; r < pattern->n_rects; r++) +for (r_ =0 ; r_ <= r; r_++) +draw_rect (pattern, &fbs[r],IGT_DRAW_PWRITE , + r_); + }else { +for (r =0 ; r < pattern->n_rects; r++) +draw_rect (pattern, &fbs[r],IGT_DRAW_PWRITE , r); + } + +for (r =0 ; r < pattern->n_rects; r++) { + rc =drmModeSetCrtc (drm.fd, prim_mode_params.crtc_id, + fbs[r].fb_id,0 ,0 , + &prim_mode_params.connector_id,1 , + prim_mode_params.mode); +igt_assert (rc ==0 ); +collect_crcs (&pattern->crcs[r]); + } + +for (r =0 ; r < pattern->n_rects; r++) { +igt_debug ("Rect %d CRC:" , r); +print_crc ("" , &pattern->crcs[r]); + } + +unset_all_crtcs (); + +for (r =0 ; r < pattern->n_rects; r++) +igt_remove_fb (drm.fd, &fbs[r]);tests/kms_frontbuffer_tracking.c line 848
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ + pattern->initialized = true; +} + +static void setup_drm (void ) +{ +int i; + + drm.fd =drm_open_any_master (); +igt_require (drm.fd >=0 );The file descriptor check is done inside
drm_open_any_master.Quoted 54 lines
tests/kms_frontbuffer_tracking.c new file +54
-0+ + drm.res =drmModeGetResources (drm.fd); +igt_assert (drm.res->count_connectors <=MAX_CONNECTORS ); + +for (i =0 ; i < drm.res->count_connectors; i++) + drm.connectors[i] =drmModeGetConnector (drm.fd, + drm.res->connectors[i]); + + drm.planes =drmModeGetPlaneResources (drm.fd); + + drm.bufmgr =drm_intel_bufmgr_gem_init (drm.fd,4096 ); +igt_assert (drm.bufmgr); +drm_intel_bufmgr_gem_enable_reuse (drm.bufmgr); +} + +static void teardown_drm (void ) +{ +int i; + +drm_intel_bufmgr_destroy (drm.bufmgr); + +drmModeFreePlaneResources (drm.planes); + +for (i =0 ; i < drm.res->count_connectors; i++) +drmModeFreeConnector (drm.connectors[i]); + +drmModeFreeResources (drm.res); +close (drm.fd); +} + +static void setup_modeset (void ) +{ +igt_require (init_modeset_cached_params ()); + +kmstest_set_vt_graphics_mode (); + +igt_create_fb (drm.fd,1024 ,1024 ,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &offscreen_fb); +} + +static void teardown_modeset (void ) +{ +if (scnd_mode_params.connector_id) { +igt_remove_fb (drm.fd, &scnd_mode_params.fb); +igt_remove_fb (drm.fd, &scnd_mode_params.cursor); +igt_remove_fb (drm.fd, &scnd_mode_params.sprite); + } +igt_remove_fb (drm.fd, &prim_mode_params.fb); +igt_remove_fb (drm.fd, &prim_mode_params.cursor); +igt_remove_fb (drm.fd, &prim_mode_params.sprite); +igt_remove_fb (drm.fd, &offscreen_fb); +} + +static void setup_crcs (void )
Quoted 8 lines
tests/kms_frontbuffer_tracking.c line 907
Quoted 5 lines
tests/kms_frontbuffer_tracking.c new file +5
-0+{ + pipe_crc =igt_pipe_crc_new (0 ,INTEL_PIPE_CRC_SOURCE_AUTO ); + + sink_crc.fd =open ("/sys/kernel/debug/dri/0/i915_sink_crc_eDP1" , +O_RDONLY );
igt_debugfs_openwould take care of ensuring debugfs is mounted and the path is correct.
Oh, I see. Will use it.
Quoted 137 lines
Quoted 137 lines
tests/kms_frontbuffer_tracking.c new file +135
-0+igt_assert (sink_crc.fd >=0 ); + +init_blue_crc (); + + pattern1.initialized = false; + pattern1.frames_stack = true; + pattern1.n_rects =5 ; + pattern1.crcs =NULL ; + pattern1.get_rect = pat1_get_rect; + + pattern2.initialized = false; + pattern2.frames_stack = true; + pattern2.n_rects =5 ; + pattern2.crcs =NULL ; + pattern2.get_rect = pat2_get_rect; + + pattern3.initialized = false; + pattern3.frames_stack = false; + pattern3.n_rects =5 ; + pattern3.crcs =NULL ; + pattern3.get_rect = pat3_get_rect; + + pattern4.initialized = false; + pattern4.frames_stack = false; + pattern4.n_rects =1 ; + pattern4.crcs =NULL ; + pattern4.get_rect = pat4_get_rect; +} + +static void teardown_crcs (void ) +{ +if (pattern1.crcs) +free (pattern1.crcs); +if (pattern2.crcs) +free (pattern2.crcs); +if (pattern3.crcs) +free (pattern3.crcs); +if (pattern4.crcs) +free (pattern4.crcs); + +close (sink_crc.fd); + +igt_pipe_crc_free (pipe_crc); +} + +static void restore_param (const char *file_path,char *param_value) +{ +int fd; + + fd =open (file_path,O_RDWR ); +if (fd >=0 ) { +write (fd, param_value,strlen (param_value)); +close (fd); + } +} + +static void exit_handler (int sig) +{ +restore_param (FBC_PARAM_PATH , fbc.param_original_value); +restore_param (PSR_PARAM_PATH , psr.param_original_value); +} + +static void setup_fbc (void ) +{ + fbc.fd =open ("/sys/kernel/debug/dri/0/i915_fbc_status" ,O_RDONLY ); +igt_assert (fbc.fd >=0 ); + +save_param (FBC_PARAM_PATH , fbc.param_original_value); + +fbc_setup_last_action (); +fbc_setup_compressing (); +} + +static void teardown_fbc (void ) +{ +if (fbc.fd !=-1 ) +close (fbc.fd); +} + +static bool psr_sink_has_support (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (psr.fd, buf); + +return strstr (buf,"Sink_Support: yes\n" ); +} + +static void setup_psr (void ) +{ +if (get_connector (prim_mode_params.connector_id)->connector_type != + DRM_MODE_CONNECTOR_eDP) { +igt_info ("Can't test PSR: no usable eDP screen.\n" ); +return ; + } + + psr.fd =open ("/sys/kernel/debug/dri/0/i915_edp_psr_status" ,O_RDONLY ); +igt_assert (psr.fd >=0 ); + +if (!psr_sink_has_support ()) { +igt_info ("Can't test PSR: not supported by sink.\n" ); +return ; + } + psr.can_test = true; + +save_param (PSR_PARAM_PATH , psr.param_original_value); +} + +static void teardown_psr (void ) +{ +if (psr.fd !=-1 ) +close (psr.fd); +} + +static void setup_environment (void ) +{ +setup_drm (); +setup_modeset (); + +igt_install_exit_handler (exit_handler); +setup_fbc (); +setup_psr (); + +setup_crcs (); +} + +static void teardown_environment (void ) +{ +teardown_crcs (); +teardown_psr (); +teardown_fbc (); +teardown_modeset (); +teardown_drm (); +} +
Quoted 8 lines
tests/kms_frontbuffer_tracking.c line 1047
Quoted 5 lines
tests/kms_frontbuffer_tracking.c new file +5
-0+static void wait_user (void ) +{ +igt_info ("Press enter...\n" ); +while (getchar () !='\n' ) + ;Could this be done with the interactive debug option? (i.e. using
igt_debug_wait_for_keypress)
What I don't like about igt_debug_wait_for_keypress() is that I usually ctrl+c the test after I get past the part I want, so I'm left with a terminal that just doesn't work, so I have to blindly "reset" the terminal. I'm willing to add 100 lines of code to each test I write in order to avoid that annoyance.
Quoted 80 lines
Quoted 80 lines
tests/kms_frontbuffer_tracking.c new file +79
-0+} + +static struct modeset_params *pick_params (const struct test_mode *t) +{ +switch (t->screen) { +case SCREEN_PRIM : +return &prim_mode_params; +case SCREEN_SCND : +return &scnd_mode_params; +case SCREEN_OFFSCREEN : +return NULL ; +default : +igt_assert (false); + } +} + +static struct igt_fb *pick_target (const struct test_mode *t, +struct modeset_params *params) +{ +if (!params) +return &offscreen_fb; + +switch (t->plane) { +case PLANE_PRI : +return ¶ms->fb; +case PLANE_CUR : +return ¶ms->cursor; +case PLANE_SPR : +return ¶ms->sprite; +default : +igt_assert (false); + } +} + +static void do_flush (const struct test_mode *t) +{ +struct modeset_params *params =pick_params (t); +struct igt_fb *target =pick_target (t, params); + +gem_set_domain (drm.fd, target->gem_handle,I915_GEM_DOMAIN_GTT ,0 ); +} + +#define DONT_ASSERT_CRC (1 << 0) + +#define FBC_ASSERT_FLAGS (0xF << 1) +#define ASSERT_FBC_ENABLED (1 << 1) +#define ASSERT_FBC_DISABLED (1 << 2) +#define ASSERT_LAST_ACTION_CHANGED (1 << 3) +#define ASSERT_NO_ACTION_CHANGE (1 << 4) + +#define PSR_ASSERT_FLAGS (3 << 5) +#define ASSERT_PSR_ENABLED (1 << 5) +#define ASSERT_PSR_DISABLED (1 << 6) + +static int adjust_assertion_flags (const struct test_mode *t,int flags) +{ +if (!(flags &ASSERT_FBC_DISABLED )) + flags |=ASSERT_FBC_ENABLED ; +if (!(flags &ASSERT_PSR_DISABLED )) + flags |=ASSERT_PSR_ENABLED ; + +if (t->feature !=FEATURE_FBC ) + flags &= ~FBC_ASSERT_FLAGS ; +if (t->feature !=FEATURE_PSR ) + flags &= ~PSR_ASSERT_FLAGS ; + +return flags; +} + +#define do_crc_assertions (flags) do { \ + int flags__ = (flags); \ + struct both_crcs crc_; \ + \ + if (!opt.check_crc || (flags__ & DONT_ASSERT_CRC)) \ + break; \ + \ + collect_crcs(&crc_); \ + print_crc("Calculated CRC:", &crc_); \ + \
Quoted 8 lines
tests/kms_frontbuffer_tracking.c line 1132
Quoted 6 lines
tests/kms_frontbuffer_tracking.c new file +6
-0+igt_assert (wanted_crc); \ +igt_assert_crc_equal (&crc_.pipe, &wanted_crc->pipe); \ +assert_sink_crc_equal (&crc_.sink, &wanted_crc->sink); \ +} while (0) + +#define do_assertions (flags) do { \Could this be a function rather than a macro to make debugging easier?
Nooooooo. Macros give me a correct line number when igt_assert() fails, while functions would always give me the same line number for every assertion in the code. I know we print the backtrace, but I don't get line numbers from the backtraces either, so they're not very useful. By the way, I have the same complaint about igt_assert_crc_equal(): can we please revert it back to a macro?
Quoted 116 lines
Quoted 116 lines
tests/kms_frontbuffer_tracking.c new file +114
-0+int flags_ =adjust_assertion_flags (t, (flags)); \ + \ +if (opt.step >1 ) \ +wait_user (); \ + \ +/* Check the CRC to make sure the drawing operations work \ +* immediately, independently of the features being enabled */ \ +do_crc_assertions (flags_); \ + \ +/* Now we can flush things to make the test faster. */ \ +do_flush (t); \ + \ +if (opt.check_status) { \ +if (flags_ &ASSERT_FBC_ENABLED ) { \ +igt_assert (fbc_wait_for_status (ENABLED )); \ + \ +if (fbc.supports_compressing && \ + opt.fbc_check_compression) \ +igt_assert (fbc_wait_for_compression ()); \ + }else if (flags_ &ASSERT_FBC_DISABLED ) { \ +igt_assert (fbc_wait_for_status (DISABLED )); \ + } \ + \ +if (flags_ &ASSERT_PSR_ENABLED ) \ +igt_assert (psr_wait_for_status (ENABLED )); \ +else if (flags_ &ASSERT_PSR_DISABLED ) \ +igt_assert (psr_wait_for_status (DISABLED )); \ + }else { \ +/* Make sure we settle before continuing. */ \ +sleep (1 ); \ + } \ + \ +/* Check CRC again to make sure the compressed screen is ok. */ \ +do_crc_assertions (flags_); \ + \ +if (fbc.supports_last_action && opt.fbc_check_last_action) { \ +if (flags_ &ASSERT_LAST_ACTION_CHANGED ) \ +igt_assert (fbc_last_action_changed ()); \ +else if (flags_ &ASSERT_NO_ACTION_CHANGE ) \ +igt_assert (!fbc_last_action_changed ()); \ + } \ + \ +if (opt.step) \ +wait_user (); \ +}while (0 ) + +static void enable_prim_screen_and_wait(const struct test_mode *t) +{ +igt_draw_fill_fb (drm.fd, &prim_mode_params.fb,0xFF ); +set_mode_for_params (&prim_mode_params); + + wanted_crc = &blue_crc; +fbc_update_last_action (); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void enable_scnd_screen_and_wait (const struct test_mode *t) +{ +igt_draw_fill_fb (drm.fd, &scnd_mode_params.fb,0x80 ); +set_mode_for_params (&scnd_mode_params); +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void set_cursor_for_test (const struct test_mode *t, +struct modeset_params *params) +{ +int rc; + +igt_draw_fill_fb (drm.fd, ¶ms->cursor,0xFF0000FF ); + + rc =drmModeMoveCursor (drm.fd, params->crtc_id,0 ,0 ); +igt_assert (rc ==0 ); + + rc =drmModeSetCursor (drm.fd, params->crtc_id, + params->cursor.gem_handle, params->cursor.width, + params->cursor.height); +igt_assert (rc ==0 ); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void set_sprite_for_test (const struct test_mode *t, +struct modeset_params *params) +{ +int rc; + +igt_draw_fill_fb (drm.fd, ¶ms->sprite,0xFF0000FF ); + + rc =drmModeSetPlane (drm.fd, params->sprite_id, params->crtc_id, + params->sprite.fb_id,0 ,0 ,0 , + params->sprite.width, params->sprite.height, +0 ,0 , params->sprite.width <<16 , + params->sprite.height <<16 ); +igt_assert (rc ==0 ); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void enable_features_for_test (const struct test_mode *t) +{ +switch (t->feature) { +case FEATURE_NONE : +break ; +case FEATURE_FBC : +fbc_enable (); +break ; +case FEATURE_PSR : +psr_enable (); +break ; +default : +igt_assert (false); + } +}
Quoted 8 lines
tests/kms_frontbuffer_tracking.c line 1251
Quoted 5 lines
tests/kms_frontbuffer_tracking.c new file +5
-0+ +static void check_test_requirements (const struct test_mode *t) +{ +if (t->pipes ==PIPE_DUAL ) +igt_require (scnd_mode_params.connector_id);It might be nice to use
igt_require_fon these checks, so that a better message is printed if the test skips.
Yeah, that one is going to happen a lot.
Quoted 471 lines
Quoted 471 lines
tests/kms_frontbuffer_tracking.c new file +469
-0+ +if (t->feature ==FEATURE_PSR ) +igt_require (psr.can_test); + +if (opt.only_feature !=FEATURE_COUNT ) +igt_require (t->feature == opt.only_feature); + +if (opt.only_pipes !=PIPE_COUNT ) +igt_require (t->pipes == opt.only_pipes); +} + +static void set_screens_for_test (const struct test_mode *t, +struct draw_pattern_info *pattern) +{ +check_test_requirements (t); + +if (t->screen ==SCREEN_OFFSCREEN ) +igt_draw_fill_fb (drm.fd, &offscreen_fb,0x80 ); + +disable_features (); +unset_all_crtcs (); +init_crcs (pattern); +enable_features_for_test (t); + +enable_prim_screen_and_wait (t); +if (t->screen ==SCREEN_PRIM ) { +if (t->plane ==PLANE_CUR ) +set_cursor_for_test (t, &prim_mode_params); +if (t->plane ==PLANE_SPR ) +set_sprite_for_test (t, &prim_mode_params); + } + +if (t->pipes ==PIPE_SINGLE ) +return ; + +enable_scnd_screen_and_wait (t); +if (t->screen ==SCREEN_SCND ) { +if (t->plane ==PLANE_CUR ) +set_cursor_for_test (t, &scnd_mode_params); +if (t->plane ==PLANE_SPR ) +set_sprite_for_test (t, &scnd_mode_params); + } +} + +static void rte_subtest (const struct test_mode *t) +{ +check_test_requirements (t); + +disable_features (); +enable_features_for_test (t); +unset_all_crtcs (); +do_assertions (ASSERT_FBC_DISABLED |ASSERT_PSR_DISABLED | +DONT_ASSERT_CRC ); + +enable_prim_screen_and_wait (t); +set_cursor_for_test (t, &prim_mode_params); +set_sprite_for_test (t, &prim_mode_params); + +if (t->pipes ==PIPE_SINGLE ) +return ; + +enable_scnd_screen_and_wait (t); +set_cursor_for_test (t, &scnd_mode_params); +set_sprite_for_test (t, &scnd_mode_params); +} + +static void update_wanted_crc (const struct test_mode *t,struct both_crcs *crc) +{ +if (t->screen ==SCREEN_PRIM ) + wanted_crc = crc; +} + +static void draw_subtest (const struct test_mode *t) +{ +int r; +int assertions =0 ; +struct draw_pattern_info *pattern; +struct modeset_params *params =pick_params (t); +struct igt_fb *target =pick_target (t, params); + +switch (t->screen) { +case SCREEN_PRIM : +if (t->method !=IGT_DRAW_MMAP_GTT && t->plane ==PLANE_PRI ) + assertions |=ASSERT_LAST_ACTION_CHANGED ; +break ; +case SCREEN_SCND : +case SCREEN_OFFSCREEN : + assertions |=ASSERT_NO_ACTION_CHANGE ; +break ; +default : +igt_assert (false); + } + +switch (t->plane) { +case PLANE_PRI : + pattern = &pattern1; +break ; +case PLANE_CUR : +case PLANE_SPR : + pattern = &pattern2; +break ; +default : +igt_assert (false); + } + +set_screens_for_test (t, pattern); + +for (r =0 ; r < pattern->n_rects; r++) { +draw_rect (pattern, target, t->method, r); +update_wanted_crc (t, &pattern->crcs[r]); +do_assertions (assertions); + } +} + +static void flip_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =0 ; +struct igt_fb fb2, *target; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern1; +uint32_t bg_color; + +switch (t->screen) { +case SCREEN_PRIM : + assertions |=ASSERT_LAST_ACTION_CHANGED ; + bg_color =0xFF ; +break ; +case SCREEN_SCND : + assertions |=ASSERT_NO_ACTION_CHANGE ; + bg_color =0x80 ; +break ; +default : +igt_assert (false); + } + +set_screens_for_test (t, pattern); + +igt_create_fb (drm.fd, params->mode->hdisplay, params->mode->vdisplay, +DRM_FORMAT_XRGB8888 ,LOCAL_I915_FORMAT_MOD_X_TILED , &fb2); +igt_draw_fill_fb (drm.fd, &fb2, bg_color); + +for (r =0 ; r < pattern->n_rects; r++) { + target = (r %2 ==0 ) ? &fb2 : ¶ms->fb; + +if (r !=0 ) +draw_rect (pattern, target, t->method, r -1 ); +draw_rect (pattern, target, t->method, r); +update_wanted_crc (t, &pattern->crcs[r]); + + rc =drmModePageFlip (drm.fd, params->crtc_id, target->fb_id,0 , +NULL ); +igt_assert (rc ==0 ); + +do_assertions (assertions); + } + +igt_remove_fb (drm.fd, &fb2); +} + +static void move_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =ASSERT_NO_ACTION_CHANGE ; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern3; +bool repeat = false; + +set_screens_for_test (t, pattern); + +/* Just paint the right color since we start at 0x0. */ +draw_rect (pattern,pick_target (t, params), t->method,0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); + +do_assertions (assertions); + +for (r =1 ; r < pattern->n_rects; r++) { +struct rect rect = pattern->get_rect (¶ms->fb, r); + +switch (t->plane) { +case PLANE_CUR : + rc =drmModeMoveCursor (drm.fd, params->crtc_id, rect.x, + rect.y); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, + params->crtc_id, + params->sprite.fb_id,0 , + rect.x, rect.y, rect.w, + rect.h,0 ,0 , rect.w <<16 , + rect.h <<16 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &pattern->crcs[r]); + +do_assertions (assertions); + +/* "Move" the last rect to the same position just to make sure +* this works too. */ +if (r+1 == pattern->n_rects && !repeat) { + repeat = true; + r--; + } + } +} + +static void onoff_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =ASSERT_NO_ACTION_CHANGE ; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern3; + +set_screens_for_test (t, pattern); + +/* Just paint the right color since we start at 0x0. */ +draw_rect (pattern,pick_target (t, params), t->method,0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); +do_assertions (assertions); + +for (r =0 ; r <4 ; r++) { +if (r %2 ==0 ) { +switch (t->plane) { +case PLANE_CUR : + rc =drmModeSetCursor (drm.fd, params->crtc_id, +0 ,0 ,0 ); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, +0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +0 ,0 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &blue_crc); + + }else { +switch (t->plane) { +case PLANE_CUR : + rc =drmModeSetCursor (drm.fd, params->crtc_id, + params->cursor.gem_handle, + params->cursor.width, + params->cursor.height); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, + params->crtc_id, + params->sprite.fb_id,0 , +0 ,0 , params->sprite.width, + params->sprite.height,0 , +0 , + params->sprite.width <<16 , + params->sprite.height <<16 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &pattern->crcs[0 ]); + + } + +do_assertions (assertions); + } +} + +static void fullscreen_plane_subtest (const struct test_mode *t) +{ +struct draw_pattern_info *pattern = &pattern4; +struct igt_fb fullscreen_fb; +struct rect rect; +struct modeset_params *params =pick_params (t); +int assertions; +int rc; + +set_screens_for_test (t, pattern); + + rect = pattern->get_rect (¶ms->fb,0 ); +igt_create_fb (drm.fd, rect.w, rect.h,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &fullscreen_fb); +igt_draw_fill_fb (drm.fd, &fullscreen_fb, rect.color); + + rc =drmModeSetPlane (drm.fd, params->sprite_id, params->crtc_id, + fullscreen_fb.fb_id,0 ,0 ,0 , fullscreen_fb.width, + fullscreen_fb.height,0 ,0 , + fullscreen_fb.width <<16 , + fullscreen_fb.height <<16 ); +igt_assert (rc ==0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); + +switch (t->screen) { +case SCREEN_PRIM : + assertions =ASSERT_FBC_DISABLED | +ASSERT_LAST_ACTION_CHANGED ; +break ; +case SCREEN_SCND : + assertions =ASSERT_NO_ACTION_CHANGE ; +break ; +default : +igt_assert (false); + } +do_assertions (assertions); + + rc =drmModeSetPlane (drm.fd, params->sprite_id,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +0 ,0 ,0 ); +igt_assert (rc ==0 ); + +if (t->screen ==SCREEN_PRIM ) + assertions =ASSERT_LAST_ACTION_CHANGED ; +update_wanted_crc (t, &blue_crc); +do_assertions (assertions); + +igt_remove_fb (drm.fd, &fullscreen_fb); +} + +static int opt_handler (int option,int option_index) +{ +switch (option) { +case 's' : + opt.check_status = false; +break ; +case 'c' : + opt.check_crc = false; +break ; +case 'o' : + opt.fbc_check_compression = false; +break ; +case 'a' : + opt.fbc_check_last_action = false; +break ; +case 'e' : + opt.no_edp = true; +break ; +case 'm' : + opt.small_modes = true; +break ; +case 't' : + opt.step++; +break ; +case 'n' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_NONE ; +break ; +case 'f' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_FBC ; +break ; +case 'p' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_PSR ; +break ; +case '1' : +igt_assert (opt.only_pipes ==PIPE_COUNT ); + opt.only_pipes =PIPE_SINGLE ; +break ; +case '2' : +igt_assert (opt.only_pipes ==PIPE_COUNT ); + opt.only_pipes =PIPE_DUAL ; +break ; +default : +igt_assert (false); + } + +return 0 ; +} + +const char *help_str = +" --no-status-check Don't check for enable/disable status\n" +" --no-crc-check Don't check for CRC values\n" +" --no-fbc-compression-check Don't check for the FBC compression status\n" +" --no-fbc-action-check Don't check for the FBC last action\n" +" --no-edp Don't use eDP monitors\n" +" --use-small-modes Use smaller resolutions for the modes\n" +" --step Stop on each step so you can check the screen\n" +" --nop-only Only run the \"nop\" feature subtests\n" +" --fbc-only Only run the \"fbc\" feature subtests\n" +" --psr-only Only run the \"psr\" feature subtests\n" +" --1p-only Only run subtests that use 1 pipe\n" +" --2p-only Only run subtests that use 2 pipes\n" ; + +static const char *pipes_str (int pipes) +{ +switch (pipes) { +case PIPE_SINGLE : +return "1p" ; +case PIPE_DUAL : +return "2p" ; +default : +igt_assert (false); + } +} + +static const char *screen_str (int screen) +{ +switch (screen) { +case SCREEN_PRIM : +return "primscrn" ; +case SCREEN_SCND : +return "scndscrn" ; +case SCREEN_OFFSCREEN : +return "offscren" ; +default : +igt_assert (false); + } +} + +static const char *plane_str (int plane) +{ +switch (plane) { +case PLANE_PRI : +return "pri" ; +case PLANE_CUR : +return "cur" ; +case PLANE_SPR : +return "spr" ; +default : +igt_assert (false); + } +} + +static const char *feature_str (int feature) +{ +switch (feature) { +case FEATURE_NONE : +return "nop" ; +case FEATURE_FBC : +return "fbc" ; +case FEATURE_PSR : +return "psr" ; +default : +igt_assert (false); + } +} + +#define TEST_MODE_ITER_BEGIN (t) \ + for (t.pipes = 0; t.pipes < PIPE_COUNT; t.pipes++) { \ + for (t.screen = 0; t.screen < SCREEN_COUNT; t.screen++) { \ + for (t.plane = 0; t.plane < PLANE_COUNT; t.plane++) { \ + for (t.method = 0; t.method < IGT_DRAW_METHOD_COUNT; t.method++) { \ + for (t.feature = 0; t.feature < FEATURE_COUNT; t.feature++) { \ + if (t.pipes == PIPE_SINGLE && t.screen == SCREEN_SCND) \ + continue; + +#define TEST_MODE_ITER_END } } } } } + +int main (int argc,char *argv[]) +{ +struct test_mode t; +struct option long_options[] = { + {"no-status-check" ,0 ,0 ,'s' }, + {"no-crc-check" ,0 ,0 ,'c' }, + {"no-fbc-compression-check" ,0 ,0 ,'o' }, + {"no-fbc-action-check" ,0 ,0 ,'a' }, + {"no-edp" ,0 ,0 ,'e' }, + {"use-small-modes" ,0 ,0 ,'m' }, + {"step" ,0 ,0 ,'t' }, + {"nop-only" ,0 ,0 ,'n' }, + {"fbc-only" ,0 ,0 ,'f' }, + {"psr-only" ,0 ,0 ,'p' }, + {"1p-only" ,0 ,0 ,'1' }, + {"2p-only" ,0 ,0 ,'2' },
Quoted 8 lines
tests/kms_frontbuffer_tracking.c line 1725
Quoted 5 lines
tests/kms_frontbuffer_tracking.c new file +5
-0+ { 0, 0, 0, 0 } + }; + +igt_subtest_init_parse_opts (&argc, argv,"" , long_options, help_str, + opt_handler);This needs updating for the latest changes as this function and the option handler now have a user data pointer.
I'll take a look at the other users.
Thanks for reviewing such a big file!
Quoted 109 lines
Quoted 109 lines
tests/kms_frontbuffer_tracking.c new file +100
-1+ +igt_fixture +setup_environment (); + +for (t.pipes =0 ; t.pipes <PIPE_COUNT ; t.pipes++) { +for (t.feature =0 ; t.feature <FEATURE_COUNT ; t.feature++) { + t.screen =SCREEN_PRIM ; + t.plane =PLANE_PRI ; +/* Make sure nothing is using this value. */ + t.method =-1 ; + +igt_subtest_f ("%s-rte-%s" , +pipes_str (t.pipes), + feature_str(t.feature)) +rte_subtest (&t); + } + } + + TEST_MODE_ITER_BEGIN(t) + igt_subtest_f("%s-%s-%s-draw-%s-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + igt_draw_get_method_name(t.method), + feature_str(t.feature)) +draw_subtest (&t); + TEST_MODE_ITER_END + + + TEST_MODE_ITER_BEGIN(t) + if (t.plane != PLANE_PRI) + continue; + + if (t.screen == SCREEN_OFFSCREEN) + continue; + + igt_subtest_f("%s-%s-flip-%s-%s", + pipes_str(t.pipes), + screen_str(t.screen), + igt_draw_get_method_name(t.method), + feature_str(t.feature)) +flip_subtest (&t); + TEST_MODE_ITER_END + + TEST_MODE_ITER_BEGIN(t) + if (t.screen == SCREEN_OFFSCREEN) + continue; + if (t.method != IGT_DRAW_BLT) + continue; + if (t.plane == PLANE_PRI) + continue; + + igt_subtest_f("%s-%s-%s-move-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + feature_str(t.feature)) +move_subtest (&t); + +igt_subtest_f ("%s-%s-%s-onoff-%s" , +pipes_str (t.pipes), +screen_str (t.screen), +plane_str (t.plane), + feature_str(t.feature)) +onoff_subtest (&t); + TEST_MODE_ITER_END + + TEST_MODE_ITER_BEGIN(t) + if (t.screen == SCREEN_OFFSCREEN) + continue; + if (t.method != IGT_DRAW_BLT) + continue; + if (t.plane != PLANE_SPR) + continue; + + igt_subtest_f("%s-%s-%s-fullscreen-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + feature_str(t.feature)) +fullscreen_plane_subtest (&t); +TEST_MODE_ITER_END + +/* +* TODO: ideas for subtests: +* - Add a new pipe configuration where both pipes can share a big +* framebuffer (instead of each pipe having its own FB). This will +* possibly require some wrapping of struct igt_fb to make the +* implementation easier. +* - Add a test that alternates between different writing methods. Don't +* forget to add the proper domain handling. +* - Add a new enum to struct test_mode that allows us to specify the +* BPP/depth configuration. +*/ + + igt_fixture +teardown_environment (); + +igt_exit (); +} --2.1.4
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 5 lines
Paulo Zanoni _______________________________________________ Intel-gfx mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/intel-gfx
2015-05-26 8:13 GMT-03:00 Thomas Wood <[email protected]>:
Quoted 13 lines · Paulo Zanoni
Quoted 11 lines
From: Paulo Zanoni <[email protected]>
This is a new test that should exercise the frontbuffer tracking feature of the Kernel in a number of different ways. We use different drawing methods, we use the primary, cursor and sprite planes, we can test both on single and dual pipes, also on buffers not associated with any CRTCs, etc.
We currently have assertions for both FBC and PSR, and we also have a "nop" test mode that should disable both FBC and PSR, and can be used for debugging.
Quoted 6 lines
It would be good to have this information in the test as a comment somewhere as well as adding a short description for the
IGT_TEST_DESCRIPTIONmacro.Also, there are a few suggestions from
lib/igt.coccithat might be worth implementing.
I just looked at that and I'm really not interested in any of the changes. Is igt.cocci optional or is someone, at some point just going to run it for everything and commit?
My main complaint is about the igt assertion changes: igt_assert_lte is, IMHO, very hard to understand compared to what's currently at the code. I know there's the advantage that the value can be printed in case we fail the assertion, but I really think it doesn't outweigh the readability loss. I don't want to state for 30 seconds trying to remember what "lte" stands for, and if it checks for A < B, or B < A, or A <= B, or B <= A. Also, most of the comparisons are against constants, and in a lot of the assertions what we really want is the errno instead of the comparison values, which we already get.
IMHO, if it turns out some assertion is getting hit too often and having the values would be useful, then I can replace it with the appropriate igt_assert_x macro or just use hardcode igt_assert_f() for that case.
Also, I should remember the recent regressions that were caused by lib/igt.cocci macro changes. Just git log tests/kms_fbc_crc.c for _multiple_ examples.
The cocci script is also requesting some changes at the exit handler, and I'm really not sure if those changes are safe for an exit handler, so I'd like to avoid them. Remember we also had hard-to-spot bugs on our exit handlers, so it's not like we're going to quickly notice these bugs and then fix them.
Quoted 1,940 lines
Quoted 283 lines
This test is also capable of testing both FBC and PSR even if they are disabled by default on the Kernel: the test knows how to change the i915.ko parameters and then set them back after testing.
I am getting a small number of failures when I run this test, which means we have some work to do on the Kernel.
I also still have a small list of additional subtests that I plan to add to this test, and those tests are documented on the main function.
Signed-off-by Paulo Zanoni <[email protected]>--- tests/.gitignore | 1 + tests/Makefile.sources | 1 + tests/kms_frontbuffer_tracking.c | 1825 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1827 insertions(+) create mode 100644 tests/kms_frontbuffer_tracking.cSome interesting details:
On a tree from 2015, May 06, I get 18 failures and 357 successes. The only FBC failures I get are from the
MMAP_WCdraw method, which is maybe lacking proper frontbuffer tracking support on the Kernel. The other 16 failures are for PSR, most of them with GTT MMAPs.But if I use a tree from 2015, May 25, every single PSR test fails. We need to investigate that. Maybe if I had finished this earlier we would have an automated bisect. This also highlights the importance of testing stuff even when they are disabled by default! I plan to patch the other tests to do the same thing.
I am also seeing some FBC failures that happen right after booting. It seems that the very first tests fail until I run a test that uses the render ring. I'll have to investigate this.
I am also seeing some occasional corruptions on my eDP panel, but on these cases both the pipe and sink CRC tests succeed! Maybe this is some weird panel malfunction caused by the fact that we're doing tons and tons of modesets on the panel.
tests/.gitignore +1
-0@@ -134,6 +134,7 @@ kms_flip kms_flip_event_leak kms_flip_tiling kms_force_connector +kms_frontbuffer_tracking kms_legacy_colorkey kms_mmio_vs_cs_flip kms_pipe_b_c_ivbtests/Makefile.sources +1
-0@@ -66,6 +66,7 @@ TESTS_progs_M = \ kms_flip \ kms_flip_event_leak \ kms_flip_tiling \ + kms_frontbuffer_tracking \ kms_legacy_colorkey \ kms_mmio_vs_cs_flip \ kms_pipe_b_c_ivb \tests/kms_frontbuffer_tracking.c new file +210
-0@@ -0,0 +1,1825 @@ +/* +* Copyright © 2015 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 <[email protected]> +* +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "drmtest.h" +#include "igt_aux.h" +#include "igt_draw.h" +#include "igt_kms.h" +#include "igt_debugfs.h" +#include "intel_chipset.h" +#include "ioctl_wrappers.h" + +#define FBC_PARAM_PATH "/sys/module/i915/parameters/enable_fbc" +#define PSR_PARAM_PATH "/sys/module/i915/parameters/enable_psr" + +struct test_mode { +enum { +PIPE_SINGLE =0 , +PIPE_DUAL , +PIPE_COUNT , + } pipes; + +enum { +SCREEN_PRIM =0 , +SCREEN_SCND , +SCREEN_OFFSCREEN , +SCREEN_COUNT , + } screen; + +enum { +PLANE_PRI =0 , +PLANE_CUR , +PLANE_SPR , +PLANE_COUNT , + } plane; + +enum { +FEATURE_NONE =0 , +FEATURE_FBC , +FEATURE_PSR , +FEATURE_COUNT , + } feature; + +enum igt_draw_method method; +}; + +enum feature_status { +ENABLED , +DISABLED , +}; + +struct rect { +int x; +int y; +int w; +int h; +uint32_t color; +}; + +#define MAX_CONNECTORS 32 +struct { +int fd; +drmModeResPtr res; +drmModeConnectorPtr connectors[MAX_CONNECTORS ]; +drmModePlaneResPtr planes; +drm_intel_bufmgr *bufmgr; +} drm; + +struct { +int fd; + +char param_original_value[16 ]; + +bool supports_compressing; +bool supports_last_action; + +struct timespec last_action; +} fbc = { + .fd =-1 , + .supports_last_action = false, + .supports_compressing = false, +}; + +struct { +int fd; +bool can_test; + +char param_original_value[16 ]; +} psr = { + .fd =-1 , + .can_test = false, +}; + + +#define SINK_CRC_SIZE 12 +typedef struct { +char data[SINK_CRC_SIZE ]; +}sink_crc_t ; + +struct both_crcs { +igt_crc_t pipe; +sink_crc_t sink; +}; + +igt_pipe_crc_t *pipe_crc; +struct both_crcs blue_crc; +struct both_crcs *wanted_crc; + +struct { +int fd; +} sink_crc; + +struct draw_pattern_info { +bool initialized; +bool frames_stack; +int n_rects; +struct both_crcs *crcs; +struct rect (*get_rect)(struct igt_fb *fb,int r); +}; + +/* Draw big rectangles on the screen. */ +struct draw_pattern_info pattern1; +/* 64x64 rectangles at x:0,y:0, just so we can draw on the cursor and sprite. */ +struct draw_pattern_info pattern2; +/* 64x64 rectangles at different positions, same color, for the move test. */ +struct draw_pattern_info pattern3; +/* Just a fullscreen green square. */ +struct draw_pattern_info pattern4; + +/* Command line parameters. */ +struct { +bool check_status; +bool check_crc; +bool fbc_check_compression; +bool fbc_check_last_action; +bool no_edp; +bool small_modes; +int step; +int only_feature; +int only_pipes; +} opt = { + .check_status = true, + .check_crc = true, + .fbc_check_compression = true, + .fbc_check_last_action = true, + .no_edp = false, + .small_modes = false, + .step =0 , + .only_feature =FEATURE_COUNT , + .only_pipes =PIPE_COUNT , +}; + +struct modeset_params { +uint32_t crtc_id; +uint32_t connector_id; +uint32_t sprite_id; +drmModeModeInfoPtr mode; +struct igt_fb fb; +struct igt_fb cursor; +struct igt_fb sprite; +}; + +struct modeset_params prim_mode_params; +struct modeset_params scnd_mode_params; +struct igt_fb offscreen_fb; + +static drmModeModeInfoPtr get_connector_smallest_mode (drmModeConnectorPtr c) +{ +int i; +drmModeModeInfoPtr smallest =NULL ; + +for (i =0 ; i < c->count_modes; i++) { +drmModeModeInfoPtr mode = &c->modes[i]; + +if (!smallest) + smallest = mode; + +if (mode->hdisplay * mode->vdisplay < + smallest->hdisplay * smallest->vdisplay) + smallest = mode; + } + +return smallest; +}tests/kms_frontbuffer_tracking.c line 220
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ +static drmModeConnectorPtr get_connector (uint32_t id) +{ +int i; + +for (i =0 ; i < drm.res->count_connectors; i++) +if (drm.res->connectors[i] == id) +return drm.connectors[i]; + +igt_assert (false);
igt_assert_f()could be used here to provide a more descriptive error message.Quoted 375 lines
tests/kms_frontbuffer_tracking.c new file +375
-0+} + +static void print_mode_info (const char *screen,struct modeset_params *params) +{ +drmModeConnectorPtr c =get_connector (params->connector_id); + +igt_info ("%s screen: %s %s\n" , + screen, +kmstest_connector_type_str (c->connector_type), + params->mode->name); +} + +static void init_mode_params (struct modeset_params *params,uint32_t crtc_id, +int crtc_index,uint32_t connector_id, +drmModeModeInfoPtr mode) +{ +uint32_t plane_id =0 ; +int i; + +igt_create_fb (drm.fd, mode->hdisplay, mode->vdisplay, +DRM_FORMAT_XRGB8888 ,LOCAL_I915_FORMAT_MOD_X_TILED , + ¶ms->fb); +igt_create_fb (drm.fd,64 ,64 ,DRM_FORMAT_ARGB8888 , +LOCAL_DRM_FORMAT_MOD_NONE , ¶ms->cursor); +igt_create_fb (drm.fd,64 ,64 ,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , ¶ms->sprite); + +for (i =0 ; i < drm.planes->count_planes && plane_id ==0 ; i++) { +drmModePlanePtr plane; + + plane =drmModeGetPlane (drm.fd, drm.planes->planes[i]); +igt_assert (plane); + +if (plane->possible_crtcs & (1 << crtc_index)) + plane_id = plane->plane_id; + +drmModeFreePlane (plane); + } +igt_assert (plane_id); + + params->crtc_id = crtc_id; + params->connector_id = connector_id; + params->mode = mode; + params->sprite_id = plane_id; +} + +drmModeModeInfo std_1024_mode = { + .clock =65000 , + .hdisplay =1024 , + .hsync_start =1048 , + .hsync_end =1184 , + .htotal =1344 , + .vtotal =806 , + .hskew =0 , + .vdisplay =768 , + .vsync_start =771 , + .vsync_end =777 , + .vtotal =806 , + .vscan =0 , + .vrefresh =60 , + .flags =0xA , + .type =0x40 , + .name ="Custom 1024x768" , +}; + +static bool connector_get_mode (drmModeConnectorPtr c,drmModeModeInfoPtr *mode) +{ + *mode =NULL ; + +if (c->connection !=DRM_MODE_CONNECTED || !c->count_modes) +return false; + +if (c->connector_type == DRM_MODE_CONNECTOR_eDP && opt.no_edp) +return false; + +if (opt.small_modes) + *mode =get_connector_smallest_mode (c); +else + *mode = &c->modes[0 ]; + +/* Because on some machines we don't have enough stolen memory to fit in +* those 3k panels. And on HSW the CRC WA is so awful that it makes you +* think everything is bugged. */ +if (c->connector_type == DRM_MODE_CONNECTOR_eDP) + *mode = &std_1024_mode; + +return true; +} + +static bool init_modeset_cached_params (void ) +{ +int i; +uint32_t prim_connector_id =0 , scnd_connector_id =0 ; +drmModeModeInfoPtr prim_mode =NULL , scnd_mode =NULL ; +drmModeModeInfoPtr tmp_mode; + +/* First, try to find an eDP monitor since it's the only possible type +* for PSR. */ +for (i =0 ; i < drm.res->count_connectors; i++) { +if (drm.connectors[i]->connector_type != DRM_MODE_CONNECTOR_eDP) +continue ; + +if (connector_get_mode (drm.connectors[i], &tmp_mode)) { + prim_connector_id = drm.res->connectors[i]; + prim_mode = tmp_mode; + } + } +for (i =0 ; i < drm.res->count_connectors; i++) { +/* Don't pick again what we just selected on the above loop. */ +if (drm.res->connectors[i] == prim_connector_id) +continue ; + +if (connector_get_mode (drm.connectors[i], &tmp_mode)) { +if (!prim_connector_id) { + prim_connector_id = drm.res->connectors[i]; + prim_mode = tmp_mode; + }else if (!scnd_connector_id) { + scnd_connector_id = drm.res->connectors[i]; + scnd_mode = tmp_mode; +break ; + } + } + } + +if (!prim_connector_id) +return false; + +init_mode_params (&prim_mode_params, drm.res->crtcs[0 ],0 , + prim_connector_id, prim_mode); +print_mode_info ("Primary" , &prim_mode_params); + +if (!scnd_connector_id) { + scnd_mode_params.connector_id =0 ; +return true; + } + +igt_assert (drm.res->count_crtcs >=2 ); +init_mode_params (&scnd_mode_params, drm.res->crtcs[1 ],1 , + scnd_connector_id, scnd_mode); +print_mode_info ("Secondary" , &scnd_mode_params); + +return true; +} + +static bool set_mode_for_params (struct modeset_params *params) +{ +int rc; + + rc =drmModeSetCrtc (drm.fd, params->crtc_id, params->fb.fb_id,0 ,0 , + ¶ms->connector_id,1 , params->mode); +return (rc ==0 ); +} + +#define DEBUGFS_MSG_SIZE 256 + +static void get_debugfs_string (int fd,char *buf) +{ +ssize_t n_read; + +lseek (fd,0 ,SEEK_SET ); + + n_read =read (fd, buf,DEBUGFS_MSG_SIZE -1 ); +igt_assert (n_read >=0 ); + buf[n_read] ='\0' ; +} + +static enum feature_status fbc_get_status (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); + +if (strstr (buf,"FBC enabled\n" )) +return ENABLED ; +else +return DISABLED ; +} + +static enum feature_status psr_get_status (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (psr.fd, buf); + +if (strstr (buf,"\nActive: yes\n" )) +return ENABLED ; +else +return DISABLED ; +} + +static struct timespec fbc_get_last_action (void ) +{ +struct timespec ret = {0 ,0 }; +char buf[DEBUGFS_MSG_SIZE ]; +char *action; +ssize_t n_read; + +get_debugfs_string (fbc.fd, buf); + + action =strstr (buf,"\nLast action:" ); +igt_assert (action); + + n_read =sscanf (action,"Last action: %ld.%ld" , + &ret.tv_sec, &ret.tv_nsec); +igt_assert (n_read ==2 ); + +return ret; +} + +static bool fbc_last_action_changed (void ) +{ +struct timespec t_new, t_old; + + t_old = fbc.last_action; + t_new =fbc_get_last_action (); + + fbc.last_action = t_new; + +#if 0 +igt_info ("old: %ld.%ld\n" , t_old.tv_sec, t_old.tv_nsec); +igt_info ("new: %ld.%ld\n" , t_new.tv_sec, t_new.tv_nsec); +#endif + +return t_old.tv_sec != t_new.tv_sec || + t_old.tv_nsec != t_new.tv_nsec; +} + +static void fbc_update_last_action (void ) +{ +if (!fbc.supports_last_action) +return ; + + fbc.last_action =fbc_get_last_action (); + +#if 0 +igt_info ("Last action: %ld.%ld\n" , + fbc.last_action.tv_sec, fbc.last_action.tv_nsec); +#endif +} + +static void fbc_setup_last_action (void ) +{ +ssize_t n_read; +char buf[DEBUGFS_MSG_SIZE ]; +char *action; + +get_debugfs_string (fbc.fd, buf); + + action =strstr (buf,"\nLast action:" ); +if (!action) { +igt_info ("FBC last action not supported\n" ); +return ; + } + + fbc.supports_last_action = true; + + n_read =sscanf (action,"Last action: %ld.%ld" , + &fbc.last_action.tv_sec, &fbc.last_action.tv_nsec); +igt_assert (n_read ==2 ); +} + +static bool fbc_is_compressing (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); +return strstr (buf,"\nCompressing: yes\n" ) !=NULL ; +} + +static bool fbc_wait_for_compression (void ) +{ +return igt_wait (fbc_is_compressing (),5000 ,1 ); +} + +static void fbc_setup_compressing (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (fbc.fd, buf); + +if (strstr (buf,"\nCompressing:" )) + fbc.supports_compressing = true; +else +igt_info ("FBC compression information not supported\n" ); +} + +static bool fbc_wait_for_status (enum feature_status status) +{ +return igt_wait (fbc_get_status () == status,5000 ,1 ); +} + +static bool psr_wait_for_status (enum feature_status status) +{ +return igt_wait (psr_get_status () == status,5000 ,1 ); +} + +static void set_param (const char *path,bool enable) +{ +int fd; +const char *str; + + fd =open (path,O_RDWR ); +igt_assert (fd >=0 ); + + str = enable ?"1\n" :"0\n" ; +igt_assert (write (fd, str,2 ) ==2 ); + +igt_assert (close (fd) ==0 ); +} +#define fbc_enable () set_param(FBC_PARAM_PATH, true) +#define fbc_disable () set_param(FBC_PARAM_PATH, false) +#define psr_enable () set_param(PSR_PARAM_PATH, true) +#define psr_disable () set_param(PSR_PARAM_PATH, false) + +static void save_param (const char *file_path,char *param_value) +{ +int fd; +ssize_t n; + + fd =open (file_path,O_RDWR ); +igt_assert (fd >=0 ); + + n =read (fd, param_value,15 ); +igt_assert (n >0 ); + param_value[n] ='\0' ; +igt_assert (close (fd) ==0 ); +} + +static void get_sink_crc (sink_crc_t *crc) +{ +lseek (sink_crc.fd,0 ,SEEK_SET ); + +igt_assert (read (sink_crc.fd, crc->data,SINK_CRC_SIZE ) == +SINK_CRC_SIZE ); +} + +static bool sink_crc_equal (sink_crc_t *a,sink_crc_t *b) +{ +return (memcmp (a->data, b->data,SINK_CRC_SIZE ) ==0 ); +} + +#define assert_sink_crc_equal (a, b) igt_assert(sink_crc_equal(a, b)) + +static struct rect pat1_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + +switch (r) { +case 0 : + rect.x =0 ; + rect.y =0 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0x00FF00 ; +break ; +case 1 : + rect.x = fb->width /8 ; + rect.y = fb->height /8 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0xFF0000 ; +break ; +case 2 : + rect.x = fb->width /8 *4 ; + rect.y = fb->height /8 *4 ; + rect.w = fb->width /8 *2 ; + rect.h = fb->height /8 *2 ; + rect.color =0xFF00FF ; +break ; +case 3 : + rect.x = fb->width /16 ; + rect.y = fb->height /16 ; + rect.w = fb->width /8 ; + rect.h = fb->height /8 ; + rect.color =0x00FFFF ;tests/kms_frontbuffer_tracking.c line 605
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+break ; +case 4 : + rect.x = fb->width -64 ; + rect.y = fb->height -64 ; + rect.w =64 ; + rect.h =64 ; + rect.color =0xFFFFFF ; +break ; +default : +igt_assert (0 );It might be worth adding an
igt_assert_not_reachedfunction (or similar) for these, which could print a better error message.Quoted 233 lines
tests/kms_frontbuffer_tracking.c new file +233
-0+ } + +return rect; +} + +static struct rect pat2_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + + rect.x =0 ; + rect.y =0 ; + rect.w =64 ; + rect.h =64 ; + +switch (r) { +case 0 : + rect.color =0xFF00FF00 ; +break ; +case 1 : + rect.w =32 ; + rect.h =32 ; + rect.color =0xFFFF0000 ; +break ; +case 2 : + rect.x =32 ; + rect.y =32 ; + rect.w =32 ; + rect.h =32 ; + rect.color =0xFFFF00FF ; +break ; +case 3 : + rect.x =16 ; + rect.y =16 ; + rect.w =32 ; + rect.h =32 ; + rect.color =0xFF00FFFF ; +break ; +case 4 : + rect.color =0xFFFFFF00 ; +break ; +default : +igt_assert (0 ); + } + +return rect; +} + +static struct rect pat3_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + + rect.w =64 ; + rect.h =64 ; + rect.color =0xFF00FF00 ; + +switch (r) { +case 0 : + rect.x =0 ; + rect.y =0 ; +break ; +case 1 : + rect.x =64 ; + rect.y =64 ; +break ; +case 2 : + rect.x =1 ; + rect.y =1 ; +break ; +case 3 : + rect.x = fb->width -64 ; + rect.y = fb->height -64 ; +break ; +case 4 : + rect.x = fb->width /2 -32 ; + rect.y = fb->height /2 -32 ; +break ; +default : +igt_assert (0 ); + } + +return rect; +} + +static struct rect pat4_get_rect (struct igt_fb *fb,int r) +{ +struct rect rect; + +igt_assert (r ==0 ); + + rect.x =0 ; + rect.y =0 ; + rect.w = fb->width; + rect.h = fb->height; + rect.color =0xFF00FF00 ; + +return rect; +} + +static void draw_rect (struct draw_pattern_info *pattern,struct igt_fb *fb, +enum igt_draw_method method,int r) +{ +struct rect rect = pattern->get_rect (fb, r); + +igt_draw_rect_fb (drm.fd, drm.bufmgr,NULL , fb, method, rect.x, rect.y, + rect.w, rect.h, rect.color); +} + +static void unset_all_crtcs (void ) +{ +int i, rc; + +for (i =0 ; i < drm.res->count_crtcs; i++) { + rc =drmModeSetCrtc (drm.fd, drm.res->crtcs[i],-1 ,0 ,0 ,NULL , +0 ,NULL ); +igt_assert (rc ==0 ); + + rc =drmModeSetCursor (drm.fd, drm.res->crtcs[i],0 ,0 ,0 ); +igt_assert (rc ==0 ); + } + +for (i =0 ; i < drm.planes->count_planes; i++) { + rc =drmModeSetPlane (drm.fd, drm.planes->planes[i],0 ,0 ,0 ,0 , +0 ,0 ,0 ,0 ,0 ,0 ,0 ); +igt_assert (rc ==0 ); + } +} + +static void disable_features (void ) +{ +fbc_disable (); +psr_disable (); +} + +static void print_crc (const char *str,struct both_crcs *crc) +{ +int i; +char *pipe_str; + + pipe_str =igt_crc_to_string (&crc->pipe); + +igt_debug ("%s pipe:[%s] sink:[" , str, pipe_str); +for (i =0 ; i <SINK_CRC_SIZE ; i++) +igt_debug ("%c" , crc->sink.data[i]); +igt_debug ("]\n" ); + +free (pipe_str); +} + +static void collect_crcs (struct both_crcs *crcs) +{ +drmModeConnectorPtr c; + +igt_pipe_crc_collect_crc (pipe_crc, &crcs->pipe); + + c =get_connector (prim_mode_params.connector_id); +if (c->connector_type == DRM_MODE_CONNECTOR_eDP) +get_sink_crc (&crcs->sink); +else +memcpy (&crcs->sink,"unsupported!" ,SINK_CRC_SIZE ); +} + +static void init_blue_crc (void ) +{ +struct igt_fb blue; +int rc; + +disable_features (); +unset_all_crtcs (); + +igt_create_fb (drm.fd, prim_mode_params.mode->hdisplay, + prim_mode_params.mode->vdisplay,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &blue); + +igt_draw_fill_fb (drm.fd, &blue,0xFF ); + + rc =drmModeSetCrtc (drm.fd, prim_mode_params.crtc_id, + blue.fb_id,0 ,0 , &prim_mode_params.connector_id,1 , + prim_mode_params.mode); +igt_assert (rc ==0 ); +collect_crcs (&blue_crc); + +print_crc ("Blue CRC: " , &blue_crc); + +igt_remove_fb (drm.fd, &blue); +} + +static void init_crcs (struct draw_pattern_info *pattern) +{ +int r, r_, rc; +struct igt_fb fbs[pattern->n_rects]; + +if (pattern->initialized) +return ; + + pattern->crcs =calloc (pattern->n_rects,sizeof (*(pattern->crcs))); + +for (r =0 ; r < pattern->n_rects; r++) +igt_create_fb (drm.fd, prim_mode_params.mode->hdisplay, + prim_mode_params.mode->vdisplay, +DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &fbs[r]); + +for (r =0 ; r < pattern->n_rects; r++) +igt_draw_fill_fb (drm.fd, &fbs[r],0xFF ); + +if (pattern->frames_stack) { +for (r =0 ; r < pattern->n_rects; r++) +for (r_ =0 ; r_ <= r; r_++) +draw_rect (pattern, &fbs[r],IGT_DRAW_PWRITE , + r_); + }else { +for (r =0 ; r < pattern->n_rects; r++) +draw_rect (pattern, &fbs[r],IGT_DRAW_PWRITE , r); + } + +for (r =0 ; r < pattern->n_rects; r++) { + rc =drmModeSetCrtc (drm.fd, prim_mode_params.crtc_id, + fbs[r].fb_id,0 ,0 , + &prim_mode_params.connector_id,1 , + prim_mode_params.mode); +igt_assert (rc ==0 ); +collect_crcs (&pattern->crcs[r]); + } + +for (r =0 ; r < pattern->n_rects; r++) { +igt_debug ("Rect %d CRC:" , r); +print_crc ("" , &pattern->crcs[r]); + } + +unset_all_crtcs (); + +for (r =0 ; r < pattern->n_rects; r++) +igt_remove_fb (drm.fd, &fbs[r]);tests/kms_frontbuffer_tracking.c line 848
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ + pattern->initialized = true; +} + +static void setup_drm (void ) +{ +int i; + + drm.fd =drm_open_any_master (); +igt_require (drm.fd >=0 );The file descriptor check is done inside
drm_open_any_master.Quoted 49 lines
tests/kms_frontbuffer_tracking.c new file +49
-0+ + drm.res =drmModeGetResources (drm.fd); +igt_assert (drm.res->count_connectors <=MAX_CONNECTORS ); + +for (i =0 ; i < drm.res->count_connectors; i++) + drm.connectors[i] =drmModeGetConnector (drm.fd, + drm.res->connectors[i]); + + drm.planes =drmModeGetPlaneResources (drm.fd); + + drm.bufmgr =drm_intel_bufmgr_gem_init (drm.fd,4096 ); +igt_assert (drm.bufmgr); +drm_intel_bufmgr_gem_enable_reuse (drm.bufmgr); +} + +static void teardown_drm (void ) +{ +int i; + +drm_intel_bufmgr_destroy (drm.bufmgr); + +drmModeFreePlaneResources (drm.planes); + +for (i =0 ; i < drm.res->count_connectors; i++) +drmModeFreeConnector (drm.connectors[i]); + +drmModeFreeResources (drm.res); +close (drm.fd); +} + +static void setup_modeset (void ) +{ +igt_require (init_modeset_cached_params ()); + +kmstest_set_vt_graphics_mode (); + +igt_create_fb (drm.fd,1024 ,1024 ,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &offscreen_fb); +} + +static void teardown_modeset (void ) +{ +if (scnd_mode_params.connector_id) { +igt_remove_fb (drm.fd, &scnd_mode_params.fb); +igt_remove_fb (drm.fd, &scnd_mode_params.cursor); +igt_remove_fb (drm.fd, &scnd_mode_params.sprite); + } +igt_remove_fb (drm.fd, &prim_mode_params.fb); +igt_remove_fb (drm.fd, &prim_mode_params.cursor);tests/kms_frontbuffer_tracking.c line 907
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+igt_remove_fb (drm.fd, &prim_mode_params.sprite); +igt_remove_fb (drm.fd, &offscreen_fb); +} + +static void setup_crcs (void ) +{ + pipe_crc =igt_pipe_crc_new (0 ,INTEL_PIPE_CRC_SOURCE_AUTO ); + + sink_crc.fd =open ("/sys/kernel/debug/dri/0/i915_sink_crc_eDP1" , +O_RDONLY );
igt_debugfs_openwould take care of ensuring debugfs is mounted and the path is correct.Quoted 130 lines
tests/kms_frontbuffer_tracking.c new file +130
-0+igt_assert (sink_crc.fd >=0 ); + +init_blue_crc (); + + pattern1.initialized = false; + pattern1.frames_stack = true; + pattern1.n_rects =5 ; + pattern1.crcs =NULL ; + pattern1.get_rect = pat1_get_rect; + + pattern2.initialized = false; + pattern2.frames_stack = true; + pattern2.n_rects =5 ; + pattern2.crcs =NULL ; + pattern2.get_rect = pat2_get_rect; + + pattern3.initialized = false; + pattern3.frames_stack = false; + pattern3.n_rects =5 ; + pattern3.crcs =NULL ; + pattern3.get_rect = pat3_get_rect; + + pattern4.initialized = false; + pattern4.frames_stack = false; + pattern4.n_rects =1 ; + pattern4.crcs =NULL ; + pattern4.get_rect = pat4_get_rect; +} + +static void teardown_crcs (void ) +{ +if (pattern1.crcs) +free (pattern1.crcs); +if (pattern2.crcs) +free (pattern2.crcs); +if (pattern3.crcs) +free (pattern3.crcs); +if (pattern4.crcs) +free (pattern4.crcs); + +close (sink_crc.fd); + +igt_pipe_crc_free (pipe_crc); +} + +static void restore_param (const char *file_path,char *param_value) +{ +int fd; + + fd =open (file_path,O_RDWR ); +if (fd >=0 ) { +write (fd, param_value,strlen (param_value)); +close (fd); + } +} + +static void exit_handler (int sig) +{ +restore_param (FBC_PARAM_PATH , fbc.param_original_value); +restore_param (PSR_PARAM_PATH , psr.param_original_value); +} + +static void setup_fbc (void ) +{ + fbc.fd =open ("/sys/kernel/debug/dri/0/i915_fbc_status" ,O_RDONLY ); +igt_assert (fbc.fd >=0 ); + +save_param (FBC_PARAM_PATH , fbc.param_original_value); + +fbc_setup_last_action (); +fbc_setup_compressing (); +} + +static void teardown_fbc (void ) +{ +if (fbc.fd !=-1 ) +close (fbc.fd); +} + +static bool psr_sink_has_support (void ) +{ +char buf[DEBUGFS_MSG_SIZE ]; + +get_debugfs_string (psr.fd, buf); + +return strstr (buf,"Sink_Support: yes\n" ); +} + +static void setup_psr (void ) +{ +if (get_connector (prim_mode_params.connector_id)->connector_type != + DRM_MODE_CONNECTOR_eDP) { +igt_info ("Can't test PSR: no usable eDP screen.\n" ); +return ; + } + + psr.fd =open ("/sys/kernel/debug/dri/0/i915_edp_psr_status" ,O_RDONLY ); +igt_assert (psr.fd >=0 ); + +if (!psr_sink_has_support ()) { +igt_info ("Can't test PSR: not supported by sink.\n" ); +return ; + } + psr.can_test = true; + +save_param (PSR_PARAM_PATH , psr.param_original_value); +} + +static void teardown_psr (void ) +{ +if (psr.fd !=-1 ) +close (psr.fd); +} + +static void setup_environment (void ) +{ +setup_drm (); +setup_modeset (); + +igt_install_exit_handler (exit_handler); +setup_fbc (); +setup_psr (); + +setup_crcs (); +} + +static void teardown_environment (void ) +{ +teardown_crcs (); +teardown_psr ();tests/kms_frontbuffer_tracking.c line 1047
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+teardown_fbc (); +teardown_modeset (); +teardown_drm (); +} + +static void wait_user (void ) +{ +igt_info ("Press enter...\n" ); +while (getchar () !='\n' ) + ;Could this be done with the interactive debug option? (i.e. using
igt_debug_wait_for_keypress)Quoted 75 lines
tests/kms_frontbuffer_tracking.c new file +75
-0+} + +static struct modeset_params *pick_params (const struct test_mode *t) +{ +switch (t->screen) { +case SCREEN_PRIM : +return &prim_mode_params; +case SCREEN_SCND : +return &scnd_mode_params; +case SCREEN_OFFSCREEN : +return NULL ; +default : +igt_assert (false); + } +} + +static struct igt_fb *pick_target (const struct test_mode *t, +struct modeset_params *params) +{ +if (!params) +return &offscreen_fb; + +switch (t->plane) { +case PLANE_PRI : +return ¶ms->fb; +case PLANE_CUR : +return ¶ms->cursor; +case PLANE_SPR : +return ¶ms->sprite; +default : +igt_assert (false); + } +} + +static void do_flush (const struct test_mode *t) +{ +struct modeset_params *params =pick_params (t); +struct igt_fb *target =pick_target (t, params); + +gem_set_domain (drm.fd, target->gem_handle,I915_GEM_DOMAIN_GTT ,0 ); +} + +#define DONT_ASSERT_CRC (1 << 0) + +#define FBC_ASSERT_FLAGS (0xF << 1) +#define ASSERT_FBC_ENABLED (1 << 1) +#define ASSERT_FBC_DISABLED (1 << 2) +#define ASSERT_LAST_ACTION_CHANGED (1 << 3) +#define ASSERT_NO_ACTION_CHANGE (1 << 4) + +#define PSR_ASSERT_FLAGS (3 << 5) +#define ASSERT_PSR_ENABLED (1 << 5) +#define ASSERT_PSR_DISABLED (1 << 6) + +static int adjust_assertion_flags (const struct test_mode *t,int flags) +{ +if (!(flags &ASSERT_FBC_DISABLED )) + flags |=ASSERT_FBC_ENABLED ; +if (!(flags &ASSERT_PSR_DISABLED )) + flags |=ASSERT_PSR_ENABLED ; + +if (t->feature !=FEATURE_FBC ) + flags &= ~FBC_ASSERT_FLAGS ; +if (t->feature !=FEATURE_PSR ) + flags &= ~PSR_ASSERT_FLAGS ; + +return flags; +} + +#define do_crc_assertions (flags) do { \ + int flags__ = (flags); \ + struct both_crcs crc_; \ + \ + if (!opt.check_crc || (flags__ & DONT_ASSERT_CRC)) \ + break; \tests/kms_frontbuffer_tracking.c line 1132
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ \ +collect_crcs (&crc_); \ +print_crc ("Calculated CRC:" , &crc_); \ + \ +igt_assert (wanted_crc); \ +igt_assert_crc_equal (&crc_.pipe, &wanted_crc->pipe); \ +assert_sink_crc_equal (&crc_.sink, &wanted_crc->sink); \ +} while (0) + +#define do_assertions (flags) do { \Could this be a function rather than a macro to make debugging easier?
Quoted 109 lines
tests/kms_frontbuffer_tracking.c new file +109
-0+int flags_ =adjust_assertion_flags (t, (flags)); \ + \ +if (opt.step >1 ) \ +wait_user (); \ + \ +/* Check the CRC to make sure the drawing operations work \ +* immediately, independently of the features being enabled */ \ +do_crc_assertions (flags_); \ + \ +/* Now we can flush things to make the test faster. */ \ +do_flush (t); \ + \ +if (opt.check_status) { \ +if (flags_ &ASSERT_FBC_ENABLED ) { \ +igt_assert (fbc_wait_for_status (ENABLED )); \ + \ +if (fbc.supports_compressing && \ + opt.fbc_check_compression) \ +igt_assert (fbc_wait_for_compression ()); \ + }else if (flags_ &ASSERT_FBC_DISABLED ) { \ +igt_assert (fbc_wait_for_status (DISABLED )); \ + } \ + \ +if (flags_ &ASSERT_PSR_ENABLED ) \ +igt_assert (psr_wait_for_status (ENABLED )); \ +else if (flags_ &ASSERT_PSR_DISABLED ) \ +igt_assert (psr_wait_for_status (DISABLED )); \ + }else { \ +/* Make sure we settle before continuing. */ \ +sleep (1 ); \ + } \ + \ +/* Check CRC again to make sure the compressed screen is ok. */ \ +do_crc_assertions (flags_); \ + \ +if (fbc.supports_last_action && opt.fbc_check_last_action) { \ +if (flags_ &ASSERT_LAST_ACTION_CHANGED ) \ +igt_assert (fbc_last_action_changed ()); \ +else if (flags_ &ASSERT_NO_ACTION_CHANGE ) \ +igt_assert (!fbc_last_action_changed ()); \ + } \ + \ +if (opt.step) \ +wait_user (); \ +}while (0 ) + +static void enable_prim_screen_and_wait(const struct test_mode *t) +{ +igt_draw_fill_fb (drm.fd, &prim_mode_params.fb,0xFF ); +set_mode_for_params (&prim_mode_params); + + wanted_crc = &blue_crc; +fbc_update_last_action (); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void enable_scnd_screen_and_wait (const struct test_mode *t) +{ +igt_draw_fill_fb (drm.fd, &scnd_mode_params.fb,0x80 ); +set_mode_for_params (&scnd_mode_params); +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void set_cursor_for_test (const struct test_mode *t, +struct modeset_params *params) +{ +int rc; + +igt_draw_fill_fb (drm.fd, ¶ms->cursor,0xFF0000FF ); + + rc =drmModeMoveCursor (drm.fd, params->crtc_id,0 ,0 ); +igt_assert (rc ==0 ); + + rc =drmModeSetCursor (drm.fd, params->crtc_id, + params->cursor.gem_handle, params->cursor.width, + params->cursor.height); +igt_assert (rc ==0 ); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void set_sprite_for_test (const struct test_mode *t, +struct modeset_params *params) +{ +int rc; + +igt_draw_fill_fb (drm.fd, ¶ms->sprite,0xFF0000FF ); + + rc =drmModeSetPlane (drm.fd, params->sprite_id, params->crtc_id, + params->sprite.fb_id,0 ,0 ,0 , + params->sprite.width, params->sprite.height, +0 ,0 , params->sprite.width <<16 , + params->sprite.height <<16 ); +igt_assert (rc ==0 ); + +do_assertions (ASSERT_NO_ACTION_CHANGE ); +} + +static void enable_features_for_test (const struct test_mode *t) +{ +switch (t->feature) { +case FEATURE_NONE : +break ; +case FEATURE_FBC : +fbc_enable (); +break ; +case FEATURE_PSR : +psr_enable ();tests/kms_frontbuffer_tracking.c line 1251
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+break ; +default : +igt_assert (false); + } +} + +static void check_test_requirements (const struct test_mode *t) +{ +if (t->pipes ==PIPE_DUAL ) +igt_require (scnd_mode_params.connector_id);It might be nice to use
igt_require_fon these checks, so that a better message is printed if the test skips.Quoted 464 lines
tests/kms_frontbuffer_tracking.c new file +464
-0+ +if (t->feature ==FEATURE_PSR ) +igt_require (psr.can_test); + +if (opt.only_feature !=FEATURE_COUNT ) +igt_require (t->feature == opt.only_feature); + +if (opt.only_pipes !=PIPE_COUNT ) +igt_require (t->pipes == opt.only_pipes); +} + +static void set_screens_for_test (const struct test_mode *t, +struct draw_pattern_info *pattern) +{ +check_test_requirements (t); + +if (t->screen ==SCREEN_OFFSCREEN ) +igt_draw_fill_fb (drm.fd, &offscreen_fb,0x80 ); + +disable_features (); +unset_all_crtcs (); +init_crcs (pattern); +enable_features_for_test (t); + +enable_prim_screen_and_wait (t); +if (t->screen ==SCREEN_PRIM ) { +if (t->plane ==PLANE_CUR ) +set_cursor_for_test (t, &prim_mode_params); +if (t->plane ==PLANE_SPR ) +set_sprite_for_test (t, &prim_mode_params); + } + +if (t->pipes ==PIPE_SINGLE ) +return ; + +enable_scnd_screen_and_wait (t); +if (t->screen ==SCREEN_SCND ) { +if (t->plane ==PLANE_CUR ) +set_cursor_for_test (t, &scnd_mode_params); +if (t->plane ==PLANE_SPR ) +set_sprite_for_test (t, &scnd_mode_params); + } +} + +static void rte_subtest (const struct test_mode *t) +{ +check_test_requirements (t); + +disable_features (); +enable_features_for_test (t); +unset_all_crtcs (); +do_assertions (ASSERT_FBC_DISABLED |ASSERT_PSR_DISABLED | +DONT_ASSERT_CRC ); + +enable_prim_screen_and_wait (t); +set_cursor_for_test (t, &prim_mode_params); +set_sprite_for_test (t, &prim_mode_params); + +if (t->pipes ==PIPE_SINGLE ) +return ; + +enable_scnd_screen_and_wait (t); +set_cursor_for_test (t, &scnd_mode_params); +set_sprite_for_test (t, &scnd_mode_params); +} + +static void update_wanted_crc (const struct test_mode *t,struct both_crcs *crc) +{ +if (t->screen ==SCREEN_PRIM ) + wanted_crc = crc; +} + +static void draw_subtest (const struct test_mode *t) +{ +int r; +int assertions =0 ; +struct draw_pattern_info *pattern; +struct modeset_params *params =pick_params (t); +struct igt_fb *target =pick_target (t, params); + +switch (t->screen) { +case SCREEN_PRIM : +if (t->method !=IGT_DRAW_MMAP_GTT && t->plane ==PLANE_PRI ) + assertions |=ASSERT_LAST_ACTION_CHANGED ; +break ; +case SCREEN_SCND : +case SCREEN_OFFSCREEN : + assertions |=ASSERT_NO_ACTION_CHANGE ; +break ; +default : +igt_assert (false); + } + +switch (t->plane) { +case PLANE_PRI : + pattern = &pattern1; +break ; +case PLANE_CUR : +case PLANE_SPR : + pattern = &pattern2; +break ; +default : +igt_assert (false); + } + +set_screens_for_test (t, pattern); + +for (r =0 ; r < pattern->n_rects; r++) { +draw_rect (pattern, target, t->method, r); +update_wanted_crc (t, &pattern->crcs[r]); +do_assertions (assertions); + } +} + +static void flip_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =0 ; +struct igt_fb fb2, *target; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern1; +uint32_t bg_color; + +switch (t->screen) { +case SCREEN_PRIM : + assertions |=ASSERT_LAST_ACTION_CHANGED ; + bg_color =0xFF ; +break ; +case SCREEN_SCND : + assertions |=ASSERT_NO_ACTION_CHANGE ; + bg_color =0x80 ; +break ; +default : +igt_assert (false); + } + +set_screens_for_test (t, pattern); + +igt_create_fb (drm.fd, params->mode->hdisplay, params->mode->vdisplay, +DRM_FORMAT_XRGB8888 ,LOCAL_I915_FORMAT_MOD_X_TILED , &fb2); +igt_draw_fill_fb (drm.fd, &fb2, bg_color); + +for (r =0 ; r < pattern->n_rects; r++) { + target = (r %2 ==0 ) ? &fb2 : ¶ms->fb; + +if (r !=0 ) +draw_rect (pattern, target, t->method, r -1 ); +draw_rect (pattern, target, t->method, r); +update_wanted_crc (t, &pattern->crcs[r]); + + rc =drmModePageFlip (drm.fd, params->crtc_id, target->fb_id,0 , +NULL ); +igt_assert (rc ==0 ); + +do_assertions (assertions); + } + +igt_remove_fb (drm.fd, &fb2); +} + +static void move_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =ASSERT_NO_ACTION_CHANGE ; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern3; +bool repeat = false; + +set_screens_for_test (t, pattern); + +/* Just paint the right color since we start at 0x0. */ +draw_rect (pattern,pick_target (t, params), t->method,0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); + +do_assertions (assertions); + +for (r =1 ; r < pattern->n_rects; r++) { +struct rect rect = pattern->get_rect (¶ms->fb, r); + +switch (t->plane) { +case PLANE_CUR : + rc =drmModeMoveCursor (drm.fd, params->crtc_id, rect.x, + rect.y); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, + params->crtc_id, + params->sprite.fb_id,0 , + rect.x, rect.y, rect.w, + rect.h,0 ,0 , rect.w <<16 , + rect.h <<16 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &pattern->crcs[r]); + +do_assertions (assertions); + +/* "Move" the last rect to the same position just to make sure +* this works too. */ +if (r+1 == pattern->n_rects && !repeat) { + repeat = true; + r--; + } + } +} + +static void onoff_subtest (const struct test_mode *t) +{ +int r, rc; +int assertions =ASSERT_NO_ACTION_CHANGE ; +struct modeset_params *params =pick_params (t); +struct draw_pattern_info *pattern = &pattern3; + +set_screens_for_test (t, pattern); + +/* Just paint the right color since we start at 0x0. */ +draw_rect (pattern,pick_target (t, params), t->method,0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); +do_assertions (assertions); + +for (r =0 ; r <4 ; r++) { +if (r %2 ==0 ) { +switch (t->plane) { +case PLANE_CUR : + rc =drmModeSetCursor (drm.fd, params->crtc_id, +0 ,0 ,0 ); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, +0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +0 ,0 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &blue_crc); + + }else { +switch (t->plane) { +case PLANE_CUR : + rc =drmModeSetCursor (drm.fd, params->crtc_id, + params->cursor.gem_handle, + params->cursor.width, + params->cursor.height); +igt_assert (rc ==0 ); +break ; +case PLANE_SPR : + rc =drmModeSetPlane (drm.fd, params->sprite_id, + params->crtc_id, + params->sprite.fb_id,0 , +0 ,0 , params->sprite.width, + params->sprite.height,0 , +0 , + params->sprite.width <<16 , + params->sprite.height <<16 ); +igt_assert (rc ==0 ); +break ; +default : +igt_assert (false); + } +update_wanted_crc (t, &pattern->crcs[0 ]); + + } + +do_assertions (assertions); + } +} + +static void fullscreen_plane_subtest (const struct test_mode *t) +{ +struct draw_pattern_info *pattern = &pattern4; +struct igt_fb fullscreen_fb; +struct rect rect; +struct modeset_params *params =pick_params (t); +int assertions; +int rc; + +set_screens_for_test (t, pattern); + + rect = pattern->get_rect (¶ms->fb,0 ); +igt_create_fb (drm.fd, rect.w, rect.h,DRM_FORMAT_XRGB8888 , +LOCAL_I915_FORMAT_MOD_X_TILED , &fullscreen_fb); +igt_draw_fill_fb (drm.fd, &fullscreen_fb, rect.color); + + rc =drmModeSetPlane (drm.fd, params->sprite_id, params->crtc_id, + fullscreen_fb.fb_id,0 ,0 ,0 , fullscreen_fb.width, + fullscreen_fb.height,0 ,0 , + fullscreen_fb.width <<16 , + fullscreen_fb.height <<16 ); +igt_assert (rc ==0 ); +update_wanted_crc (t, &pattern->crcs[0 ]); + +switch (t->screen) { +case SCREEN_PRIM : + assertions =ASSERT_FBC_DISABLED | +ASSERT_LAST_ACTION_CHANGED ; +break ; +case SCREEN_SCND : + assertions =ASSERT_NO_ACTION_CHANGE ; +break ; +default : +igt_assert (false); + } +do_assertions (assertions); + + rc =drmModeSetPlane (drm.fd, params->sprite_id,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +0 ,0 ,0 ); +igt_assert (rc ==0 ); + +if (t->screen ==SCREEN_PRIM ) + assertions =ASSERT_LAST_ACTION_CHANGED ; +update_wanted_crc (t, &blue_crc); +do_assertions (assertions); + +igt_remove_fb (drm.fd, &fullscreen_fb); +} + +static int opt_handler (int option,int option_index) +{ +switch (option) { +case 's' : + opt.check_status = false; +break ; +case 'c' : + opt.check_crc = false; +break ; +case 'o' : + opt.fbc_check_compression = false; +break ; +case 'a' : + opt.fbc_check_last_action = false; +break ; +case 'e' : + opt.no_edp = true; +break ; +case 'm' : + opt.small_modes = true; +break ; +case 't' : + opt.step++; +break ; +case 'n' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_NONE ; +break ; +case 'f' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_FBC ; +break ; +case 'p' : +igt_assert (opt.only_feature ==FEATURE_COUNT ); + opt.only_feature =FEATURE_PSR ; +break ; +case '1' : +igt_assert (opt.only_pipes ==PIPE_COUNT ); + opt.only_pipes =PIPE_SINGLE ; +break ; +case '2' : +igt_assert (opt.only_pipes ==PIPE_COUNT ); + opt.only_pipes =PIPE_DUAL ; +break ; +default : +igt_assert (false); + } + +return 0 ; +} + +const char *help_str = +" --no-status-check Don't check for enable/disable status\n" +" --no-crc-check Don't check for CRC values\n" +" --no-fbc-compression-check Don't check for the FBC compression status\n" +" --no-fbc-action-check Don't check for the FBC last action\n" +" --no-edp Don't use eDP monitors\n" +" --use-small-modes Use smaller resolutions for the modes\n" +" --step Stop on each step so you can check the screen\n" +" --nop-only Only run the \"nop\" feature subtests\n" +" --fbc-only Only run the \"fbc\" feature subtests\n" +" --psr-only Only run the \"psr\" feature subtests\n" +" --1p-only Only run subtests that use 1 pipe\n" +" --2p-only Only run subtests that use 2 pipes\n" ; + +static const char *pipes_str (int pipes) +{ +switch (pipes) { +case PIPE_SINGLE : +return "1p" ; +case PIPE_DUAL : +return "2p" ; +default : +igt_assert (false); + } +} + +static const char *screen_str (int screen) +{ +switch (screen) { +case SCREEN_PRIM : +return "primscrn" ; +case SCREEN_SCND : +return "scndscrn" ; +case SCREEN_OFFSCREEN : +return "offscren" ; +default : +igt_assert (false); + } +} + +static const char *plane_str (int plane) +{ +switch (plane) { +case PLANE_PRI : +return "pri" ; +case PLANE_CUR : +return "cur" ; +case PLANE_SPR : +return "spr" ; +default : +igt_assert (false); + } +} + +static const char *feature_str (int feature) +{ +switch (feature) { +case FEATURE_NONE : +return "nop" ; +case FEATURE_FBC : +return "fbc" ; +case FEATURE_PSR : +return "psr" ; +default : +igt_assert (false); + } +} + +#define TEST_MODE_ITER_BEGIN (t) \ + for (t.pipes = 0; t.pipes < PIPE_COUNT; t.pipes++) { \ + for (t.screen = 0; t.screen < SCREEN_COUNT; t.screen++) { \ + for (t.plane = 0; t.plane < PLANE_COUNT; t.plane++) { \ + for (t.method = 0; t.method < IGT_DRAW_METHOD_COUNT; t.method++) { \ + for (t.feature = 0; t.feature < FEATURE_COUNT; t.feature++) { \ + if (t.pipes == PIPE_SINGLE && t.screen == SCREEN_SCND) \ + continue; + +#define TEST_MODE_ITER_END } } } } } + +int main (int argc,char *argv[]) +{ +struct test_mode t; +struct option long_options[] = { + {"no-status-check" ,0 ,0 ,'s' }, + {"no-crc-check" ,0 ,0 ,'c' }, + {"no-fbc-compression-check" ,0 ,0 ,'o' }, + {"no-fbc-action-check" ,0 ,0 ,'a' }, + {"no-edp" ,0 ,0 ,'e' }, + {"use-small-modes" ,0 ,0 ,'m' }, + {"step" ,0 ,0 ,'t' },tests/kms_frontbuffer_tracking.c line 1725
Quoted 10 lines
tests/kms_frontbuffer_tracking.c new file +10
-0+ { "nop-only", 0, 0, 'n'}, + { "fbc-only", 0, 0, 'f'}, + { "psr-only", 0, 0, 'p'}, + { "1p-only", 0, 0, '1'}, + { "2p-only", 0, 0, '2'}, + { 0, 0, 0, 0 } + }; + +igt_subtest_init_parse_opts (&argc, argv,"" , long_options, help_str, + opt_handler);This needs updating for the latest changes as this function and the option handler now have a user data pointer.
Quoted 107 lines
tests/kms_frontbuffer_tracking.c new file +100
-1+ +igt_fixture +setup_environment (); + +for (t.pipes =0 ; t.pipes <PIPE_COUNT ; t.pipes++) { +for (t.feature =0 ; t.feature <FEATURE_COUNT ; t.feature++) { + t.screen =SCREEN_PRIM ; + t.plane =PLANE_PRI ; +/* Make sure nothing is using this value. */ + t.method =-1 ; + +igt_subtest_f ("%s-rte-%s" , +pipes_str (t.pipes), + feature_str(t.feature)) +rte_subtest (&t); + } + } + + TEST_MODE_ITER_BEGIN(t) + igt_subtest_f("%s-%s-%s-draw-%s-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + igt_draw_get_method_name(t.method), + feature_str(t.feature)) +draw_subtest (&t); + TEST_MODE_ITER_END + + + TEST_MODE_ITER_BEGIN(t) + if (t.plane != PLANE_PRI) + continue; + + if (t.screen == SCREEN_OFFSCREEN) + continue; + + igt_subtest_f("%s-%s-flip-%s-%s", + pipes_str(t.pipes), + screen_str(t.screen), + igt_draw_get_method_name(t.method), + feature_str(t.feature)) +flip_subtest (&t); + TEST_MODE_ITER_END + + TEST_MODE_ITER_BEGIN(t) + if (t.screen == SCREEN_OFFSCREEN) + continue; + if (t.method != IGT_DRAW_BLT) + continue; + if (t.plane == PLANE_PRI) + continue; + + igt_subtest_f("%s-%s-%s-move-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + feature_str(t.feature)) +move_subtest (&t); + +igt_subtest_f ("%s-%s-%s-onoff-%s" , +pipes_str (t.pipes), +screen_str (t.screen), +plane_str (t.plane), + feature_str(t.feature)) +onoff_subtest (&t); + TEST_MODE_ITER_END + + TEST_MODE_ITER_BEGIN(t) + if (t.screen == SCREEN_OFFSCREEN) + continue; + if (t.method != IGT_DRAW_BLT) + continue; + if (t.plane != PLANE_SPR) + continue; + + igt_subtest_f("%s-%s-%s-fullscreen-%s", + pipes_str(t.pipes), + screen_str(t.screen), + plane_str(t.plane), + feature_str(t.feature)) +fullscreen_plane_subtest (&t); +TEST_MODE_ITER_END + +/* +* TODO: ideas for subtests: +* - Add a new pipe configuration where both pipes can share a big +* framebuffer (instead of each pipe having its own FB). This will +* possibly require some wrapping of struct igt_fb to make the +* implementation easier. +* - Add a test that alternates between different writing methods. Don't +* forget to add the proper domain handling. +* - Add a new enum to struct test_mode that allows us to specify the +* BPP/depth configuration. +*/ + + igt_fixture +teardown_environment (); + +igt_exit (); +} --2.1.4
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 5 lines
Paulo Zanoni _______________________________________________ Intel-gfx mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/intel-gfx
PATCH 1/1 tests: add kms_frontbuffer_tracking
From: Paulo Zanoni <[email protected]>
This is a new test that should exercise the frontbuffer tracking feature of the Kernel in a number of different ways. We use different drawing methods, we use the primary, cursor and sprite planes, we can test both on single and dual pipes, also on buffers not associated with any CRTCs, etc.
We currently have assertions for both FBC and PSR, and we also have a "nop" test mode that should disable both FBC and PSR, and can be used for debugging.
This test is also capable of testing both FBC and PSR even if they are disabled by default on the Kernel: the test knows how to change the i915.ko parameters and then set them back after testing.
I am getting a significant number of failures when I run this test, which means we have some work to do on the Kernel.
I also still have a small list of additional subtests that I plan to add to this test, and those tests are documented on the main function.
v2:
- Use igt_debugfs_open() (Thomas).
- Use igt_test_description() (Thomas).
- Don't check drm_open_any_master()'s result (Thomas).
- Use igt_require_f() in some cases (Thomas).
- Standardize some assertions.
- Use the new module param functions.
- Check if FBC is supported by the chipset.
- Add new subtests (multidraw, enum fbs, fbc+psr).
- Make tests a little shorter.
- Reorganize which tests ara ran by default.
- Better comments everywhere.
- Rebase.
--- tests/.gitignore | 1 + tests/Makefile.sources | 1 + tests/kms_frontbuffer_tracking.c | 2224 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 2226 insertions(+) create mode 100644 tests/kms_frontbuffer_tracking.c
tests/.gitignore +1 -0
@@ -134,6 +134,7 @@ kms_flip kms_flip_event_leak kms_flip_tiling kms_force_connector +kms_frontbuffer_tracking kms_legacy_colorkey kms_mmio_vs_cs_flip kms_pipe_b_c_ivb
tests/Makefile.sources +1 -0
@@ -66,6 +66,7 @@ TESTS_progs_M = \ kms_flip \ kms_flip_event_leak \ kms_flip_tiling \ + kms_frontbuffer_tracking \ kms_legacy_colorkey \ kms_mmio_vs_cs_flip \ kms_pipe_b_c_ivb \
tests/kms_frontbuffer_tracking.c new file +2224 -0
2,224 lines not on this page · raw message
Signature · 6 lines
2.1.4 _______________________________________________ Intel-gfx mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/intel-gfx