mirror of
https://github.com/tiagovignatti/intel-gpu-tools.git
synced 2025-06-09 00:46:17 +00:00
lib: Introduce a modeset API
The goals here are: - Reduce duplicated code in each KMS test - Provide an API that looks more like what we want for atomic modesets. The hope is then that it'll be easy to switch, at run-time, between the "legacy" path and atomic modesets, keeping the same API for tests. Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
This commit is contained in:
parent
01757d052c
commit
3670d6dbff
364
lib/igt_kms.c
364
lib/igt_kms.c
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -764,3 +765,366 @@ void kmstest_free_connector_config(struct kmstest_connector_config *config)
|
|||||||
drmModeFreeConnector(config->connector);
|
drmModeFreeConnector(config->connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A small modeset API
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_SPACES " "
|
||||||
|
#define LOG_N_SPACES (sizeof(LOG_SPACES) - 1)
|
||||||
|
|
||||||
|
#define LOG_INDENT(d, section) \
|
||||||
|
do { \
|
||||||
|
igt_display_log(d, "%s {\n", section); \
|
||||||
|
igt_display_log_shift(d, 1); \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_UNINDENT(d) \
|
||||||
|
do { \
|
||||||
|
igt_display_log_shift(d, -1); \
|
||||||
|
igt_display_log(d, "}\n"); \
|
||||||
|
} while (0)
|
||||||
|
#define LOG(d, fmt, ...) igt_display_log(d, fmt, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
static int __attribute__((format(printf, 2, 3)))
|
||||||
|
igt_display_log(igt_display_t *display, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
int n, i;
|
||||||
|
|
||||||
|
if (!display->verbose)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
n = printf("display: ");
|
||||||
|
for (i = 0; i < display->log_shift; i++)
|
||||||
|
n += printf("%s", LOG_SPACES);
|
||||||
|
n += vprintf(fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void igt_display_log_shift(igt_display_t *display, int shift)
|
||||||
|
{
|
||||||
|
display->log_shift += shift;
|
||||||
|
igt_assert(display->log_shift >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void igt_output_refresh(igt_output_t *output)
|
||||||
|
{
|
||||||
|
igt_display_t *display = output->display;
|
||||||
|
int ret;
|
||||||
|
unsigned long crtc_idx_mask;
|
||||||
|
|
||||||
|
/* we mask out the pipes already in use */
|
||||||
|
crtc_idx_mask = output->pending_crtc_idx_mask & ~display->pipes_in_use;
|
||||||
|
|
||||||
|
if (output->valid)
|
||||||
|
kmstest_free_connector_config(&output->config);
|
||||||
|
ret = kmstest_get_connector_config(display->drm_fd,
|
||||||
|
output->id,
|
||||||
|
crtc_idx_mask,
|
||||||
|
&output->config);
|
||||||
|
if (ret == 0)
|
||||||
|
output->valid = true;
|
||||||
|
else
|
||||||
|
output->valid = false;
|
||||||
|
|
||||||
|
if (!output->valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!output->name) {
|
||||||
|
drmModeConnector *c = output->config.connector;
|
||||||
|
|
||||||
|
asprintf(&output->name, "%s-%d",
|
||||||
|
kmstest_connector_type_str(c->connector_type),
|
||||||
|
c->connector_type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(display, "%s: Selecting pipe %c\n", output->name,
|
||||||
|
pipe_name(output->config.pipe));
|
||||||
|
|
||||||
|
display->pipes_in_use |= 1 << output->config.pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
void igt_display_init(igt_display_t *display, int drm_fd)
|
||||||
|
{
|
||||||
|
drmModeRes *resources;
|
||||||
|
bool verbose;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's valid to set verbose before the init so we can get debugging
|
||||||
|
* output for the init() itself.
|
||||||
|
*/
|
||||||
|
verbose = display->verbose;
|
||||||
|
memset(display, 0, sizeof(igt_display_t));
|
||||||
|
display->verbose = verbose;
|
||||||
|
|
||||||
|
LOG_INDENT(display, "init");
|
||||||
|
|
||||||
|
display->drm_fd = drm_fd;
|
||||||
|
|
||||||
|
resources = drmModeGetResources(display->drm_fd);
|
||||||
|
igt_assert(resources);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We cache the number of pipes, that number is a physical limit of the
|
||||||
|
* hardware and cannot change of time (for now, at least).
|
||||||
|
*/
|
||||||
|
display->n_pipes = resources->count_crtcs;
|
||||||
|
|
||||||
|
for (i = 0; i < display->n_pipes; i++) {
|
||||||
|
igt_pipe_t *pipe = &display->pipes[i];
|
||||||
|
igt_plane_t *plane;
|
||||||
|
|
||||||
|
pipe->display = display;
|
||||||
|
pipe->pipe = i;
|
||||||
|
pipe->n_planes = 1;
|
||||||
|
|
||||||
|
/* primary plane */
|
||||||
|
plane = &pipe->planes[0];
|
||||||
|
plane->pipe = pipe;
|
||||||
|
plane->index = 0;
|
||||||
|
plane->is_primary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of connectors is set, so we just initialize the outputs
|
||||||
|
* array in _init(). This may change when we need dynamic connectors
|
||||||
|
* (say DisplayPort MST).
|
||||||
|
*/
|
||||||
|
display->n_outputs = resources->count_connectors;
|
||||||
|
display->outputs = calloc(display->n_outputs, sizeof(igt_output_t));
|
||||||
|
igt_assert(display->outputs);
|
||||||
|
|
||||||
|
for (i = 0; i < display->n_outputs; i++) {
|
||||||
|
igt_output_t *output = &display->outputs[i];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We're free to select any pipe to drive that output until
|
||||||
|
* a constraint is set with igt_output_set_pipe().
|
||||||
|
*/
|
||||||
|
output->pending_crtc_idx_mask = -1UL;
|
||||||
|
output->id = resources->connectors[i];
|
||||||
|
output->display = display;
|
||||||
|
|
||||||
|
igt_output_refresh(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeFreeResources(resources);
|
||||||
|
|
||||||
|
LOG_UNINDENT(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void igt_display_set_verbose(igt_display_t *display, bool verbose)
|
||||||
|
{
|
||||||
|
display->verbose = verbose;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void igt_output_fini(igt_output_t *output)
|
||||||
|
{
|
||||||
|
if (output->valid)
|
||||||
|
kmstest_free_connector_config(&output->config);
|
||||||
|
free(output->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void igt_display_fini(igt_display_t *display)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < display->n_outputs; i++)
|
||||||
|
igt_output_fini(&display->outputs[i]);
|
||||||
|
free(display->outputs);
|
||||||
|
display->outputs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void igt_display_refresh(igt_display_t *display)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
display->pipes_in_use = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The pipe allocation has to be done in two phases:
|
||||||
|
* - first, try to satisfy the outputs where a pipe has been specified
|
||||||
|
* - then, allocate the outputs with PIPE_ANY
|
||||||
|
*/
|
||||||
|
for (i = 0; i < display->n_outputs; i++) {
|
||||||
|
igt_output_t *output = &display->outputs[i];
|
||||||
|
|
||||||
|
if (output->pending_crtc_idx_mask == -1UL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
igt_output_refresh(output);
|
||||||
|
}
|
||||||
|
for (i = 0; i < display->n_outputs; i++) {
|
||||||
|
igt_output_t *output = &display->outputs[i];
|
||||||
|
|
||||||
|
if (output->pending_crtc_idx_mask != -1UL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
igt_output_refresh(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output)
|
||||||
|
{
|
||||||
|
igt_display_t *display = output->display;
|
||||||
|
enum pipe pipe;
|
||||||
|
|
||||||
|
if (output->pending_crtc_idx_mask == -1UL) {
|
||||||
|
/*
|
||||||
|
* The user hasn't specified a pipe to use, take the one
|
||||||
|
* configured by the last refresh()
|
||||||
|
*/
|
||||||
|
pipe = output->config.pipe;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Otherwise, return the pending pipe (ie the pipe that should
|
||||||
|
* drive this output after the commit()
|
||||||
|
*/
|
||||||
|
pipe = ffs(output->pending_crtc_idx_mask) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
igt_assert(pipe >= 0 && pipe < display->n_pipes);
|
||||||
|
|
||||||
|
return &display->pipes[pipe];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t igt_plane_get_fd_id(igt_plane_t *plane)
|
||||||
|
{
|
||||||
|
if (plane->fb)
|
||||||
|
return plane->fb->fb_id;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int igt_output_commit(igt_output_t *output)
|
||||||
|
{
|
||||||
|
igt_display_t *display = output->display;
|
||||||
|
igt_pipe_t *pipe;
|
||||||
|
|
||||||
|
pipe = igt_output_get_driving_pipe(output);
|
||||||
|
if (pipe->need_set_crtc) {
|
||||||
|
igt_plane_t *primary = &pipe->planes[0];
|
||||||
|
drmModeModeInfo *mode;
|
||||||
|
uint32_t fb_id, crtc_id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
crtc_id = output->config.crtc->crtc_id;
|
||||||
|
fb_id = igt_plane_get_fd_id(primary);
|
||||||
|
if (fb_id)
|
||||||
|
mode = igt_output_get_mode(output);
|
||||||
|
else
|
||||||
|
mode = NULL;
|
||||||
|
|
||||||
|
if (fb_id) {
|
||||||
|
LOG(display,
|
||||||
|
"%s: SetCrtc pipe %c, fb %u, panning (%d, %d), "
|
||||||
|
"mode %dx%d\n",
|
||||||
|
igt_output_name(output),
|
||||||
|
pipe_name(output->config.pipe),
|
||||||
|
fb_id,
|
||||||
|
0, 0,
|
||||||
|
mode->hdisplay, mode->vdisplay);
|
||||||
|
|
||||||
|
ret = drmModeSetCrtc(display->drm_fd,
|
||||||
|
crtc_id,
|
||||||
|
fb_id,
|
||||||
|
0, 0, /* x, y */
|
||||||
|
&output->id,
|
||||||
|
1,
|
||||||
|
mode);
|
||||||
|
} else {
|
||||||
|
LOG(display,
|
||||||
|
"%s: SetCrtc pipe %c, fb %u\n",
|
||||||
|
igt_output_name(output),
|
||||||
|
pipe_name(output->config.pipe),
|
||||||
|
fb_id);
|
||||||
|
|
||||||
|
ret = drmModeSetCrtc(display->drm_fd,
|
||||||
|
crtc_id,
|
||||||
|
fb_id,
|
||||||
|
0, 0, /* x, y */
|
||||||
|
NULL, /* connectors */
|
||||||
|
0, /* n_connectors */
|
||||||
|
NULL /* mode */);
|
||||||
|
}
|
||||||
|
|
||||||
|
igt_assert(ret == 0);
|
||||||
|
|
||||||
|
pipe->need_set_crtc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int igt_display_commit(igt_display_t *display)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
LOG_INDENT(display, "commit");
|
||||||
|
|
||||||
|
igt_display_refresh(display);
|
||||||
|
|
||||||
|
for (i = 0; i < display->n_outputs; i++) {
|
||||||
|
igt_output_t *output = &display->outputs[i];
|
||||||
|
|
||||||
|
if (!output->valid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
igt_output_commit(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_UNINDENT(display);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *igt_output_name(igt_output_t *output)
|
||||||
|
{
|
||||||
|
return output->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
drmModeModeInfo *igt_output_get_mode(igt_output_t *output)
|
||||||
|
{
|
||||||
|
return &output->config.default_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
|
||||||
|
{
|
||||||
|
igt_display_t *display = output->display;
|
||||||
|
|
||||||
|
LOG(display, "%s: set_pipe(%c)\n", igt_output_name(output),
|
||||||
|
pipe_name(pipe));
|
||||||
|
|
||||||
|
output->pending_crtc_idx_mask = 1 << pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, int index)
|
||||||
|
{
|
||||||
|
igt_assert(index >= 0 && index < pipe->n_planes);
|
||||||
|
return &pipe->planes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
igt_plane_t *igt_ouput_get_plane(igt_output_t *output, int index)
|
||||||
|
{
|
||||||
|
igt_pipe_t *pipe;
|
||||||
|
|
||||||
|
pipe = igt_output_get_driving_pipe(output);
|
||||||
|
return igt_pipe_get_plane(pipe, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void igt_plane_set_fb(igt_plane_t *plane, struct kmstest_fb *fb)
|
||||||
|
{
|
||||||
|
igt_pipe_t *pipe = plane->pipe;
|
||||||
|
igt_display_t *display = pipe->display;
|
||||||
|
|
||||||
|
LOG(display, "%c.%d: plane_set_fb(%p)\n", pipe_name(pipe->pipe),
|
||||||
|
plane->index, fb);
|
||||||
|
|
||||||
|
plane->fb = fb;
|
||||||
|
|
||||||
|
if (plane->is_primary)
|
||||||
|
pipe->need_set_crtc = true;
|
||||||
|
}
|
||||||
|
@ -25,8 +25,12 @@
|
|||||||
#ifndef __IGT_KMS_H__
|
#ifndef __IGT_KMS_H__
|
||||||
#define __IGT_KMS_H__
|
#define __IGT_KMS_H__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
|
||||||
|
#include <igt_display.h>
|
||||||
|
|
||||||
struct kmstest_connector_config {
|
struct kmstest_connector_config {
|
||||||
drmModeCrtc *crtc;
|
drmModeCrtc *crtc;
|
||||||
drmModeConnector *connector;
|
drmModeConnector *connector;
|
||||||
@ -99,5 +103,60 @@ const char *kmstest_connector_type_str(int type);
|
|||||||
|
|
||||||
uint32_t drm_format_to_bpp(uint32_t drm_format);
|
uint32_t drm_format_to_bpp(uint32_t drm_format);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A small modeset API
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct igt_display igt_display_t;
|
||||||
|
typedef struct igt_pipe igt_pipe_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
igt_pipe_t *pipe;
|
||||||
|
int index;
|
||||||
|
unsigned int is_primary : 1;
|
||||||
|
struct kmstest_fb *fb;
|
||||||
|
} igt_plane_t;
|
||||||
|
|
||||||
|
struct igt_pipe {
|
||||||
|
igt_display_t *display;
|
||||||
|
enum pipe pipe;
|
||||||
|
unsigned int need_set_crtc : 1;
|
||||||
|
#define IGT_MAX_PLANES 4
|
||||||
|
int n_planes;
|
||||||
|
igt_plane_t planes[IGT_MAX_PLANES];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
igt_display_t *display;
|
||||||
|
uint32_t id; /* KMS id */
|
||||||
|
struct kmstest_connector_config config;
|
||||||
|
char *name;
|
||||||
|
bool valid;
|
||||||
|
unsigned long pending_crtc_idx_mask;
|
||||||
|
} igt_output_t;
|
||||||
|
|
||||||
|
struct igt_display {
|
||||||
|
int drm_fd;
|
||||||
|
unsigned int verbose : 1;
|
||||||
|
int log_shift;
|
||||||
|
int n_pipes;
|
||||||
|
int n_outputs;
|
||||||
|
unsigned long pipes_in_use;
|
||||||
|
igt_output_t *outputs;
|
||||||
|
igt_pipe_t pipes[I915_MAX_PIPES];
|
||||||
|
};
|
||||||
|
|
||||||
|
void igt_display_init(igt_display_t *display, int drm_fd);
|
||||||
|
void igt_display_fini(igt_display_t *display);
|
||||||
|
int igt_display_commit(igt_display_t *display);
|
||||||
|
void igt_display_set_verbose(igt_display_t *display, bool verbose);
|
||||||
|
|
||||||
|
const char *igt_output_name(igt_output_t *output);
|
||||||
|
drmModeModeInfo *igt_output_get_mode(igt_output_t *output);
|
||||||
|
void igt_output_set_pipe(igt_output_t *output, enum pipe pipe);
|
||||||
|
igt_plane_t *igt_ouput_get_plane(igt_output_t *output, int index);
|
||||||
|
|
||||||
|
void igt_plane_set_fb(igt_plane_t *plane, struct kmstest_fb *fb);
|
||||||
|
|
||||||
#endif /* __IGT_KMS_H__ */
|
#endif /* __IGT_KMS_H__ */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user