Blame tests/modetest/modetest.c

Packit 631bab
/*
Packit 631bab
 * DRM based mode setting test program
Packit 631bab
 * Copyright 2008 Tungsten Graphics
Packit 631bab
 *   Jakob Bornecrantz <jakob@tungstengraphics.com>
Packit 631bab
 * Copyright 2008 Intel Corporation
Packit 631bab
 *   Jesse Barnes <jesse.barnes@intel.com>
Packit 631bab
 *
Packit 631bab
 * Permission is hereby granted, free of charge, to any person obtaining a
Packit 631bab
 * copy of this software and associated documentation files (the "Software"),
Packit 631bab
 * to deal in the Software without restriction, including without limitation
Packit 631bab
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
Packit 631bab
 * and/or sell copies of the Software, and to permit persons to whom the
Packit 631bab
 * Software is furnished to do so, subject to the following conditions:
Packit 631bab
 *
Packit 631bab
 * The above copyright notice and this permission notice shall be included in
Packit 631bab
 * all copies or substantial portions of the Software.
Packit 631bab
 *
Packit 631bab
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit 631bab
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit 631bab
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit 631bab
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit 631bab
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit 631bab
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit 631bab
 * IN THE SOFTWARE.
Packit 631bab
 */
Packit 631bab
Packit 631bab
/*
Packit 631bab
 * This fairly simple test program dumps output in a similar format to the
Packit 631bab
 * "xrandr" tool everyone knows & loves.  It's necessarily slightly different
Packit 631bab
 * since the kernel separates outputs into encoder and connector structures,
Packit 631bab
 * each with their own unique ID.  The program also allows test testing of the
Packit 631bab
 * memory management and mode setting APIs by allowing the user to specify a
Packit 631bab
 * connector and mode to use for mode setting.  If all works as expected, a
Packit 631bab
 * blue background should be painted on the monitor attached to the specified
Packit 631bab
 * connector after the selected mode is set.
Packit 631bab
 *
Packit 631bab
 * TODO: use cairo to write the mode info on the selected output once
Packit 631bab
 *       the mode has been programmed, along with possible test patterns.
Packit 631bab
 */
Packit 631bab
Packit 631bab
#include <assert.h>
Packit 631bab
#include <ctype.h>
Packit 631bab
#include <stdbool.h>
Packit 631bab
#include <stdio.h>
Packit 631bab
#include <stdlib.h>
Packit 631bab
#include <stdint.h>
Packit 631bab
#include <inttypes.h>
Packit 631bab
#include <unistd.h>
Packit 631bab
#include <string.h>
Packit 631bab
#include <strings.h>
Packit 631bab
#include <errno.h>
Packit 631bab
#include <poll.h>
Packit 631bab
#include <sys/time.h>
Packit 631bab
#ifdef HAVE_SYS_SELECT_H
Packit 631bab
#include <sys/select.h>
Packit 631bab
#endif
Packit 631bab
Packit 631bab
#include "xf86drm.h"
Packit 631bab
#include "xf86drmMode.h"
Packit 631bab
#include "drm_fourcc.h"
Packit 631bab
Packit 631bab
#include "util/common.h"
Packit 631bab
#include "util/format.h"
Packit 631bab
#include "util/kms.h"
Packit 631bab
#include "util/pattern.h"
Packit 631bab
Packit 631bab
#include "buffers.h"
Packit 631bab
#include "cursor.h"
Packit 631bab
Packit 631bab
static enum util_fill_pattern primary_fill = UTIL_PATTERN_SMPTE;
Packit 631bab
static enum util_fill_pattern secondary_fill = UTIL_PATTERN_TILES;
Packit 631bab
Packit 631bab
struct crtc {
Packit 631bab
	drmModeCrtc *crtc;
Packit 631bab
	drmModeObjectProperties *props;
Packit 631bab
	drmModePropertyRes **props_info;
Packit 631bab
	drmModeModeInfo *mode;
Packit 631bab
};
Packit 631bab
Packit 631bab
struct encoder {
Packit 631bab
	drmModeEncoder *encoder;
Packit 631bab
};
Packit 631bab
Packit 631bab
struct connector {
Packit 631bab
	drmModeConnector *connector;
Packit 631bab
	drmModeObjectProperties *props;
Packit 631bab
	drmModePropertyRes **props_info;
Packit 631bab
	char *name;
Packit 631bab
};
Packit 631bab
Packit 631bab
struct fb {
Packit 631bab
	drmModeFB *fb;
Packit 631bab
};
Packit 631bab
Packit 631bab
struct plane {
Packit 631bab
	drmModePlane *plane;
Packit 631bab
	drmModeObjectProperties *props;
Packit 631bab
	drmModePropertyRes **props_info;
Packit 631bab
};
Packit 631bab
Packit 631bab
struct resources {
Packit 631bab
	drmModeRes *res;
Packit 631bab
	drmModePlaneRes *plane_res;
Packit 631bab
Packit 631bab
	struct crtc *crtcs;
Packit 631bab
	struct encoder *encoders;
Packit 631bab
	struct connector *connectors;
Packit 631bab
	struct fb *fbs;
Packit 631bab
	struct plane *planes;
Packit 631bab
};
Packit 631bab
Packit 631bab
struct device {
Packit 631bab
	int fd;
Packit 631bab
Packit 631bab
	struct resources *resources;
Packit 631bab
Packit 631bab
	struct {
Packit 631bab
		unsigned int width;
Packit 631bab
		unsigned int height;
Packit 631bab
Packit 631bab
		unsigned int fb_id;
Packit 631bab
		struct bo *bo;
Packit 631bab
		struct bo *cursor_bo;
Packit 631bab
	} mode;
Packit 631bab
Packit 631bab
	int use_atomic;
Packit 631bab
	drmModeAtomicReq *req;
Packit 631bab
};
Packit 631bab
Packit 631bab
static inline int64_t U642I64(uint64_t val)
Packit 631bab
{
Packit 631bab
	return (int64_t)*((int64_t *)&val;;
Packit 631bab
}
Packit 631bab
Packit 631bab
#define bit_name_fn(res)					\
Packit 631bab
const char * res##_str(int type) {				\
Packit 631bab
	unsigned int i;						\
Packit 631bab
	const char *sep = "";					\
Packit 631bab
	for (i = 0; i < ARRAY_SIZE(res##_names); i++) {		\
Packit 631bab
		if (type & (1 << i)) {				\
Packit 631bab
			printf("%s%s", sep, res##_names[i]);	\
Packit 631bab
			sep = ", ";				\
Packit 631bab
		}						\
Packit 631bab
	}							\
Packit 631bab
	return NULL;						\
Packit 631bab
}
Packit 631bab
Packit 631bab
static const char *mode_type_names[] = {
Packit 631bab
	"builtin",
Packit 631bab
	"clock_c",
Packit 631bab
	"crtc_c",
Packit 631bab
	"preferred",
Packit 631bab
	"default",
Packit 631bab
	"userdef",
Packit 631bab
	"driver",
Packit 631bab
};
Packit 631bab
Packit 631bab
static bit_name_fn(mode_type)
Packit 631bab
Packit 631bab
static const char *mode_flag_names[] = {
Packit 631bab
	"phsync",
Packit 631bab
	"nhsync",
Packit 631bab
	"pvsync",
Packit 631bab
	"nvsync",
Packit 631bab
	"interlace",
Packit 631bab
	"dblscan",
Packit 631bab
	"csync",
Packit 631bab
	"pcsync",
Packit 631bab
	"ncsync",
Packit 631bab
	"hskew",
Packit 631bab
	"bcast",
Packit 631bab
	"pixmux",
Packit 631bab
	"dblclk",
Packit 631bab
	"clkdiv2"
Packit 631bab
};
Packit 631bab
Packit 631bab
static bit_name_fn(mode_flag)
Packit 631bab
Packit 631bab
static void dump_fourcc(uint32_t fourcc)
Packit 631bab
{
Packit 631bab
	printf(" %c%c%c%c",
Packit 631bab
		fourcc,
Packit 631bab
		fourcc >> 8,
Packit 631bab
		fourcc >> 16,
Packit 631bab
		fourcc >> 24);
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_encoders(struct device *dev)
Packit 631bab
{
Packit 631bab
	drmModeEncoder *encoder;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	printf("Encoders:\n");
Packit 631bab
	printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
Packit 631bab
	for (i = 0; i < dev->resources->res->count_encoders; i++) {
Packit 631bab
		encoder = dev->resources->encoders[i].encoder;
Packit 631bab
		if (!encoder)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
Packit 631bab
		       encoder->encoder_id,
Packit 631bab
		       encoder->crtc_id,
Packit 631bab
		       util_lookup_encoder_type_name(encoder->encoder_type),
Packit 631bab
		       encoder->possible_crtcs,
Packit 631bab
		       encoder->possible_clones);
Packit 631bab
	}
Packit 631bab
	printf("\n");
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_mode(drmModeModeInfo *mode)
Packit 631bab
{
Packit 631bab
	printf("  %s %d %d %d %d %d %d %d %d %d %d",
Packit 631bab
	       mode->name,
Packit 631bab
	       mode->vrefresh,
Packit 631bab
	       mode->hdisplay,
Packit 631bab
	       mode->hsync_start,
Packit 631bab
	       mode->hsync_end,
Packit 631bab
	       mode->htotal,
Packit 631bab
	       mode->vdisplay,
Packit 631bab
	       mode->vsync_start,
Packit 631bab
	       mode->vsync_end,
Packit 631bab
	       mode->vtotal,
Packit 631bab
	       mode->clock);
Packit 631bab
Packit 631bab
	printf(" flags: ");
Packit 631bab
	mode_flag_str(mode->flags);
Packit 631bab
	printf("; type: ");
Packit 631bab
	mode_type_str(mode->type);
Packit 631bab
	printf("\n");
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_blob(struct device *dev, uint32_t blob_id)
Packit 631bab
{
Packit 631bab
	uint32_t i;
Packit 631bab
	unsigned char *blob_data;
Packit 631bab
	drmModePropertyBlobPtr blob;
Packit 631bab
Packit 631bab
	blob = drmModeGetPropertyBlob(dev->fd, blob_id);
Packit 631bab
	if (!blob) {
Packit 631bab
		printf("\n");
Packit 631bab
		return;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	blob_data = blob->data;
Packit 631bab
Packit 631bab
	for (i = 0; i < blob->length; i++) {
Packit 631bab
		if (i % 16 == 0)
Packit 631bab
			printf("\n\t\t\t");
Packit 631bab
		printf("%.2hhx", blob_data[i]);
Packit 631bab
	}
Packit 631bab
	printf("\n");
Packit 631bab
Packit 631bab
	drmModeFreePropertyBlob(blob);
Packit 631bab
}
Packit 631bab
Packit 631bab
static const char *modifier_to_string(uint64_t modifier)
Packit 631bab
{
Packit 631bab
	switch (modifier) {
Packit 631bab
	case DRM_FORMAT_MOD_INVALID:
Packit 631bab
		return "INVALID";
Packit 631bab
	case DRM_FORMAT_MOD_LINEAR:
Packit 631bab
		return "LINEAR";
Packit 631bab
	case I915_FORMAT_MOD_X_TILED:
Packit 631bab
		return "X_TILED";
Packit 631bab
	case I915_FORMAT_MOD_Y_TILED:
Packit 631bab
		return "Y_TILED";
Packit 631bab
	case I915_FORMAT_MOD_Yf_TILED:
Packit 631bab
		return "Yf_TILED";
Packit 631bab
	case I915_FORMAT_MOD_Y_TILED_CCS:
Packit 631bab
		return "Y_TILED_CCS";
Packit 631bab
	case I915_FORMAT_MOD_Yf_TILED_CCS:
Packit 631bab
		return "Yf_TILED_CCS";
Packit 631bab
	case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
Packit 631bab
		return "SAMSUNG_64_32_TILE";
Packit 631bab
	case DRM_FORMAT_MOD_VIVANTE_TILED:
Packit 631bab
		return "VIVANTE_TILED";
Packit 631bab
	case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
Packit 631bab
		return "VIVANTE_SUPER_TILED";
Packit 631bab
	case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
Packit 631bab
		return "VIVANTE_SPLIT_TILED";
Packit 631bab
	case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
Packit 631bab
		return "VIVANTE_SPLIT_SUPER_TILED";
Packit 631bab
	case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
Packit 631bab
		return "NVIDIA_TEGRA_TILED";
Packit 631bab
	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0):
Packit 631bab
		return "NVIDIA_16BX2_BLOCK(0)";
Packit 631bab
	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1):
Packit 631bab
		return "NVIDIA_16BX2_BLOCK(1)";
Packit 631bab
	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2):
Packit 631bab
		return "NVIDIA_16BX2_BLOCK(2)";
Packit 631bab
	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3):
Packit 631bab
		return "NVIDIA_16BX2_BLOCK(3)";
Packit 631bab
	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4):
Packit 631bab
		return "NVIDIA_16BX2_BLOCK(4)";
Packit 631bab
	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5):
Packit 631bab
		return "NVIDIA_16BX2_BLOCK(5)";
Packit 631bab
	case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
Packit 631bab
		return "MOD_BROADCOM_VC4_T_TILED";
Packit 631bab
	case DRM_FORMAT_MOD_QCOM_COMPRESSED:
Packit 631bab
		return "QCOM_COMPRESSED";
Packit 631bab
	default:
Packit 631bab
		return "(UNKNOWN MODIFIER)";
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_in_formats(struct device *dev, uint32_t blob_id)
Packit 631bab
{
Packit 631bab
	uint32_t i, j;
Packit 631bab
	drmModePropertyBlobPtr blob;
Packit 631bab
	struct drm_format_modifier_blob *header;
Packit 631bab
	uint32_t *formats;
Packit 631bab
	struct drm_format_modifier *modifiers;
Packit 631bab
Packit 631bab
	printf("\t\tin_formats blob decoded:\n");
Packit 631bab
	blob = drmModeGetPropertyBlob(dev->fd, blob_id);
Packit 631bab
	if (!blob) {
Packit 631bab
		printf("\n");
Packit 631bab
		return;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	header = blob->data;
Packit 631bab
	formats = (uint32_t *) ((char *) header + header->formats_offset);
Packit 631bab
	modifiers = (struct drm_format_modifier *)
Packit 631bab
		((char *) header + header->modifiers_offset);
Packit 631bab
Packit 631bab
	for (i = 0; i < header->count_formats; i++) {
Packit 631bab
		printf("\t\t\t");
Packit 631bab
		dump_fourcc(formats[i]);
Packit 631bab
		printf(": ");
Packit 631bab
		for (j = 0; j < header->count_modifiers; j++) {
Packit 631bab
			uint64_t mask = 1ULL << i;
Packit 631bab
			if (modifiers[j].formats & mask)
Packit 631bab
				printf(" %s", modifier_to_string(modifiers[j].modifier));
Packit 631bab
		}
Packit 631bab
		printf("\n");
Packit 631bab
	}
Packit 631bab
Packit 631bab
	drmModeFreePropertyBlob(blob);
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_prop(struct device *dev, drmModePropertyPtr prop,
Packit 631bab
		      uint32_t prop_id, uint64_t value)
Packit 631bab
{
Packit 631bab
	int i;
Packit 631bab
	printf("\t%d", prop_id);
Packit 631bab
	if (!prop) {
Packit 631bab
		printf("\n");
Packit 631bab
		return;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	printf(" %s:\n", prop->name);
Packit 631bab
Packit 631bab
	printf("\t\tflags:");
Packit 631bab
	if (prop->flags & DRM_MODE_PROP_PENDING)
Packit 631bab
		printf(" pending");
Packit 631bab
	if (prop->flags & DRM_MODE_PROP_IMMUTABLE)
Packit 631bab
		printf(" immutable");
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
Packit 631bab
		printf(" signed range");
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE))
Packit 631bab
		printf(" range");
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM))
Packit 631bab
		printf(" enum");
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK))
Packit 631bab
		printf(" bitmask");
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
Packit 631bab
		printf(" blob");
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT))
Packit 631bab
		printf(" object");
Packit 631bab
	printf("\n");
Packit 631bab
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) {
Packit 631bab
		printf("\t\tvalues:");
Packit 631bab
		for (i = 0; i < prop->count_values; i++)
Packit 631bab
			printf(" %"PRId64, U642I64(prop->values[i]));
Packit 631bab
		printf("\n");
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) {
Packit 631bab
		printf("\t\tvalues:");
Packit 631bab
		for (i = 0; i < prop->count_values; i++)
Packit 631bab
			printf(" %"PRIu64, prop->values[i]);
Packit 631bab
		printf("\n");
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) {
Packit 631bab
		printf("\t\tenums:");
Packit 631bab
		for (i = 0; i < prop->count_enums; i++)
Packit 631bab
			printf(" %s=%llu", prop->enums[i].name,
Packit 631bab
			       prop->enums[i].value);
Packit 631bab
		printf("\n");
Packit 631bab
	} else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
Packit 631bab
		printf("\t\tvalues:");
Packit 631bab
		for (i = 0; i < prop->count_enums; i++)
Packit 631bab
			printf(" %s=0x%llx", prop->enums[i].name,
Packit 631bab
			       (1LL << prop->enums[i].value));
Packit 631bab
		printf("\n");
Packit 631bab
	} else {
Packit 631bab
		assert(prop->count_enums == 0);
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) {
Packit 631bab
		printf("\t\tblobs:\n");
Packit 631bab
		for (i = 0; i < prop->count_blobs; i++)
Packit 631bab
			dump_blob(dev, prop->blob_ids[i]);
Packit 631bab
		printf("\n");
Packit 631bab
	} else {
Packit 631bab
		assert(prop->count_blobs == 0);
Packit 631bab
	}
Packit 631bab
Packit 631bab
	printf("\t\tvalue:");
Packit 631bab
	if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB))
Packit 631bab
		dump_blob(dev, value);
Packit 631bab
	else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE))
Packit 631bab
		printf(" %"PRId64"\n", value);
Packit 631bab
	else
Packit 631bab
		printf(" %"PRIu64"\n", value);
Packit 631bab
Packit 631bab
	if (strcmp(prop->name, "IN_FORMATS") == 0)
Packit 631bab
		dump_in_formats(dev, value);
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_connectors(struct device *dev)
Packit 631bab
{
Packit 631bab
	int i, j;
Packit 631bab
Packit 631bab
	printf("Connectors:\n");
Packit 631bab
	printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n");
Packit 631bab
	for (i = 0; i < dev->resources->res->count_connectors; i++) {
Packit 631bab
		struct connector *_connector = &dev->resources->connectors[i];
Packit 631bab
		drmModeConnector *connector = _connector->connector;
Packit 631bab
		if (!connector)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t",
Packit 631bab
		       connector->connector_id,
Packit 631bab
		       connector->encoder_id,
Packit 631bab
		       util_lookup_connector_status_name(connector->connection),
Packit 631bab
		       _connector->name,
Packit 631bab
		       connector->mmWidth, connector->mmHeight,
Packit 631bab
		       connector->count_modes);
Packit 631bab
Packit 631bab
		for (j = 0; j < connector->count_encoders; j++)
Packit 631bab
			printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]);
Packit 631bab
		printf("\n");
Packit 631bab
Packit 631bab
		if (connector->count_modes) {
Packit 631bab
			printf("  modes:\n");
Packit 631bab
			printf("\tname refresh (Hz) hdisp hss hse htot vdisp "
Packit 631bab
			       "vss vse vtot)\n");
Packit 631bab
			for (j = 0; j < connector->count_modes; j++)
Packit 631bab
				dump_mode(&connector->modes[j]);
Packit 631bab
		}
Packit 631bab
Packit 631bab
		if (_connector->props) {
Packit 631bab
			printf("  props:\n");
Packit 631bab
			for (j = 0; j < (int)_connector->props->count_props; j++)
Packit 631bab
				dump_prop(dev, _connector->props_info[j],
Packit 631bab
					  _connector->props->props[j],
Packit 631bab
					  _connector->props->prop_values[j]);
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
	printf("\n");
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_crtcs(struct device *dev)
Packit 631bab
{
Packit 631bab
	int i;
Packit 631bab
	uint32_t j;
Packit 631bab
Packit 631bab
	printf("CRTCs:\n");
Packit 631bab
	printf("id\tfb\tpos\tsize\n");
Packit 631bab
	for (i = 0; i < dev->resources->res->count_crtcs; i++) {
Packit 631bab
		struct crtc *_crtc = &dev->resources->crtcs[i];
Packit 631bab
		drmModeCrtc *crtc = _crtc->crtc;
Packit 631bab
		if (!crtc)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
Packit 631bab
		       crtc->crtc_id,
Packit 631bab
		       crtc->buffer_id,
Packit 631bab
		       crtc->x, crtc->y,
Packit 631bab
		       crtc->width, crtc->height);
Packit 631bab
		dump_mode(&crtc->mode);
Packit 631bab
Packit 631bab
		if (_crtc->props) {
Packit 631bab
			printf("  props:\n");
Packit 631bab
			for (j = 0; j < _crtc->props->count_props; j++)
Packit 631bab
				dump_prop(dev, _crtc->props_info[j],
Packit 631bab
					  _crtc->props->props[j],
Packit 631bab
					  _crtc->props->prop_values[j]);
Packit 631bab
		} else {
Packit 631bab
			printf("  no properties found\n");
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
	printf("\n");
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_framebuffers(struct device *dev)
Packit 631bab
{
Packit 631bab
	drmModeFB *fb;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	printf("Frame buffers:\n");
Packit 631bab
	printf("id\tsize\tpitch\n");
Packit 631bab
	for (i = 0; i < dev->resources->res->count_fbs; i++) {
Packit 631bab
		fb = dev->resources->fbs[i].fb;
Packit 631bab
		if (!fb)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		printf("%u\t(%ux%u)\t%u\n",
Packit 631bab
		       fb->fb_id,
Packit 631bab
		       fb->width, fb->height,
Packit 631bab
		       fb->pitch);
Packit 631bab
	}
Packit 631bab
	printf("\n");
Packit 631bab
}
Packit 631bab
Packit 631bab
static void dump_planes(struct device *dev)
Packit 631bab
{
Packit 631bab
	unsigned int i, j;
Packit 631bab
Packit 631bab
	printf("Planes:\n");
Packit 631bab
	printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
Packit 631bab
Packit 631bab
	if (!dev->resources->plane_res)
Packit 631bab
		return;
Packit 631bab
Packit 631bab
	for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
Packit 631bab
		struct plane *plane = &dev->resources->planes[i];
Packit 631bab
		drmModePlane *ovr = plane->plane;
Packit 631bab
		if (!ovr)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n",
Packit 631bab
		       ovr->plane_id, ovr->crtc_id, ovr->fb_id,
Packit 631bab
		       ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
Packit 631bab
		       ovr->gamma_size, ovr->possible_crtcs);
Packit 631bab
Packit 631bab
		if (!ovr->count_formats)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		printf("  formats:");
Packit 631bab
		for (j = 0; j < ovr->count_formats; j++)
Packit 631bab
			dump_fourcc(ovr->formats[j]);
Packit 631bab
		printf("\n");
Packit 631bab
Packit 631bab
		if (plane->props) {
Packit 631bab
			printf("  props:\n");
Packit 631bab
			for (j = 0; j < plane->props->count_props; j++)
Packit 631bab
				dump_prop(dev, plane->props_info[j],
Packit 631bab
					  plane->props->props[j],
Packit 631bab
					  plane->props->prop_values[j]);
Packit 631bab
		} else {
Packit 631bab
			printf("  no properties found\n");
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
	printf("\n");
Packit 631bab
Packit 631bab
	return;
Packit 631bab
}
Packit 631bab
Packit 631bab
static void free_resources(struct resources *res)
Packit 631bab
{
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	if (!res)
Packit 631bab
		return;
Packit 631bab
Packit 631bab
#define free_resource(_res, __res, type, Type)					\
Packit 631bab
	do {									\
Packit 631bab
		if (!(_res)->type##s)						\
Packit 631bab
			break;							\
Packit 631bab
		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
Packit 631bab
			if (!(_res)->type##s[i].type)				\
Packit 631bab
				break;						\
Packit 631bab
			drmModeFree##Type((_res)->type##s[i].type);		\
Packit 631bab
		}								\
Packit 631bab
		free((_res)->type##s);						\
Packit 631bab
	} while (0)
Packit 631bab
Packit 631bab
#define free_properties(_res, __res, type)					\
Packit 631bab
	do {									\
Packit 631bab
		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
Packit 631bab
			drmModeFreeObjectProperties(res->type##s[i].props);	\
Packit 631bab
			free(res->type##s[i].props_info);			\
Packit 631bab
		}								\
Packit 631bab
	} while (0)
Packit 631bab
Packit 631bab
	if (res->res) {
Packit 631bab
		free_properties(res, res, crtc);
Packit 631bab
Packit 631bab
		free_resource(res, res, crtc, Crtc);
Packit 631bab
		free_resource(res, res, encoder, Encoder);
Packit 631bab
Packit 631bab
		for (i = 0; i < res->res->count_connectors; i++)
Packit 631bab
			free(res->connectors[i].name);
Packit 631bab
Packit 631bab
		free_resource(res, res, connector, Connector);
Packit 631bab
		free_resource(res, res, fb, FB);
Packit 631bab
Packit 631bab
		drmModeFreeResources(res->res);
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (res->plane_res) {
Packit 631bab
		free_properties(res, plane_res, plane);
Packit 631bab
Packit 631bab
		free_resource(res, plane_res, plane, Plane);
Packit 631bab
Packit 631bab
		drmModeFreePlaneResources(res->plane_res);
Packit 631bab
	}
Packit 631bab
Packit 631bab
	free(res);
Packit 631bab
}
Packit 631bab
Packit 631bab
static struct resources *get_resources(struct device *dev)
Packit 631bab
{
Packit 631bab
	struct resources *res;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	res = calloc(1, sizeof(*res));
Packit 631bab
	if (res == 0)
Packit 631bab
		return NULL;
Packit 631bab
Packit 631bab
	drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
Packit 631bab
Packit 631bab
	res->res = drmModeGetResources(dev->fd);
Packit 631bab
	if (!res->res) {
Packit 631bab
		fprintf(stderr, "drmModeGetResources failed: %s\n",
Packit 631bab
			strerror(errno));
Packit 631bab
		goto error;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	res->crtcs = calloc(res->res->count_crtcs, sizeof(*res->crtcs));
Packit 631bab
	res->encoders = calloc(res->res->count_encoders, sizeof(*res->encoders));
Packit 631bab
	res->connectors = calloc(res->res->count_connectors, sizeof(*res->connectors));
Packit 631bab
	res->fbs = calloc(res->res->count_fbs, sizeof(*res->fbs));
Packit 631bab
Packit 631bab
	if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs)
Packit 631bab
		goto error;
Packit 631bab
Packit 631bab
#define get_resource(_res, __res, type, Type)					\
Packit 631bab
	do {									\
Packit 631bab
		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
Packit 631bab
			(_res)->type##s[i].type =				\
Packit 631bab
				drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \
Packit 631bab
			if (!(_res)->type##s[i].type)				\
Packit 631bab
				fprintf(stderr, "could not get %s %i: %s\n",	\
Packit 631bab
					#type, (_res)->__res->type##s[i],	\
Packit 631bab
					strerror(errno));			\
Packit 631bab
		}								\
Packit 631bab
	} while (0)
Packit 631bab
Packit 631bab
	get_resource(res, res, crtc, Crtc);
Packit 631bab
	get_resource(res, res, encoder, Encoder);
Packit 631bab
	get_resource(res, res, connector, Connector);
Packit 631bab
	get_resource(res, res, fb, FB);
Packit 631bab
Packit 631bab
	/* Set the name of all connectors based on the type name and the per-type ID. */
Packit 631bab
	for (i = 0; i < res->res->count_connectors; i++) {
Packit 631bab
		struct connector *connector = &res->connectors[i];
Packit 631bab
		drmModeConnector *conn = connector->connector;
Packit 631bab
		int num;
Packit 631bab
Packit 631bab
		num = asprintf(&connector->name, "%s-%u",
Packit 631bab
			 util_lookup_connector_type_name(conn->connector_type),
Packit 631bab
			 conn->connector_type_id);
Packit 631bab
		if (num < 0)
Packit 631bab
			goto error;
Packit 631bab
	}
Packit 631bab
Packit 631bab
#define get_properties(_res, __res, type, Type)					\
Packit 631bab
	do {									\
Packit 631bab
		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
Packit 631bab
			struct type *obj = &res->type##s[i];			\
Packit 631bab
			unsigned int j;						\
Packit 631bab
			obj->props =						\
Packit 631bab
				drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \
Packit 631bab
							   DRM_MODE_OBJECT_##Type); \
Packit 631bab
			if (!obj->props) {					\
Packit 631bab
				fprintf(stderr,					\
Packit 631bab
					"could not get %s %i properties: %s\n", \
Packit 631bab
					#type, obj->type->type##_id,		\
Packit 631bab
					strerror(errno));			\
Packit 631bab
				continue;					\
Packit 631bab
			}							\
Packit 631bab
			obj->props_info = calloc(obj->props->count_props,	\
Packit 631bab
						 sizeof(*obj->props_info));	\
Packit 631bab
			if (!obj->props_info)					\
Packit 631bab
				continue;					\
Packit 631bab
			for (j = 0; j < obj->props->count_props; ++j)		\
Packit 631bab
				obj->props_info[j] =				\
Packit 631bab
					drmModeGetProperty(dev->fd, obj->props->props[j]); \
Packit 631bab
		}								\
Packit 631bab
	} while (0)
Packit 631bab
Packit 631bab
	get_properties(res, res, crtc, CRTC);
Packit 631bab
	get_properties(res, res, connector, CONNECTOR);
Packit 631bab
Packit 631bab
	for (i = 0; i < res->res->count_crtcs; ++i)
Packit 631bab
		res->crtcs[i].mode = &res->crtcs[i].crtc->mode;
Packit 631bab
Packit 631bab
	res->plane_res = drmModeGetPlaneResources(dev->fd);
Packit 631bab
	if (!res->plane_res) {
Packit 631bab
		fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
Packit 631bab
			strerror(errno));
Packit 631bab
		return res;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	res->planes = calloc(res->plane_res->count_planes, sizeof(*res->planes));
Packit 631bab
	if (!res->planes)
Packit 631bab
		goto error;
Packit 631bab
Packit 631bab
	get_resource(res, plane_res, plane, Plane);
Packit 631bab
	get_properties(res, plane_res, plane, PLANE);
Packit 631bab
Packit 631bab
	return res;
Packit 631bab
Packit 631bab
error:
Packit 631bab
	free_resources(res);
Packit 631bab
	return NULL;
Packit 631bab
}
Packit 631bab
Packit 631bab
static int get_crtc_index(struct device *dev, uint32_t id)
Packit 631bab
{
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	for (i = 0; i < dev->resources->res->count_crtcs; ++i) {
Packit 631bab
		drmModeCrtc *crtc = dev->resources->crtcs[i].crtc;
Packit 631bab
		if (crtc && crtc->crtc_id == id)
Packit 631bab
			return i;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return -1;
Packit 631bab
}
Packit 631bab
Packit 631bab
static drmModeConnector *get_connector_by_name(struct device *dev, const char *name)
Packit 631bab
{
Packit 631bab
	struct connector *connector;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	for (i = 0; i < dev->resources->res->count_connectors; i++) {
Packit 631bab
		connector = &dev->resources->connectors[i];
Packit 631bab
Packit 631bab
		if (strcmp(connector->name, name) == 0)
Packit 631bab
			return connector->connector;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return NULL;
Packit 631bab
}
Packit 631bab
Packit 631bab
static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id)
Packit 631bab
{
Packit 631bab
	drmModeConnector *connector;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	for (i = 0; i < dev->resources->res->count_connectors; i++) {
Packit 631bab
		connector = dev->resources->connectors[i].connector;
Packit 631bab
		if (connector && connector->connector_id == id)
Packit 631bab
			return connector;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return NULL;
Packit 631bab
}
Packit 631bab
Packit 631bab
static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id)
Packit 631bab
{
Packit 631bab
	drmModeEncoder *encoder;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	for (i = 0; i < dev->resources->res->count_encoders; i++) {
Packit 631bab
		encoder = dev->resources->encoders[i].encoder;
Packit 631bab
		if (encoder && encoder->encoder_id == id)
Packit 631bab
			return encoder;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return NULL;
Packit 631bab
}
Packit 631bab
Packit 631bab
/* -----------------------------------------------------------------------------
Packit 631bab
 * Pipes and planes
Packit 631bab
 */
Packit 631bab
Packit 631bab
/*
Packit 631bab
 * Mode setting with the kernel interfaces is a bit of a chore.
Packit 631bab
 * First you have to find the connector in question and make sure the
Packit 631bab
 * requested mode is available.
Packit 631bab
 * Then you need to find the encoder attached to that connector so you
Packit 631bab
 * can bind it with a free crtc.
Packit 631bab
 */
Packit 631bab
struct pipe_arg {
Packit 631bab
	const char **cons;
Packit 631bab
	uint32_t *con_ids;
Packit 631bab
	unsigned int num_cons;
Packit 631bab
	uint32_t crtc_id;
Packit 631bab
	char mode_str[64];
Packit 631bab
	char format_str[5];
Packit 631bab
	unsigned int vrefresh;
Packit 631bab
	unsigned int fourcc;
Packit 631bab
	drmModeModeInfo *mode;
Packit 631bab
	struct crtc *crtc;
Packit 631bab
	unsigned int fb_id[2], current_fb_id;
Packit 631bab
	struct timeval start;
Packit 631bab
Packit 631bab
	int swap_count;
Packit 631bab
};
Packit 631bab
Packit 631bab
struct plane_arg {
Packit 631bab
	uint32_t plane_id;  /* the id of plane to use */
Packit 631bab
	uint32_t crtc_id;  /* the id of CRTC to bind to */
Packit 631bab
	bool has_position;
Packit 631bab
	int32_t x, y;
Packit 631bab
	uint32_t w, h;
Packit 631bab
	double scale;
Packit 631bab
	unsigned int fb_id;
Packit 631bab
	unsigned int old_fb_id;
Packit 631bab
	struct bo *bo;
Packit 631bab
	struct bo *old_bo;
Packit 631bab
	char format_str[5]; /* need to leave room for terminating \0 */
Packit 631bab
	unsigned int fourcc;
Packit 631bab
};
Packit 631bab
Packit 631bab
static drmModeModeInfo *
Packit 631bab
connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str,
Packit 631bab
        const unsigned int vrefresh)
Packit 631bab
{
Packit 631bab
	drmModeConnector *connector;
Packit 631bab
	drmModeModeInfo *mode;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	connector = get_connector_by_id(dev, con_id);
Packit 631bab
	if (!connector || !connector->count_modes)
Packit 631bab
		return NULL;
Packit 631bab
Packit 631bab
	for (i = 0; i < connector->count_modes; i++) {
Packit 631bab
		mode = &connector->modes[i];
Packit 631bab
		if (!strcmp(mode->name, mode_str)) {
Packit 631bab
			/* If the vertical refresh frequency is not specified then return the
Packit 631bab
			 * first mode that match with the name. Else, return the mode that match
Packit 631bab
			 * the name and the specified vertical refresh frequency.
Packit 631bab
			 */
Packit 631bab
			if (vrefresh == 0)
Packit 631bab
				return mode;
Packit 631bab
			else if (mode->vrefresh == vrefresh)
Packit 631bab
				return mode;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return NULL;
Packit 631bab
}
Packit 631bab
Packit 631bab
static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe)
Packit 631bab
{
Packit 631bab
	uint32_t possible_crtcs = ~0;
Packit 631bab
	uint32_t active_crtcs = 0;
Packit 631bab
	unsigned int crtc_idx;
Packit 631bab
	unsigned int i;
Packit 631bab
	int j;
Packit 631bab
Packit 631bab
	for (i = 0; i < pipe->num_cons; ++i) {
Packit 631bab
		uint32_t crtcs_for_connector = 0;
Packit 631bab
		drmModeConnector *connector;
Packit 631bab
		drmModeEncoder *encoder;
Packit 631bab
		int idx;
Packit 631bab
Packit 631bab
		connector = get_connector_by_id(dev, pipe->con_ids[i]);
Packit 631bab
		if (!connector)
Packit 631bab
			return NULL;
Packit 631bab
Packit 631bab
		for (j = 0; j < connector->count_encoders; ++j) {
Packit 631bab
			encoder = get_encoder_by_id(dev, connector->encoders[j]);
Packit 631bab
			if (!encoder)
Packit 631bab
				continue;
Packit 631bab
Packit 631bab
			crtcs_for_connector |= encoder->possible_crtcs;
Packit 631bab
Packit 631bab
			idx = get_crtc_index(dev, encoder->crtc_id);
Packit 631bab
			if (idx >= 0)
Packit 631bab
				active_crtcs |= 1 << idx;
Packit 631bab
		}
Packit 631bab
Packit 631bab
		possible_crtcs &= crtcs_for_connector;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (!possible_crtcs)
Packit 631bab
		return NULL;
Packit 631bab
Packit 631bab
	/* Return the first possible and active CRTC if one exists, or the first
Packit 631bab
	 * possible CRTC otherwise.
Packit 631bab
	 */
Packit 631bab
	if (possible_crtcs & active_crtcs)
Packit 631bab
		crtc_idx = ffs(possible_crtcs & active_crtcs);
Packit 631bab
	else
Packit 631bab
		crtc_idx = ffs(possible_crtcs);
Packit 631bab
Packit 631bab
	return &dev->resources->crtcs[crtc_idx - 1];
Packit 631bab
}
Packit 631bab
Packit 631bab
static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe)
Packit 631bab
{
Packit 631bab
	drmModeModeInfo *mode = NULL;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	pipe->mode = NULL;
Packit 631bab
Packit 631bab
	for (i = 0; i < (int)pipe->num_cons; i++) {
Packit 631bab
		mode = connector_find_mode(dev, pipe->con_ids[i],
Packit 631bab
					   pipe->mode_str, pipe->vrefresh);
Packit 631bab
		if (mode == NULL) {
Packit 631bab
			fprintf(stderr,
Packit 631bab
				"failed to find mode \"%s\" for connector %s\n",
Packit 631bab
				pipe->mode_str, pipe->cons[i]);
Packit 631bab
			return -EINVAL;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	/* If the CRTC ID was specified, get the corresponding CRTC. Otherwise
Packit 631bab
	 * locate a CRTC that can be attached to all the connectors.
Packit 631bab
	 */
Packit 631bab
	if (pipe->crtc_id != (uint32_t)-1) {
Packit 631bab
		for (i = 0; i < dev->resources->res->count_crtcs; i++) {
Packit 631bab
			struct crtc *crtc = &dev->resources->crtcs[i];
Packit 631bab
Packit 631bab
			if (pipe->crtc_id == crtc->crtc->crtc_id) {
Packit 631bab
				pipe->crtc = crtc;
Packit 631bab
				break;
Packit 631bab
			}
Packit 631bab
		}
Packit 631bab
	} else {
Packit 631bab
		pipe->crtc = pipe_find_crtc(dev, pipe);
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (!pipe->crtc) {
Packit 631bab
		fprintf(stderr, "failed to find CRTC for pipe\n");
Packit 631bab
		return -EINVAL;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	pipe->mode = mode;
Packit 631bab
	pipe->crtc->mode = mode;
Packit 631bab
Packit 631bab
	return 0;
Packit 631bab
}
Packit 631bab
Packit 631bab
/* -----------------------------------------------------------------------------
Packit 631bab
 * Properties
Packit 631bab
 */
Packit 631bab
Packit 631bab
struct property_arg {
Packit 631bab
	uint32_t obj_id;
Packit 631bab
	uint32_t obj_type;
Packit 631bab
	char name[DRM_PROP_NAME_LEN+1];
Packit 631bab
	uint32_t prop_id;
Packit 631bab
	uint64_t value;
Packit 631bab
	bool optional;
Packit 631bab
};
Packit 631bab
Packit 631bab
static bool set_property(struct device *dev, struct property_arg *p)
Packit 631bab
{
Packit 631bab
	drmModeObjectProperties *props = NULL;
Packit 631bab
	drmModePropertyRes **props_info = NULL;
Packit 631bab
	const char *obj_type;
Packit 631bab
	int ret;
Packit 631bab
	int i;
Packit 631bab
Packit 631bab
	p->obj_type = 0;
Packit 631bab
	p->prop_id = 0;
Packit 631bab
Packit 631bab
#define find_object(_res, __res, type, Type)					\
Packit 631bab
	do {									\
Packit 631bab
		for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) {	\
Packit 631bab
			struct type *obj = &(_res)->type##s[i];			\
Packit 631bab
			if (obj->type->type##_id != p->obj_id)			\
Packit 631bab
				continue;					\
Packit 631bab
			p->obj_type = DRM_MODE_OBJECT_##Type;			\
Packit 631bab
			obj_type = #Type;					\
Packit 631bab
			props = obj->props;					\
Packit 631bab
			props_info = obj->props_info;				\
Packit 631bab
		}								\
Packit 631bab
	} while(0)								\
Packit 631bab
Packit 631bab
	find_object(dev->resources, res, crtc, CRTC);
Packit 631bab
	if (p->obj_type == 0)
Packit 631bab
		find_object(dev->resources, res, connector, CONNECTOR);
Packit 631bab
	if (p->obj_type == 0)
Packit 631bab
		find_object(dev->resources, plane_res, plane, PLANE);
Packit 631bab
	if (p->obj_type == 0) {
Packit 631bab
		fprintf(stderr, "Object %i not found, can't set property\n",
Packit 631bab
			p->obj_id);
Packit 631bab
		return false;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (!props) {
Packit 631bab
		fprintf(stderr, "%s %i has no properties\n",
Packit 631bab
			obj_type, p->obj_id);
Packit 631bab
		return false;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	for (i = 0; i < (int)props->count_props; ++i) {
Packit 631bab
		if (!props_info[i])
Packit 631bab
			continue;
Packit 631bab
		if (strcmp(props_info[i]->name, p->name) == 0)
Packit 631bab
			break;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (i == (int)props->count_props) {
Packit 631bab
		if (!p->optional)
Packit 631bab
			fprintf(stderr, "%s %i has no %s property\n",
Packit 631bab
				obj_type, p->obj_id, p->name);
Packit 631bab
		return false;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	p->prop_id = props->props[i];
Packit 631bab
Packit 631bab
	if (!dev->use_atomic)
Packit 631bab
		ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
Packit 631bab
									   p->prop_id, p->value);
Packit 631bab
	else
Packit 631bab
		ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value);
Packit 631bab
Packit 631bab
	if (ret < 0)
Packit 631bab
		fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
Packit 631bab
			obj_type, p->obj_id, p->name, p->value, strerror(errno));
Packit 631bab
Packit 631bab
	return true;
Packit 631bab
}
Packit 631bab
Packit 631bab
/* -------------------------------------------------------------------------- */
Packit 631bab
Packit 631bab
static void
Packit 631bab
page_flip_handler(int fd, unsigned int frame,
Packit 631bab
		  unsigned int sec, unsigned int usec, void *data)
Packit 631bab
{
Packit 631bab
	struct pipe_arg *pipe;
Packit 631bab
	unsigned int new_fb_id;
Packit 631bab
	struct timeval end;
Packit 631bab
	double t;
Packit 631bab
Packit 631bab
	pipe = data;
Packit 631bab
	if (pipe->current_fb_id == pipe->fb_id[0])
Packit 631bab
		new_fb_id = pipe->fb_id[1];
Packit 631bab
	else
Packit 631bab
		new_fb_id = pipe->fb_id[0];
Packit 631bab
Packit 631bab
	drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id,
Packit 631bab
			DRM_MODE_PAGE_FLIP_EVENT, pipe);
Packit 631bab
	pipe->current_fb_id = new_fb_id;
Packit 631bab
	pipe->swap_count++;
Packit 631bab
	if (pipe->swap_count == 60) {
Packit 631bab
		gettimeofday(&end, NULL);
Packit 631bab
		t = end.tv_sec + end.tv_usec * 1e-6 -
Packit 631bab
			(pipe->start.tv_sec + pipe->start.tv_usec * 1e-6);
Packit 631bab
		fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t);
Packit 631bab
		pipe->swap_count = 0;
Packit 631bab
		pipe->start = end;
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static bool format_support(const drmModePlanePtr ovr, uint32_t fmt)
Packit 631bab
{
Packit 631bab
	unsigned int i;
Packit 631bab
Packit 631bab
	for (i = 0; i < ovr->count_formats; ++i) {
Packit 631bab
		if (ovr->formats[i] == fmt)
Packit 631bab
			return true;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return false;
Packit 631bab
}
Packit 631bab
Packit 631bab
static void add_property(struct device *dev, uint32_t obj_id,
Packit 631bab
			       const char *name, uint64_t value)
Packit 631bab
{
Packit 631bab
	struct property_arg p;
Packit 631bab
Packit 631bab
	p.obj_id = obj_id;
Packit 631bab
	strcpy(p.name, name);
Packit 631bab
	p.value = value;
Packit 631bab
Packit 631bab
	set_property(dev, &p);
Packit 631bab
}
Packit 631bab
Packit 631bab
static bool add_property_optional(struct device *dev, uint32_t obj_id,
Packit 631bab
				  const char *name, uint64_t value)
Packit 631bab
{
Packit 631bab
	struct property_arg p;
Packit 631bab
Packit 631bab
	p.obj_id = obj_id;
Packit 631bab
	strcpy(p.name, name);
Packit 631bab
	p.value = value;
Packit 631bab
	p.optional = true;
Packit 631bab
Packit 631bab
	return set_property(dev, &p);
Packit 631bab
}
Packit 631bab
Packit 631bab
static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc)
Packit 631bab
{
Packit 631bab
	unsigned blob_id = 0;
Packit 631bab
	/* TODO: support 1024-sized LUTs, when the use-case arises */
Packit 631bab
	struct drm_color_lut gamma_lut[256];
Packit 631bab
	int i, ret;
Packit 631bab
Packit 631bab
	if (fourcc == DRM_FORMAT_C8) {
Packit 631bab
		/* TODO: Add C8 support for more patterns */
Packit 631bab
		util_smpte_c8_gamma(256, gamma_lut);
Packit 631bab
		drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id);
Packit 631bab
	} else {
Packit 631bab
		for (i = 0; i < 256; i++) {
Packit 631bab
			gamma_lut[i].red =
Packit 631bab
			gamma_lut[i].green =
Packit 631bab
			gamma_lut[i].blue = i << 8;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0);
Packit 631bab
	add_property_optional(dev, crtc_id, "CTM", 0);
Packit 631bab
	if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) {
Packit 631bab
		uint16_t r[256], g[256], b[256];
Packit 631bab
Packit 631bab
		for (i = 0; i < 256; i++) {
Packit 631bab
			r[i] = gamma_lut[i].red;
Packit 631bab
			g[i] = gamma_lut[i].green;
Packit 631bab
			b[i] = gamma_lut[i].blue;
Packit 631bab
		}
Packit 631bab
Packit 631bab
		ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b);
Packit 631bab
		if (ret)
Packit 631bab
			fprintf(stderr, "failed to set gamma: %s\n", strerror(errno));
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static int atomic_set_plane(struct device *dev, struct plane_arg *p,
Packit 631bab
							int pattern, bool update)
Packit 631bab
{
Packit 631bab
	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Packit 631bab
	struct bo *plane_bo;
Packit 631bab
	int crtc_x, crtc_y, crtc_w, crtc_h;
Packit 631bab
	struct crtc *crtc = NULL;
Packit 631bab
	unsigned int i;
Packit 631bab
	unsigned int old_fb_id;
Packit 631bab
Packit 631bab
	/* Find an unused plane which can be connected to our CRTC. Find the
Packit 631bab
	 * CRTC index first, then iterate over available planes.
Packit 631bab
	 */
Packit 631bab
	for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
Packit 631bab
		if (p->crtc_id == dev->resources->res->crtcs[i]) {
Packit 631bab
			crtc = &dev->resources->crtcs[i];
Packit 631bab
			break;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (!crtc) {
Packit 631bab
		fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (!update)
Packit 631bab
		fprintf(stderr, "testing %dx%d@%s on plane %u, crtc %u\n",
Packit 631bab
			p->w, p->h, p->format_str, p->plane_id, p->crtc_id);
Packit 631bab
Packit 631bab
	plane_bo = p->old_bo;
Packit 631bab
	p->old_bo = p->bo;
Packit 631bab
Packit 631bab
	if (!plane_bo) {
Packit 631bab
		plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h,
Packit 631bab
				     handles, pitches, offsets, pattern);
Packit 631bab
Packit 631bab
		if (plane_bo == NULL)
Packit 631bab
			return -1;
Packit 631bab
Packit 631bab
		if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
Packit 631bab
			handles, pitches, offsets, &p->fb_id, 0)) {
Packit 631bab
			fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
Packit 631bab
			return -1;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	p->bo = plane_bo;
Packit 631bab
Packit 631bab
	old_fb_id = p->fb_id;
Packit 631bab
	p->old_fb_id = old_fb_id;
Packit 631bab
Packit 631bab
	crtc_w = p->w * p->scale;
Packit 631bab
	crtc_h = p->h * p->scale;
Packit 631bab
	if (!p->has_position) {
Packit 631bab
		/* Default to the middle of the screen */
Packit 631bab
		crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
Packit 631bab
		crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
Packit 631bab
	} else {
Packit 631bab
		crtc_x = p->x;
Packit 631bab
		crtc_y = p->y;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	add_property(dev, p->plane_id, "FB_ID", p->fb_id);
Packit 631bab
	add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id);
Packit 631bab
	add_property(dev, p->plane_id, "SRC_X", 0);
Packit 631bab
	add_property(dev, p->plane_id, "SRC_Y", 0);
Packit 631bab
	add_property(dev, p->plane_id, "SRC_W", p->w << 16);
Packit 631bab
	add_property(dev, p->plane_id, "SRC_H", p->h << 16);
Packit 631bab
	add_property(dev, p->plane_id, "CRTC_X", crtc_x);
Packit 631bab
	add_property(dev, p->plane_id, "CRTC_Y", crtc_y);
Packit 631bab
	add_property(dev, p->plane_id, "CRTC_W", crtc_w);
Packit 631bab
	add_property(dev, p->plane_id, "CRTC_H", crtc_h);
Packit 631bab
Packit 631bab
	return 0;
Packit 631bab
}
Packit 631bab
Packit 631bab
static int set_plane(struct device *dev, struct plane_arg *p)
Packit 631bab
{
Packit 631bab
	drmModePlane *ovr;
Packit 631bab
	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Packit 631bab
	uint32_t plane_id;
Packit 631bab
	struct bo *plane_bo;
Packit 631bab
	uint32_t plane_flags = 0;
Packit 631bab
	int crtc_x, crtc_y, crtc_w, crtc_h;
Packit 631bab
	struct crtc *crtc = NULL;
Packit 631bab
	unsigned int pipe;
Packit 631bab
	unsigned int i;
Packit 631bab
Packit 631bab
	/* Find an unused plane which can be connected to our CRTC. Find the
Packit 631bab
	 * CRTC index first, then iterate over available planes.
Packit 631bab
	 */
Packit 631bab
	for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
Packit 631bab
		if (p->crtc_id == dev->resources->res->crtcs[i]) {
Packit 631bab
			crtc = &dev->resources->crtcs[i];
Packit 631bab
			pipe = i;
Packit 631bab
			break;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (!crtc) {
Packit 631bab
		fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	plane_id = p->plane_id;
Packit 631bab
Packit 631bab
	for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
Packit 631bab
		ovr = dev->resources->planes[i].plane;
Packit 631bab
		if (!ovr)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		if (plane_id && plane_id != ovr->plane_id)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		if (!format_support(ovr, p->fourcc))
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		if ((ovr->possible_crtcs & (1 << pipe)) &&
Packit 631bab
		    (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) {
Packit 631bab
			plane_id = ovr->plane_id;
Packit 631bab
			break;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (i == dev->resources->plane_res->count_planes) {
Packit 631bab
		fprintf(stderr, "no unused plane available for CRTC %u\n",
Packit 631bab
			crtc->crtc->crtc_id);
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	fprintf(stderr, "testing %dx%d@%s overlay plane %u\n",
Packit 631bab
		p->w, p->h, p->format_str, plane_id);
Packit 631bab
Packit 631bab
	plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, handles,
Packit 631bab
			     pitches, offsets, secondary_fill);
Packit 631bab
	if (plane_bo == NULL)
Packit 631bab
		return -1;
Packit 631bab
Packit 631bab
	p->bo = plane_bo;
Packit 631bab
Packit 631bab
	/* just use single plane format for now.. */
Packit 631bab
	if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
Packit 631bab
			handles, pitches, offsets, &p->fb_id, plane_flags)) {
Packit 631bab
		fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	crtc_w = p->w * p->scale;
Packit 631bab
	crtc_h = p->h * p->scale;
Packit 631bab
	if (!p->has_position) {
Packit 631bab
		/* Default to the middle of the screen */
Packit 631bab
		crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
Packit 631bab
		crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
Packit 631bab
	} else {
Packit 631bab
		crtc_x = p->x;
Packit 631bab
		crtc_y = p->y;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	/* note src coords (last 4 args) are in Q16 format */
Packit 631bab
	if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id,
Packit 631bab
			    plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
Packit 631bab
			    0, 0, p->w << 16, p->h << 16)) {
Packit 631bab
		fprintf(stderr, "failed to enable plane: %s\n",
Packit 631bab
			strerror(errno));
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	ovr->crtc_id = crtc->crtc->crtc_id;
Packit 631bab
Packit 631bab
	return 0;
Packit 631bab
}
Packit 631bab
Packit 631bab
static void atomic_set_planes(struct device *dev, struct plane_arg *p,
Packit 631bab
			      unsigned int count, bool update)
Packit 631bab
{
Packit 631bab
	unsigned int i, pattern = primary_fill;
Packit 631bab
Packit 631bab
	/* set up planes */
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		if (i > 0)
Packit 631bab
			pattern = secondary_fill;
Packit 631bab
		else
Packit 631bab
			set_gamma(dev, p[i].crtc_id, p[i].fourcc);
Packit 631bab
Packit 631bab
		if (atomic_set_plane(dev, &p[i], pattern, update))
Packit 631bab
			return;
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
Packit 631bab
{
Packit 631bab
	unsigned int i;
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		add_property(dev, p[i].plane_id, "FB_ID", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "CRTC_ID", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "SRC_X", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "SRC_Y", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "SRC_W", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "SRC_H", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "CRTC_X", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "CRTC_Y", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "CRTC_W", 0);
Packit 631bab
		add_property(dev, p[i].plane_id, "CRTC_H", 0);
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static void atomic_clear_FB(struct device *dev, struct plane_arg *p, unsigned int count)
Packit 631bab
{
Packit 631bab
	unsigned int i;
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		if (p[i].fb_id) {
Packit 631bab
			drmModeRmFB(dev->fd, p[i].fb_id);
Packit 631bab
			p[i].fb_id = 0;
Packit 631bab
		}
Packit 631bab
		if (p[i].old_fb_id) {
Packit 631bab
			drmModeRmFB(dev->fd, p[i].old_fb_id);
Packit 631bab
			p[i].old_fb_id = 0;
Packit 631bab
		}
Packit 631bab
		if (p[i].bo) {
Packit 631bab
			bo_destroy(p[i].bo);
Packit 631bab
			p[i].bo = NULL;
Packit 631bab
		}
Packit 631bab
		if (p[i].old_bo) {
Packit 631bab
			bo_destroy(p[i].old_bo);
Packit 631bab
			p[i].old_bo = NULL;
Packit 631bab
		}
Packit 631bab
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
Packit 631bab
{
Packit 631bab
	unsigned int i;
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		if (p[i].fb_id)
Packit 631bab
			drmModeRmFB(dev->fd, p[i].fb_id);
Packit 631bab
		if (p[i].bo)
Packit 631bab
			bo_destroy(p[i].bo);
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static void atomic_set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
Packit 631bab
{
Packit 631bab
	unsigned int i;
Packit 631bab
	unsigned int j;
Packit 631bab
	int ret;
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		struct pipe_arg *pipe = &pipes[i];
Packit 631bab
Packit 631bab
		ret = pipe_find_crtc_and_mode(dev, pipe);
Packit 631bab
		if (ret < 0)
Packit 631bab
			continue;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		struct pipe_arg *pipe = &pipes[i];
Packit 631bab
		uint32_t blob_id;
Packit 631bab
Packit 631bab
		if (pipe->mode == NULL)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		printf("setting mode %s-%dHz on connectors ",
Packit 631bab
		       pipe->mode_str, pipe->mode->vrefresh);
Packit 631bab
		for (j = 0; j < pipe->num_cons; ++j) {
Packit 631bab
			printf("%s, ", pipe->cons[j]);
Packit 631bab
			add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc->crtc->crtc_id);
Packit 631bab
		}
Packit 631bab
		printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
Packit 631bab
Packit 631bab
		drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id);
Packit 631bab
		add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", blob_id);
Packit 631bab
		add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 1);
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
Packit 631bab
{
Packit 631bab
	unsigned int i;
Packit 631bab
	unsigned int j;
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		struct pipe_arg *pipe = &pipes[i];
Packit 631bab
Packit 631bab
		if (pipe->mode == NULL)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		for (j = 0; j < pipe->num_cons; ++j)
Packit 631bab
			add_property(dev, pipe->con_ids[j], "CRTC_ID",0);
Packit 631bab
Packit 631bab
		add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", 0);
Packit 631bab
		add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 0);
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
Packit 631bab
{
Packit 631bab
	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Packit 631bab
	unsigned int fb_id;
Packit 631bab
	struct bo *bo;
Packit 631bab
	unsigned int i;
Packit 631bab
	unsigned int j;
Packit 631bab
	int ret, x;
Packit 631bab
Packit 631bab
	dev->mode.width = 0;
Packit 631bab
	dev->mode.height = 0;
Packit 631bab
	dev->mode.fb_id = 0;
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		struct pipe_arg *pipe = &pipes[i];
Packit 631bab
Packit 631bab
		ret = pipe_find_crtc_and_mode(dev, pipe);
Packit 631bab
		if (ret < 0)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		dev->mode.width += pipe->mode->hdisplay;
Packit 631bab
		if (dev->mode.height < pipe->mode->vdisplay)
Packit 631bab
			dev->mode.height = pipe->mode->vdisplay;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
Packit 631bab
		       dev->mode.height, handles, pitches, offsets,
Packit 631bab
		       primary_fill);
Packit 631bab
	if (bo == NULL)
Packit 631bab
		return;
Packit 631bab
Packit 631bab
	dev->mode.bo = bo;
Packit 631bab
Packit 631bab
	ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
Packit 631bab
			    pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0);
Packit 631bab
	if (ret) {
Packit 631bab
		fprintf(stderr, "failed to add fb (%ux%u): %s\n",
Packit 631bab
			dev->mode.width, dev->mode.height, strerror(errno));
Packit 631bab
		return;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	dev->mode.fb_id = fb_id;
Packit 631bab
Packit 631bab
	x = 0;
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		struct pipe_arg *pipe = &pipes[i];
Packit 631bab
Packit 631bab
		if (pipe->mode == NULL)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		printf("setting mode %s-%dHz@%s on connectors ",
Packit 631bab
		       pipe->mode_str, pipe->mode->vrefresh, pipe->format_str);
Packit 631bab
		for (j = 0; j < pipe->num_cons; ++j)
Packit 631bab
			printf("%s, ", pipe->cons[j]);
Packit 631bab
		printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
Packit 631bab
Packit 631bab
		ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id,
Packit 631bab
				     x, 0, pipe->con_ids, pipe->num_cons,
Packit 631bab
				     pipe->mode);
Packit 631bab
Packit 631bab
		/* XXX: Actually check if this is needed */
Packit 631bab
		drmModeDirtyFB(dev->fd, fb_id, NULL, 0);
Packit 631bab
Packit 631bab
		x += pipe->mode->hdisplay;
Packit 631bab
Packit 631bab
		if (ret) {
Packit 631bab
			fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
Packit 631bab
			return;
Packit 631bab
		}
Packit 631bab
Packit 631bab
		set_gamma(dev, pipe->crtc->crtc->crtc_id, pipe->fourcc);
Packit 631bab
	}
Packit 631bab
}
Packit 631bab
Packit 631bab
static void clear_mode(struct device *dev)
Packit 631bab
{
Packit 631bab
	if (dev->mode.fb_id)
Packit 631bab
		drmModeRmFB(dev->fd, dev->mode.fb_id);
Packit 631bab
	if (dev->mode.bo)
Packit 631bab
		bo_destroy(dev->mode.bo);
Packit 631bab
}
Packit 631bab
Packit 631bab
static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count)
Packit 631bab
{
Packit 631bab
	unsigned int i;
Packit 631bab
Packit 631bab
	/* set up planes/overlays */
Packit 631bab
	for (i = 0; i < count; i++)
Packit 631bab
		if (set_plane(dev, &p[i]))
Packit 631bab
			return;
Packit 631bab
}
Packit 631bab
Packit 631bab
static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count)
Packit 631bab
{
Packit 631bab
	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Packit 631bab
	struct bo *bo;
Packit 631bab
	unsigned int i;
Packit 631bab
	int ret;
Packit 631bab
Packit 631bab
	/* maybe make cursor width/height configurable some day */
Packit 631bab
	uint32_t cw = 64;
Packit 631bab
	uint32_t ch = 64;
Packit 631bab
Packit 631bab
	/* create cursor bo.. just using PATTERN_PLAIN as it has
Packit 631bab
	 * translucent alpha
Packit 631bab
	 */
Packit 631bab
	bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches,
Packit 631bab
		       offsets, UTIL_PATTERN_PLAIN);
Packit 631bab
	if (bo == NULL)
Packit 631bab
		return;
Packit 631bab
Packit 631bab
	dev->mode.cursor_bo = bo;
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		struct pipe_arg *pipe = &pipes[i];
Packit 631bab
		ret = cursor_init(dev->fd, handles[0],
Packit 631bab
				pipe->crtc->crtc->crtc_id,
Packit 631bab
				pipe->mode->hdisplay, pipe->mode->vdisplay,
Packit 631bab
				cw, ch);
Packit 631bab
		if (ret) {
Packit 631bab
			fprintf(stderr, "failed to init cursor for CRTC[%u]\n",
Packit 631bab
					pipe->crtc_id);
Packit 631bab
			return;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	cursor_start();
Packit 631bab
}
Packit 631bab
Packit 631bab
static void clear_cursors(struct device *dev)
Packit 631bab
{
Packit 631bab
	cursor_stop();
Packit 631bab
Packit 631bab
	if (dev->mode.cursor_bo)
Packit 631bab
		bo_destroy(dev->mode.cursor_bo);
Packit 631bab
}
Packit 631bab
Packit 631bab
static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count)
Packit 631bab
{
Packit 631bab
	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
Packit 631bab
	unsigned int other_fb_id;
Packit 631bab
	struct bo *other_bo;
Packit 631bab
	drmEventContext evctx;
Packit 631bab
	unsigned int i;
Packit 631bab
	int ret;
Packit 631bab
Packit 631bab
	other_bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
Packit 631bab
			     dev->mode.height, handles, pitches, offsets,
Packit 631bab
			     UTIL_PATTERN_PLAIN);
Packit 631bab
	if (other_bo == NULL)
Packit 631bab
		return;
Packit 631bab
Packit 631bab
	ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
Packit 631bab
			    pipes[0].fourcc, handles, pitches, offsets,
Packit 631bab
			    &other_fb_id, 0);
Packit 631bab
	if (ret) {
Packit 631bab
		fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
Packit 631bab
		goto err;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		struct pipe_arg *pipe = &pipes[i];
Packit 631bab
Packit 631bab
		if (pipe->mode == NULL)
Packit 631bab
			continue;
Packit 631bab
Packit 631bab
		ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id,
Packit 631bab
				      other_fb_id, DRM_MODE_PAGE_FLIP_EVENT,
Packit 631bab
				      pipe);
Packit 631bab
		if (ret) {
Packit 631bab
			fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
Packit 631bab
			goto err_rmfb;
Packit 631bab
		}
Packit 631bab
		gettimeofday(&pipe->start, NULL);
Packit 631bab
		pipe->swap_count = 0;
Packit 631bab
		pipe->fb_id[0] = dev->mode.fb_id;
Packit 631bab
		pipe->fb_id[1] = other_fb_id;
Packit 631bab
		pipe->current_fb_id = other_fb_id;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	memset(&evctx, 0, sizeof evctx);
Packit 631bab
	evctx.version = DRM_EVENT_CONTEXT_VERSION;
Packit 631bab
	evctx.vblank_handler = NULL;
Packit 631bab
	evctx.page_flip_handler = page_flip_handler;
Packit 631bab
Packit 631bab
	while (1) {
Packit 631bab
#if 0
Packit 631bab
		struct pollfd pfd[2];
Packit 631bab
Packit 631bab
		pfd[0].fd = 0;
Packit 631bab
		pfd[0].events = POLLIN;
Packit 631bab
		pfd[1].fd = fd;
Packit 631bab
		pfd[1].events = POLLIN;
Packit 631bab
Packit 631bab
		if (poll(pfd, 2, -1) < 0) {
Packit 631bab
			fprintf(stderr, "poll error\n");
Packit 631bab
			break;
Packit 631bab
		}
Packit 631bab
Packit 631bab
		if (pfd[0].revents)
Packit 631bab
			break;
Packit 631bab
#else
Packit 631bab
		struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
Packit 631bab
		fd_set fds;
Packit 631bab
Packit 631bab
		FD_ZERO(&fds);
Packit 631bab
		FD_SET(0, &fds);
Packit 631bab
		FD_SET(dev->fd, &fds);
Packit 631bab
		ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout);
Packit 631bab
Packit 631bab
		if (ret <= 0) {
Packit 631bab
			fprintf(stderr, "select timed out or error (ret %d)\n",
Packit 631bab
				ret);
Packit 631bab
			continue;
Packit 631bab
		} else if (FD_ISSET(0, &fds)) {
Packit 631bab
			break;
Packit 631bab
		}
Packit 631bab
#endif
Packit 631bab
Packit 631bab
		drmHandleEvent(dev->fd, &evctx);
Packit 631bab
	}
Packit 631bab
Packit 631bab
err_rmfb:
Packit 631bab
	drmModeRmFB(dev->fd, other_fb_id);
Packit 631bab
err:
Packit 631bab
	bo_destroy(other_bo);
Packit 631bab
}
Packit 631bab
Packit 631bab
#define min(a, b)	((a) < (b) ? (a) : (b))
Packit 631bab
Packit 631bab
static int parse_connector(struct pipe_arg *pipe, const char *arg)
Packit 631bab
{
Packit 631bab
	unsigned int len;
Packit 631bab
	unsigned int i;
Packit 631bab
	const char *p;
Packit 631bab
	char *endp;
Packit 631bab
Packit 631bab
	pipe->vrefresh = 0;
Packit 631bab
	pipe->crtc_id = (uint32_t)-1;
Packit 631bab
	strcpy(pipe->format_str, "XR24");
Packit 631bab
Packit 631bab
	/* Count the number of connectors and allocate them. */
Packit 631bab
	pipe->num_cons = 1;
Packit 631bab
	for (p = arg; *p && *p != ':' && *p != '@'; ++p) {
Packit 631bab
		if (*p == ',')
Packit 631bab
			pipe->num_cons++;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids));
Packit 631bab
	pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons));
Packit 631bab
	if (pipe->con_ids == NULL || pipe->cons == NULL)
Packit 631bab
		return -1;
Packit 631bab
Packit 631bab
	/* Parse the connectors. */
Packit 631bab
	for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) {
Packit 631bab
		endp = strpbrk(p, ",@:");
Packit 631bab
		if (!endp)
Packit 631bab
			break;
Packit 631bab
Packit 631bab
		pipe->cons[i] = strndup(p, endp - p);
Packit 631bab
Packit 631bab
		if (*endp != ',')
Packit 631bab
			break;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (i != pipe->num_cons - 1)
Packit 631bab
		return -1;
Packit 631bab
Packit 631bab
	/* Parse the remaining parameters. */
Packit 631bab
	if (*endp == '@') {
Packit 631bab
		arg = endp + 1;
Packit 631bab
		pipe->crtc_id = strtoul(arg, &endp, 10);
Packit 631bab
	}
Packit 631bab
	if (*endp != ':')
Packit 631bab
		return -1;
Packit 631bab
Packit 631bab
	arg = endp + 1;
Packit 631bab
Packit 631bab
	/* Search for the vertical refresh or the format. */
Packit 631bab
	p = strpbrk(arg, "-@");
Packit 631bab
	if (p == NULL)
Packit 631bab
		p = arg + strlen(arg);
Packit 631bab
	len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg));
Packit 631bab
	strncpy(pipe->mode_str, arg, len);
Packit 631bab
	pipe->mode_str[len] = '\0';
Packit 631bab
Packit 631bab
	if (*p == '-') {
Packit 631bab
		pipe->vrefresh = strtoul(p + 1, &endp, 10);
Packit 631bab
		p = endp;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (*p == '@') {
Packit 631bab
		strncpy(pipe->format_str, p + 1, 4);
Packit 631bab
		pipe->format_str[4] = '\0';
Packit 631bab
	}
Packit 631bab
Packit 631bab
	pipe->fourcc = util_format_fourcc(pipe->format_str);
Packit 631bab
	if (pipe->fourcc == 0)  {
Packit 631bab
		fprintf(stderr, "unknown format %s\n", pipe->format_str);
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return 0;
Packit 631bab
}
Packit 631bab
Packit 631bab
static int parse_plane(struct plane_arg *plane, const char *p)
Packit 631bab
{
Packit 631bab
	char *end;
Packit 631bab
Packit 631bab
	plane->plane_id = strtoul(p, &end, 10);
Packit 631bab
	if (*end != '@')
Packit 631bab
		return -EINVAL;
Packit 631bab
Packit 631bab
	p = end + 1;
Packit 631bab
	plane->crtc_id = strtoul(p, &end, 10);
Packit 631bab
	if (*end != ':')
Packit 631bab
		return -EINVAL;
Packit 631bab
Packit 631bab
	p = end + 1;
Packit 631bab
	plane->w = strtoul(p, &end, 10);
Packit 631bab
	if (*end != 'x')
Packit 631bab
		return -EINVAL;
Packit 631bab
Packit 631bab
	p = end + 1;
Packit 631bab
	plane->h = strtoul(p, &end, 10);
Packit 631bab
Packit 631bab
	if (*end == '+' || *end == '-') {
Packit 631bab
		plane->x = strtol(end, &end, 10);
Packit 631bab
		if (*end != '+' && *end != '-')
Packit 631bab
			return -EINVAL;
Packit 631bab
		plane->y = strtol(end, &end, 10);
Packit 631bab
Packit 631bab
		plane->has_position = true;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (*end == '*') {
Packit 631bab
		p = end + 1;
Packit 631bab
		plane->scale = strtod(p, &end;;
Packit 631bab
		if (plane->scale <= 0.0)
Packit 631bab
			return -EINVAL;
Packit 631bab
	} else {
Packit 631bab
		plane->scale = 1.0;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (*end == '@') {
Packit 631bab
		strncpy(plane->format_str, end + 1, 4);
Packit 631bab
		plane->format_str[4] = '\0';
Packit 631bab
	} else {
Packit 631bab
		strcpy(plane->format_str, "XR24");
Packit 631bab
	}
Packit 631bab
Packit 631bab
	plane->fourcc = util_format_fourcc(plane->format_str);
Packit 631bab
	if (plane->fourcc == 0) {
Packit 631bab
		fprintf(stderr, "unknown format %s\n", plane->format_str);
Packit 631bab
		return -EINVAL;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return 0;
Packit 631bab
}
Packit 631bab
Packit 631bab
static int parse_property(struct property_arg *p, const char *arg)
Packit 631bab
{
Packit 631bab
	if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3)
Packit 631bab
		return -1;
Packit 631bab
Packit 631bab
	p->obj_type = 0;
Packit 631bab
	p->name[DRM_PROP_NAME_LEN] = '\0';
Packit 631bab
Packit 631bab
	return 0;
Packit 631bab
}
Packit 631bab
Packit 631bab
static void parse_fill_patterns(char *arg)
Packit 631bab
{
Packit 631bab
	char *fill = strtok(arg, ",");
Packit 631bab
	if (!fill)
Packit 631bab
		return;
Packit 631bab
	primary_fill = util_pattern_enum(fill);
Packit 631bab
	fill = strtok(NULL, ",");
Packit 631bab
	if (!fill)
Packit 631bab
		return;
Packit 631bab
	secondary_fill = util_pattern_enum(fill);
Packit 631bab
}
Packit 631bab
Packit 631bab
static void usage(char *name)
Packit 631bab
{
Packit 631bab
	fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name);
Packit 631bab
Packit 631bab
	fprintf(stderr, "\n Query options:\n\n");
Packit 631bab
	fprintf(stderr, "\t-c\tlist connectors\n");
Packit 631bab
	fprintf(stderr, "\t-e\tlist encoders\n");
Packit 631bab
	fprintf(stderr, "\t-f\tlist framebuffers\n");
Packit 631bab
	fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
Packit 631bab
Packit 631bab
	fprintf(stderr, "\n Test options:\n\n");
Packit 631bab
	fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
Packit 631bab
	fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n");
Packit 631bab
	fprintf(stderr, "\t-C\ttest hw cursor\n");
Packit 631bab
	fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
Packit 631bab
	fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
Packit 631bab
	fprintf(stderr, "\t-a \tuse atomic API\n");
Packit 631bab
	fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n");
Packit 631bab
Packit 631bab
	fprintf(stderr, "\n Generic options:\n\n");
Packit 631bab
	fprintf(stderr, "\t-d\tdrop master after mode set\n");
Packit 631bab
	fprintf(stderr, "\t-M module\tuse the given driver\n");
Packit 631bab
	fprintf(stderr, "\t-D device\tuse the given device\n");
Packit 631bab
Packit 631bab
	fprintf(stderr, "\n\tDefault is to dump all info.\n");
Packit 631bab
	exit(0);
Packit 631bab
}
Packit 631bab
Packit 631bab
static int page_flipping_supported(void)
Packit 631bab
{
Packit 631bab
	/*FIXME: generic ioctl needed? */
Packit 631bab
	return 1;
Packit 631bab
#if 0
Packit 631bab
	int ret, value;
Packit 631bab
	struct drm_i915_getparam gp;
Packit 631bab
Packit 631bab
	gp.param = I915_PARAM_HAS_PAGEFLIPPING;
Packit 631bab
	gp.value = &value;
Packit 631bab
Packit 631bab
	ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
Packit 631bab
	if (ret) {
Packit 631bab
		fprintf(stderr, "drm_i915_getparam: %m\n");
Packit 631bab
		return 0;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return *gp.value;
Packit 631bab
#endif
Packit 631bab
}
Packit 631bab
Packit 631bab
static int cursor_supported(void)
Packit 631bab
{
Packit 631bab
	/*FIXME: generic ioctl needed? */
Packit 631bab
	return 1;
Packit 631bab
}
Packit 631bab
Packit 631bab
static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
Packit 631bab
{
Packit 631bab
	drmModeConnector *connector;
Packit 631bab
	unsigned int i;
Packit 631bab
	uint32_t id;
Packit 631bab
	char *endp;
Packit 631bab
Packit 631bab
	for (i = 0; i < pipe->num_cons; i++) {
Packit 631bab
		id = strtoul(pipe->cons[i], &endp, 10);
Packit 631bab
		if (endp == pipe->cons[i]) {
Packit 631bab
			connector = get_connector_by_name(dev, pipe->cons[i]);
Packit 631bab
			if (!connector) {
Packit 631bab
				fprintf(stderr, "no connector named '%s'\n",
Packit 631bab
					pipe->cons[i]);
Packit 631bab
				return -ENODEV;
Packit 631bab
			}
Packit 631bab
Packit 631bab
			id = connector->connector_id;
Packit 631bab
		}
Packit 631bab
Packit 631bab
		pipe->con_ids[i] = id;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	return 0;
Packit 631bab
}
Packit 631bab
Packit 631bab
static char optstr[] = "acdD:efF:M:P:ps:Cvw:";
Packit 631bab
Packit 631bab
int main(int argc, char **argv)
Packit 631bab
{
Packit 631bab
	struct device dev;
Packit 631bab
Packit 631bab
	int c;
Packit 631bab
	int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0;
Packit 631bab
	int drop_master = 0;
Packit 631bab
	int test_vsync = 0;
Packit 631bab
	int test_cursor = 0;
Packit 631bab
	int use_atomic = 0;
Packit 631bab
	char *device = NULL;
Packit 631bab
	char *module = NULL;
Packit 631bab
	unsigned int i;
Packit 631bab
	unsigned int count = 0, plane_count = 0;
Packit 631bab
	unsigned int prop_count = 0;
Packit 631bab
	struct pipe_arg *pipe_args = NULL;
Packit 631bab
	struct plane_arg *plane_args = NULL;
Packit 631bab
	struct property_arg *prop_args = NULL;
Packit 631bab
	unsigned int args = 0;
Packit 631bab
	int ret;
Packit 631bab
Packit 631bab
	memset(&dev, 0, sizeof dev);
Packit 631bab
Packit 631bab
	opterr = 0;
Packit 631bab
	while ((c = getopt(argc, argv, optstr)) != -1) {
Packit 631bab
		args++;
Packit 631bab
Packit 631bab
		switch (c) {
Packit 631bab
		case 'a':
Packit 631bab
			use_atomic = 1;
Packit 631bab
			break;
Packit 631bab
		case 'c':
Packit 631bab
			connectors = 1;
Packit 631bab
			break;
Packit 631bab
		case 'D':
Packit 631bab
			device = optarg;
Packit 631bab
			args--;
Packit 631bab
			break;
Packit 631bab
		case 'd':
Packit 631bab
			drop_master = 1;
Packit 631bab
			break;
Packit 631bab
		case 'e':
Packit 631bab
			encoders = 1;
Packit 631bab
			break;
Packit 631bab
		case 'f':
Packit 631bab
			framebuffers = 1;
Packit 631bab
			break;
Packit 631bab
		case 'F':
Packit 631bab
			parse_fill_patterns(optarg);
Packit 631bab
			break;
Packit 631bab
		case 'M':
Packit 631bab
			module = optarg;
Packit 631bab
			/* Preserve the default behaviour of dumping all information. */
Packit 631bab
			args--;
Packit 631bab
			break;
Packit 631bab
		case 'P':
Packit 631bab
			plane_args = realloc(plane_args,
Packit 631bab
					     (plane_count + 1) * sizeof *plane_args);
Packit 631bab
			if (plane_args == NULL) {
Packit 631bab
				fprintf(stderr, "memory allocation failed\n");
Packit 631bab
				return 1;
Packit 631bab
			}
Packit 631bab
			memset(&plane_args[plane_count], 0, sizeof(*plane_args));
Packit 631bab
Packit 631bab
			if (parse_plane(&plane_args[plane_count], optarg) < 0)
Packit 631bab
				usage(argv[0]);
Packit 631bab
Packit 631bab
			plane_count++;
Packit 631bab
			break;
Packit 631bab
		case 'p':
Packit 631bab
			crtcs = 1;
Packit 631bab
			planes = 1;
Packit 631bab
			break;
Packit 631bab
		case 's':
Packit 631bab
			pipe_args = realloc(pipe_args,
Packit 631bab
					    (count + 1) * sizeof *pipe_args);
Packit 631bab
			if (pipe_args == NULL) {
Packit 631bab
				fprintf(stderr, "memory allocation failed\n");
Packit 631bab
				return 1;
Packit 631bab
			}
Packit 631bab
			memset(&pipe_args[count], 0, sizeof(*pipe_args));
Packit 631bab
Packit 631bab
			if (parse_connector(&pipe_args[count], optarg) < 0)
Packit 631bab
				usage(argv[0]);
Packit 631bab
Packit 631bab
			count++;
Packit 631bab
			break;
Packit 631bab
		case 'C':
Packit 631bab
			test_cursor = 1;
Packit 631bab
			break;
Packit 631bab
		case 'v':
Packit 631bab
			test_vsync = 1;
Packit 631bab
			break;
Packit 631bab
		case 'w':
Packit 631bab
			prop_args = realloc(prop_args,
Packit 631bab
					   (prop_count + 1) * sizeof *prop_args);
Packit 631bab
			if (prop_args == NULL) {
Packit 631bab
				fprintf(stderr, "memory allocation failed\n");
Packit 631bab
				return 1;
Packit 631bab
			}
Packit 631bab
			memset(&prop_args[prop_count], 0, sizeof(*prop_args));
Packit 631bab
Packit 631bab
			if (parse_property(&prop_args[prop_count], optarg) < 0)
Packit 631bab
				usage(argv[0]);
Packit 631bab
Packit 631bab
			prop_count++;
Packit 631bab
			break;
Packit 631bab
		default:
Packit 631bab
			usage(argv[0]);
Packit 631bab
			break;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (!args || (args == 1 && use_atomic))
Packit 631bab
		encoders = connectors = crtcs = planes = framebuffers = 1;
Packit 631bab
Packit 631bab
	dev.fd = util_open(device, module);
Packit 631bab
	if (dev.fd < 0)
Packit 631bab
		return -1;
Packit 631bab
Packit 631bab
	ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
Packit 631bab
	if (ret && use_atomic) {
Packit 631bab
		fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
Packit 631bab
		drmClose(dev.fd);
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	dev.use_atomic = use_atomic;
Packit 631bab
Packit 631bab
	if (test_vsync && !page_flipping_supported()) {
Packit 631bab
		fprintf(stderr, "page flipping not supported by drm.\n");
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (test_vsync && !count) {
Packit 631bab
		fprintf(stderr, "page flipping requires at least one -s option.\n");
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	if (test_cursor && !cursor_supported()) {
Packit 631bab
		fprintf(stderr, "hw cursor not supported by drm.\n");
Packit 631bab
		return -1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	dev.resources = get_resources(&dev;;
Packit 631bab
	if (!dev.resources) {
Packit 631bab
		drmClose(dev.fd);
Packit 631bab
		return 1;
Packit 631bab
	}
Packit 631bab
Packit 631bab
	for (i = 0; i < count; i++) {
Packit 631bab
		if (pipe_resolve_connectors(&dev, &pipe_args[i]) < 0) {
Packit 631bab
			free_resources(dev.resources);
Packit 631bab
			drmClose(dev.fd);
Packit 631bab
			return 1;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
#define dump_resource(dev, res) if (res) dump_##res(dev)
Packit 631bab
Packit 631bab
	dump_resource(&dev, encoders);
Packit 631bab
	dump_resource(&dev, connectors);
Packit 631bab
	dump_resource(&dev, crtcs);
Packit 631bab
	dump_resource(&dev, planes);
Packit 631bab
	dump_resource(&dev, framebuffers);
Packit 631bab
Packit 631bab
	for (i = 0; i < prop_count; ++i)
Packit 631bab
		set_property(&dev, &prop_args[i]);
Packit 631bab
Packit 631bab
	if (dev.use_atomic) {
Packit 631bab
		dev.req = drmModeAtomicAlloc();
Packit 631bab
Packit 631bab
		if (count && plane_count) {
Packit 631bab
			uint64_t cap = 0;
Packit 631bab
Packit 631bab
			ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
Packit 631bab
			if (ret || cap == 0) {
Packit 631bab
				fprintf(stderr, "driver doesn't support the dumb buffer API\n");
Packit 631bab
				return 1;
Packit 631bab
			}
Packit 631bab
Packit 631bab
			atomic_set_mode(&dev, pipe_args, count);
Packit 631bab
			atomic_set_planes(&dev, plane_args, plane_count, false);
Packit 631bab
Packit 631bab
			ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
Packit 631bab
			if (ret) {
Packit 631bab
				fprintf(stderr, "Atomic Commit failed [1]\n");
Packit 631bab
				return 1;
Packit 631bab
			}
Packit 631bab
Packit 631bab
			gettimeofday(&pipe_args->start, NULL);
Packit 631bab
			pipe_args->swap_count = 0;
Packit 631bab
Packit 631bab
			while (test_vsync) {
Packit 631bab
				drmModeAtomicFree(dev.req);
Packit 631bab
				dev.req = drmModeAtomicAlloc();
Packit 631bab
				atomic_set_planes(&dev, plane_args, plane_count, true);
Packit 631bab
Packit 631bab
				ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
Packit 631bab
				if (ret) {
Packit 631bab
					fprintf(stderr, "Atomic Commit failed [2]\n");
Packit 631bab
					return 1;
Packit 631bab
				}
Packit 631bab
Packit 631bab
				pipe_args->swap_count++;
Packit 631bab
				if (pipe_args->swap_count == 60) {
Packit 631bab
					struct timeval end;
Packit 631bab
					double t;
Packit 631bab
Packit 631bab
					gettimeofday(&end, NULL);
Packit 631bab
					t = end.tv_sec + end.tv_usec * 1e-6 -
Packit 631bab
				    (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6);
Packit 631bab
					fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t);
Packit 631bab
					pipe_args->swap_count = 0;
Packit 631bab
					pipe_args->start = end;
Packit 631bab
				}
Packit 631bab
			}
Packit 631bab
Packit 631bab
			if (drop_master)
Packit 631bab
				drmDropMaster(dev.fd);
Packit 631bab
Packit 631bab
			getchar();
Packit 631bab
Packit 631bab
			drmModeAtomicFree(dev.req);
Packit 631bab
			dev.req = drmModeAtomicAlloc();
Packit 631bab
Packit 631bab
			atomic_clear_mode(&dev, pipe_args, count);
Packit 631bab
			atomic_clear_planes(&dev, plane_args, plane_count);
Packit 631bab
			ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
Packit 631bab
			if (ret) {
Packit 631bab
				fprintf(stderr, "Atomic Commit failed\n");
Packit 631bab
				return 1;
Packit 631bab
			}
Packit 631bab
Packit 631bab
			atomic_clear_FB(&dev, plane_args, plane_count);
Packit 631bab
		}
Packit 631bab
Packit 631bab
		drmModeAtomicFree(dev.req);
Packit 631bab
	} else {
Packit 631bab
		if (count || plane_count) {
Packit 631bab
			uint64_t cap = 0;
Packit 631bab
Packit 631bab
			ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
Packit 631bab
			if (ret || cap == 0) {
Packit 631bab
				fprintf(stderr, "driver doesn't support the dumb buffer API\n");
Packit 631bab
				return 1;
Packit 631bab
			}
Packit 631bab
Packit 631bab
			if (count)
Packit 631bab
				set_mode(&dev, pipe_args, count);
Packit 631bab
Packit 631bab
			if (plane_count)
Packit 631bab
				set_planes(&dev, plane_args, plane_count);
Packit 631bab
Packit 631bab
			if (test_cursor)
Packit 631bab
				set_cursors(&dev, pipe_args, count);
Packit 631bab
Packit 631bab
			if (test_vsync)
Packit 631bab
				test_page_flip(&dev, pipe_args, count);
Packit 631bab
Packit 631bab
			if (drop_master)
Packit 631bab
				drmDropMaster(dev.fd);
Packit 631bab
Packit 631bab
			getchar();
Packit 631bab
Packit 631bab
			if (test_cursor)
Packit 631bab
				clear_cursors(&dev;;
Packit 631bab
Packit 631bab
			if (plane_count)
Packit 631bab
				clear_planes(&dev, plane_args, plane_count);
Packit 631bab
Packit 631bab
			if (count)
Packit 631bab
				clear_mode(&dev;;
Packit 631bab
		}
Packit 631bab
	}
Packit 631bab
Packit 631bab
	free_resources(dev.resources);
Packit 631bab
Packit 631bab
	return 0;
Packit 631bab
}