2011-09-29 12:49:26 +02:00
|
|
|
/*
|
|
|
|
* Copyright © 2007 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
* Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Dave Airlie <airlied@redhat.com>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-08-26 20:06:23 +02:00
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
|
|
#include "dix-config.h"
|
2011-09-29 12:49:26 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/mman.h>
|
2012-07-25 07:38:34 +02:00
|
|
|
#include <unistd.h>
|
2014-12-09 20:17:30 +01:00
|
|
|
#include "dumb_bo.h"
|
2019-06-24 21:46:26 +02:00
|
|
|
#include "inputstr.h"
|
2011-09-29 12:49:26 +02:00
|
|
|
#include "xf86str.h"
|
|
|
|
#include "X11/Xatom.h"
|
2020-01-14 09:23:34 +01:00
|
|
|
#include "mi.h"
|
2011-09-29 12:49:26 +02:00
|
|
|
#include "micmap.h"
|
|
|
|
#include "xf86cmap.h"
|
|
|
|
#include "xf86DDC.h"
|
2018-02-28 02:19:38 +01:00
|
|
|
#include <drm_fourcc.h>
|
|
|
|
#include <drm_mode.h>
|
2011-09-29 12:49:26 +02:00
|
|
|
|
|
|
|
#include <xf86drm.h>
|
|
|
|
#include "xf86Crtc.h"
|
|
|
|
#include "drmmode_display.h"
|
2018-02-28 02:19:44 +01:00
|
|
|
#include "present.h"
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-01-20 02:06:42 +01:00
|
|
|
#include <cursorstr.h>
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
#include <X11/extensions/dpmsconst.h>
|
|
|
|
|
2014-02-12 19:06:51 +01:00
|
|
|
#include "driver.h"
|
|
|
|
|
2015-06-10 05:41:02 +02:00
|
|
|
static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
|
2016-05-02 22:54:56 +02:00
|
|
|
static PixmapPtr drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
|
|
|
|
int depth, int bitsPerPixel, int devKind,
|
|
|
|
void *pPixData);
|
2018-02-28 02:19:40 +01:00
|
|
|
|
|
|
|
static inline uint32_t *
|
|
|
|
formats_ptr(struct drm_format_modifier_blob *blob)
|
|
|
|
{
|
|
|
|
return (uint32_t *)(((char *)blob) + blob->formats_offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct drm_format_modifier *
|
|
|
|
modifiers_ptr(struct drm_format_modifier_blob *blob)
|
|
|
|
{
|
|
|
|
return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
|
|
|
|
}
|
|
|
|
|
2018-03-29 07:07:25 +02:00
|
|
|
static uint32_t
|
|
|
|
get_opaque_format(uint32_t format)
|
|
|
|
{
|
|
|
|
switch (format) {
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
|
|
|
return DRM_FORMAT_XRGB8888;
|
|
|
|
case DRM_FORMAT_ARGB2101010:
|
|
|
|
return DRM_FORMAT_XRGB2101010;
|
|
|
|
default:
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:42 +01:00
|
|
|
Bool
|
|
|
|
drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier)
|
|
|
|
{
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
|
|
|
|
int c, i, j;
|
|
|
|
|
2018-03-29 07:07:25 +02:00
|
|
|
/* BO are imported as opaque surface, so let's pretend there is no alpha */
|
|
|
|
format = get_opaque_format(format);
|
|
|
|
|
2018-02-28 02:19:42 +01:00
|
|
|
for (c = 0; c < xf86_config->num_crtc; c++) {
|
|
|
|
xf86CrtcPtr crtc = xf86_config->crtc[c];
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
Bool found = FALSE;
|
|
|
|
|
|
|
|
if (!crtc->enabled)
|
|
|
|
continue;
|
|
|
|
|
2018-04-04 03:49:02 +02:00
|
|
|
if (drmmode_crtc->num_formats == 0)
|
|
|
|
continue;
|
|
|
|
|
2018-02-28 02:19:42 +01:00
|
|
|
for (i = 0; i < drmmode_crtc->num_formats; i++) {
|
|
|
|
drmmode_format_ptr iter = &drmmode_crtc->formats[i];
|
|
|
|
|
|
|
|
if (iter->format != format)
|
|
|
|
continue;
|
|
|
|
|
2018-04-04 03:49:02 +02:00
|
|
|
if (modifier == DRM_FORMAT_MOD_INVALID ||
|
|
|
|
iter->num_modifiers == 0) {
|
2018-02-28 02:19:42 +01:00
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < iter->num_modifiers; j++) {
|
|
|
|
if (iter->modifiers[j] == modifier) {
|
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:41 +01:00
|
|
|
#ifdef GBM_BO_WITH_MODIFIERS
|
|
|
|
static uint32_t
|
|
|
|
get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
|
|
|
|
Bool enabled_crtc_only, Bool exclude_multiplane)
|
|
|
|
{
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
drmmode_ptr drmmode = &ms->drmmode;
|
|
|
|
int c, i, j, k, count_modifiers = 0;
|
|
|
|
uint64_t *tmp, *ret = NULL;
|
|
|
|
|
2018-03-29 07:07:25 +02:00
|
|
|
/* BOs are imported as opaque surfaces, so pretend the same thing here */
|
|
|
|
format = get_opaque_format(format);
|
|
|
|
|
2018-02-28 02:19:41 +01:00
|
|
|
*modifiers = NULL;
|
|
|
|
for (c = 0; c < xf86_config->num_crtc; c++) {
|
|
|
|
xf86CrtcPtr crtc = xf86_config->crtc[c];
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
if (enabled_crtc_only && !crtc->enabled)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (i = 0; i < drmmode_crtc->num_formats; i++) {
|
|
|
|
drmmode_format_ptr iter = &drmmode_crtc->formats[i];
|
|
|
|
|
|
|
|
if (iter->format != format)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < iter->num_modifiers; j++) {
|
|
|
|
Bool found = FALSE;
|
|
|
|
|
|
|
|
/* Don't choose multi-plane formats for our screen pixmap.
|
|
|
|
* These will get used with frontbuffer rendering, which will
|
|
|
|
* lead to worse-than-tearing with multi-plane formats, as the
|
|
|
|
* primary and auxiliary planes go out of sync. */
|
|
|
|
if (exclude_multiplane &&
|
|
|
|
gbm_device_get_format_modifier_plane_count(drmmode->gbm,
|
|
|
|
format,
|
|
|
|
iter->modifiers[j]) > 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = 0; k < count_modifiers; k++) {
|
|
|
|
if (iter->modifiers[j] == ret[k])
|
|
|
|
found = TRUE;
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
count_modifiers++;
|
|
|
|
tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
|
|
|
|
if (!tmp) {
|
|
|
|
free(ret);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = tmp;
|
|
|
|
ret[count_modifiers - 1] = iter->modifiers[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*modifiers = ret;
|
|
|
|
return count_modifiers;
|
|
|
|
}
|
2018-02-28 02:19:44 +01:00
|
|
|
|
|
|
|
static Bool
|
|
|
|
get_drawable_modifiers(DrawablePtr draw, uint32_t format,
|
|
|
|
uint32_t *num_modifiers, uint64_t **modifiers)
|
|
|
|
{
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
|
|
|
|
if (!present_can_window_flip((WindowPtr) draw) ||
|
|
|
|
!ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) {
|
|
|
|
*num_modifiers = 0;
|
|
|
|
*modifiers = NULL;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2018-02-28 02:19:41 +01:00
|
|
|
#endif
|
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
static Bool
|
|
|
|
drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
|
|
|
|
{
|
2017-10-27 16:11:53 +02:00
|
|
|
char **token = xstrtokenize(s, ", \t\n\r");
|
|
|
|
Bool ret = FALSE;
|
|
|
|
|
|
|
|
if (!token)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
for (int i = 0; token[i]; i++) {
|
|
|
|
if (strcmp(token[i], output_name) == 0)
|
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
free(token[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(token);
|
|
|
|
|
|
|
|
return ret;
|
2015-07-22 04:56:13 +02:00
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:37 +01:00
|
|
|
static uint64_t
|
|
|
|
drmmode_prop_get_value(drmmode_prop_info_ptr info,
|
|
|
|
drmModeObjectPropertiesPtr props,
|
|
|
|
uint64_t def)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (info->prop_id == 0)
|
|
|
|
return def;
|
|
|
|
|
|
|
|
for (i = 0; i < props->count_props; i++) {
|
|
|
|
unsigned int j;
|
|
|
|
|
|
|
|
if (props->props[i] != info->prop_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Simple (non-enum) types can return the value directly */
|
|
|
|
if (info->num_enum_values == 0)
|
|
|
|
return props->prop_values[i];
|
|
|
|
|
|
|
|
/* Map from raw value to enum value */
|
|
|
|
for (j = 0; j < info->num_enum_values; j++) {
|
|
|
|
if (!info->enum_values[j].valid)
|
|
|
|
continue;
|
|
|
|
if (info->enum_values[j].value != props->prop_values[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
drmmode_prop_info_update(drmmode_ptr drmmode,
|
|
|
|
drmmode_prop_info_ptr info,
|
|
|
|
unsigned int num_infos,
|
|
|
|
drmModeObjectProperties *props)
|
|
|
|
{
|
|
|
|
drmModePropertyRes *prop;
|
|
|
|
uint32_t valid_mask = 0;
|
|
|
|
unsigned i, j;
|
|
|
|
|
|
|
|
assert(num_infos <= 32 && "update return type");
|
|
|
|
|
|
|
|
for (i = 0; i < props->count_props; i++) {
|
|
|
|
Bool props_incomplete = FALSE;
|
|
|
|
unsigned int k;
|
|
|
|
|
|
|
|
for (j = 0; j < num_infos; j++) {
|
|
|
|
if (info[j].prop_id == props->props[i])
|
|
|
|
break;
|
|
|
|
if (!info[j].prop_id)
|
|
|
|
props_incomplete = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We've already discovered this property. */
|
|
|
|
if (j != num_infos)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* We haven't found this property ID, but as we've already
|
|
|
|
* found all known properties, we don't need to look any
|
|
|
|
* further. */
|
|
|
|
if (!props_incomplete)
|
|
|
|
break;
|
|
|
|
|
|
|
|
prop = drmModeGetProperty(drmmode->fd, props->props[i]);
|
|
|
|
if (!prop)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < num_infos; j++) {
|
|
|
|
if (!strcmp(prop->name, info[j].name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We don't know/care about this property. */
|
|
|
|
if (j == num_infos) {
|
|
|
|
drmModeFreeProperty(prop);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
info[j].prop_id = props->props[i];
|
|
|
|
valid_mask |= 1U << j;
|
|
|
|
|
|
|
|
if (info[j].num_enum_values == 0) {
|
|
|
|
drmModeFreeProperty(prop);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
|
|
|
|
xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
|
|
|
|
"expected property %s to be an enum,"
|
|
|
|
" but it is not; ignoring\n", prop->name);
|
|
|
|
drmModeFreeProperty(prop);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = 0; k < info[j].num_enum_values; k++) {
|
|
|
|
int l;
|
|
|
|
|
|
|
|
if (info[j].enum_values[k].valid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (l = 0; l < prop->count_enums; l++) {
|
|
|
|
if (!strcmp(prop->enums[l].name,
|
|
|
|
info[j].enum_values[k].name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l == prop->count_enums)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
info[j].enum_values[k].valid = TRUE;
|
|
|
|
info[j].enum_values[k].value = prop->enums[l].value;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeProperty(prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
return valid_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
|
|
|
|
const drmmode_prop_info_rec *src,
|
|
|
|
unsigned int num_props,
|
|
|
|
Bool copy_prop_id)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
memcpy(dst, src, num_props * sizeof(*dst));
|
|
|
|
|
|
|
|
for (i = 0; i < num_props; i++) {
|
|
|
|
unsigned int j;
|
|
|
|
|
|
|
|
if (copy_prop_id)
|
|
|
|
dst[i].prop_id = src[i].prop_id;
|
|
|
|
else
|
|
|
|
dst[i].prop_id = 0;
|
|
|
|
|
|
|
|
if (src[i].num_enum_values == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dst[i].enum_values =
|
|
|
|
malloc(src[i].num_enum_values *
|
|
|
|
sizeof(*dst[i].enum_values));
|
|
|
|
if (!dst[i].enum_values)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
memcpy(dst[i].enum_values, src[i].enum_values,
|
|
|
|
src[i].num_enum_values * sizeof(*dst[i].enum_values));
|
|
|
|
|
|
|
|
for (j = 0; j < dst[i].num_enum_values; j++)
|
|
|
|
dst[i].enum_values[j].valid = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
err:
|
|
|
|
while (i--)
|
|
|
|
free(dst[i].enum_values);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < num_props; i++)
|
|
|
|
free(info[i].enum_values);
|
|
|
|
}
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
static void
|
|
|
|
drmmode_ConvertToKMode(ScrnInfoPtr scrn,
|
|
|
|
drmModeModeInfo * kmode, DisplayModePtr mode);
|
|
|
|
|
|
|
|
|
2018-02-28 02:19:37 +01:00
|
|
|
static int
|
|
|
|
plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
|
|
|
|
enum drmmode_plane_property prop, uint64_t val)
|
|
|
|
{
|
|
|
|
drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
|
|
|
|
info->prop_id, val);
|
|
|
|
return (ret <= 0) ? -1 : 0;
|
|
|
|
}
|
2018-02-28 02:19:39 +01:00
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
static int
|
|
|
|
plane_add_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
|
|
|
|
uint32_t fb_id, int x, int y)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
|
|
|
|
fb_id);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
|
|
|
|
fb_id ? drmmode_crtc->mode_crtc->crtc_id : 0);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
|
|
|
|
crtc->mode.HDisplay << 16);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
|
|
|
|
crtc->mode.VDisplay << 16);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
|
|
|
|
crtc->mode.HDisplay);
|
|
|
|
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
|
|
|
|
crtc->mode.VDisplay);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:39 +01:00
|
|
|
static int
|
|
|
|
crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
|
|
|
|
enum drmmode_crtc_property prop, uint64_t val)
|
|
|
|
{
|
|
|
|
drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
info->prop_id, val);
|
|
|
|
return (ret <= 0) ? -1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
|
|
|
|
enum drmmode_connector_property prop, uint64_t val)
|
|
|
|
{
|
|
|
|
drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
|
|
|
|
info->prop_id, val);
|
|
|
|
return (ret <= 0) ? -1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
|
|
|
|
{
|
|
|
|
return memcmp(kmode, other, sizeof(*kmode));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
|
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_mode_ptr mode;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (drmmode_crtc->current_mode &&
|
|
|
|
drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
mode = calloc(sizeof(drmmode_mode_rec), 1);
|
|
|
|
if (!mode)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
mode->mode_info = mode_info;
|
|
|
|
ret = drmModeCreatePropertyBlob(ms->fd,
|
|
|
|
&mode->mode_info,
|
|
|
|
sizeof(mode->mode_info),
|
|
|
|
&mode->blob_id);
|
|
|
|
drmmode_crtc->current_mode = mode;
|
|
|
|
xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
static int
|
|
|
|
crtc_add_dpms_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
|
|
|
|
int new_dpms, Bool *active)
|
|
|
|
{
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
Bool crtc_active = FALSE;
|
|
|
|
int i;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[i];
|
2018-04-04 06:01:15 +02:00
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
2018-04-04 06:01:14 +02:00
|
|
|
|
2018-04-04 06:01:15 +02:00
|
|
|
if (output->crtc != crtc) {
|
|
|
|
if (drmmode_output->current_crtc == crtc) {
|
|
|
|
ret |= connector_add_prop(req, drmmode_output,
|
|
|
|
DRMMODE_CONNECTOR_CRTC_ID, 0);
|
|
|
|
}
|
2018-04-04 06:01:14 +02:00
|
|
|
continue;
|
2018-04-04 06:01:15 +02:00
|
|
|
}
|
2018-04-04 06:01:14 +02:00
|
|
|
|
|
|
|
if (drmmode_output->output_id == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (new_dpms == DPMSModeOn)
|
|
|
|
crtc_active = TRUE;
|
|
|
|
|
|
|
|
ret |= connector_add_prop(req, drmmode_output,
|
|
|
|
DRMMODE_CONNECTOR_CRTC_ID,
|
|
|
|
crtc_active ?
|
|
|
|
drmmode_crtc->mode_crtc->crtc_id : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (crtc_active) {
|
|
|
|
drmModeModeInfo kmode;
|
|
|
|
|
|
|
|
drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode);
|
|
|
|
ret |= drm_mode_ensure_blob(crtc, kmode);
|
|
|
|
|
|
|
|
ret |= crtc_add_prop(req, drmmode_crtc,
|
|
|
|
DRMMODE_CRTC_ACTIVE, 1);
|
|
|
|
ret |= crtc_add_prop(req, drmmode_crtc,
|
|
|
|
DRMMODE_CRTC_MODE_ID,
|
|
|
|
drmmode_crtc->current_mode->blob_id);
|
|
|
|
} else {
|
|
|
|
ret |= crtc_add_prop(req, drmmode_crtc,
|
|
|
|
DRMMODE_CRTC_ACTIVE, 0);
|
|
|
|
ret |= crtc_add_prop(req, drmmode_crtc,
|
|
|
|
DRMMODE_CRTC_MODE_ID, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (active)
|
|
|
|
*active = crtc_active;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:39 +01:00
|
|
|
static void
|
|
|
|
drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
|
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
|
|
|
if (mode->blob_id)
|
|
|
|
drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
|
|
|
|
xorg_list_del(&mode->entry);
|
|
|
|
free(mode);
|
|
|
|
}
|
2018-02-28 02:19:37 +01:00
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
static int
|
|
|
|
drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)
|
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
2018-02-28 02:19:39 +01:00
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
return ms->atomic_modeset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
int ret;
|
|
|
|
|
2018-06-28 02:29:42 +02:00
|
|
|
*fb_id = 0;
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
if (drmmode_crtc->prime_pixmap) {
|
|
|
|
if (!drmmode->reverse_prime_offload_mode) {
|
|
|
|
msPixmapPrivPtr ppriv =
|
|
|
|
msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap);
|
|
|
|
*fb_id = ppriv->fb_id;
|
|
|
|
*x = 0;
|
|
|
|
} else
|
|
|
|
*x = drmmode_crtc->prime_pixmap_x;
|
|
|
|
*y = 0;
|
|
|
|
}
|
|
|
|
else if (drmmode_crtc->rotate_fb_id) {
|
|
|
|
*fb_id = drmmode_crtc->rotate_fb_id;
|
|
|
|
*x = *y = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*fb_id = drmmode->fb_id;
|
|
|
|
*x = crtc->x;
|
|
|
|
*y = crtc->y;
|
|
|
|
}
|
|
|
|
|
2018-04-05 17:47:39 +02:00
|
|
|
if (*fb_id == 0) {
|
2018-04-04 06:01:14 +02:00
|
|
|
ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
|
|
|
|
&drmmode->fb_id);
|
|
|
|
if (ret < 0) {
|
|
|
|
ErrorF("failed to add fb %d\n", ret);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
*fb_id = drmmode->fb_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
drmmode_set_dpms(ScrnInfoPtr scrn, int dpms, int flags)
|
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
|
|
|
|
drmModeAtomicReq *req = drmModeAtomicAlloc();
|
|
|
|
uint32_t mode_flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
|
|
int ret = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(ms->atomic_modeset);
|
|
|
|
|
|
|
|
if (!req)
|
|
|
|
return;
|
|
|
|
|
2018-04-04 06:01:15 +02:00
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[i];
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
|
|
|
|
if (output->crtc != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = connector_add_prop(req, drmmode_output,
|
|
|
|
DRMMODE_CONNECTOR_CRTC_ID, 0);
|
|
|
|
}
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
for (i = 0; i < xf86_config->num_crtc; i++) {
|
|
|
|
xf86CrtcPtr crtc = xf86_config->crtc[i];
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
Bool active = FALSE;
|
|
|
|
|
|
|
|
ret |= crtc_add_dpms_props(req, crtc, dpms, &active);
|
|
|
|
|
|
|
|
if (dpms == DPMSModeOn && active && drmmode_crtc->need_modeset) {
|
|
|
|
uint32_t fb_id;
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
|
|
|
|
continue;
|
|
|
|
ret |= plane_add_props(req, crtc, fb_id, x, y);
|
|
|
|
drmmode_crtc->need_modeset = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
drmModeAtomicCommit(ms->fd, req, mode_flags, NULL);
|
|
|
|
drmModeAtomicFree(req);
|
|
|
|
|
|
|
|
ms->pending_modeset = TRUE;
|
|
|
|
xf86DPMSSet(scrn, dpms, flags);
|
|
|
|
ms->pending_modeset = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
drmmode_output_disable(xf86OutputPtr output)
|
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(output->scrn);
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
2018-06-08 02:30:34 +02:00
|
|
|
xf86CrtcPtr crtc = drmmode_output->current_crtc;
|
2018-04-04 06:01:14 +02:00
|
|
|
drmModeAtomicReq *req = drmModeAtomicAlloc();
|
|
|
|
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
2018-06-08 02:30:34 +02:00
|
|
|
int ret = 0;
|
2018-04-04 06:01:14 +02:00
|
|
|
|
|
|
|
assert(ms->atomic_modeset);
|
|
|
|
|
|
|
|
if (!req)
|
|
|
|
return 1;
|
|
|
|
|
2018-06-08 02:30:34 +02:00
|
|
|
ret |= connector_add_prop(req, drmmode_output,
|
|
|
|
DRMMODE_CONNECTOR_CRTC_ID, 0);
|
|
|
|
if (crtc)
|
|
|
|
ret |= crtc_add_dpms_props(req, crtc, DPMSModeOff, NULL);
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
if (ret == 0)
|
|
|
|
ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
|
|
|
|
|
2018-04-04 06:01:15 +02:00
|
|
|
if (ret == 0)
|
|
|
|
drmmode_output->current_crtc = NULL;
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
drmModeAtomicFree(req);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
drmmode_crtc_disable(xf86CrtcPtr crtc)
|
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmModeAtomicReq *req = drmModeAtomicAlloc();
|
|
|
|
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
assert(ms->atomic_modeset);
|
|
|
|
|
|
|
|
if (!req)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
ret |= crtc_add_prop(req, drmmode_crtc,
|
|
|
|
DRMMODE_CRTC_ACTIVE, 0);
|
|
|
|
ret |= crtc_add_prop(req, drmmode_crtc,
|
|
|
|
DRMMODE_CRTC_MODE_ID, 0);
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
|
|
|
|
|
|
|
|
drmModeAtomicFree(req);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
|
2018-02-28 02:19:37 +01:00
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2018-02-28 02:19:39 +01:00
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
2018-04-04 06:01:14 +02:00
|
|
|
drmModeModeInfo kmode;
|
2018-02-28 02:19:39 +01:00
|
|
|
int output_count = 0;
|
|
|
|
uint32_t *output_ids = NULL;
|
2018-04-04 06:01:14 +02:00
|
|
|
uint32_t fb_id;
|
|
|
|
int x, y;
|
2018-02-28 02:19:39 +01:00
|
|
|
int i, ret = 0;
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
|
|
|
|
return 1;
|
2018-02-28 02:19:37 +01:00
|
|
|
|
2019-11-22 17:58:12 +01:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
/* Make sure any pending drawing will be visible in a new scanout buffer */
|
|
|
|
if (drmmode->glamor)
|
2020-02-10 18:57:42 +01:00
|
|
|
glamor_finish(crtc->scrn->pScreen);
|
2019-11-22 17:58:12 +01:00
|
|
|
#endif
|
|
|
|
|
2018-02-28 02:19:37 +01:00
|
|
|
if (ms->atomic_modeset) {
|
|
|
|
drmModeAtomicReq *req = drmModeAtomicAlloc();
|
2018-04-04 06:01:14 +02:00
|
|
|
Bool active;
|
|
|
|
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
2018-02-28 02:19:37 +01:00
|
|
|
|
|
|
|
if (!req)
|
|
|
|
return 1;
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
ret |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active);
|
|
|
|
ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
|
2018-02-28 02:19:39 +01:00
|
|
|
|
2018-04-04 06:01:15 +02:00
|
|
|
/* Orphaned CRTCs need to be disabled right now in atomic mode */
|
|
|
|
for (i = 0; i < xf86_config->num_crtc; i++) {
|
|
|
|
xf86CrtcPtr other_crtc = xf86_config->crtc[i];
|
|
|
|
drmmode_crtc_private_ptr other_drmmode_crtc = other_crtc->driver_private;
|
|
|
|
int lost_outputs = 0;
|
|
|
|
int remaining_outputs = 0;
|
2018-04-05 15:58:40 +02:00
|
|
|
int j;
|
2018-04-04 06:01:15 +02:00
|
|
|
|
|
|
|
if (other_crtc == crtc)
|
|
|
|
continue;
|
|
|
|
|
2018-04-05 15:58:40 +02:00
|
|
|
for (j = 0; j < xf86_config->num_output; j++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[j];
|
2018-04-04 06:01:15 +02:00
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
|
|
|
|
if (drmmode_output->current_crtc == other_crtc) {
|
|
|
|
if (output->crtc == crtc)
|
|
|
|
lost_outputs++;
|
|
|
|
else
|
|
|
|
remaining_outputs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lost_outputs > 0 && remaining_outputs == 0) {
|
|
|
|
ret |= crtc_add_prop(req, other_drmmode_crtc,
|
|
|
|
DRMMODE_CRTC_ACTIVE, 0);
|
|
|
|
ret |= crtc_add_prop(req, other_drmmode_crtc,
|
|
|
|
DRMMODE_CRTC_MODE_ID, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
if (test_only)
|
|
|
|
flags |= DRM_MODE_ATOMIC_TEST_ONLY;
|
2018-02-28 02:19:37 +01:00
|
|
|
|
|
|
|
if (ret == 0)
|
2018-04-04 06:01:14 +02:00
|
|
|
ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
|
2018-02-28 02:19:37 +01:00
|
|
|
|
2018-04-04 06:01:15 +02:00
|
|
|
if (ret == 0 && !test_only) {
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[i];
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
|
|
|
|
if (output->crtc == crtc)
|
|
|
|
drmmode_output->current_crtc = crtc;
|
|
|
|
else if (drmmode_output->current_crtc == crtc)
|
|
|
|
drmmode_output->current_crtc = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:37 +01:00
|
|
|
drmModeAtomicFree(req);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:39 +01:00
|
|
|
output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
|
|
|
|
if (!output_ids)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[i];
|
|
|
|
drmmode_output_private_ptr drmmode_output;
|
|
|
|
|
|
|
|
if (output->crtc != crtc)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
drmmode_output = output->driver_private;
|
|
|
|
if (drmmode_output->output_id == -1)
|
|
|
|
continue;
|
|
|
|
output_ids[output_count] = drmmode_output->output_id;
|
|
|
|
output_count++;
|
|
|
|
}
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode);
|
2018-02-28 02:19:39 +01:00
|
|
|
ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
fb_id, x, y, output_ids, output_count, &kmode);
|
|
|
|
|
|
|
|
free(output_ids);
|
|
|
|
return ret;
|
2018-02-28 02:19:37 +01:00
|
|
|
}
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
int
|
|
|
|
drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
|
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (ms->atomic_modeset) {
|
|
|
|
drmModeAtomicReq *req = drmModeAtomicAlloc();
|
|
|
|
|
|
|
|
if (!req)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
ret = plane_add_props(req, crtc, fb_id, crtc->x, crtc->y);
|
|
|
|
flags |= DRM_MODE_ATOMIC_NONBLOCK;
|
|
|
|
if (ret == 0)
|
|
|
|
ret = drmModeAtomicCommit(ms->fd, req, flags, data);
|
|
|
|
drmModeAtomicFree(req);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
fb_id, flags, data);
|
|
|
|
}
|
2018-02-28 02:19:37 +01:00
|
|
|
|
modesetting: Implement page flipping support for Present.
Based on code by Keith Packard, Eric Anholt, and Jason Ekstrand.
v2:
- Fix double free and flip_count underrun (caught by Mario Kleiner).
- Don't leak flip_vblank_event on the error_out path (Mario).
- Use the updated ms_flush_drm_events API (Mario, Ken).
v3: Hack around DPMS shenanigans. If all monitors are DPMS off, then
there is no active framebuffer; attempting to pageflip will hit the
error_undo paths, causing us to drmModeRmFB with no framebuffer,
which confuses the kernel into doing full modesets and generally
breaks things. To avoid this, make ms_present_check_flip check that
some CRTCs are enabled and DPMS on. This is an ugly hack that would
get better with atomic modesetting, or some core Present work.
v4:
- Don't do pageflipping if CRTCs are rotated (caught by Jason Ekstrand).
- Make pageflipping optional (Option "PageFlip" in xorg.conf.d), but
enabled by default.
v5: Initialize num_crtcs_on to 0 (caught by Michel Dänzer).
[airlied: took over]
v6: merge async flip support from Mario Kleiner
free sequence after failed vblank queue
handle unflip while DPMS'ed off (Michel)
move flip tracking into its own structure, and
fix up reference counting issues, and add comments.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2015-01-27 06:29:23 +01:00
|
|
|
int
|
2014-12-10 00:20:44 +01:00
|
|
|
drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2014-12-09 21:43:57 +01:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
if (bo->gbm) {
|
|
|
|
gbm_bo_destroy(bo->gbm);
|
|
|
|
bo->gbm = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
if (bo->dumb) {
|
|
|
|
ret = dumb_bo_destroy(drmmode->fd, bo->dumb);
|
|
|
|
if (ret == 0)
|
|
|
|
bo->dumb = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
modesetting: Implement page flipping support for Present.
Based on code by Keith Packard, Eric Anholt, and Jason Ekstrand.
v2:
- Fix double free and flip_count underrun (caught by Mario Kleiner).
- Don't leak flip_vblank_event on the error_out path (Mario).
- Use the updated ms_flush_drm_events API (Mario, Ken).
v3: Hack around DPMS shenanigans. If all monitors are DPMS off, then
there is no active framebuffer; attempting to pageflip will hit the
error_undo paths, causing us to drmModeRmFB with no framebuffer,
which confuses the kernel into doing full modesets and generally
breaks things. To avoid this, make ms_present_check_flip check that
some CRTCs are enabled and DPMS on. This is an ugly hack that would
get better with atomic modesetting, or some core Present work.
v4:
- Don't do pageflipping if CRTCs are rotated (caught by Jason Ekstrand).
- Make pageflipping optional (Option "PageFlip" in xorg.conf.d), but
enabled by default.
v5: Initialize num_crtcs_on to 0 (caught by Michel Dänzer).
[airlied: took over]
v6: merge async flip support from Mario Kleiner
free sequence after failed vblank queue
handle unflip while DPMS'ed off (Michel)
move flip tracking into its own structure, and
fix up reference counting issues, and add comments.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2015-01-27 06:29:23 +01:00
|
|
|
uint32_t
|
2014-12-10 00:20:44 +01:00
|
|
|
drmmode_bo_get_pitch(drmmode_bo *bo)
|
|
|
|
{
|
2014-12-09 21:43:57 +01:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
if (bo->gbm)
|
|
|
|
return gbm_bo_get_stride(bo->gbm);
|
|
|
|
#endif
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
return bo->dumb->pitch;
|
|
|
|
}
|
|
|
|
|
2015-01-14 00:08:36 +01:00
|
|
|
static Bool
|
|
|
|
drmmode_bo_has_bo(drmmode_bo *bo)
|
|
|
|
{
|
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
if (bo->gbm)
|
|
|
|
return TRUE;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return bo->dumb != NULL;
|
|
|
|
}
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
uint32_t
|
|
|
|
drmmode_bo_get_handle(drmmode_bo *bo)
|
|
|
|
{
|
2014-12-09 21:43:57 +01:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
if (bo->gbm)
|
|
|
|
return gbm_bo_get_handle(bo->gbm).u32;
|
|
|
|
#endif
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
return bo->dumb->handle;
|
|
|
|
}
|
|
|
|
|
2015-01-14 00:08:36 +01:00
|
|
|
static void *
|
|
|
|
drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
if (bo->gbm)
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (bo->dumb->ptr)
|
|
|
|
return bo->dumb->ptr;
|
|
|
|
|
|
|
|
ret = dumb_bo_map(drmmode->fd, bo->dumb);
|
|
|
|
if (ret)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return bo->dumb->ptr;
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:38 +01:00
|
|
|
int
|
|
|
|
drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
|
|
|
|
uint32_t *fb_id)
|
|
|
|
{
|
|
|
|
#ifdef GBM_BO_WITH_MODIFIERS
|
2018-04-20 19:59:40 +02:00
|
|
|
modesettingPtr ms = modesettingPTR(drmmode->scrn);
|
|
|
|
if (bo->gbm && ms->kms_has_modifiers &&
|
2018-02-28 02:19:38 +01:00
|
|
|
gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
|
|
|
|
int num_fds;
|
|
|
|
|
|
|
|
num_fds = gbm_bo_get_plane_count(bo->gbm);
|
|
|
|
if (num_fds > 0) {
|
|
|
|
int i;
|
|
|
|
uint32_t format;
|
|
|
|
uint32_t handles[4];
|
|
|
|
uint32_t strides[4];
|
|
|
|
uint32_t offsets[4];
|
|
|
|
uint64_t modifiers[4];
|
|
|
|
|
|
|
|
memset(handles, 0, sizeof(handles));
|
|
|
|
memset(strides, 0, sizeof(strides));
|
|
|
|
memset(offsets, 0, sizeof(offsets));
|
|
|
|
memset(modifiers, 0, sizeof(modifiers));
|
|
|
|
|
|
|
|
format = gbm_bo_get_format(bo->gbm);
|
2018-03-29 07:07:25 +02:00
|
|
|
format = get_opaque_format(format);
|
2018-02-28 02:19:38 +01:00
|
|
|
for (i = 0; i < num_fds; i++) {
|
|
|
|
handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
|
|
|
|
strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
|
|
|
|
offsets[i] = gbm_bo_get_offset(bo->gbm, i);
|
|
|
|
modifiers[i] = gbm_bo_get_modifier(bo->gbm);
|
|
|
|
}
|
|
|
|
|
|
|
|
return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
|
|
|
|
format, handles, strides,
|
|
|
|
offsets, modifiers, fb_id,
|
|
|
|
DRM_MODE_FB_MODIFIERS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return drmModeAddFB(drmmode->fd, bo->width, bo->height,
|
2018-07-19 14:38:19 +02:00
|
|
|
drmmode->scrn->depth, drmmode->kbpp,
|
2018-02-28 02:19:38 +01:00
|
|
|
drmmode_bo_get_pitch(bo),
|
|
|
|
drmmode_bo_get_handle(bo), fb_id);
|
|
|
|
}
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
static Bool
|
|
|
|
drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
|
|
|
|
unsigned width, unsigned height, unsigned bpp)
|
|
|
|
{
|
2018-02-28 02:19:38 +01:00
|
|
|
bo->width = width;
|
|
|
|
bo->height = height;
|
|
|
|
|
2014-12-09 21:43:57 +01:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
if (drmmode->glamor) {
|
2019-06-24 21:49:59 +02:00
|
|
|
#ifdef GBM_BO_WITH_MODIFIERS
|
|
|
|
uint32_t num_modifiers;
|
|
|
|
uint64_t *modifiers = NULL;
|
|
|
|
#endif
|
2018-04-16 08:37:45 +02:00
|
|
|
uint32_t format;
|
|
|
|
|
2020-03-06 18:22:19 +01:00
|
|
|
switch (drmmode->scrn->depth) {
|
|
|
|
case 15:
|
|
|
|
format = GBM_FORMAT_ARGB1555;
|
|
|
|
break;
|
|
|
|
case 16:
|
2020-03-05 15:02:26 +01:00
|
|
|
format = GBM_FORMAT_RGB565;
|
2020-03-06 18:22:19 +01:00
|
|
|
break;
|
|
|
|
case 30:
|
|
|
|
format = GBM_FORMAT_ARGB2101010;
|
|
|
|
break;
|
|
|
|
default:
|
2018-04-16 08:37:45 +02:00
|
|
|
format = GBM_FORMAT_ARGB8888;
|
2020-03-06 18:22:19 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-04-16 08:37:45 +02:00
|
|
|
|
2018-02-28 02:19:41 +01:00
|
|
|
#ifdef GBM_BO_WITH_MODIFIERS
|
|
|
|
num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
|
|
|
|
FALSE, TRUE);
|
|
|
|
if (num_modifiers > 0 &&
|
|
|
|
!(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
|
|
|
|
bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
|
|
|
|
format, modifiers,
|
|
|
|
num_modifiers);
|
|
|
|
free(modifiers);
|
2018-04-04 17:16:33 +02:00
|
|
|
if (bo->gbm) {
|
|
|
|
bo->used_modifiers = TRUE;
|
2018-02-28 02:19:41 +01:00
|
|
|
return TRUE;
|
2018-04-04 17:16:33 +02:00
|
|
|
}
|
2018-02-28 02:19:41 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
|
2014-12-09 21:43:57 +01:00
|
|
|
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
|
2018-04-04 17:16:33 +02:00
|
|
|
bo->used_modifiers = FALSE;
|
2014-12-09 21:43:57 +01:00
|
|
|
return bo->gbm != NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
bo->dumb = dumb_bo_create(drmmode->fd, width, height, bpp);
|
|
|
|
return bo->dumb != NULL;
|
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
Bool
|
|
|
|
drmmode_SetSlaveBO(PixmapPtr ppix,
|
|
|
|
drmmode_ptr drmmode, int fd_handle, int pitch, int size)
|
2012-07-19 06:12:59 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
|
2012-07-19 06:12:59 +02:00
|
|
|
|
2016-05-06 02:46:14 +02:00
|
|
|
if (fd_handle == -1) {
|
|
|
|
dumb_bo_destroy(drmmode->fd, ppriv->backing_bo);
|
|
|
|
ppriv->backing_bo = NULL;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
ppriv->backing_bo =
|
2013-12-30 09:25:37 +01:00
|
|
|
dumb_get_bo_from_fd(drmmode->fd, fd_handle, pitch, size);
|
2014-10-08 09:39:15 +02:00
|
|
|
if (!ppriv->backing_bo)
|
|
|
|
return FALSE;
|
2012-07-19 06:12:59 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
close(fd_handle);
|
|
|
|
return TRUE;
|
2012-07-19 06:12:59 +02:00
|
|
|
}
|
|
|
|
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
static Bool
|
|
|
|
drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc,
|
|
|
|
drmmode_ptr drmmode)
|
|
|
|
{
|
2020-07-05 23:00:50 +02:00
|
|
|
ScreenPtr primary = crtc->randr_crtc->pScreen->current_primary;
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
|
2020-07-05 23:00:50 +02:00
|
|
|
if (primary->PresentSharedPixmap(ppix)) {
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
/* Success, queue flip to back target */
|
|
|
|
if (drmmode_SharedPixmapFlip(ppix, crtc, drmmode))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
|
|
|
|
"drmmode_SharedPixmapFlip() failed, trying again next vblank\n");
|
|
|
|
|
|
|
|
return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Failed to present, try again on next vblank after damage */
|
2020-07-05 23:00:50 +02:00
|
|
|
if (primary->RequestSharedPixmapNotifyDamage) {
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
|
|
|
|
|
|
|
|
/* Set flag first in case we are immediately notified */
|
|
|
|
ppriv->wait_for_damage = TRUE;
|
|
|
|
|
2020-07-05 23:00:50 +02:00
|
|
|
if (primary->RequestSharedPixmapNotifyDamage(ppix))
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
ppriv->wait_for_damage = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Damage notification not available, just try again on vblank */
|
|
|
|
return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct vblank_event_args {
|
|
|
|
PixmapPtr frontTarget;
|
|
|
|
PixmapPtr backTarget;
|
|
|
|
xf86CrtcPtr crtc;
|
|
|
|
drmmode_ptr drmmode;
|
|
|
|
Bool flip;
|
|
|
|
};
|
|
|
|
static void
|
|
|
|
drmmode_SharedPixmapVBlankEventHandler(uint64_t frame, uint64_t usec,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct vblank_event_args *args = data;
|
|
|
|
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = args->crtc->driver_private;
|
|
|
|
|
|
|
|
if (args->flip) {
|
|
|
|
/* frontTarget is being displayed, update crtc to reflect */
|
|
|
|
drmmode_crtc->prime_pixmap = args->frontTarget;
|
|
|
|
drmmode_crtc->prime_pixmap_back = args->backTarget;
|
|
|
|
|
|
|
|
/* Safe to present on backTarget, no longer displayed */
|
|
|
|
drmmode_SharedPixmapPresent(args->backTarget, args->crtc, args->drmmode);
|
|
|
|
} else {
|
|
|
|
/* backTarget is still being displayed, present on frontTarget */
|
|
|
|
drmmode_SharedPixmapPresent(args->frontTarget, args->crtc, args->drmmode);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_SharedPixmapVBlankEventAbort(void *data)
|
|
|
|
{
|
|
|
|
struct vblank_event_args *args = data;
|
|
|
|
|
|
|
|
msGetPixmapPriv(args->drmmode, args->frontTarget)->flip_seq = 0;
|
|
|
|
|
|
|
|
free(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix, xf86CrtcPtr crtc,
|
|
|
|
drmmode_ptr drmmode)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
|
|
|
|
struct vblank_event_args *event_args;
|
|
|
|
|
|
|
|
if (ppix == drmmode_crtc->prime_pixmap)
|
|
|
|
return FALSE; /* Already flipped to this pixmap */
|
|
|
|
if (ppix != drmmode_crtc->prime_pixmap_back)
|
|
|
|
return FALSE; /* Pixmap is not a scanout pixmap for CRTC */
|
|
|
|
|
|
|
|
event_args = calloc(1, sizeof(*event_args));
|
|
|
|
if (!event_args)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
event_args->frontTarget = ppix;
|
|
|
|
event_args->backTarget = drmmode_crtc->prime_pixmap;
|
|
|
|
event_args->crtc = crtc;
|
|
|
|
event_args->drmmode = drmmode;
|
|
|
|
event_args->flip = FALSE;
|
|
|
|
|
|
|
|
ppriv->flip_seq =
|
|
|
|
ms_drm_queue_alloc(crtc, event_args,
|
|
|
|
drmmode_SharedPixmapVBlankEventHandler,
|
|
|
|
drmmode_SharedPixmapVBlankEventAbort);
|
|
|
|
|
2017-09-29 17:48:33 +02:00
|
|
|
return ms_queue_vblank(crtc, MS_QUEUE_RELATIVE, 1, NULL, ppriv->flip_seq);
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
|
|
|
|
drmmode_ptr drmmode)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
msPixmapPrivPtr ppriv_front = msGetPixmapPriv(drmmode, frontTarget);
|
|
|
|
|
|
|
|
struct vblank_event_args *event_args;
|
|
|
|
|
|
|
|
event_args = calloc(1, sizeof(*event_args));
|
|
|
|
if (!event_args)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
event_args->frontTarget = frontTarget;
|
|
|
|
event_args->backTarget = drmmode_crtc->prime_pixmap;
|
|
|
|
event_args->crtc = crtc;
|
|
|
|
event_args->drmmode = drmmode;
|
|
|
|
event_args->flip = TRUE;
|
|
|
|
|
|
|
|
ppriv_front->flip_seq =
|
|
|
|
ms_drm_queue_alloc(crtc, event_args,
|
|
|
|
drmmode_SharedPixmapVBlankEventHandler,
|
|
|
|
drmmode_SharedPixmapVBlankEventAbort);
|
|
|
|
|
|
|
|
if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
ppriv_front->fb_id, DRM_MODE_PAGE_FLIP_EVENT,
|
|
|
|
(void *)(intptr_t) ppriv_front->flip_seq) < 0) {
|
|
|
|
ms_drm_abort_seq(crtc->scrn, ppriv_front->flip_seq);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
if (!drmmode_crtc->enable_flipping)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (drmmode_crtc->flipping_active)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
drmmode_crtc->flipping_active =
|
|
|
|
drmmode_SharedPixmapPresent(drmmode_crtc->prime_pixmap_back,
|
|
|
|
crtc, drmmode);
|
|
|
|
|
|
|
|
return drmmode_crtc->flipping_active;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
|
|
|
|
{
|
|
|
|
uint32_t seq;
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
if (!drmmode_crtc->flipping_active)
|
|
|
|
return;
|
|
|
|
|
|
|
|
drmmode_crtc->flipping_active = FALSE;
|
|
|
|
|
|
|
|
/* Abort page flip event handler on prime_pixmap */
|
|
|
|
seq = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap)->flip_seq;
|
|
|
|
if (seq)
|
|
|
|
ms_drm_abort_seq(crtc->scrn, seq);
|
|
|
|
|
|
|
|
/* Abort page flip event handler on prime_pixmap_back */
|
|
|
|
seq = msGetPixmapPriv(drmmode,
|
|
|
|
drmmode_crtc->prime_pixmap_back)->flip_seq;
|
|
|
|
if (seq)
|
|
|
|
ms_drm_abort_seq(crtc->scrn, seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
|
|
|
|
PixmapPtr *target);
|
|
|
|
|
|
|
|
Bool
|
|
|
|
drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
|
|
|
|
PixmapPtr front, PixmapPtr back)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
drmmode_crtc->enable_flipping = TRUE;
|
|
|
|
|
|
|
|
/* Set front scanout pixmap */
|
|
|
|
drmmode_crtc->enable_flipping &=
|
|
|
|
drmmode_set_target_scanout_pixmap(crtc, front,
|
|
|
|
&drmmode_crtc->prime_pixmap);
|
|
|
|
if (!drmmode_crtc->enable_flipping)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Set back scanout pixmap */
|
|
|
|
drmmode_crtc->enable_flipping &=
|
|
|
|
drmmode_set_target_scanout_pixmap(crtc, back,
|
|
|
|
&drmmode_crtc->prime_pixmap_back);
|
|
|
|
if (!drmmode_crtc->enable_flipping) {
|
|
|
|
drmmode_set_target_scanout_pixmap(crtc, NULL,
|
|
|
|
&drmmode_crtc->prime_pixmap);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
drmmode_crtc->enable_flipping = FALSE;
|
|
|
|
|
|
|
|
drmmode_FiniSharedPixmapFlipping(crtc, drmmode);
|
|
|
|
|
|
|
|
drmmode_set_target_scanout_pixmap(crtc, NULL, &drmmode_crtc->prime_pixmap);
|
|
|
|
|
|
|
|
drmmode_set_target_scanout_pixmap(crtc, NULL,
|
|
|
|
&drmmode_crtc->prime_pixmap_back);
|
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static void
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_ConvertFromKMode(ScrnInfoPtr scrn,
|
|
|
|
drmModeModeInfo * kmode, DisplayModePtr mode)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
memset(mode, 0, sizeof(DisplayModeRec));
|
|
|
|
mode->status = MODE_OK;
|
|
|
|
|
|
|
|
mode->Clock = kmode->clock;
|
|
|
|
|
|
|
|
mode->HDisplay = kmode->hdisplay;
|
|
|
|
mode->HSyncStart = kmode->hsync_start;
|
|
|
|
mode->HSyncEnd = kmode->hsync_end;
|
|
|
|
mode->HTotal = kmode->htotal;
|
|
|
|
mode->HSkew = kmode->hskew;
|
|
|
|
|
|
|
|
mode->VDisplay = kmode->vdisplay;
|
|
|
|
mode->VSyncStart = kmode->vsync_start;
|
|
|
|
mode->VSyncEnd = kmode->vsync_end;
|
|
|
|
mode->VTotal = kmode->vtotal;
|
|
|
|
mode->VScan = kmode->vscan;
|
|
|
|
|
|
|
|
mode->Flags = kmode->flags; //& FLAG_BITS;
|
|
|
|
mode->name = strdup(kmode->name);
|
|
|
|
|
|
|
|
if (kmode->type & DRM_MODE_TYPE_DRIVER)
|
|
|
|
mode->type = M_T_DRIVER;
|
|
|
|
if (kmode->type & DRM_MODE_TYPE_PREFERRED)
|
|
|
|
mode->type |= M_T_PREFERRED;
|
|
|
|
xf86SetModeCrtc(mode, scrn->adjustFlags);
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_ConvertToKMode(ScrnInfoPtr scrn,
|
|
|
|
drmModeModeInfo * kmode, DisplayModePtr mode)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
memset(kmode, 0, sizeof(*kmode));
|
|
|
|
|
|
|
|
kmode->clock = mode->Clock;
|
|
|
|
kmode->hdisplay = mode->HDisplay;
|
|
|
|
kmode->hsync_start = mode->HSyncStart;
|
|
|
|
kmode->hsync_end = mode->HSyncEnd;
|
|
|
|
kmode->htotal = mode->HTotal;
|
|
|
|
kmode->hskew = mode->HSkew;
|
|
|
|
|
|
|
|
kmode->vdisplay = mode->VDisplay;
|
|
|
|
kmode->vsync_start = mode->VSyncStart;
|
|
|
|
kmode->vsync_end = mode->VSyncEnd;
|
|
|
|
kmode->vtotal = mode->VTotal;
|
|
|
|
kmode->vscan = mode->VScan;
|
|
|
|
|
|
|
|
kmode->flags = mode->Flags; //& FLAG_BITS;
|
|
|
|
if (mode->name)
|
|
|
|
strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
|
|
|
|
kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
|
|
|
|
{
|
2018-04-04 06:01:14 +02:00
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
2014-12-19 02:55:29 +01:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2018-11-14 02:14:10 +01:00
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
2018-04-04 06:01:14 +02:00
|
|
|
|
|
|
|
/* XXX Check if DPMS mode is already the right one */
|
|
|
|
|
2014-12-19 02:55:29 +01:00
|
|
|
drmmode_crtc->dpms_mode = mode;
|
2018-04-04 06:01:14 +02:00
|
|
|
|
2018-11-14 02:14:10 +01:00
|
|
|
if (ms->atomic_modeset) {
|
|
|
|
if (mode != DPMSModeOn && !ms->pending_modeset)
|
|
|
|
drmmode_crtc_disable(crtc);
|
|
|
|
} else if (crtc->enabled == FALSE) {
|
|
|
|
drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
0, 0, 0, NULL, 0, NULL);
|
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2017-05-16 20:37:14 +02:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
2011-09-29 12:49:26 +02:00
|
|
|
static PixmapPtr
|
2016-05-02 22:54:56 +02:00
|
|
|
create_pixmap_for_fbcon(drmmode_ptr drmmode, ScrnInfoPtr pScrn, int fbcon_id)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2016-05-02 22:54:56 +02:00
|
|
|
PixmapPtr pixmap = drmmode->fbcon_pixmap;
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeFBPtr fbcon;
|
2016-05-02 22:54:56 +02:00
|
|
|
ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
|
2019-11-18 22:46:44 +01:00
|
|
|
modesettingPtr ms = modesettingPTR(pScrn);
|
2016-05-02 22:54:56 +02:00
|
|
|
Bool ret;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2016-05-02 22:54:56 +02:00
|
|
|
if (pixmap)
|
|
|
|
return pixmap;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2016-05-02 22:54:56 +02:00
|
|
|
fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
|
2014-10-08 09:39:15 +02:00
|
|
|
if (fbcon == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2016-05-02 22:54:56 +02:00
|
|
|
if (fbcon->depth != pScrn->depth ||
|
|
|
|
fbcon->width != pScrn->virtualX ||
|
|
|
|
fbcon->height != pScrn->virtualY)
|
|
|
|
goto out_free_fb;
|
|
|
|
|
|
|
|
pixmap = drmmode_create_pixmap_header(pScreen, fbcon->width,
|
|
|
|
fbcon->height, fbcon->depth,
|
|
|
|
fbcon->bpp, fbcon->pitch, NULL);
|
2014-10-08 09:39:15 +02:00
|
|
|
if (!pixmap)
|
2016-05-02 22:54:56 +02:00
|
|
|
goto out_free_fb;
|
|
|
|
|
2019-11-18 22:46:44 +01:00
|
|
|
ret = ms->glamor.egl_create_textured_pixmap(pixmap, fbcon->handle,
|
|
|
|
fbcon->pitch);
|
2016-05-02 22:54:56 +02:00
|
|
|
if (!ret) {
|
|
|
|
FreePixmap(pixmap);
|
|
|
|
pixmap = NULL;
|
|
|
|
}
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2016-05-02 22:54:56 +02:00
|
|
|
drmmode->fbcon_pixmap = pixmap;
|
|
|
|
out_free_fb:
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeFreeFB(fbcon);
|
|
|
|
return pixmap;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
2016-05-05 21:41:58 +02:00
|
|
|
#endif
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2016-05-02 22:54:56 +02:00
|
|
|
void
|
|
|
|
drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
|
|
|
|
{
|
2017-05-16 20:37:14 +02:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
2016-05-02 22:54:56 +02:00
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
|
|
|
|
ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
|
|
|
|
PixmapPtr src, dst;
|
|
|
|
int fbcon_id = 0;
|
|
|
|
GCPtr gc;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < xf86_config->num_crtc; i++) {
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
|
|
|
|
if (drmmode_crtc->mode_crtc->buffer_id)
|
|
|
|
fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fbcon_id)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (fbcon_id == drmmode->fb_id) {
|
|
|
|
/* in some rare case there might be no fbcon and we might already
|
|
|
|
* be the one with the current fb to avoid a false deadlck in
|
|
|
|
* kernel ttm code just do nothing as anyway there is nothing
|
|
|
|
* to do
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
|
|
|
|
if (!src)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dst = pScreen->GetScreenPixmap(pScreen);
|
|
|
|
|
|
|
|
gc = GetScratchGC(pScrn->depth, pScreen);
|
|
|
|
ValidateGC(&dst->drawable, gc);
|
|
|
|
|
|
|
|
(*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
|
|
|
|
pScrn->virtualX, pScrn->virtualY, 0, 0);
|
|
|
|
|
|
|
|
FreeScratchGC(gc);
|
|
|
|
|
|
|
|
pScreen->canDoBGNoneRoot = TRUE;
|
|
|
|
|
|
|
|
if (drmmode->fbcon_pixmap)
|
|
|
|
pScrn->pScreen->DestroyPixmap(drmmode->fbcon_pixmap);
|
|
|
|
drmmode->fbcon_pixmap = NULL;
|
2016-05-05 21:41:58 +02:00
|
|
|
#endif
|
2016-05-02 22:54:56 +02:00
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
|
|
|
|
static Bool
|
|
|
|
drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
|
2014-10-08 09:39:15 +02:00
|
|
|
Rotation rotation, int x, int y)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2018-04-04 06:01:14 +02:00
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
int saved_x, saved_y;
|
|
|
|
Rotation saved_rotation;
|
|
|
|
DisplayModeRec saved_mode;
|
|
|
|
Bool ret = TRUE;
|
2018-04-04 06:01:14 +02:00
|
|
|
Bool can_test;
|
2014-10-08 09:39:15 +02:00
|
|
|
int i;
|
2017-12-17 21:23:02 +01:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
saved_mode = crtc->mode;
|
|
|
|
saved_x = crtc->x;
|
|
|
|
saved_y = crtc->y;
|
|
|
|
saved_rotation = crtc->rotation;
|
|
|
|
|
|
|
|
if (mode) {
|
|
|
|
crtc->mode = *mode;
|
|
|
|
crtc->x = x;
|
|
|
|
crtc->y = y;
|
|
|
|
crtc->rotation = rotation;
|
|
|
|
|
|
|
|
if (!xf86CrtcRotate(crtc)) {
|
|
|
|
goto done;
|
|
|
|
}
|
2018-02-28 02:19:39 +01:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
|
|
|
|
crtc->gamma_blue, crtc->gamma_size);
|
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
can_test = drmmode_crtc_can_test_mode(crtc);
|
|
|
|
if (drmmode_crtc_set_mode(crtc, can_test)) {
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
|
2015-10-29 14:58:09 +01:00
|
|
|
"failed to set mode: %s\n", strerror(errno));
|
|
|
|
ret = FALSE;
|
|
|
|
goto done;
|
|
|
|
} else
|
2014-10-08 09:39:15 +02:00
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
if (crtc->scrn->pScreen)
|
|
|
|
xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
|
2014-12-19 02:55:29 +01:00
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
ms->pending_modeset = TRUE;
|
modesetting: Implement page flipping support for Present.
Based on code by Keith Packard, Eric Anholt, and Jason Ekstrand.
v2:
- Fix double free and flip_count underrun (caught by Mario Kleiner).
- Don't leak flip_vblank_event on the error_out path (Mario).
- Use the updated ms_flush_drm_events API (Mario, Ken).
v3: Hack around DPMS shenanigans. If all monitors are DPMS off, then
there is no active framebuffer; attempting to pageflip will hit the
error_undo paths, causing us to drmModeRmFB with no framebuffer,
which confuses the kernel into doing full modesets and generally
breaks things. To avoid this, make ms_present_check_flip check that
some CRTCs are enabled and DPMS on. This is an ugly hack that would
get better with atomic modesetting, or some core Present work.
v4:
- Don't do pageflipping if CRTCs are rotated (caught by Jason Ekstrand).
- Make pageflipping optional (Option "PageFlip" in xorg.conf.d), but
enabled by default.
v5: Initialize num_crtcs_on to 0 (caught by Michel Dänzer).
[airlied: took over]
v6: merge async flip support from Mario Kleiner
free sequence after failed vblank queue
handle unflip while DPMS'ed off (Michel)
move flip tracking into its own structure, and
fix up reference counting issues, and add comments.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2015-01-27 06:29:23 +01:00
|
|
|
drmmode_crtc->need_modeset = FALSE;
|
2014-12-19 02:55:29 +01:00
|
|
|
crtc->funcs->dpms(crtc, DPMSModeOn);
|
|
|
|
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
if (drmmode_crtc->prime_pixmap_back)
|
|
|
|
drmmode_InitSharedPixmapFlipping(crtc, drmmode);
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
/* go through all the outputs and force DPMS them back on? */
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[i];
|
2015-01-28 08:35:21 +01:00
|
|
|
drmmode_output_private_ptr drmmode_output;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
if (output->crtc != crtc)
|
|
|
|
continue;
|
|
|
|
|
2015-01-28 08:35:21 +01:00
|
|
|
drmmode_output = output->driver_private;
|
|
|
|
if (drmmode_output->output_id == -1)
|
|
|
|
continue;
|
2014-10-08 09:39:15 +02:00
|
|
|
output->funcs->dpms(output, DPMSModeOn);
|
|
|
|
}
|
2018-04-04 06:01:14 +02:00
|
|
|
|
|
|
|
/* if we only tested the mode previously, really set it now */
|
|
|
|
if (can_test)
|
|
|
|
drmmode_crtc_set_mode(crtc, FALSE);
|
|
|
|
ms->pending_modeset = FALSE;
|
2014-10-08 09:39:15 +02:00
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
done:
|
|
|
|
if (!ret) {
|
|
|
|
crtc->x = saved_x;
|
|
|
|
crtc->y = saved_y;
|
|
|
|
crtc->rotation = saved_rotation;
|
|
|
|
crtc->mode = saved_mode;
|
2015-10-29 14:58:11 +01:00
|
|
|
} else
|
2014-10-08 09:39:15 +02:00
|
|
|
crtc->active = TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
return ret;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2015-02-16 17:00:54 +01:00
|
|
|
static Bool
|
2014-12-17 08:14:34 +01:00
|
|
|
drmmode_set_cursor(xf86CrtcPtr crtc)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2014-12-17 08:14:34 +01:00
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
2014-10-08 09:39:15 +02:00
|
|
|
uint32_t handle = drmmode_crtc->cursor_bo->handle;
|
2014-12-17 08:14:34 +01:00
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
2016-09-30 15:18:45 +02:00
|
|
|
CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen);
|
2016-09-16 17:51:25 +02:00
|
|
|
int ret = -EINVAL;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2017-06-23 01:29:13 +02:00
|
|
|
if (cursor == NullCursor)
|
|
|
|
return TRUE;
|
|
|
|
|
2016-09-30 15:18:45 +02:00
|
|
|
ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
handle, ms->cursor_width, ms->cursor_height,
|
|
|
|
cursor->bits->xhot, cursor->bits->yhot);
|
2014-12-17 08:14:34 +01:00
|
|
|
|
2016-09-30 15:18:45 +02:00
|
|
|
/* -EINVAL can mean that an old kernel supports drmModeSetCursor but
|
|
|
|
* not drmModeSetCursor2, though it can mean other things too. */
|
2016-09-16 17:51:25 +02:00
|
|
|
if (ret == -EINVAL)
|
|
|
|
ret = drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
handle, ms->cursor_width, ms->cursor_height);
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2016-09-30 15:18:45 +02:00
|
|
|
/* -ENXIO normally means that the current drm driver supports neither
|
|
|
|
* cursor_set nor cursor_set2. Disable hardware cursor support for
|
|
|
|
* the rest of the session in that case. */
|
|
|
|
if (ret == -ENXIO) {
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
|
|
|
|
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
|
|
|
|
|
|
|
|
cursor_info->MaxWidth = cursor_info->MaxHeight = 0;
|
|
|
|
drmmode_crtc->drmmode->sw_cursor = TRUE;
|
2016-09-30 15:18:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ret)
|
2014-10-08 09:39:15 +02:00
|
|
|
/* fallback to swcursor */
|
2015-02-16 17:00:54 +01:00
|
|
|
return FALSE;
|
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2015-02-16 17:00:54 +01:00
|
|
|
static void drmmode_hide_cursor(xf86CrtcPtr crtc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The load_cursor_argb_check driver hook.
|
|
|
|
*
|
|
|
|
* Sets the hardware cursor by calling the drmModeSetCursor2 ioctl.
|
|
|
|
* On failure, returns FALSE indicating that the X server should fall
|
|
|
|
* back to software cursors.
|
|
|
|
*/
|
|
|
|
static Bool
|
|
|
|
drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2014-12-17 08:14:34 +01:00
|
|
|
int i;
|
|
|
|
uint32_t *ptr;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-12-17 08:14:34 +01:00
|
|
|
/* cursor should be mapped already */
|
|
|
|
ptr = (uint32_t *) (drmmode_crtc->cursor_bo->ptr);
|
|
|
|
|
|
|
|
for (i = 0; i < ms->cursor_width * ms->cursor_height; i++)
|
|
|
|
ptr[i] = image[i]; // cpu_to_le32(image[i]);
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2016-09-30 08:02:09 +02:00
|
|
|
if (drmmode_crtc->cursor_up)
|
|
|
|
return drmmode_set_cursor(crtc);
|
2015-02-16 17:00:54 +01:00
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-12-17 08:14:34 +01:00
|
|
|
drmmode_hide_cursor(xf86CrtcPtr crtc)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
|
2014-12-17 08:14:34 +01:00
|
|
|
drmmode_crtc->cursor_up = FALSE;
|
|
|
|
drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
|
2014-10-08 09:39:15 +02:00
|
|
|
ms->cursor_width, ms->cursor_height);
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2016-09-30 08:02:09 +02:00
|
|
|
static Bool
|
2014-12-17 08:14:34 +01:00
|
|
|
drmmode_show_cursor(xf86CrtcPtr crtc)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_crtc->cursor_up = TRUE;
|
2016-09-30 08:02:09 +02:00
|
|
|
return drmmode_set_cursor(crtc);
|
2014-12-17 08:14:34 +01:00
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static void
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
|
|
|
|
uint16_t * blue, int size)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
size, red, green, blue);
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2012-07-19 06:12:59 +02:00
|
|
|
static Bool
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
|
|
|
|
PixmapPtr *target)
|
2015-06-10 05:41:02 +02:00
|
|
|
{
|
|
|
|
ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
|
|
|
|
PixmapPtr screenpix = screen->GetScreenPixmap(screen);
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2016-06-01 14:59:38 +02:00
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
2015-06-10 05:41:02 +02:00
|
|
|
int c, total_width = 0, max_height = 0, this_x = 0;
|
|
|
|
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
if (*target) {
|
2017-04-14 12:08:41 +02:00
|
|
|
PixmapStopDirtyTracking(&(*target)->drawable, screenpix);
|
2016-06-17 05:06:50 +02:00
|
|
|
if (drmmode->fb_id) {
|
|
|
|
drmModeRmFB(drmmode->fd, drmmode->fb_id);
|
|
|
|
drmmode->fb_id = 0;
|
2016-06-01 14:59:38 +02:00
|
|
|
}
|
2015-06-10 05:41:02 +02:00
|
|
|
drmmode_crtc->prime_pixmap_x = 0;
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
*target = NULL;
|
2015-06-10 05:41:02 +02:00
|
|
|
}
|
2016-06-17 05:06:50 +02:00
|
|
|
|
|
|
|
if (!ppix)
|
|
|
|
return TRUE;
|
|
|
|
|
2015-06-10 05:41:02 +02:00
|
|
|
/* iterate over all the attached crtcs to work out the bounding box */
|
|
|
|
for (c = 0; c < xf86_config->num_crtc; c++) {
|
|
|
|
xf86CrtcPtr iter = xf86_config->crtc[c];
|
|
|
|
if (!iter->enabled && iter != crtc)
|
|
|
|
continue;
|
|
|
|
if (iter == crtc) {
|
|
|
|
this_x = total_width;
|
|
|
|
total_width += ppix->drawable.width;
|
|
|
|
if (max_height < ppix->drawable.height)
|
|
|
|
max_height = ppix->drawable.height;
|
|
|
|
} else {
|
|
|
|
total_width += iter->mode.HDisplay;
|
|
|
|
if (max_height < iter->mode.VDisplay)
|
|
|
|
max_height = iter->mode.VDisplay;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (total_width != screenpix->drawable.width ||
|
|
|
|
max_height != screenpix->drawable.height) {
|
|
|
|
|
|
|
|
if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
screenpix = screen->GetScreenPixmap(screen);
|
|
|
|
screen->width = screenpix->drawable.width = total_width;
|
|
|
|
screen->height = screenpix->drawable.height = max_height;
|
|
|
|
}
|
|
|
|
drmmode_crtc->prime_pixmap_x = this_x;
|
2017-04-14 12:08:41 +02:00
|
|
|
PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0,
|
|
|
|
RR_Rotate_0);
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
*target = ppix;
|
2015-06-10 05:41:02 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix,
|
|
|
|
PixmapPtr *target)
|
2012-07-19 06:12:59 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
msPixmapPrivPtr ppriv;
|
|
|
|
void *ptr;
|
|
|
|
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
if (*target) {
|
|
|
|
ppriv = msGetPixmapPriv(drmmode, *target);
|
2016-06-17 05:06:50 +02:00
|
|
|
drmModeRmFB(drmmode->fd, ppriv->fb_id);
|
|
|
|
ppriv->fb_id = 0;
|
2020-07-05 23:00:50 +02:00
|
|
|
if (ppriv->secondary_damage) {
|
|
|
|
DamageUnregister(ppriv->secondary_damage);
|
|
|
|
ppriv->secondary_damage = NULL;
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
}
|
2016-07-07 23:50:03 +02:00
|
|
|
*target = NULL;
|
2016-06-17 05:06:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!ppix)
|
|
|
|
return TRUE;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
ppriv = msGetPixmapPriv(drmmode, ppix);
|
2020-07-05 23:00:50 +02:00
|
|
|
if (!ppriv->secondary_damage) {
|
|
|
|
ppriv->secondary_damage = DamageCreate(NULL, NULL,
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
DamageReportNone,
|
|
|
|
TRUE,
|
|
|
|
crtc->randr_crtc->pScreen,
|
|
|
|
NULL);
|
2014-10-08 09:39:15 +02:00
|
|
|
}
|
2020-07-05 23:00:50 +02:00
|
|
|
ptr = drmmode_map_secondary_bo(drmmode, ppriv);
|
2014-10-08 09:39:15 +02:00
|
|
|
ppix->devPrivate.ptr = ptr;
|
2020-07-05 23:00:50 +02:00
|
|
|
DamageRegister(&ppix->drawable, ppriv->secondary_damage);
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
if (ppriv->fb_id == 0) {
|
|
|
|
drmModeAddFB(drmmode->fd, ppix->drawable.width,
|
|
|
|
ppix->drawable.height,
|
|
|
|
ppix->drawable.depth,
|
|
|
|
ppix->drawable.bitsPerPixel,
|
|
|
|
ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id);
|
|
|
|
}
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
*target = ppix;
|
2014-10-08 09:39:15 +02:00
|
|
|
return TRUE;
|
2012-07-19 06:12:59 +02:00
|
|
|
}
|
|
|
|
|
2015-06-10 05:41:02 +02:00
|
|
|
static Bool
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
|
|
|
|
PixmapPtr *target)
|
2015-06-10 05:41:02 +02:00
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
|
|
|
|
if (drmmode->reverse_prime_offload_mode)
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target);
|
2015-06-10 05:41:02 +02:00
|
|
|
else
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target);
|
|
|
|
}
|
2016-06-17 05:06:49 +02:00
|
|
|
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
static Bool
|
|
|
|
drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2016-06-17 05:06:49 +02:00
|
|
|
|
modesetting: Implement PRIME syncing as a sink
Implements (Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage, the sink functions for PRIME synchronization and
double buffering. Allows modesetting driver to be used as a sink with PRIME
synchronization.
Changes dispatch_slave_dirty to flush damage from both scanout pixmaps.
Changes drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target. Then, treat *target as it did prime_pixmap. This allows
me to use it to explicitly set both prime_pixmap and prime_pixmap_back
individually. drmmode_set_scanout_pixmap() without the extra parameter
remains to cover the single-buffered case, but only works if we aren't
already double buffered.
driver.c:
Add plumbing for rr(Enable/Disable)SharedPixmapFlipping and
SharedPixmapNotifyDamage.
Change dispatch_dirty_crtc to dispatch_dirty_pixmap, which functions the
same but flushes damage associated with a ppriv instead of the crtc, and
chanage dispatch_slave_dirty to use it on both scanout pixmaps if
applicable.
drmmode_display.h:
Add flip_seq field to msPixmapPrivRec to keep track of the event handler
associated with a given pixmap, if any.
Add wait_for_damage field to msPixmapPrivRec to keep track if we have
requested a damage notification from the source.
Add enable_flipping field to drmmode_crtc_private_rec to keep track if
flipping is enabled or disabled.
Add prime_pixmap_back to drmmode_crtc_private_rec to keep track of back
buffer internally.
Add declarations for drmmode_SetupPageFlipFence(),
drmmode_EnableSharedPixmapFlipping(),
drmmode_DisableSharedPixmapFlipping, drmmode_SharedPixmapFlip(), and
drmmode_SharedPixmapPresentOnVBlank().
Move slave damage from crtc to ppriv.
drmmode_display.c:
Change drmmode_set_scanout_pixmap*() functions to
drmmode_set_target_scanout_pixmap*() that take an additional parameter
PixmapPtr *target for explicitly setting different scanout pixmaps.
Add definitions for functions drmmode_SharedPixmapFlip(),
drmmode_SharedPixmapPresentOnVBlank(),
drmmode_SharedPixmapPresent(),
drmmode_SharedPixmapVBlankEventHandler(),
drmmode_SharedPixmapVBlankEventAbort(),
drmmode_EnableSharedPixmapFlipping(), and
drmmode_DisableSharedPixmapFlipping,
drmmode_InitSharedPixmapFlipping(), and
drmmode_FiniSharedPixmapFlipping, along with struct
vblank_event_args.
The control flow is as follows:
pScrPriv->rrEnableSharedPixmapFlipping() makes its way to
drmmode_EnableSharedPixmapFlipping(), which sets enable_flipping to
TRUE and sets both scanout pixmaps prime_pixmap and
prime_pixmap_back.
When setting a mode, if prime_pixmap is defined, modesetting
driver will call drmmode_InitSharedPixmapFlipping(), which if
flipping is enabled will call drmmode_SharedPixmapPresent() on
scanout_pixmap_back.
drmmode_SharedPixmapPresent() requests that for the source to
present on the given buffer using master->PresentSharedPixmap(). If
it succeeds, it will then attempt to flip to that buffer using
drmmode_SharedPixmapFlip(). Flipping shouldn't fail, but if it
does, it will raise a warning and try drmmode_SharedPixmapPresent()
again on the next vblank using
drmmode_SharedPixmapPresentOnVBlank().
master->PresentSharedPixmap() could fail, in most cases because
there is no outstanding damage on the mscreenpix tracked by the
shared pixmap. In this case, drmmode_SharedPixmapPresent() will
attempt to use master->RequestSharedPixmapNotifyDamage() to request
for the source driver to call slave->SharedPixmapNotifyDamage() in
response to damage on mscreenpix. This will ultimately call
into drmmode_SharedPixmapPresentOnVBlank() to retry
drmmode_SharedPixmapPresent() on the next vblank after
accumulating damage.
drmmode_SharedPixmapFlip() sets up page flip event handler by
packing struct vblank_event_args with the necessary parameters, and
registering drmmode_SharedPixmapVBlankEventHandler() and
drmmode_SharedPixmapVBlankEventAbort() with the modesetting DRM
event handler queue. Then, it uses the drmModePageFlip() to flip on
the next vblank and raise an event.
drmmode_SharedPixmapPresentOnVBlank() operates similarly to
drmmode_SharedPixmapFlip(), but uses drmWaitVBlank() instead of
drmModePageFlip() to raise the event without flipping.
On the next vblank, DRM will raise an event that will ultimately be
handled by drmmode_SharedPixmapVBlankEventHandler(). If we flipped,
it will update prime_pixmap and prime_pixmap_back to reflect that
frontTarget is now being displayed, and use
drmmode_SharedPixmapPresent(backTarget) to start the process again
on the now-hidden shared pixmap. If we didn't flip, it will just
use drmmode_SharedPixmapPresent(frontTarget) to start the process
again on the still-hidden shared pixmap.
Note that presentation generally happens asynchronously, so with
these changes alone tearing is reduced, but we can't always
guarantee that the present will finish before the flip. These
changes are meant to be paired with changes to the sink DRM driver
that makes flips wait on fences attached to dmabuf backed buffers.
The source driver is responsible for attaching the fences and
signaling them when presentation is finished.
Note that because presentation is requested in response to a
vblank, PRIME sources will now conform to the sink's refresh rate.
At teardown, pScrPriv->rrDisableSharedPixmapFlipping() will be
called, making its way to drmmode_FiniSharedPixmapFlipping().
There, the event handlers for prime_pixmap and prime_pixmap_back
are aborted, freeing the left over parameter structure. Then,
prime_pixmap and prime_pixmap back are unset as scanout pixmaps.
Register and tear down slave damage per-scanout pixmap instead of
per-crtc.
v1: Initial commit
v2: Renamed PresentTrackedFlippingPixmap to PresentSharedPixmap
Renamed flipSeq to flip_seq
Warn if flip failed
Use SharedPixmapNotifyDamage to retry on next vblank after damage
v3: Refactor to accomodate moving (rr)StartFlippingPixmapTracking and
(rr)(Enable/Disable)SharedPixmapFlipping to rrScrPrivRec from ScreenRec
Do damage tracking on both scanout pixmaps
v4: Tweaks to commit message
v5: Revise for internal storage of prime pixmap ptrs
Move disabling for reverse PRIME from source commit to here
Use drmmode_set_target_scanout_pixmap*() to set scanout pixmaps
internally to EnableSharedPixmapFlipping().
Don't support flipping if ms->drmmode.pageflip == FALSE.
Move flipping_active check to this commit
v6: Rebase onto ToT
v7: Unchanged
Reviewed-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Goins <agoins@nvidia.com>
2016-06-17 05:06:52 +02:00
|
|
|
/* Use DisableSharedPixmapFlipping before switching to single buf */
|
|
|
|
if (drmmode_crtc->enable_flipping)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return drmmode_set_target_scanout_pixmap(crtc, ppix,
|
|
|
|
&drmmode_crtc->prime_pixmap);
|
2015-06-10 05:41:02 +02:00
|
|
|
}
|
|
|
|
|
2019-11-18 18:06:28 +01:00
|
|
|
static void
|
|
|
|
drmmode_clear_pixmap(PixmapPtr pixmap)
|
|
|
|
{
|
|
|
|
ScreenPtr screen = pixmap->drawable.pScreen;
|
|
|
|
GCPtr gc;
|
2019-11-22 18:32:38 +01:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(screen));
|
|
|
|
|
|
|
|
if (ms->drmmode.glamor) {
|
|
|
|
ms->glamor.clear_pixmap(pixmap);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2019-11-18 18:06:28 +01:00
|
|
|
|
|
|
|
gc = GetScratchGC(pixmap->drawable.depth, screen);
|
|
|
|
if (gc) {
|
|
|
|
miClearDrawable(&pixmap->drawable, gc);
|
|
|
|
FreeScratchGC(gc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
static void *
|
|
|
|
drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
|
2013-02-07 03:24:20 +01:00
|
|
|
{
|
2015-01-14 00:08:37 +01:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
|
2015-07-22 18:14:06 +02:00
|
|
|
width, height, drmmode->kbpp)) {
|
2015-01-14 00:08:37 +01:00
|
|
|
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
|
|
|
|
"Couldn't allocate shadow memory for rotated CRTC\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-06-15 08:57:12 +02:00
|
|
|
ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
|
|
|
|
&drmmode_crtc->rotate_fb_id);
|
2015-01-14 00:08:37 +01:00
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
ErrorF("failed to add rotate fb\n");
|
|
|
|
drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
if (drmmode->gbm)
|
|
|
|
return drmmode_crtc->rotate_bo.gbm;
|
|
|
|
#endif
|
|
|
|
return drmmode_crtc->rotate_bo.dumb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PixmapPtr
|
|
|
|
drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
|
|
|
|
int depth, int bitsPerPixel, int devKind,
|
|
|
|
void *pPixData)
|
|
|
|
{
|
|
|
|
PixmapPtr pixmap;
|
|
|
|
|
|
|
|
/* width and height of 0 means don't allocate any pixmap data */
|
|
|
|
pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
|
|
|
|
|
|
|
|
if (pixmap) {
|
|
|
|
if ((*pScreen->ModifyPixmapHeader)(pixmap, width, height, depth,
|
|
|
|
bitsPerPixel, devKind, pPixData))
|
|
|
|
return pixmap;
|
|
|
|
(*pScreen->DestroyPixmap)(pixmap);
|
|
|
|
}
|
|
|
|
return NullPixmap;
|
2013-02-07 03:24:20 +01:00
|
|
|
}
|
|
|
|
|
2015-01-14 00:08:37 +01:00
|
|
|
static Bool
|
|
|
|
drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
static PixmapPtr
|
|
|
|
drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
|
2013-02-07 03:24:20 +01:00
|
|
|
{
|
2015-01-14 00:08:37 +01:00
|
|
|
ScrnInfoPtr scrn = crtc->scrn;
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
uint32_t rotate_pitch;
|
|
|
|
PixmapPtr rotate_pixmap;
|
|
|
|
void *pPixData = NULL;
|
|
|
|
|
|
|
|
if (!data) {
|
|
|
|
data = drmmode_shadow_allocate(crtc, width, height);
|
|
|
|
if (!data) {
|
|
|
|
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
|
|
|
|
"Couldn't allocate shadow pixmap for rotated CRTC\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
|
|
|
|
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
|
|
|
|
"Couldn't allocate shadow pixmap for rotated CRTC\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
|
2019-05-16 21:24:01 +02:00
|
|
|
rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo);
|
2015-01-14 00:08:37 +01:00
|
|
|
|
|
|
|
rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
|
|
|
|
width, height,
|
|
|
|
scrn->depth,
|
2015-07-22 18:14:06 +02:00
|
|
|
drmmode->kbpp,
|
2015-01-14 00:08:37 +01:00
|
|
|
rotate_pitch,
|
|
|
|
pPixData);
|
|
|
|
|
|
|
|
if (rotate_pixmap == NULL) {
|
|
|
|
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
|
|
|
|
"Couldn't allocate shadow pixmap for rotated CRTC\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
|
|
|
|
|
|
|
|
return rotate_pixmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
|
|
|
|
if (rotate_pixmap) {
|
|
|
|
rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
|
|
|
|
drmmode_crtc->rotate_fb_id = 0;
|
|
|
|
|
|
|
|
drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
|
|
|
|
memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
|
|
|
|
}
|
2013-02-07 03:24:20 +01:00
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:37 +01:00
|
|
|
static void
|
|
|
|
drmmode_crtc_destroy(xf86CrtcPtr crtc)
|
|
|
|
{
|
2018-02-28 02:19:39 +01:00
|
|
|
drmmode_mode_ptr iterator, next;
|
2018-02-28 02:19:37 +01:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2018-03-22 19:47:21 +01:00
|
|
|
modesettingPtr ms = modesettingPTR(crtc->scrn);
|
|
|
|
|
|
|
|
if (!ms->atomic_modeset)
|
|
|
|
return;
|
2018-02-28 02:19:37 +01:00
|
|
|
|
|
|
|
drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
|
2018-02-28 02:19:39 +01:00
|
|
|
xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
|
|
|
|
drm_mode_destroy(crtc, iterator);
|
|
|
|
}
|
2018-02-28 02:19:37 +01:00
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
|
|
|
|
.dpms = drmmode_crtc_dpms,
|
|
|
|
.set_mode_major = drmmode_set_mode_major,
|
|
|
|
.set_cursor_colors = drmmode_set_cursor_colors,
|
|
|
|
.set_cursor_position = drmmode_set_cursor_position,
|
2016-09-30 08:02:09 +02:00
|
|
|
.show_cursor_check = drmmode_show_cursor,
|
2011-09-29 12:49:26 +02:00
|
|
|
.hide_cursor = drmmode_hide_cursor,
|
2015-02-16 17:00:54 +01:00
|
|
|
.load_cursor_argb_check = drmmode_load_cursor_argb_check,
|
2011-09-29 12:49:26 +02:00
|
|
|
|
|
|
|
.gamma_set = drmmode_crtc_gamma_set,
|
2018-02-28 02:19:37 +01:00
|
|
|
.destroy = drmmode_crtc_destroy,
|
2012-07-19 06:12:59 +02:00
|
|
|
.set_scanout_pixmap = drmmode_set_scanout_pixmap,
|
2013-02-07 03:24:20 +01:00
|
|
|
.shadow_allocate = drmmode_shadow_allocate,
|
|
|
|
.shadow_create = drmmode_shadow_create,
|
2015-01-14 00:08:37 +01:00
|
|
|
.shadow_destroy = drmmode_shadow_destroy,
|
2011-09-29 12:49:26 +02:00
|
|
|
};
|
|
|
|
|
modesetting: Add support for DRI2 with glamor.
This is derived from the intel driver DRI2 code, with swapchain and
pageflipping dropped, functions renamed, and vblank event management
shared code moved to a vblank.c for reuse by Present.
This allows AIGLX to load, which means that you get appropriate
visuals exposed in GL, along with many extensions under
direct-rendering that require presence in GLX (which aren't supported
in glxdriswrast.c).
v2: Drop unused header includes in pageflip.c, wrap in #ifdef GLAMOR.
Drop triple-buffering, which was totally broken in practice (I'll
try to fix this later). Fix up some style nits. Document the
general flow of pageflipping and why, rename the DRI2 frame event
type enums to reflect what they're for, and handle them in a
single switch statement so you can understand the state machine
more easily.
v3: Drop pageflipping entirely -- it's unstable on my Intel laptop
(not that the normal 2D driver is stable with pageflipping for
me), and I won't get it fixed before the merge window. It now
passes all of the OML_sync_control tests from Jamey and Theo
(except for occasional warns in timing -fullscreen -divisor 2).
v4: Fix doxygen at the top of vblank.c
Signed-off-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2013-12-31 02:23:38 +01:00
|
|
|
static uint32_t
|
|
|
|
drmmode_crtc_vblank_pipe(int crtc_id)
|
|
|
|
{
|
|
|
|
if (crtc_id > 1)
|
|
|
|
return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT;
|
|
|
|
else if (crtc_id > 0)
|
|
|
|
return DRM_VBLANK_SECONDARY;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:37 +01:00
|
|
|
static Bool
|
|
|
|
is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
|
|
|
|
{
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
|
|
|
|
int c;
|
|
|
|
|
|
|
|
for (c = 0; c < xf86_config->num_crtc; c++) {
|
|
|
|
xf86CrtcPtr iter = xf86_config->crtc[c];
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
|
|
|
|
if (drmmode_crtc->plane_id == plane_id)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:40 +01:00
|
|
|
/**
|
|
|
|
* Populates the formats array, and the modifiers of each format for a drm_plane.
|
|
|
|
*/
|
|
|
|
static Bool
|
|
|
|
populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
|
|
|
|
uint32_t blob_id)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
unsigned i, j;
|
|
|
|
drmModePropertyBlobRes *blob;
|
|
|
|
struct drm_format_modifier_blob *fmt_mod_blob;
|
|
|
|
uint32_t *blob_formats;
|
|
|
|
struct drm_format_modifier *blob_modifiers;
|
|
|
|
|
2018-04-20 19:59:40 +02:00
|
|
|
if (!blob_id)
|
|
|
|
return FALSE;
|
|
|
|
|
2018-02-28 02:19:40 +01:00
|
|
|
blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
|
|
|
|
if (!blob)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
fmt_mod_blob = blob->data;
|
|
|
|
blob_formats = formats_ptr(fmt_mod_blob);
|
|
|
|
blob_modifiers = modifiers_ptr(fmt_mod_blob);
|
|
|
|
|
|
|
|
assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
|
|
|
|
|
|
|
|
for (i = 0; i < fmt_mod_blob->count_formats; i++) {
|
|
|
|
uint32_t num_modifiers = 0;
|
|
|
|
uint64_t *modifiers = NULL;
|
|
|
|
uint64_t *tmp;
|
|
|
|
for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
|
|
|
|
struct drm_format_modifier *mod = &blob_modifiers[j];
|
|
|
|
|
|
|
|
if ((i < mod->offset) || (i > mod->offset + 63))
|
|
|
|
continue;
|
|
|
|
if (!(mod->formats & (1 << (i - mod->offset))))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
num_modifiers++;
|
|
|
|
tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
|
|
|
|
if (!tmp) {
|
|
|
|
free(modifiers);
|
|
|
|
drmModeFreePropertyBlob(blob);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
modifiers = tmp;
|
|
|
|
modifiers[num_modifiers - 1] = mod->modifier;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmmode_crtc->formats[i].format = blob_formats[i];
|
|
|
|
drmmode_crtc->formats[i].modifiers = modifiers;
|
|
|
|
drmmode_crtc->formats[i].num_modifiers = num_modifiers;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreePropertyBlob(blob);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:37 +01:00
|
|
|
static void
|
|
|
|
drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
|
|
|
|
{
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
|
|
|
drmModePlaneRes *kplane_res;
|
2018-02-28 02:19:40 +01:00
|
|
|
drmModePlane *kplane, *best_kplane = NULL;
|
2018-02-28 02:19:37 +01:00
|
|
|
drmModeObjectProperties *props;
|
2018-02-28 02:19:40 +01:00
|
|
|
uint32_t i, type, blob_id;
|
2018-02-28 02:19:37 +01:00
|
|
|
int current_crtc, best_plane = 0;
|
|
|
|
|
|
|
|
static drmmode_prop_enum_info_rec plane_type_enums[] = {
|
|
|
|
[DRMMODE_PLANE_TYPE_PRIMARY] = {
|
|
|
|
.name = "Primary",
|
|
|
|
},
|
|
|
|
[DRMMODE_PLANE_TYPE_OVERLAY] = {
|
|
|
|
.name = "Overlay",
|
|
|
|
},
|
|
|
|
[DRMMODE_PLANE_TYPE_CURSOR] = {
|
|
|
|
.name = "Cursor",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
static const drmmode_prop_info_rec plane_props[] = {
|
|
|
|
[DRMMODE_PLANE_TYPE] = {
|
|
|
|
.name = "type",
|
|
|
|
.enum_values = plane_type_enums,
|
|
|
|
.num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
|
|
|
|
},
|
|
|
|
[DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
|
|
|
|
[DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
|
2018-02-28 02:19:40 +01:00
|
|
|
[DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
|
2018-02-28 02:19:37 +01:00
|
|
|
[DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
|
|
|
|
[DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
|
2018-02-28 02:19:39 +01:00
|
|
|
[DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
|
|
|
|
[DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
|
|
|
|
[DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
|
|
|
|
[DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
|
|
|
|
[DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
|
|
|
|
[DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
|
2018-02-28 02:19:37 +01:00
|
|
|
};
|
|
|
|
drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
|
|
|
|
|
|
|
|
if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
|
|
|
|
xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
|
|
|
|
"failed to copy plane property info\n");
|
|
|
|
drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
kplane_res = drmModeGetPlaneResources(drmmode->fd);
|
|
|
|
if (!kplane_res) {
|
|
|
|
xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
|
|
|
|
"failed to get plane resources: %s\n", strerror(errno));
|
|
|
|
drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < kplane_res->count_planes; i++) {
|
|
|
|
int plane_id;
|
|
|
|
|
|
|
|
kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
|
|
|
|
if (!kplane)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(kplane->possible_crtcs & (1 << num)) ||
|
|
|
|
is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
|
|
|
|
drmModeFreePlane(kplane);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
plane_id = kplane->plane_id;
|
|
|
|
|
|
|
|
props = drmModeObjectGetProperties(drmmode->fd, plane_id,
|
|
|
|
DRM_MODE_OBJECT_PLANE);
|
|
|
|
if (!props) {
|
|
|
|
xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
|
|
|
|
"couldn't get plane properties\n");
|
2018-02-28 02:19:40 +01:00
|
|
|
drmModeFreePlane(kplane);
|
2018-02-28 02:19:37 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
|
|
|
|
|
|
|
|
/* Only primary planes are important for atomic page-flipping */
|
|
|
|
type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
|
|
|
|
props, DRMMODE_PLANE_TYPE__COUNT);
|
|
|
|
if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
|
2018-02-28 02:19:40 +01:00
|
|
|
drmModeFreePlane(kplane);
|
2018-02-28 02:19:37 +01:00
|
|
|
drmModeFreeObjectProperties(props);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if plane is already on this CRTC */
|
|
|
|
current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
|
|
|
|
props, 0);
|
|
|
|
if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
|
2018-02-28 02:19:40 +01:00
|
|
|
if (best_plane) {
|
|
|
|
drmModeFreePlane(best_kplane);
|
2018-02-28 02:19:37 +01:00
|
|
|
drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
|
2018-02-28 02:19:40 +01:00
|
|
|
}
|
2018-02-28 02:19:37 +01:00
|
|
|
best_plane = plane_id;
|
2018-02-28 02:19:40 +01:00
|
|
|
best_kplane = kplane;
|
|
|
|
blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
|
|
|
|
props, 0);
|
2018-02-28 02:19:37 +01:00
|
|
|
drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
|
|
|
|
DRMMODE_PLANE__COUNT, 1);
|
|
|
|
drmModeFreeObjectProperties(props);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!best_plane) {
|
|
|
|
best_plane = plane_id;
|
2018-02-28 02:19:40 +01:00
|
|
|
best_kplane = kplane;
|
|
|
|
blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
|
|
|
|
props, 0);
|
2018-02-28 02:19:37 +01:00
|
|
|
drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
|
|
|
|
DRMMODE_PLANE__COUNT, 1);
|
2018-02-28 02:19:40 +01:00
|
|
|
} else {
|
|
|
|
drmModeFreePlane(kplane);
|
2018-02-28 02:19:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreeObjectProperties(props);
|
|
|
|
}
|
|
|
|
|
|
|
|
drmmode_crtc->plane_id = best_plane;
|
2018-02-28 02:19:40 +01:00
|
|
|
if (best_kplane) {
|
|
|
|
drmmode_crtc->num_formats = best_kplane->count_formats;
|
|
|
|
drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
|
|
|
|
best_kplane->count_formats);
|
2018-04-20 19:59:40 +02:00
|
|
|
if (!populate_format_modifiers(crtc, best_kplane, blob_id)) {
|
2018-02-28 02:19:40 +01:00
|
|
|
for (i = 0; i < best_kplane->count_formats; i++)
|
|
|
|
drmmode_crtc->formats[i].format = best_kplane->formats[i];
|
|
|
|
}
|
|
|
|
drmModeFreePlane(best_kplane);
|
|
|
|
}
|
2018-02-28 02:19:37 +01:00
|
|
|
|
|
|
|
drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
|
|
|
|
drmModeFreePlaneResources(kplane_res);
|
|
|
|
}
|
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
static unsigned int
|
2015-01-28 08:25:00 +01:00
|
|
|
drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcPtr crtc;
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc;
|
2015-07-22 04:56:13 +02:00
|
|
|
modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
|
2018-03-22 19:47:21 +01:00
|
|
|
modesettingPtr ms = modesettingPTR(pScrn);
|
2018-02-28 02:19:39 +01:00
|
|
|
drmModeObjectPropertiesPtr props;
|
|
|
|
static const drmmode_prop_info_rec crtc_props[] = {
|
|
|
|
[DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
|
|
|
|
[DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
|
|
|
|
};
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
|
|
|
|
if (crtc == NULL)
|
2015-07-22 04:56:13 +02:00
|
|
|
return 0;
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
|
2018-02-28 02:19:39 +01:00
|
|
|
crtc->driver_private = drmmode_crtc;
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc->mode_crtc =
|
2015-01-28 08:25:00 +01:00
|
|
|
drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc->drmmode = drmmode;
|
modesetting: Add support for DRI2 with glamor.
This is derived from the intel driver DRI2 code, with swapchain and
pageflipping dropped, functions renamed, and vblank event management
shared code moved to a vblank.c for reuse by Present.
This allows AIGLX to load, which means that you get appropriate
visuals exposed in GL, along with many extensions under
direct-rendering that require presence in GLX (which aren't supported
in glxdriswrast.c).
v2: Drop unused header includes in pageflip.c, wrap in #ifdef GLAMOR.
Drop triple-buffering, which was totally broken in practice (I'll
try to fix this later). Fix up some style nits. Document the
general flow of pageflipping and why, rename the DRI2 frame event
type enums to reflect what they're for, and handle them in a
single switch statement so you can understand the state machine
more easily.
v3: Drop pageflipping entirely -- it's unstable on my Intel laptop
(not that the normal 2D driver is stable with pageflipping for
me), and I won't get it fixed before the merge window. It now
passes all of the OML_sync_control tests from Jamey and Theo
(except for occasional warns in timing -fullscreen -divisor 2).
v4: Fix doxygen at the top of vblank.c
Signed-off-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2013-12-31 02:23:38 +01:00
|
|
|
drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
|
2018-02-28 02:19:39 +01:00
|
|
|
xorg_list_init(&drmmode_crtc->mode_list);
|
2015-07-22 04:56:13 +02:00
|
|
|
|
2018-03-22 19:47:21 +01:00
|
|
|
if (ms->atomic_modeset) {
|
|
|
|
props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
|
|
|
|
DRM_MODE_OBJECT_CRTC);
|
|
|
|
if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
|
|
|
|
DRMMODE_CRTC__COUNT, 0)) {
|
|
|
|
xf86CrtcDestroy(crtc);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-02-28 02:19:39 +01:00
|
|
|
|
2018-03-22 19:47:21 +01:00
|
|
|
drmmode_prop_info_update(drmmode, drmmode_crtc->props,
|
|
|
|
DRMMODE_CRTC__COUNT, props);
|
|
|
|
drmModeFreeObjectProperties(props);
|
|
|
|
drmmode_crtc_create_planes(crtc, num);
|
|
|
|
}
|
2018-02-28 02:19:37 +01:00
|
|
|
|
2016-08-31 15:37:20 +02:00
|
|
|
/* Hide any cursors which may be active from previous users */
|
|
|
|
drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
|
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
/* Mark num'th crtc as in use on this device. */
|
|
|
|
ms_ent->assigned_crtcs |= (1 << num);
|
|
|
|
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
|
|
|
|
"Allocated crtc nr. %d to this screen.\n", num);
|
|
|
|
|
|
|
|
return 1;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2017-12-22 03:54:34 +01:00
|
|
|
/*
|
|
|
|
* Update all of the property values for an output
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
drmmode_output_update_properties(xf86OutputPtr output)
|
|
|
|
{
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
int i, j, k;
|
|
|
|
int err;
|
|
|
|
drmModeConnectorPtr koutput;
|
|
|
|
|
|
|
|
/* Use the most recently fetched values from the kernel */
|
|
|
|
koutput = drmmode_output->mode_output;
|
|
|
|
|
|
|
|
if (!koutput)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < drmmode_output->num_props; i++) {
|
|
|
|
drmmode_prop_ptr p = &drmmode_output->props[i];
|
|
|
|
|
|
|
|
for (j = 0; koutput && j < koutput->count_props; j++) {
|
|
|
|
if (koutput->props[j] == p->mode_prop->prop_id) {
|
|
|
|
|
|
|
|
/* Check to see if the property value has changed */
|
|
|
|
if (koutput->prop_values[j] != p->value) {
|
|
|
|
|
|
|
|
p->value = koutput->prop_values[j];
|
|
|
|
|
|
|
|
if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
|
|
|
|
INT32 value = p->value;
|
|
|
|
|
|
|
|
err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
|
|
|
|
XA_INTEGER, 32, PropModeReplace, 1,
|
|
|
|
&value, FALSE, TRUE);
|
|
|
|
|
|
|
|
if (err != 0) {
|
|
|
|
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
|
|
|
|
"RRChangeOutputProperty error, %d\n", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
|
|
|
|
for (k = 0; k < p->mode_prop->count_enums; k++)
|
|
|
|
if (p->mode_prop->enums[k].value == p->value)
|
|
|
|
break;
|
|
|
|
if (k < p->mode_prop->count_enums) {
|
|
|
|
err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
|
|
|
|
XA_ATOM, 32, PropModeReplace, 1,
|
|
|
|
&p->atoms[k + 1], FALSE, TRUE);
|
|
|
|
if (err != 0) {
|
|
|
|
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
|
|
|
|
"RRChangeOutputProperty error, %d\n", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static xf86OutputStatus
|
|
|
|
drmmode_output_detect(xf86OutputPtr output)
|
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
/* go to the hw and retrieve a new output struct */
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_output->drmmode;
|
|
|
|
xf86OutputStatus status;
|
|
|
|
|
2015-01-28 08:35:21 +01:00
|
|
|
if (drmmode_output->output_id == -1)
|
|
|
|
return XF86OutputStatusDisconnected;
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeFreeConnector(drmmode_output->mode_output);
|
|
|
|
|
|
|
|
drmmode_output->mode_output =
|
|
|
|
drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
|
2017-12-22 03:54:34 +01:00
|
|
|
|
2017-11-20 10:47:41 +01:00
|
|
|
if (!drmmode_output->mode_output) {
|
|
|
|
drmmode_output->output_id = -1;
|
2014-10-08 09:39:15 +02:00
|
|
|
return XF86OutputStatusDisconnected;
|
2017-11-20 10:47:41 +01:00
|
|
|
}
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2017-12-22 03:54:34 +01:00
|
|
|
drmmode_output_update_properties(output);
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
switch (drmmode_output->mode_output->connection) {
|
|
|
|
case DRM_MODE_CONNECTED:
|
|
|
|
status = XF86OutputStatusConnected;
|
|
|
|
break;
|
|
|
|
case DRM_MODE_DISCONNECTED:
|
|
|
|
status = XF86OutputStatusDisconnected;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case DRM_MODE_UNKNOWNCONNECTION:
|
|
|
|
status = XF86OutputStatusUnknown;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return status;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
|
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
return MODE_OK;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2017-10-23 10:31:21 +02:00
|
|
|
static int
|
|
|
|
koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
|
|
|
|
int type, const char *name)
|
|
|
|
{
|
|
|
|
int idx = -1;
|
|
|
|
|
|
|
|
for (int i = 0; i < koutput->count_props; i++) {
|
|
|
|
drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
|
|
|
|
|
|
|
|
if (!prop)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
|
|
|
|
idx = i;
|
|
|
|
|
|
|
|
drmModeFreeProperty(prop);
|
|
|
|
|
|
|
|
if (idx > -1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
|
|
|
|
int type, const char *name)
|
|
|
|
{
|
|
|
|
int idx = koutput_get_prop_idx(fd, koutput, type, name);
|
|
|
|
|
|
|
|
return (idx > -1) ? koutput->props[idx] : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static drmModePropertyBlobPtr
|
|
|
|
koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
|
|
|
|
{
|
|
|
|
drmModePropertyBlobPtr blob = NULL;
|
|
|
|
int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
|
|
|
|
|
|
|
|
if (idx > -1)
|
|
|
|
blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
|
|
|
|
|
|
|
|
return blob;
|
|
|
|
}
|
|
|
|
|
2015-03-23 02:33:23 +01:00
|
|
|
static void
|
|
|
|
drmmode_output_attach_tile(xf86OutputPtr output)
|
|
|
|
{
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
drmModeConnectorPtr koutput = drmmode_output->mode_output;
|
|
|
|
drmmode_ptr drmmode = drmmode_output->drmmode;
|
|
|
|
struct xf86CrtcTileInfo tile_info, *set = NULL;
|
|
|
|
|
|
|
|
if (!koutput) {
|
|
|
|
xf86OutputSetTile(output, NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-23 10:31:21 +02:00
|
|
|
drmModeFreePropertyBlob(drmmode_output->tile_blob);
|
2015-03-23 02:33:23 +01:00
|
|
|
|
2017-10-23 10:31:21 +02:00
|
|
|
/* look for a TILE property */
|
|
|
|
drmmode_output->tile_blob =
|
|
|
|
koutput_get_prop_blob(drmmode->fd, koutput, "TILE");
|
2015-03-23 02:33:23 +01:00
|
|
|
|
|
|
|
if (drmmode_output->tile_blob) {
|
|
|
|
if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
|
|
|
|
set = &tile_info;
|
|
|
|
}
|
|
|
|
xf86OutputSetTile(output, set);
|
|
|
|
}
|
|
|
|
|
2012-12-03 14:25:19 +01:00
|
|
|
static Bool
|
|
|
|
has_panel_fitter(xf86OutputPtr output)
|
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
drmModeConnectorPtr koutput = drmmode_output->mode_output;
|
|
|
|
drmmode_ptr drmmode = drmmode_output->drmmode;
|
2017-10-23 10:31:21 +02:00
|
|
|
int idx;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
/* Presume that if the output supports scaling, then we have a
|
|
|
|
* panel fitter capable of adjust any mode to suit.
|
|
|
|
*/
|
2017-10-23 10:31:21 +02:00
|
|
|
idx = koutput_get_prop_idx(drmmode->fd, koutput,
|
|
|
|
DRM_MODE_PROP_ENUM, "scaling mode");
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2017-10-23 10:31:21 +02:00
|
|
|
return (idx > -1);
|
2012-12-03 14:25:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static DisplayModePtr
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
|
2012-12-03 14:25:19 +01:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86MonPtr mon = output->MonInfo;
|
|
|
|
DisplayModePtr i, m, preferred = NULL;
|
|
|
|
int max_x = 0, max_y = 0;
|
|
|
|
float max_vrefresh = 0.0;
|
|
|
|
|
2020-04-11 11:29:35 +02:00
|
|
|
if (mon && gtf_supported(mon))
|
2014-10-08 09:39:15 +02:00
|
|
|
return Modes;
|
|
|
|
|
|
|
|
if (!has_panel_fitter(output))
|
|
|
|
return Modes;
|
|
|
|
|
|
|
|
for (m = Modes; m; m = m->next) {
|
|
|
|
if (m->type & M_T_PREFERRED)
|
|
|
|
preferred = m;
|
|
|
|
max_x = max(max_x, m->HDisplay);
|
|
|
|
max_y = max(max_y, m->VDisplay);
|
|
|
|
max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
|
|
|
|
}
|
|
|
|
|
|
|
|
max_vrefresh = max(max_vrefresh, 60.0);
|
|
|
|
max_vrefresh *= (1 + SYNC_TOLERANCE);
|
|
|
|
|
|
|
|
m = xf86GetDefaultModes();
|
|
|
|
xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
|
|
|
|
|
|
|
|
for (i = m; i; i = i->next) {
|
|
|
|
if (xf86ModeVRefresh(i) > max_vrefresh)
|
|
|
|
i->status = MODE_VSYNC;
|
|
|
|
if (preferred &&
|
|
|
|
i->HDisplay >= preferred->HDisplay &&
|
|
|
|
i->VDisplay >= preferred->VDisplay &&
|
|
|
|
xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred))
|
|
|
|
i->status = MODE_VSYNC;
|
|
|
|
}
|
|
|
|
|
|
|
|
xf86PruneInvalidModes(output->scrn, &m, FALSE);
|
|
|
|
|
|
|
|
return xf86ModesAdd(Modes, m);
|
2012-12-03 14:25:19 +01:00
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static DisplayModePtr
|
|
|
|
drmmode_output_get_modes(xf86OutputPtr output)
|
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
drmModeConnectorPtr koutput = drmmode_output->mode_output;
|
|
|
|
drmmode_ptr drmmode = drmmode_output->drmmode;
|
|
|
|
int i;
|
|
|
|
DisplayModePtr Modes = NULL, Mode;
|
|
|
|
xf86MonPtr mon = NULL;
|
|
|
|
|
|
|
|
if (!koutput)
|
|
|
|
return NULL;
|
|
|
|
|
2017-10-23 10:31:21 +02:00
|
|
|
drmModeFreePropertyBlob(drmmode_output->edid_blob);
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
/* look for an EDID property */
|
2017-10-23 10:31:21 +02:00
|
|
|
drmmode_output->edid_blob =
|
|
|
|
koutput_get_prop_blob(drmmode->fd, koutput, "EDID");
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
if (drmmode_output->edid_blob) {
|
|
|
|
mon = xf86InterpretEDID(output->scrn->scrnIndex,
|
|
|
|
drmmode_output->edid_blob->data);
|
|
|
|
if (mon && drmmode_output->edid_blob->length > 128)
|
|
|
|
mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
|
|
|
|
}
|
|
|
|
xf86OutputSetEDID(output, mon);
|
|
|
|
|
2015-03-23 02:33:23 +01:00
|
|
|
drmmode_output_attach_tile(output);
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
/* modes should already be available */
|
|
|
|
for (i = 0; i < koutput->count_modes; i++) {
|
|
|
|
Mode = xnfalloc(sizeof(DisplayModeRec));
|
|
|
|
|
|
|
|
drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
|
|
|
|
Modes = xf86ModesAdd(Modes, Mode);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return drmmode_output_add_gtf_modes(output, Modes);
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_output_destroy(xf86OutputPtr output)
|
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
int i;
|
|
|
|
|
2017-10-23 10:31:20 +02:00
|
|
|
drmModeFreePropertyBlob(drmmode_output->edid_blob);
|
|
|
|
drmModeFreePropertyBlob(drmmode_output->tile_blob);
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
for (i = 0; i < drmmode_output->num_props; i++) {
|
|
|
|
drmModeFreeProperty(drmmode_output->props[i].mode_prop);
|
|
|
|
free(drmmode_output->props[i].atoms);
|
|
|
|
}
|
|
|
|
free(drmmode_output->props);
|
2015-01-28 08:35:21 +01:00
|
|
|
if (drmmode_output->mode_output) {
|
|
|
|
for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
|
|
|
|
drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
|
|
|
|
}
|
|
|
|
drmModeFreeConnector(drmmode_output->mode_output);
|
2014-10-08 09:39:15 +02:00
|
|
|
}
|
|
|
|
free(drmmode_output->mode_encoders);
|
|
|
|
free(drmmode_output);
|
|
|
|
output->driver_private = NULL;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_output_dpms(xf86OutputPtr output, int mode)
|
|
|
|
{
|
2018-04-04 06:01:14 +02:00
|
|
|
modesettingPtr ms = modesettingPTR(output->scrn);
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
2018-04-04 06:01:14 +02:00
|
|
|
drmmode_ptr drmmode = drmmode_output->drmmode;
|
modesetting: Implement page flipping support for Present.
Based on code by Keith Packard, Eric Anholt, and Jason Ekstrand.
v2:
- Fix double free and flip_count underrun (caught by Mario Kleiner).
- Don't leak flip_vblank_event on the error_out path (Mario).
- Use the updated ms_flush_drm_events API (Mario, Ken).
v3: Hack around DPMS shenanigans. If all monitors are DPMS off, then
there is no active framebuffer; attempting to pageflip will hit the
error_undo paths, causing us to drmModeRmFB with no framebuffer,
which confuses the kernel into doing full modesets and generally
breaks things. To avoid this, make ms_present_check_flip check that
some CRTCs are enabled and DPMS on. This is an ugly hack that would
get better with atomic modesetting, or some core Present work.
v4:
- Don't do pageflipping if CRTCs are rotated (caught by Jason Ekstrand).
- Make pageflipping optional (Option "PageFlip" in xorg.conf.d), but
enabled by default.
v5: Initialize num_crtcs_on to 0 (caught by Michel Dänzer).
[airlied: took over]
v6: merge async flip support from Mario Kleiner
free sequence after failed vblank queue
handle unflip while DPMS'ed off (Michel)
move flip tracking into its own structure, and
fix up reference counting issues, and add comments.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2015-01-27 06:29:23 +01:00
|
|
|
xf86CrtcPtr crtc = output->crtc;
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeConnectorPtr koutput = drmmode_output->mode_output;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
if (!koutput)
|
|
|
|
return;
|
2013-01-09 03:48:30 +01:00
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
/* XXX Check if DPMS mode is already the right one */
|
modesetting/drmmode: add NULL pointer check in drmmode_output_dpms
drmmode_output_dpms is called especially with !output->crtc found in
xf86DisableUnusedFunctions so we have to guard for it, else the server
segfaults:
0 0x00007fdc1706054b in drmmode_output_dpms (output=0x55e15243c210, mode=3) at
drmmode_display.c:2243
1 0x000055e1500b6873 in xf86DisableUnusedFunctions (pScrn=0x55e152133f00) at
xf86Crtc.c:3021
2 0x000055e1500be940 in xf86RandR12CrtcSet (pScreen=<optimized out>,
randr_crtc=0x55e1524b2b90, randr_mode=0x0, x=0, y=0, rotation=<optimized out>,
num_randr_outputs=0, randr_outputs=0x0) at xf86RandR12.c:1244
3 0x000055e1500fa1c2 in RRCrtcSet (crtc=<optimized out>, mode=0x0, x=0, y=0,
rotation=rotation@entry=1, numOutputs=numOutputs@entry=0, outputs=0x0) at
rrcrtc.c:763
4 0x000055e1500fba9e in ProcRRSetCrtcConfig (client=0x55e152bfae50) at
rrcrtc.c:1390
5 0x000055e150044008 in Dispatch () at dispatch.c:478
6 0x000055e150047ff8 in dix_main (argc=13, argv=0x7ffc68561038,
envp=<optimized out>) at main.c:276
7 0x00007fdc1a0c6a87 in __libc_start_main () at /lib64/libc.so.6
8 0x000055e150031d0a in _start () at ../sysdeps/x86_64/start.S:120
Fixes: ba0c75177 ("modesetting: Fix up some XXX from removing GLAMOR_HAS_DRM_*")
Signed-off-by: Tobias Klausmann <tobias.johannes.klausmann@mni.thm.de>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-03-30 22:32:13 +02:00
|
|
|
|
2018-04-04 06:01:14 +02:00
|
|
|
drmmode_output->dpms = mode;
|
|
|
|
|
|
|
|
if (ms->atomic_modeset) {
|
|
|
|
if (mode != DPMSModeOn && !ms->pending_modeset)
|
|
|
|
drmmode_output_disable(output);
|
2018-03-22 19:47:21 +01:00
|
|
|
} else {
|
|
|
|
drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
|
|
|
|
drmmode_output->dpms_enum_id, mode);
|
|
|
|
}
|
modesetting: Implement page flipping support for Present.
Based on code by Keith Packard, Eric Anholt, and Jason Ekstrand.
v2:
- Fix double free and flip_count underrun (caught by Mario Kleiner).
- Don't leak flip_vblank_event on the error_out path (Mario).
- Use the updated ms_flush_drm_events API (Mario, Ken).
v3: Hack around DPMS shenanigans. If all monitors are DPMS off, then
there is no active framebuffer; attempting to pageflip will hit the
error_undo paths, causing us to drmModeRmFB with no framebuffer,
which confuses the kernel into doing full modesets and generally
breaks things. To avoid this, make ms_present_check_flip check that
some CRTCs are enabled and DPMS on. This is an ugly hack that would
get better with atomic modesetting, or some core Present work.
v4:
- Don't do pageflipping if CRTCs are rotated (caught by Jason Ekstrand).
- Make pageflipping optional (Option "PageFlip" in xorg.conf.d), but
enabled by default.
v5: Initialize num_crtcs_on to 0 (caught by Michel Dänzer).
[airlied: took over]
v6: merge async flip support from Mario Kleiner
free sequence after failed vblank queue
handle unflip while DPMS'ed off (Michel)
move flip tracking into its own structure, and
fix up reference counting issues, and add comments.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2015-01-27 06:29:23 +01:00
|
|
|
|
2016-06-17 05:06:53 +02:00
|
|
|
if (crtc) {
|
modesetting: Implement page flipping support for Present.
Based on code by Keith Packard, Eric Anholt, and Jason Ekstrand.
v2:
- Fix double free and flip_count underrun (caught by Mario Kleiner).
- Don't leak flip_vblank_event on the error_out path (Mario).
- Use the updated ms_flush_drm_events API (Mario, Ken).
v3: Hack around DPMS shenanigans. If all monitors are DPMS off, then
there is no active framebuffer; attempting to pageflip will hit the
error_undo paths, causing us to drmModeRmFB with no framebuffer,
which confuses the kernel into doing full modesets and generally
breaks things. To avoid this, make ms_present_check_flip check that
some CRTCs are enabled and DPMS on. This is an ugly hack that would
get better with atomic modesetting, or some core Present work.
v4:
- Don't do pageflipping if CRTCs are rotated (caught by Jason Ekstrand).
- Make pageflipping optional (Option "PageFlip" in xorg.conf.d), but
enabled by default.
v5: Initialize num_crtcs_on to 0 (caught by Michel Dänzer).
[airlied: took over]
v6: merge async flip support from Mario Kleiner
free sequence after failed vblank queue
handle unflip while DPMS'ed off (Michel)
move flip tracking into its own structure, and
fix up reference counting issues, and add comments.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2015-01-27 06:29:23 +01:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2016-06-17 05:06:53 +02:00
|
|
|
|
|
|
|
if (mode == DPMSModeOn) {
|
|
|
|
if (drmmode_crtc->need_modeset)
|
|
|
|
drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
|
|
|
|
crtc->x, crtc->y);
|
|
|
|
|
|
|
|
if (drmmode_crtc->enable_flipping)
|
|
|
|
drmmode_InitSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
|
|
|
|
} else {
|
|
|
|
if (drmmode_crtc->enable_flipping)
|
|
|
|
drmmode_FiniSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
|
|
|
|
}
|
modesetting: Implement page flipping support for Present.
Based on code by Keith Packard, Eric Anholt, and Jason Ekstrand.
v2:
- Fix double free and flip_count underrun (caught by Mario Kleiner).
- Don't leak flip_vblank_event on the error_out path (Mario).
- Use the updated ms_flush_drm_events API (Mario, Ken).
v3: Hack around DPMS shenanigans. If all monitors are DPMS off, then
there is no active framebuffer; attempting to pageflip will hit the
error_undo paths, causing us to drmModeRmFB with no framebuffer,
which confuses the kernel into doing full modesets and generally
breaks things. To avoid this, make ms_present_check_flip check that
some CRTCs are enabled and DPMS on. This is an ugly hack that would
get better with atomic modesetting, or some core Present work.
v4:
- Don't do pageflipping if CRTCs are rotated (caught by Jason Ekstrand).
- Make pageflipping optional (Option "PageFlip" in xorg.conf.d), but
enabled by default.
v5: Initialize num_crtcs_on to 0 (caught by Michel Dänzer).
[airlied: took over]
v6: merge async flip support from Mario Kleiner
free sequence after failed vblank queue
handle unflip while DPMS'ed off (Michel)
move flip tracking into its own structure, and
fix up reference counting issues, and add comments.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
2015-01-27 06:29:23 +01:00
|
|
|
}
|
2016-06-17 05:06:53 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
return;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
drmmode_property_ignore(drmModePropertyPtr prop)
|
|
|
|
{
|
|
|
|
if (!prop)
|
2014-10-08 09:39:15 +02:00
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
/* ignore blob prop */
|
|
|
|
if (prop->flags & DRM_MODE_PROP_BLOB)
|
2014-10-08 09:39:15 +02:00
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
/* ignore standard property */
|
2018-02-28 02:19:37 +01:00
|
|
|
if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
|
|
|
|
!strcmp(prop->name, "CRTC_ID"))
|
2014-10-08 09:39:15 +02:00
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_output_create_resources(xf86OutputPtr output)
|
|
|
|
{
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
drmModeConnectorPtr mode_output = drmmode_output->mode_output;
|
|
|
|
drmmode_ptr drmmode = drmmode_output->drmmode;
|
|
|
|
drmModePropertyPtr drmmode_prop;
|
|
|
|
int i, j, err;
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output->props =
|
|
|
|
calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
|
2011-09-29 12:49:26 +02:00
|
|
|
if (!drmmode_output->props)
|
2014-10-08 09:39:15 +02:00
|
|
|
return;
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
drmmode_output->num_props = 0;
|
|
|
|
for (i = 0, j = 0; i < mode_output->count_props; i++) {
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
|
|
|
|
if (drmmode_property_ignore(drmmode_prop)) {
|
|
|
|
drmModeFreeProperty(drmmode_prop);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
drmmode_output->props[j].mode_prop = drmmode_prop;
|
|
|
|
drmmode_output->props[j].value = mode_output->prop_values[i];
|
|
|
|
drmmode_output->num_props++;
|
|
|
|
j++;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2018-02-12 22:51:55 +01:00
|
|
|
/* Create CONNECTOR_ID property */
|
|
|
|
{
|
|
|
|
Atom name = MakeAtom("CONNECTOR_ID", 12, TRUE);
|
|
|
|
INT32 value = mode_output->connector_id;
|
|
|
|
|
|
|
|
if (name != BAD_RESOURCE) {
|
|
|
|
err = RRConfigureOutputProperty(output->randr_output, name,
|
|
|
|
FALSE, FALSE, TRUE,
|
|
|
|
1, &value);
|
|
|
|
if (err != 0) {
|
|
|
|
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
|
|
|
|
"RRConfigureOutputProperty error, %d\n", err);
|
|
|
|
}
|
|
|
|
err = RRChangeOutputProperty(output->randr_output, name,
|
|
|
|
XA_INTEGER, 32, PropModeReplace, 1,
|
|
|
|
&value, FALSE, FALSE);
|
|
|
|
if (err != 0) {
|
|
|
|
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
|
|
|
|
"RRChangeOutputProperty error, %d\n", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
for (i = 0; i < drmmode_output->num_props; i++) {
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_prop_ptr p = &drmmode_output->props[i];
|
|
|
|
|
|
|
|
drmmode_prop = p->mode_prop;
|
|
|
|
|
|
|
|
if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
|
|
|
|
INT32 prop_range[2];
|
|
|
|
INT32 value = p->value;
|
|
|
|
|
|
|
|
p->num_atoms = 1;
|
|
|
|
p->atoms = calloc(p->num_atoms, sizeof(Atom));
|
|
|
|
if (!p->atoms)
|
|
|
|
continue;
|
|
|
|
p->atoms[0] =
|
|
|
|
MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
|
|
|
|
prop_range[0] = drmmode_prop->values[0];
|
|
|
|
prop_range[1] = drmmode_prop->values[1];
|
|
|
|
err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
|
|
|
|
FALSE, TRUE,
|
|
|
|
drmmode_prop->
|
|
|
|
flags & DRM_MODE_PROP_IMMUTABLE ?
|
|
|
|
TRUE : FALSE, 2, prop_range);
|
|
|
|
if (err != 0) {
|
|
|
|
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
|
|
|
|
"RRConfigureOutputProperty error, %d\n", err);
|
|
|
|
}
|
|
|
|
err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
|
|
|
|
XA_INTEGER, 32, PropModeReplace, 1,
|
|
|
|
&value, FALSE, TRUE);
|
|
|
|
if (err != 0) {
|
|
|
|
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
|
|
|
|
"RRChangeOutputProperty error, %d\n", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
|
|
|
|
p->num_atoms = drmmode_prop->count_enums + 1;
|
|
|
|
p->atoms = calloc(p->num_atoms, sizeof(Atom));
|
|
|
|
if (!p->atoms)
|
|
|
|
continue;
|
|
|
|
p->atoms[0] =
|
|
|
|
MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
|
|
|
|
for (j = 1; j <= drmmode_prop->count_enums; j++) {
|
|
|
|
struct drm_mode_property_enum *e = &drmmode_prop->enums[j - 1];
|
|
|
|
|
|
|
|
p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
|
|
|
|
}
|
|
|
|
err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
|
|
|
|
FALSE, FALSE,
|
|
|
|
drmmode_prop->
|
|
|
|
flags & DRM_MODE_PROP_IMMUTABLE ?
|
|
|
|
TRUE : FALSE, p->num_atoms - 1,
|
|
|
|
(INT32 *) &p->atoms[1]);
|
|
|
|
if (err != 0) {
|
|
|
|
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
|
|
|
|
"RRConfigureOutputProperty error, %d\n", err);
|
|
|
|
}
|
|
|
|
for (j = 0; j < drmmode_prop->count_enums; j++)
|
|
|
|
if (drmmode_prop->enums[j].value == p->value)
|
|
|
|
break;
|
|
|
|
/* there's always a matching value */
|
|
|
|
err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
|
|
|
|
XA_ATOM, 32, PropModeReplace, 1,
|
|
|
|
&p->atoms[j + 1], FALSE, TRUE);
|
|
|
|
if (err != 0) {
|
|
|
|
xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
|
|
|
|
"RRChangeOutputProperty error, %d\n", err);
|
|
|
|
}
|
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
drmmode_output_set_property(xf86OutputPtr output, Atom property,
|
2014-10-08 09:39:15 +02:00
|
|
|
RRPropertyValuePtr value)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
drmmode_ptr drmmode = drmmode_output->drmmode;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < drmmode_output->num_props; i++) {
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_prop_ptr p = &drmmode_output->props[i];
|
|
|
|
|
|
|
|
if (p->atoms[0] != property)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
|
|
|
|
uint32_t val;
|
|
|
|
|
|
|
|
if (value->type != XA_INTEGER || value->format != 32 ||
|
|
|
|
value->size != 1)
|
|
|
|
return FALSE;
|
|
|
|
val = *(uint32_t *) value->data;
|
|
|
|
|
|
|
|
drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
|
|
|
|
p->mode_prop->prop_id, (uint64_t) val);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
|
|
|
|
Atom atom;
|
|
|
|
const char *name;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
if (value->type != XA_ATOM || value->format != 32 ||
|
|
|
|
value->size != 1)
|
|
|
|
return FALSE;
|
|
|
|
memcpy(&atom, value->data, 4);
|
2017-06-12 20:43:23 +02:00
|
|
|
if (!(name = NameForAtom(atom)))
|
|
|
|
return FALSE;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
/* search for matching name string, then set its value down */
|
|
|
|
for (j = 0; j < p->mode_prop->count_enums; j++) {
|
|
|
|
if (!strcmp(p->mode_prop->enums[j].name, name)) {
|
|
|
|
drmModeConnectorSetProperty(drmmode->fd,
|
|
|
|
drmmode_output->output_id,
|
|
|
|
p->mode_prop->prop_id,
|
|
|
|
p->mode_prop->enums[j].value);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
drmmode_output_get_property(xf86OutputPtr output, Atom property)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const xf86OutputFuncsRec drmmode_output_funcs = {
|
|
|
|
.dpms = drmmode_output_dpms,
|
|
|
|
.create_resources = drmmode_output_create_resources,
|
|
|
|
.set_property = drmmode_output_set_property,
|
|
|
|
.get_property = drmmode_output_get_property,
|
|
|
|
.detect = drmmode_output_detect,
|
|
|
|
.mode_valid = drmmode_output_mode_valid,
|
|
|
|
|
|
|
|
.get_modes = drmmode_output_get_modes,
|
|
|
|
.destroy = drmmode_output_destroy
|
|
|
|
};
|
|
|
|
|
2014-10-08 09:41:13 +02:00
|
|
|
static int subpixel_conv_table[7] = {
|
|
|
|
0,
|
|
|
|
SubPixelUnknown,
|
2014-10-08 09:39:15 +02:00
|
|
|
SubPixelHorizontalRGB,
|
|
|
|
SubPixelHorizontalBGR,
|
|
|
|
SubPixelVerticalRGB,
|
|
|
|
SubPixelVerticalBGR,
|
|
|
|
SubPixelNone
|
|
|
|
};
|
|
|
|
|
2014-10-08 09:41:13 +02:00
|
|
|
static const char *const output_names[] = {
|
|
|
|
"None",
|
2014-10-08 09:39:15 +02:00
|
|
|
"VGA",
|
2015-09-05 00:56:19 +02:00
|
|
|
"DVI-I",
|
|
|
|
"DVI-D",
|
|
|
|
"DVI-A",
|
2014-10-08 09:39:15 +02:00
|
|
|
"Composite",
|
2015-09-05 00:56:19 +02:00
|
|
|
"SVIDEO",
|
2014-10-08 09:39:15 +02:00
|
|
|
"LVDS",
|
2015-09-05 00:56:19 +02:00
|
|
|
"Component",
|
2014-10-08 09:39:15 +02:00
|
|
|
"DIN",
|
2015-09-05 00:56:19 +02:00
|
|
|
"DP",
|
2014-10-08 09:39:15 +02:00
|
|
|
"HDMI",
|
2015-09-05 00:56:19 +02:00
|
|
|
"HDMI-B",
|
2014-10-08 09:39:15 +02:00
|
|
|
"TV",
|
|
|
|
"eDP",
|
|
|
|
"Virtual",
|
|
|
|
"DSI",
|
2017-04-25 20:33:50 +02:00
|
|
|
"DPI",
|
2011-09-29 12:49:26 +02:00
|
|
|
};
|
|
|
|
|
2015-01-28 08:35:21 +01:00
|
|
|
static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
|
|
|
|
{
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[i];
|
|
|
|
drmmode_output_private_ptr drmmode_output;
|
|
|
|
|
|
|
|
drmmode_output = output->driver_private;
|
|
|
|
if (drmmode_output->output_id == id)
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
|
|
|
|
{
|
|
|
|
char *conn;
|
|
|
|
char conn_id[5];
|
|
|
|
int id, len;
|
|
|
|
char *blob_data;
|
|
|
|
|
|
|
|
if (!path_blob)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
blob_data = path_blob->data;
|
|
|
|
/* we only handle MST paths for now */
|
|
|
|
if (strncmp(blob_data, "mst:", 4))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
conn = strchr(blob_data + 4, '-');
|
|
|
|
if (!conn)
|
|
|
|
return -1;
|
|
|
|
len = conn - (blob_data + 4);
|
|
|
|
if (len + 1> 5)
|
|
|
|
return -1;
|
|
|
|
memcpy(conn_id, blob_data + 4, len);
|
2018-12-11 05:34:11 +01:00
|
|
|
conn_id[len] = '\0';
|
2015-01-28 08:35:21 +01:00
|
|
|
id = strtoul(conn_id, NULL, 10);
|
|
|
|
|
|
|
|
*conn_base_id = id;
|
|
|
|
|
|
|
|
*path = conn + 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static void
|
2015-01-28 08:35:21 +01:00
|
|
|
drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
|
|
|
|
drmModePropertyBlobPtr path_blob)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2015-01-28 08:35:21 +01:00
|
|
|
int ret;
|
|
|
|
char *extra_path;
|
|
|
|
int conn_id;
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86OutputPtr output;
|
2015-01-28 08:35:21 +01:00
|
|
|
|
|
|
|
ret = parse_path_blob(path_blob, &conn_id, &extra_path);
|
|
|
|
if (ret == -1)
|
|
|
|
goto fallback;
|
|
|
|
|
|
|
|
output = find_output(pScrn, conn_id);
|
|
|
|
if (!output)
|
|
|
|
goto fallback;
|
|
|
|
|
|
|
|
snprintf(name, 32, "%s-%s", output->name, extra_path);
|
|
|
|
return;
|
|
|
|
|
|
|
|
fallback:
|
2017-10-27 16:11:56 +02:00
|
|
|
if (koutput->connector_type >= ARRAY_SIZE(output_names))
|
2015-09-05 00:56:19 +02:00
|
|
|
snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id);
|
2015-01-28 08:35:21 +01:00
|
|
|
else if (pScrn->is_gpu)
|
2015-09-05 00:56:19 +02:00
|
|
|
snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id);
|
2015-01-28 08:35:21 +01:00
|
|
|
else
|
2015-09-05 00:56:19 +02:00
|
|
|
snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
|
2015-01-28 08:35:21 +01:00
|
|
|
}
|
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
static unsigned int
|
|
|
|
drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
|
2015-01-28 08:35:21 +01:00
|
|
|
{
|
|
|
|
xf86OutputPtr output;
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
|
2018-03-22 19:47:21 +01:00
|
|
|
modesettingPtr ms = modesettingPTR(pScrn);
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeConnectorPtr koutput;
|
|
|
|
drmModeEncoderPtr *kencoders = NULL;
|
|
|
|
drmmode_output_private_ptr drmmode_output;
|
|
|
|
char name[32];
|
|
|
|
int i;
|
2018-02-12 22:51:53 +01:00
|
|
|
Bool nonDesktop = FALSE;
|
2015-01-28 08:35:21 +01:00
|
|
|
drmModePropertyBlobPtr path_blob = NULL;
|
2015-07-22 04:56:13 +02:00
|
|
|
const char *s;
|
2018-02-28 02:19:39 +01:00
|
|
|
drmModeObjectPropertiesPtr props;
|
|
|
|
static const drmmode_prop_info_rec connector_props[] = {
|
|
|
|
[DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
|
|
|
|
};
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
koutput =
|
2015-01-28 08:25:00 +01:00
|
|
|
drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
|
2014-10-08 09:39:15 +02:00
|
|
|
if (!koutput)
|
2015-07-22 04:56:13 +02:00
|
|
|
return 0;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2017-10-23 10:31:21 +02:00
|
|
|
path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
|
2018-02-12 22:51:53 +01:00
|
|
|
i = koutput_get_prop_idx(drmmode->fd, koutput, DRM_MODE_PROP_RANGE, RR_PROPERTY_NON_DESKTOP);
|
|
|
|
if (i >= 0)
|
|
|
|
nonDesktop = koutput->prop_values[i] != 0;
|
2015-01-28 08:35:21 +01:00
|
|
|
|
|
|
|
drmmode_create_name(pScrn, koutput, name, path_blob);
|
|
|
|
|
|
|
|
if (path_blob)
|
|
|
|
drmModeFreePropertyBlob(path_blob);
|
|
|
|
|
|
|
|
if (path_blob && dynamic) {
|
|
|
|
/* see if we have an output with this name already
|
|
|
|
and hook stuff up */
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
output = xf86_config->output[i];
|
|
|
|
|
|
|
|
if (strncmp(output->name, name, 32))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
drmmode_output = output->driver_private;
|
|
|
|
drmmode_output->output_id = mode_res->connectors[num];
|
|
|
|
drmmode_output->mode_output = koutput;
|
2018-02-12 22:51:53 +01:00
|
|
|
output->non_desktop = nonDesktop;
|
2015-07-22 04:56:13 +02:00
|
|
|
return 1;
|
2015-01-28 08:35:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
|
|
|
|
if (!kencoders) {
|
|
|
|
goto out_free_encoders;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < koutput->count_encoders; i++) {
|
|
|
|
kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
|
|
|
|
if (!kencoders[i]) {
|
|
|
|
goto out_free_encoders;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
if (xf86IsEntityShared(pScrn->entityList[0])) {
|
|
|
|
if ((s = xf86GetOptValString(drmmode->Options, OPTION_ZAPHOD_HEADS))) {
|
|
|
|
if (!drmmode_zaphod_string_matches(pScrn, s, name))
|
|
|
|
goto out_free_encoders;
|
|
|
|
} else {
|
|
|
|
if (!drmmode->is_secondary && (num != 0))
|
|
|
|
goto out_free_encoders;
|
|
|
|
else if (drmmode->is_secondary && (num != 1))
|
|
|
|
goto out_free_encoders;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
|
|
|
|
if (!output) {
|
|
|
|
goto out_free_encoders;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
|
|
|
|
if (!drmmode_output) {
|
|
|
|
xf86OutputDestroy(output);
|
|
|
|
goto out_free_encoders;
|
|
|
|
}
|
|
|
|
|
2015-01-28 08:25:00 +01:00
|
|
|
drmmode_output->output_id = mode_res->connectors[num];
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output->mode_output = koutput;
|
|
|
|
drmmode_output->mode_encoders = kencoders;
|
|
|
|
drmmode_output->drmmode = drmmode;
|
|
|
|
output->mm_width = koutput->mmWidth;
|
|
|
|
output->mm_height = koutput->mmHeight;
|
|
|
|
|
|
|
|
output->subpixel_order = subpixel_conv_table[koutput->subpixel];
|
|
|
|
output->interlaceAllowed = TRUE;
|
|
|
|
output->doubleScanAllowed = TRUE;
|
|
|
|
output->driver_private = drmmode_output;
|
2018-02-12 22:51:53 +01:00
|
|
|
output->non_desktop = nonDesktop;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2019-09-03 15:44:56 +02:00
|
|
|
output->possible_crtcs = 0;
|
2014-10-08 09:39:15 +02:00
|
|
|
for (i = 0; i < koutput->count_encoders; i++) {
|
2019-09-03 15:44:56 +02:00
|
|
|
output->possible_crtcs |= (kencoders[i]->possible_crtcs >> crtcshift) & 0x7f;
|
2014-10-08 09:39:15 +02:00
|
|
|
}
|
|
|
|
/* work out the possible clones later */
|
|
|
|
output->possible_clones = 0;
|
|
|
|
|
2018-03-22 19:47:21 +01:00
|
|
|
if (ms->atomic_modeset) {
|
|
|
|
if (!drmmode_prop_info_copy(drmmode_output->props_connector,
|
|
|
|
connector_props, DRMMODE_CONNECTOR__COUNT,
|
|
|
|
0)) {
|
|
|
|
goto out_free_encoders;
|
|
|
|
}
|
|
|
|
props = drmModeObjectGetProperties(drmmode->fd,
|
|
|
|
drmmode_output->output_id,
|
|
|
|
DRM_MODE_OBJECT_CONNECTOR);
|
|
|
|
drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
|
|
|
|
DRMMODE_CONNECTOR__COUNT, props);
|
|
|
|
} else {
|
|
|
|
drmmode_output->dpms_enum_id =
|
|
|
|
koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM,
|
|
|
|
"DPMS");
|
2018-02-28 02:19:39 +01:00
|
|
|
}
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2019-08-20 16:46:09 +02:00
|
|
|
if (dynamic) {
|
2015-01-28 08:35:21 +01:00
|
|
|
output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
|
2019-08-20 16:46:09 +02:00
|
|
|
if (output->randr_output) {
|
|
|
|
drmmode_output_create_resources(output);
|
|
|
|
RRPostPendingProperties(output->randr_output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
return 1;
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
out_free_encoders:
|
|
|
|
if (kencoders) {
|
|
|
|
for (i = 0; i < koutput->count_encoders; i++)
|
|
|
|
drmModeFreeEncoder(kencoders[i]);
|
|
|
|
free(kencoders);
|
|
|
|
}
|
|
|
|
drmModeFreeConnector(koutput);
|
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
return 0;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
static uint32_t
|
|
|
|
find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output_private_ptr drmmode_output =
|
|
|
|
output->driver_private, clone_drmout;
|
|
|
|
int i;
|
|
|
|
xf86OutputPtr clone_output;
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
|
|
|
|
int index_mask = 0;
|
|
|
|
|
|
|
|
if (drmmode_output->enc_clone_mask == 0)
|
|
|
|
return index_mask;
|
|
|
|
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
clone_output = xf86_config->output[i];
|
|
|
|
clone_drmout = clone_output->driver_private;
|
|
|
|
if (output == clone_output)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (clone_drmout->enc_mask == 0)
|
|
|
|
continue;
|
|
|
|
if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
|
|
|
|
index_mask |= (1 << i);
|
|
|
|
}
|
|
|
|
return index_mask;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-01-28 08:25:00 +01:00
|
|
|
drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
int i, j;
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
|
|
|
|
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[i];
|
|
|
|
drmmode_output_private_ptr drmmode_output;
|
|
|
|
|
|
|
|
drmmode_output = output->driver_private;
|
|
|
|
drmmode_output->enc_clone_mask = 0xff;
|
|
|
|
/* and all the possible encoder clones for this output together */
|
|
|
|
for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
|
|
|
|
int k;
|
|
|
|
|
2015-01-28 08:25:00 +01:00
|
|
|
for (k = 0; k < mode_res->count_encoders; k++) {
|
|
|
|
if (mode_res->encoders[k] ==
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_output->mode_encoders[j]->encoder_id)
|
|
|
|
drmmode_output->enc_mask |= (1 << k);
|
|
|
|
}
|
|
|
|
|
|
|
|
drmmode_output->enc_clone_mask &=
|
|
|
|
drmmode_output->mode_encoders[j]->possible_clones;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < xf86_config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = xf86_config->output[i];
|
|
|
|
|
|
|
|
output->possible_clones = find_clones(scrn, output);
|
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2015-01-14 00:08:35 +01:00
|
|
|
static Bool
|
|
|
|
drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo)
|
2014-12-10 00:18:39 +01:00
|
|
|
{
|
2017-05-16 20:37:14 +02:00
|
|
|
#ifdef GLAMOR_HAS_GBM
|
2014-12-10 00:18:39 +01:00
|
|
|
ScrnInfoPtr scrn = drmmode->scrn;
|
2019-11-18 22:46:44 +01:00
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
2014-12-10 00:18:39 +01:00
|
|
|
|
|
|
|
if (!drmmode->glamor)
|
|
|
|
return TRUE;
|
|
|
|
|
2019-11-18 22:46:44 +01:00
|
|
|
if (!ms->glamor.egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm,
|
|
|
|
bo->used_modifiers)) {
|
2017-11-20 10:47:40 +01:00
|
|
|
xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n");
|
2014-12-09 21:43:57 +01:00
|
|
|
return FALSE;
|
|
|
|
}
|
2014-12-10 00:18:39 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2015-01-14 00:08:35 +01:00
|
|
|
Bool
|
|
|
|
drmmode_glamor_handle_new_screen_pixmap(drmmode_ptr drmmode)
|
|
|
|
{
|
|
|
|
ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
|
|
|
|
PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
|
|
|
|
|
|
|
|
if (!drmmode_set_pixmap_bo(drmmode, screen_pixmap, &drmmode->front_bo))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static Bool
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
|
2016-06-14 11:58:01 +02:00
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
drmmode_ptr drmmode = &ms->drmmode;
|
2014-12-10 00:20:44 +01:00
|
|
|
drmmode_bo old_front;
|
2014-10-08 09:39:15 +02:00
|
|
|
ScreenPtr screen = xf86ScrnToScreen(scrn);
|
|
|
|
uint32_t old_fb_id;
|
|
|
|
int i, pitch, old_width, old_height, old_pitch;
|
|
|
|
int cpp = (scrn->bitsPerPixel + 7) / 8;
|
2015-07-22 18:14:06 +02:00
|
|
|
int kcpp = (drmmode->kbpp + 7) / 8;
|
2014-10-08 09:39:15 +02:00
|
|
|
PixmapPtr ppix = screen->GetScreenPixmap(screen);
|
2014-12-09 21:43:57 +01:00
|
|
|
void *new_pixels = NULL;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
if (scrn->virtualX == width && scrn->virtualY == height)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
xf86DrvMsg(scrn->scrnIndex, X_INFO,
|
|
|
|
"Allocate new frame buffer %dx%d stride\n", width, height);
|
|
|
|
|
|
|
|
old_width = scrn->virtualX;
|
|
|
|
old_height = scrn->virtualY;
|
2014-12-10 00:20:44 +01:00
|
|
|
old_pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
|
2014-10-08 09:39:15 +02:00
|
|
|
old_front = drmmode->front_bo;
|
2016-06-01 15:11:05 +02:00
|
|
|
old_fb_id = drmmode->fb_id;
|
|
|
|
drmmode->fb_id = 0;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
if (!drmmode_create_bo(drmmode, &drmmode->front_bo,
|
2015-07-22 18:14:06 +02:00
|
|
|
width, height, drmmode->kbpp))
|
2014-10-08 09:39:15 +02:00
|
|
|
goto fail;
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
scrn->virtualX = width;
|
|
|
|
scrn->virtualY = height;
|
2015-07-22 18:14:06 +02:00
|
|
|
scrn->displayWidth = pitch / kcpp;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2014-12-09 21:43:57 +01:00
|
|
|
if (!drmmode->gbm) {
|
|
|
|
new_pixels = drmmode_map_front_bo(drmmode);
|
|
|
|
if (!new_pixels)
|
|
|
|
goto fail;
|
|
|
|
}
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2014-12-09 23:38:39 +01:00
|
|
|
if (drmmode->shadow_enable) {
|
2015-07-22 18:14:06 +02:00
|
|
|
uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
|
2014-12-09 23:38:39 +01:00
|
|
|
new_pixels = calloc(1, size);
|
|
|
|
if (new_pixels == NULL)
|
2014-10-08 09:39:15 +02:00
|
|
|
goto fail;
|
|
|
|
free(drmmode->shadow_fb);
|
2014-12-09 23:38:39 +01:00
|
|
|
drmmode->shadow_fb = new_pixels;
|
2014-10-08 09:39:15 +02:00
|
|
|
}
|
|
|
|
|
2015-07-22 18:14:08 +02:00
|
|
|
if (drmmode->shadow_enable2) {
|
|
|
|
uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
|
|
|
|
void *fb2 = calloc(1, size);
|
|
|
|
free(drmmode->shadow_fb2);
|
|
|
|
drmmode->shadow_fb2 = fb2;
|
|
|
|
}
|
|
|
|
|
2015-07-22 18:14:06 +02:00
|
|
|
screen->ModifyPixmapHeader(ppix, width, height, -1, -1,
|
|
|
|
scrn->displayWidth * cpp, new_pixels);
|
2014-12-09 23:38:39 +01:00
|
|
|
|
2014-12-10 00:18:39 +01:00
|
|
|
if (!drmmode_glamor_handle_new_screen_pixmap(drmmode))
|
|
|
|
goto fail;
|
2014-11-28 11:20:48 +01:00
|
|
|
|
2019-11-18 18:06:28 +01:00
|
|
|
drmmode_clear_pixmap(ppix);
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
for (i = 0; i < xf86_config->num_crtc; i++) {
|
|
|
|
xf86CrtcPtr crtc = xf86_config->crtc[i];
|
|
|
|
|
|
|
|
if (!crtc->enabled)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
drmmode_set_mode_major(crtc, &crtc->mode,
|
|
|
|
crtc->rotation, crtc->x, crtc->y);
|
|
|
|
}
|
|
|
|
|
2020-05-15 18:33:11 +02:00
|
|
|
if (old_fb_id)
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeRmFB(drmmode->fd, old_fb_id);
|
2020-05-15 18:33:11 +02:00
|
|
|
|
|
|
|
drmmode_bo_destroy(drmmode, &old_front);
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
|
|
|
fail:
|
2014-12-10 00:20:44 +01:00
|
|
|
drmmode_bo_destroy(drmmode, &drmmode->front_bo);
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode->front_bo = old_front;
|
|
|
|
scrn->virtualX = old_width;
|
|
|
|
scrn->virtualY = old_height;
|
2015-07-22 18:14:06 +02:00
|
|
|
scrn->displayWidth = old_pitch / kcpp;
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode->fb_id = old_fb_id;
|
|
|
|
|
|
|
|
return FALSE;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
Add RandR leases with modesetting driver support [v6]
This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.
v2: Restore CRTC mode when leases terminate
When a lease terminates for a crtc we have saved data for, go
ahead and restore the saved mode.
v3: Report RR_Rotate_0 rotations for leased crtcs.
Ignore leased CRTCs when selecting screen size.
Stop leasing encoders, the kernel doesn't do that anymore.
Turn off crtc->enabled while leased so that modesetting
ignores them.
Check lease status before calling any driver mode functions
When starting a lease, mark leased CRTCs as disabled and hide
their cursors. Also, check to see if there are other
non-leased CRTCs which are driving leased Outputs and mark
them as disabled as well. Sometimes an application will lease
an idle crtc instead of the one already associated with the
leased output.
When terminating a lease, reset any CRTCs which are driving
outputs that are no longer leased so that they start working
again.
This required splitting the DIX level lease termination code
into two pieces, one to remove the lease from the system
(RRLeaseTerminated) and a new function that frees the lease
data structure (RRLeaseFree).
v4: Report RR_Rotate_0 rotation for leased crtcs.
v5: Terminate all leases on server reset.
Leases hang around after the associated client exits so that
the client doesn't need to occupy an X server client slot and
consume a file descriptor once it has gotten the output
resources necessary.
Any leases still hanging around when the X server resets or
shuts down need to be cleaned up by calling the kernel to
terminate the lease and freeing any DIX structures.
Note that we cannot simply use the existing
drmmode_terminate_lease function on each lease as that wants
to also reset the video mode, and during server shut down that
modesetting: Validate leases on VT enter
The kernel doesn't allow any master ioctls to run when another
VT is active, including simple things like listing the active
leases. To deal with that, we check the list of leases
whenever the X server VT is activated.
xfree86: hide disabled cursors when resetting after lease termination
The lessee may well have played with cursors and left one
active on our screen. Just tell the kernel to turn it off.
v6: Add meson build infrastructure
[Also bumped libdrm requirement - ajax]
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-02-12 22:51:56 +01:00
|
|
|
static void
|
|
|
|
drmmode_validate_leases(ScrnInfoPtr scrn)
|
|
|
|
{
|
|
|
|
ScreenPtr screen = scrn->pScreen;
|
modesetting: Check whether RandR was initialized before calling rrGetScrPriv
Calling rrGetScrPriv when RandR isn't initialized causes an assertion
failure that aborts the server:
Xorg: ../include/privates.h:121: dixGetPrivateAddr: Assertion `key->initialized' failed.
Thread 1 "Xorg" received signal SIGABRT, Aborted.
0x00007ffff78a8f25 in raise () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff78a8f25 in raise () from /usr/lib/libc.so.6
#1 0x00007ffff7892897 in abort () from /usr/lib/libc.so.6
#2 0x00007ffff7892767 in __assert_fail_base.cold () from /usr/lib/libc.so.6
#3 0x00007ffff78a1526 in __assert_fail () from /usr/lib/libc.so.6
#4 0x00007ffff7fb57c1 in dixGetPrivateAddr (privates=0x555555ab1b60, key=0x555555855720 <rrPrivKeyRec>) at ../include/privates.h:121
#5 0x00007ffff7fb5822 in dixGetPrivate (privates=0x555555ab1b60, key=0x555555855720 <rrPrivKeyRec>) at ../include/privates.h:136
#6 0x00007ffff7fb586a in dixLookupPrivate (privates=0x555555ab1b60, key=0x555555855720 <rrPrivKeyRec>) at ../include/privates.h:166
#7 0x00007ffff7fb8445 in CreateScreenResources (pScreen=0x555555ab1790) at ../hw/xfree86/drivers/modesetting/driver.c:1335
#8 0x000055555576c5e4 in xf86CrtcCreateScreenResources (screen=0x555555ab1790) at ../hw/xfree86/modes/xf86Crtc.c:744
#9 0x00005555555d8bb6 in dix_main (argc=4, argv=0x7fffffffead8, envp=0x7fffffffeb00) at ../dix/main.c:214
#10 0x00005555557a4f0b in main (argc=4, argv=0x7fffffffead8, envp=0x7fffffffeb00) at ../dix/stubmain.c:34
This can happen, for example, if the server is configured with Xinerama
and there is more than one X screen:
Section "ServerLayout"
Identifier "crash"
Screen 0 "modesetting"
Screen 1 "dummy" RightOf "modesetting"
Option "Xinerama"
EndSection
Section "Device"
Identifier "modesetting"
Driver "modesetting"
EndSection
Section "Screen"
Identifier "modesetting"
Device "modesetting"
EndSection
Section "Device"
Identifier "dummy"
Driver "dummy"
EndSection
Section "Screen"
Identifier "dummy"
Device "dummy"
EndSection
The problem does not reproduce if there is only one X screen because of
this code in xf86RandR12Init:
#ifdef PANORAMIX
/* XXX disable RandR when using Xinerama */
if (!noPanoramiXExtension) {
if (xf86NumScreens == 1)
noPanoramiXExtension = TRUE;
else
return TRUE;
}
#endif
Fix the problem by checking dixPrivateKeyRegistered(rrPrivKey) before
calling rrGetScrPriv. This is similar to what the xf86-video-amdgpu
driver does:
https://gitlab.freedesktop.org/xorg/driver/xf86-video-amdgpu/blob/fd66f5c0bea2b7c22a47bfd5eb1f22d32d166d9c/src/amdgpu_kms.c#L388
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2019-12-26 22:40:17 +01:00
|
|
|
rrScrPrivPtr scr_priv;
|
Add RandR leases with modesetting driver support [v6]
This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.
v2: Restore CRTC mode when leases terminate
When a lease terminates for a crtc we have saved data for, go
ahead and restore the saved mode.
v3: Report RR_Rotate_0 rotations for leased crtcs.
Ignore leased CRTCs when selecting screen size.
Stop leasing encoders, the kernel doesn't do that anymore.
Turn off crtc->enabled while leased so that modesetting
ignores them.
Check lease status before calling any driver mode functions
When starting a lease, mark leased CRTCs as disabled and hide
their cursors. Also, check to see if there are other
non-leased CRTCs which are driving leased Outputs and mark
them as disabled as well. Sometimes an application will lease
an idle crtc instead of the one already associated with the
leased output.
When terminating a lease, reset any CRTCs which are driving
outputs that are no longer leased so that they start working
again.
This required splitting the DIX level lease termination code
into two pieces, one to remove the lease from the system
(RRLeaseTerminated) and a new function that frees the lease
data structure (RRLeaseFree).
v4: Report RR_Rotate_0 rotation for leased crtcs.
v5: Terminate all leases on server reset.
Leases hang around after the associated client exits so that
the client doesn't need to occupy an X server client slot and
consume a file descriptor once it has gotten the output
resources necessary.
Any leases still hanging around when the X server resets or
shuts down need to be cleaned up by calling the kernel to
terminate the lease and freeing any DIX structures.
Note that we cannot simply use the existing
drmmode_terminate_lease function on each lease as that wants
to also reset the video mode, and during server shut down that
modesetting: Validate leases on VT enter
The kernel doesn't allow any master ioctls to run when another
VT is active, including simple things like listing the active
leases. To deal with that, we check the list of leases
whenever the X server VT is activated.
xfree86: hide disabled cursors when resetting after lease termination
The lessee may well have played with cursors and left one
active on our screen. Just tell the kernel to turn it off.
v6: Add meson build infrastructure
[Also bumped libdrm requirement - ajax]
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-02-12 22:51:56 +01:00
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
drmmode_ptr drmmode = &ms->drmmode;
|
|
|
|
drmModeLesseeListPtr lessees;
|
|
|
|
RRLeasePtr lease, next;
|
|
|
|
int l;
|
|
|
|
|
modesetting: Check whether RandR was initialized before calling rrGetScrPriv
Calling rrGetScrPriv when RandR isn't initialized causes an assertion
failure that aborts the server:
Xorg: ../include/privates.h:121: dixGetPrivateAddr: Assertion `key->initialized' failed.
Thread 1 "Xorg" received signal SIGABRT, Aborted.
0x00007ffff78a8f25 in raise () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff78a8f25 in raise () from /usr/lib/libc.so.6
#1 0x00007ffff7892897 in abort () from /usr/lib/libc.so.6
#2 0x00007ffff7892767 in __assert_fail_base.cold () from /usr/lib/libc.so.6
#3 0x00007ffff78a1526 in __assert_fail () from /usr/lib/libc.so.6
#4 0x00007ffff7fb57c1 in dixGetPrivateAddr (privates=0x555555ab1b60, key=0x555555855720 <rrPrivKeyRec>) at ../include/privates.h:121
#5 0x00007ffff7fb5822 in dixGetPrivate (privates=0x555555ab1b60, key=0x555555855720 <rrPrivKeyRec>) at ../include/privates.h:136
#6 0x00007ffff7fb586a in dixLookupPrivate (privates=0x555555ab1b60, key=0x555555855720 <rrPrivKeyRec>) at ../include/privates.h:166
#7 0x00007ffff7fb8445 in CreateScreenResources (pScreen=0x555555ab1790) at ../hw/xfree86/drivers/modesetting/driver.c:1335
#8 0x000055555576c5e4 in xf86CrtcCreateScreenResources (screen=0x555555ab1790) at ../hw/xfree86/modes/xf86Crtc.c:744
#9 0x00005555555d8bb6 in dix_main (argc=4, argv=0x7fffffffead8, envp=0x7fffffffeb00) at ../dix/main.c:214
#10 0x00005555557a4f0b in main (argc=4, argv=0x7fffffffead8, envp=0x7fffffffeb00) at ../dix/stubmain.c:34
This can happen, for example, if the server is configured with Xinerama
and there is more than one X screen:
Section "ServerLayout"
Identifier "crash"
Screen 0 "modesetting"
Screen 1 "dummy" RightOf "modesetting"
Option "Xinerama"
EndSection
Section "Device"
Identifier "modesetting"
Driver "modesetting"
EndSection
Section "Screen"
Identifier "modesetting"
Device "modesetting"
EndSection
Section "Device"
Identifier "dummy"
Driver "dummy"
EndSection
Section "Screen"
Identifier "dummy"
Device "dummy"
EndSection
The problem does not reproduce if there is only one X screen because of
this code in xf86RandR12Init:
#ifdef PANORAMIX
/* XXX disable RandR when using Xinerama */
if (!noPanoramiXExtension) {
if (xf86NumScreens == 1)
noPanoramiXExtension = TRUE;
else
return TRUE;
}
#endif
Fix the problem by checking dixPrivateKeyRegistered(rrPrivKey) before
calling rrGetScrPriv. This is similar to what the xf86-video-amdgpu
driver does:
https://gitlab.freedesktop.org/xorg/driver/xf86-video-amdgpu/blob/fd66f5c0bea2b7c22a47bfd5eb1f22d32d166d9c/src/amdgpu_kms.c#L388
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2019-12-26 22:40:17 +01:00
|
|
|
/* Bail out if RandR wasn't initialized. */
|
|
|
|
if (!dixPrivateKeyRegistered(rrPrivKey))
|
|
|
|
return;
|
|
|
|
|
|
|
|
scr_priv = rrGetScrPriv(screen);
|
|
|
|
|
Add RandR leases with modesetting driver support [v6]
This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.
v2: Restore CRTC mode when leases terminate
When a lease terminates for a crtc we have saved data for, go
ahead and restore the saved mode.
v3: Report RR_Rotate_0 rotations for leased crtcs.
Ignore leased CRTCs when selecting screen size.
Stop leasing encoders, the kernel doesn't do that anymore.
Turn off crtc->enabled while leased so that modesetting
ignores them.
Check lease status before calling any driver mode functions
When starting a lease, mark leased CRTCs as disabled and hide
their cursors. Also, check to see if there are other
non-leased CRTCs which are driving leased Outputs and mark
them as disabled as well. Sometimes an application will lease
an idle crtc instead of the one already associated with the
leased output.
When terminating a lease, reset any CRTCs which are driving
outputs that are no longer leased so that they start working
again.
This required splitting the DIX level lease termination code
into two pieces, one to remove the lease from the system
(RRLeaseTerminated) and a new function that frees the lease
data structure (RRLeaseFree).
v4: Report RR_Rotate_0 rotation for leased crtcs.
v5: Terminate all leases on server reset.
Leases hang around after the associated client exits so that
the client doesn't need to occupy an X server client slot and
consume a file descriptor once it has gotten the output
resources necessary.
Any leases still hanging around when the X server resets or
shuts down need to be cleaned up by calling the kernel to
terminate the lease and freeing any DIX structures.
Note that we cannot simply use the existing
drmmode_terminate_lease function on each lease as that wants
to also reset the video mode, and during server shut down that
modesetting: Validate leases on VT enter
The kernel doesn't allow any master ioctls to run when another
VT is active, including simple things like listing the active
leases. To deal with that, we check the list of leases
whenever the X server VT is activated.
xfree86: hide disabled cursors when resetting after lease termination
The lessee may well have played with cursors and left one
active on our screen. Just tell the kernel to turn it off.
v6: Add meson build infrastructure
[Also bumped libdrm requirement - ajax]
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-02-12 22:51:56 +01:00
|
|
|
/* We can't talk to the kernel about leases when VT switched */
|
|
|
|
if (!scrn->vtSema)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lessees = drmModeListLessees(drmmode->fd);
|
|
|
|
if (!lessees)
|
|
|
|
return;
|
|
|
|
|
|
|
|
xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
|
|
|
|
drmmode_lease_private_ptr lease_private = lease->devPrivate;
|
|
|
|
|
|
|
|
for (l = 0; l < lessees->count; l++) {
|
|
|
|
if (lessees->lessees[l] == lease_private->lessee_id)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check to see if the lease has gone away */
|
|
|
|
if (l == lessees->count) {
|
|
|
|
free(lease_private);
|
|
|
|
lease->devPrivate = NULL;
|
|
|
|
xf86CrtcLeaseTerminated(lease);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(lessees);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
drmmode_create_lease(RRLeasePtr lease, int *fd)
|
|
|
|
{
|
|
|
|
ScreenPtr screen = lease->screen;
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
drmmode_ptr drmmode = &ms->drmmode;
|
|
|
|
int ncrtc = lease->numCrtcs;
|
|
|
|
int noutput = lease->numOutputs;
|
|
|
|
int nobjects;
|
|
|
|
int c, o;
|
|
|
|
int i;
|
|
|
|
int lease_fd;
|
|
|
|
uint32_t *objects;
|
|
|
|
drmmode_lease_private_ptr lease_private;
|
|
|
|
|
|
|
|
nobjects = ncrtc + noutput;
|
|
|
|
|
2018-06-27 01:34:29 +02:00
|
|
|
if (ms->atomic_modeset)
|
|
|
|
nobjects += ncrtc; /* account for planes as well */
|
|
|
|
|
Add RandR leases with modesetting driver support [v6]
This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.
v2: Restore CRTC mode when leases terminate
When a lease terminates for a crtc we have saved data for, go
ahead and restore the saved mode.
v3: Report RR_Rotate_0 rotations for leased crtcs.
Ignore leased CRTCs when selecting screen size.
Stop leasing encoders, the kernel doesn't do that anymore.
Turn off crtc->enabled while leased so that modesetting
ignores them.
Check lease status before calling any driver mode functions
When starting a lease, mark leased CRTCs as disabled and hide
their cursors. Also, check to see if there are other
non-leased CRTCs which are driving leased Outputs and mark
them as disabled as well. Sometimes an application will lease
an idle crtc instead of the one already associated with the
leased output.
When terminating a lease, reset any CRTCs which are driving
outputs that are no longer leased so that they start working
again.
This required splitting the DIX level lease termination code
into two pieces, one to remove the lease from the system
(RRLeaseTerminated) and a new function that frees the lease
data structure (RRLeaseFree).
v4: Report RR_Rotate_0 rotation for leased crtcs.
v5: Terminate all leases on server reset.
Leases hang around after the associated client exits so that
the client doesn't need to occupy an X server client slot and
consume a file descriptor once it has gotten the output
resources necessary.
Any leases still hanging around when the X server resets or
shuts down need to be cleaned up by calling the kernel to
terminate the lease and freeing any DIX structures.
Note that we cannot simply use the existing
drmmode_terminate_lease function on each lease as that wants
to also reset the video mode, and during server shut down that
modesetting: Validate leases on VT enter
The kernel doesn't allow any master ioctls to run when another
VT is active, including simple things like listing the active
leases. To deal with that, we check the list of leases
whenever the X server VT is activated.
xfree86: hide disabled cursors when resetting after lease termination
The lessee may well have played with cursors and left one
active on our screen. Just tell the kernel to turn it off.
v6: Add meson build infrastructure
[Also bumped libdrm requirement - ajax]
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-02-12 22:51:56 +01:00
|
|
|
if (nobjects == 0)
|
|
|
|
return BadValue;
|
|
|
|
|
|
|
|
lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
|
|
|
|
if (!lease_private)
|
|
|
|
return BadAlloc;
|
|
|
|
|
|
|
|
objects = xallocarray(nobjects, sizeof (uint32_t));
|
|
|
|
|
|
|
|
if (!objects) {
|
|
|
|
free(lease_private);
|
|
|
|
return BadAlloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
2018-06-27 01:34:29 +02:00
|
|
|
/* Add CRTC and plane ids */
|
Add RandR leases with modesetting driver support [v6]
This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.
v2: Restore CRTC mode when leases terminate
When a lease terminates for a crtc we have saved data for, go
ahead and restore the saved mode.
v3: Report RR_Rotate_0 rotations for leased crtcs.
Ignore leased CRTCs when selecting screen size.
Stop leasing encoders, the kernel doesn't do that anymore.
Turn off crtc->enabled while leased so that modesetting
ignores them.
Check lease status before calling any driver mode functions
When starting a lease, mark leased CRTCs as disabled and hide
their cursors. Also, check to see if there are other
non-leased CRTCs which are driving leased Outputs and mark
them as disabled as well. Sometimes an application will lease
an idle crtc instead of the one already associated with the
leased output.
When terminating a lease, reset any CRTCs which are driving
outputs that are no longer leased so that they start working
again.
This required splitting the DIX level lease termination code
into two pieces, one to remove the lease from the system
(RRLeaseTerminated) and a new function that frees the lease
data structure (RRLeaseFree).
v4: Report RR_Rotate_0 rotation for leased crtcs.
v5: Terminate all leases on server reset.
Leases hang around after the associated client exits so that
the client doesn't need to occupy an X server client slot and
consume a file descriptor once it has gotten the output
resources necessary.
Any leases still hanging around when the X server resets or
shuts down need to be cleaned up by calling the kernel to
terminate the lease and freeing any DIX structures.
Note that we cannot simply use the existing
drmmode_terminate_lease function on each lease as that wants
to also reset the video mode, and during server shut down that
modesetting: Validate leases on VT enter
The kernel doesn't allow any master ioctls to run when another
VT is active, including simple things like listing the active
leases. To deal with that, we check the list of leases
whenever the X server VT is activated.
xfree86: hide disabled cursors when resetting after lease termination
The lessee may well have played with cursors and left one
active on our screen. Just tell the kernel to turn it off.
v6: Add meson build infrastructure
[Also bumped libdrm requirement - ajax]
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-02-12 22:51:56 +01:00
|
|
|
for (c = 0; c < ncrtc; c++) {
|
|
|
|
xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
|
2018-06-27 01:34:29 +02:00
|
|
|
if (ms->atomic_modeset)
|
|
|
|
objects[i++] = drmmode_crtc->plane_id;
|
Add RandR leases with modesetting driver support [v6]
This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.
v2: Restore CRTC mode when leases terminate
When a lease terminates for a crtc we have saved data for, go
ahead and restore the saved mode.
v3: Report RR_Rotate_0 rotations for leased crtcs.
Ignore leased CRTCs when selecting screen size.
Stop leasing encoders, the kernel doesn't do that anymore.
Turn off crtc->enabled while leased so that modesetting
ignores them.
Check lease status before calling any driver mode functions
When starting a lease, mark leased CRTCs as disabled and hide
their cursors. Also, check to see if there are other
non-leased CRTCs which are driving leased Outputs and mark
them as disabled as well. Sometimes an application will lease
an idle crtc instead of the one already associated with the
leased output.
When terminating a lease, reset any CRTCs which are driving
outputs that are no longer leased so that they start working
again.
This required splitting the DIX level lease termination code
into two pieces, one to remove the lease from the system
(RRLeaseTerminated) and a new function that frees the lease
data structure (RRLeaseFree).
v4: Report RR_Rotate_0 rotation for leased crtcs.
v5: Terminate all leases on server reset.
Leases hang around after the associated client exits so that
the client doesn't need to occupy an X server client slot and
consume a file descriptor once it has gotten the output
resources necessary.
Any leases still hanging around when the X server resets or
shuts down need to be cleaned up by calling the kernel to
terminate the lease and freeing any DIX structures.
Note that we cannot simply use the existing
drmmode_terminate_lease function on each lease as that wants
to also reset the video mode, and during server shut down that
modesetting: Validate leases on VT enter
The kernel doesn't allow any master ioctls to run when another
VT is active, including simple things like listing the active
leases. To deal with that, we check the list of leases
whenever the X server VT is activated.
xfree86: hide disabled cursors when resetting after lease termination
The lessee may well have played with cursors and left one
active on our screen. Just tell the kernel to turn it off.
v6: Add meson build infrastructure
[Also bumped libdrm requirement - ajax]
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-02-12 22:51:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add connector ids */
|
|
|
|
|
|
|
|
for (o = 0; o < noutput; o++) {
|
|
|
|
xf86OutputPtr output = lease->outputs[o]->devPrivate;
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
|
|
|
|
objects[i++] = drmmode_output->mode_output->connector_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* call kernel to create lease */
|
|
|
|
assert (i == nobjects);
|
|
|
|
|
|
|
|
lease_fd = drmModeCreateLease(drmmode->fd, objects, nobjects, 0, &lease_private->lessee_id);
|
|
|
|
|
|
|
|
free(objects);
|
|
|
|
|
|
|
|
if (lease_fd < 0) {
|
|
|
|
free(lease_private);
|
|
|
|
return BadMatch;
|
|
|
|
}
|
|
|
|
|
|
|
|
lease->devPrivate = lease_private;
|
|
|
|
|
|
|
|
xf86CrtcLeaseStarted(lease);
|
|
|
|
|
|
|
|
*fd = lease_fd;
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
drmmode_terminate_lease(RRLeasePtr lease)
|
|
|
|
{
|
|
|
|
ScreenPtr screen = lease->screen;
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
drmmode_ptr drmmode = &ms->drmmode;
|
|
|
|
drmmode_lease_private_ptr lease_private = lease->devPrivate;
|
|
|
|
|
|
|
|
if (drmModeRevokeLease(drmmode->fd, lease_private->lessee_id) == 0) {
|
|
|
|
free(lease_private);
|
|
|
|
lease->devPrivate = NULL;
|
|
|
|
xf86CrtcLeaseTerminated(lease);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
|
Add RandR leases with modesetting driver support [v6]
This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.
v2: Restore CRTC mode when leases terminate
When a lease terminates for a crtc we have saved data for, go
ahead and restore the saved mode.
v3: Report RR_Rotate_0 rotations for leased crtcs.
Ignore leased CRTCs when selecting screen size.
Stop leasing encoders, the kernel doesn't do that anymore.
Turn off crtc->enabled while leased so that modesetting
ignores them.
Check lease status before calling any driver mode functions
When starting a lease, mark leased CRTCs as disabled and hide
their cursors. Also, check to see if there are other
non-leased CRTCs which are driving leased Outputs and mark
them as disabled as well. Sometimes an application will lease
an idle crtc instead of the one already associated with the
leased output.
When terminating a lease, reset any CRTCs which are driving
outputs that are no longer leased so that they start working
again.
This required splitting the DIX level lease termination code
into two pieces, one to remove the lease from the system
(RRLeaseTerminated) and a new function that frees the lease
data structure (RRLeaseFree).
v4: Report RR_Rotate_0 rotation for leased crtcs.
v5: Terminate all leases on server reset.
Leases hang around after the associated client exits so that
the client doesn't need to occupy an X server client slot and
consume a file descriptor once it has gotten the output
resources necessary.
Any leases still hanging around when the X server resets or
shuts down need to be cleaned up by calling the kernel to
terminate the lease and freeing any DIX structures.
Note that we cannot simply use the existing
drmmode_terminate_lease function on each lease as that wants
to also reset the video mode, and during server shut down that
modesetting: Validate leases on VT enter
The kernel doesn't allow any master ioctls to run when another
VT is active, including simple things like listing the active
leases. To deal with that, we check the list of leases
whenever the X server VT is activated.
xfree86: hide disabled cursors when resetting after lease termination
The lessee may well have played with cursors and left one
active on our screen. Just tell the kernel to turn it off.
v6: Add meson build infrastructure
[Also bumped libdrm requirement - ajax]
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-02-12 22:51:56 +01:00
|
|
|
.resize = drmmode_xf86crtc_resize,
|
|
|
|
.create_lease = drmmode_create_lease,
|
|
|
|
.terminate_lease = drmmode_terminate_lease
|
2011-09-29 12:49:26 +02:00
|
|
|
};
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
Bool
|
|
|
|
drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2015-07-22 04:56:13 +02:00
|
|
|
modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
|
2014-11-28 11:20:50 +01:00
|
|
|
int i;
|
2014-10-08 09:39:15 +02:00
|
|
|
int ret;
|
|
|
|
uint64_t value = 0;
|
2015-07-22 04:56:13 +02:00
|
|
|
unsigned int crtcs_needed = 0;
|
2015-01-28 08:25:00 +01:00
|
|
|
drmModeResPtr mode_res;
|
2015-07-22 04:56:13 +02:00
|
|
|
int crtcshift;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
/* check for dumb capability */
|
|
|
|
ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
|
|
|
|
if (ret > 0 || value != 1) {
|
|
|
|
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
|
|
|
"KMS doesn't support dumb interface\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode->scrn = pScrn;
|
|
|
|
drmmode->cpp = cpp;
|
2015-01-28 08:25:00 +01:00
|
|
|
mode_res = drmModeGetResources(drmmode->fd);
|
|
|
|
if (!mode_res)
|
2014-10-08 09:39:15 +02:00
|
|
|
return FALSE;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
crtcshift = ffs(ms_ent->assigned_crtcs ^ 0xffffffff) - 1;
|
|
|
|
for (i = 0; i < mode_res->count_connectors; i++)
|
|
|
|
crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE,
|
|
|
|
crtcshift);
|
|
|
|
|
|
|
|
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
|
|
|
|
"Up to %d crtcs needed for screen.\n", crtcs_needed);
|
|
|
|
|
2015-01-28 08:25:00 +01:00
|
|
|
xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
|
|
|
|
mode_res->max_height);
|
|
|
|
for (i = 0; i < mode_res->count_crtcs; i++)
|
2014-10-08 09:39:15 +02:00
|
|
|
if (!xf86IsEntityShared(pScrn->entityList[0]) ||
|
2015-07-22 04:56:13 +02:00
|
|
|
(crtcs_needed && !(ms_ent->assigned_crtcs & (1 << i))))
|
|
|
|
crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2015-07-22 04:56:13 +02:00
|
|
|
/* All ZaphodHeads outputs provided with matching crtcs? */
|
|
|
|
if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
|
|
|
|
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
|
|
|
|
"%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
|
|
|
|
crtcs_needed);
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
/* workout clones */
|
2015-01-28 08:25:00 +01:00
|
|
|
drmmode_clones_init(pScrn, drmmode, mode_res);
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2015-01-28 08:25:00 +01:00
|
|
|
drmModeFreeResources(mode_res);
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86ProviderSetup(pScrn, NULL, "modesetting");
|
2012-07-19 06:12:59 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86InitialConfiguration(pScrn, TRUE);
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2018-02-28 02:19:44 +01:00
|
|
|
Bool
|
|
|
|
drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
|
|
|
|
{
|
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
|
|
ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
|
2019-11-18 22:46:44 +01:00
|
|
|
modesettingPtr ms = modesettingPTR(pScrn);
|
2018-02-28 02:19:44 +01:00
|
|
|
|
|
|
|
if (drmmode->glamor) {
|
2019-11-18 22:46:44 +01:00
|
|
|
if (!ms->glamor.init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
|
2018-02-28 02:19:44 +01:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#ifdef GBM_BO_WITH_MODIFIERS
|
2019-11-18 22:46:44 +01:00
|
|
|
ms->glamor.set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
|
2018-02-28 02:19:44 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
void
|
|
|
|
drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
|
|
|
|
xf86OutputPtr output = config->output[config->compat_output];
|
|
|
|
xf86CrtcPtr crtc = output->crtc;
|
|
|
|
|
|
|
|
if (crtc && crtc->enabled) {
|
|
|
|
drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
|
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
Bool
|
2016-05-02 22:54:57 +02:00
|
|
|
drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
|
|
|
|
int c;
|
|
|
|
|
|
|
|
for (c = 0; c < config->num_crtc; c++) {
|
|
|
|
xf86CrtcPtr crtc = config->crtc[c];
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
xf86OutputPtr output = NULL;
|
|
|
|
int o;
|
|
|
|
|
|
|
|
/* Skip disabled CRTCs */
|
|
|
|
if (!crtc->enabled) {
|
2016-05-02 22:54:57 +02:00
|
|
|
if (set_hw) {
|
|
|
|
drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
|
|
|
|
0, 0, 0, NULL, 0, NULL);
|
|
|
|
}
|
2014-10-08 09:39:15 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config->output[config->compat_output]->crtc == crtc)
|
|
|
|
output = config->output[config->compat_output];
|
|
|
|
else {
|
|
|
|
for (o = 0; o < config->num_output; o++)
|
|
|
|
if (config->output[o]->crtc == crtc) {
|
|
|
|
output = config->output[o];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* paranoia */
|
|
|
|
if (!output)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Mark that we'll need to re-set the mode for sure */
|
|
|
|
memset(&crtc->mode, 0, sizeof(crtc->mode));
|
|
|
|
if (!crtc->desiredMode.CrtcHDisplay) {
|
|
|
|
DisplayModePtr mode =
|
|
|
|
xf86OutputFindClosestMode(output, pScrn->currentMode);
|
|
|
|
|
|
|
|
if (!mode)
|
|
|
|
return FALSE;
|
|
|
|
crtc->desiredMode = *mode;
|
|
|
|
crtc->desiredRotation = RR_Rotate_0;
|
|
|
|
crtc->desiredX = 0;
|
|
|
|
crtc->desiredY = 0;
|
|
|
|
}
|
|
|
|
|
2016-05-02 22:54:57 +02:00
|
|
|
if (set_hw) {
|
|
|
|
if (!crtc->funcs->
|
|
|
|
set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
|
|
|
|
crtc->desiredX, crtc->desiredY))
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
crtc->mode = crtc->desiredMode;
|
|
|
|
crtc->rotation = crtc->desiredRotation;
|
|
|
|
crtc->x = crtc->desiredX;
|
|
|
|
crtc->y = crtc->desiredY;
|
|
|
|
if (!xf86CrtcRotate(crtc))
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-10-08 09:39:15 +02:00
|
|
|
}
|
Add RandR leases with modesetting driver support [v6]
This adds support for RandR CRTC/Output leases through the modesetting
driver, creating a lease using new kernel infrastructure and returning
that to a client through an fd which will have access to only those
resources.
v2: Restore CRTC mode when leases terminate
When a lease terminates for a crtc we have saved data for, go
ahead and restore the saved mode.
v3: Report RR_Rotate_0 rotations for leased crtcs.
Ignore leased CRTCs when selecting screen size.
Stop leasing encoders, the kernel doesn't do that anymore.
Turn off crtc->enabled while leased so that modesetting
ignores them.
Check lease status before calling any driver mode functions
When starting a lease, mark leased CRTCs as disabled and hide
their cursors. Also, check to see if there are other
non-leased CRTCs which are driving leased Outputs and mark
them as disabled as well. Sometimes an application will lease
an idle crtc instead of the one already associated with the
leased output.
When terminating a lease, reset any CRTCs which are driving
outputs that are no longer leased so that they start working
again.
This required splitting the DIX level lease termination code
into two pieces, one to remove the lease from the system
(RRLeaseTerminated) and a new function that frees the lease
data structure (RRLeaseFree).
v4: Report RR_Rotate_0 rotation for leased crtcs.
v5: Terminate all leases on server reset.
Leases hang around after the associated client exits so that
the client doesn't need to occupy an X server client slot and
consume a file descriptor once it has gotten the output
resources necessary.
Any leases still hanging around when the X server resets or
shuts down need to be cleaned up by calling the kernel to
terminate the lease and freeing any DIX structures.
Note that we cannot simply use the existing
drmmode_terminate_lease function on each lease as that wants
to also reset the video mode, and during server shut down that
modesetting: Validate leases on VT enter
The kernel doesn't allow any master ioctls to run when another
VT is active, including simple things like listing the active
leases. To deal with that, we check the list of leases
whenever the X server VT is activated.
xfree86: hide disabled cursors when resetting after lease termination
The lessee may well have played with cursors and left one
active on our screen. Just tell the kernel to turn it off.
v6: Add meson build infrastructure
[Also bumped libdrm requirement - ajax]
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2018-02-12 22:51:56 +01:00
|
|
|
|
|
|
|
/* Validate leases on VT re-entry */
|
|
|
|
drmmode_validate_leases(pScrn);
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
static void
|
|
|
|
drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
|
|
|
|
int *indices, LOCO * colors, VisualPtr pVisual)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
|
|
|
|
uint16_t lut_r[256], lut_g[256], lut_b[256];
|
2011-09-29 12:49:26 +02:00
|
|
|
int index, j, i;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
for (c = 0; c < xf86_config->num_crtc; c++) {
|
|
|
|
xf86CrtcPtr crtc = xf86_config->crtc[c];
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
for (i = 0; i < 256; i++) {
|
2011-09-29 12:49:26 +02:00
|
|
|
lut_r[i] = drmmode_crtc->lut_r[i] << 6;
|
|
|
|
lut_g[i] = drmmode_crtc->lut_g[i] << 6;
|
|
|
|
lut_b[i] = drmmode_crtc->lut_b[i] << 6;
|
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
switch (pScrn->depth) {
|
2011-09-29 12:49:26 +02:00
|
|
|
case 15:
|
|
|
|
for (i = 0; i < numColors; i++) {
|
|
|
|
index = indices[i];
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
|
|
lut_r[index * 8 + j] = colors[index].red << 6;
|
|
|
|
lut_g[index * 8 + j] = colors[index].green << 6;
|
|
|
|
lut_b[index * 8 + j] = colors[index].blue << 6;
|
|
|
|
}
|
|
|
|
}
|
2014-10-08 09:39:15 +02:00
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
for (i = 0; i < numColors; i++) {
|
|
|
|
index = indices[i];
|
|
|
|
|
|
|
|
if (i <= 31) {
|
|
|
|
for (j = 0; j < 8; j++) {
|
|
|
|
lut_r[index * 8 + j] = colors[index].red << 6;
|
|
|
|
lut_b[index * 8 + j] = colors[index].blue << 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < 4; j++) {
|
|
|
|
lut_g[index * 4 + j] = colors[index].green << 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
for (i = 0; i < numColors; i++) {
|
|
|
|
index = indices[i];
|
|
|
|
lut_r[index] = colors[index].red << 6;
|
|
|
|
lut_g[index] = colors[index].green << 6;
|
|
|
|
lut_b[index] = colors[index].blue << 6;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make the change through RandR */
|
2011-09-29 12:49:26 +02:00
|
|
|
if (crtc->randr_crtc)
|
|
|
|
RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
|
|
|
|
else
|
|
|
|
crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
|
2014-10-08 09:39:15 +02:00
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
Bool
|
|
|
|
drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2018-10-31 16:43:33 +01:00
|
|
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
|
|
|
"Initializing kms color map for depth %d, %d bpc.\n",
|
|
|
|
pScrn->depth, pScrn->rgbBits);
|
2011-09-29 12:49:26 +02:00
|
|
|
if (!miCreateDefColormap(pScreen))
|
|
|
|
return FALSE;
|
2018-02-27 03:05:31 +01:00
|
|
|
|
|
|
|
/* Adapt color map size and depth to color depth of screen. */
|
|
|
|
if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10,
|
|
|
|
drmmode_load_palette, NULL,
|
|
|
|
CMAP_PALETTED_TRUECOLOR |
|
|
|
|
CMAP_RELOAD_ON_MODE_SWITCH))
|
2014-10-08 09:39:15 +02:00
|
|
|
return FALSE;
|
2011-09-29 12:49:26 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-11-28 11:20:49 +01:00
|
|
|
#ifdef CONFIG_UDEV_KMS
|
2017-04-10 15:48:21 +02:00
|
|
|
|
|
|
|
#define DRM_MODE_LINK_STATUS_GOOD 0
|
|
|
|
#define DRM_MODE_LINK_STATUS_BAD 1
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
static void
|
|
|
|
drmmode_handle_uevents(int fd, void *closure)
|
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmmode_ptr drmmode = closure;
|
|
|
|
ScrnInfoPtr scrn = drmmode->scrn;
|
|
|
|
struct udev_device *dev;
|
2015-01-28 08:35:21 +01:00
|
|
|
drmModeResPtr mode_res;
|
|
|
|
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
|
|
|
|
int i, j;
|
2015-12-11 12:05:22 +01:00
|
|
|
Bool found = FALSE;
|
2015-01-28 08:35:21 +01:00
|
|
|
Bool changed = FALSE;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
2015-12-11 12:05:22 +01:00
|
|
|
while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
|
|
|
|
udev_device_unref(dev);
|
|
|
|
found = TRUE;
|
|
|
|
}
|
|
|
|
if (!found)
|
2014-10-08 09:39:15 +02:00
|
|
|
return;
|
|
|
|
|
2017-04-10 15:48:21 +02:00
|
|
|
/* Try to re-set the mode on all the connectors with a BAD link-state:
|
|
|
|
* This may happen if a link degrades and a new modeset is necessary, using
|
|
|
|
* different link-training parameters. If the kernel found that the current
|
|
|
|
* mode is not achievable anymore, it should have pruned the mode before
|
|
|
|
* sending the hotplug event. Try to re-set the currently-set mode to keep
|
|
|
|
* the display alive, this will fail if the mode has been pruned.
|
|
|
|
* In any case, we will send randr events for the Desktop Environment to
|
|
|
|
* deal with it, if it wants to.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = config->output[i];
|
|
|
|
drmmode_output_private_ptr drmmode_output = output->driver_private;
|
|
|
|
|
2017-12-22 03:54:34 +01:00
|
|
|
drmmode_output_detect(output);
|
2017-10-20 10:05:35 +02:00
|
|
|
|
2017-04-10 15:48:21 +02:00
|
|
|
/* Get an updated view of the properties for the current connector and
|
|
|
|
* look for the link-status property
|
|
|
|
*/
|
2017-12-22 03:54:34 +01:00
|
|
|
for (j = 0; j < drmmode_output->num_props; j++) {
|
|
|
|
drmmode_prop_ptr p = &drmmode_output->props[j];
|
|
|
|
|
|
|
|
if (!strcmp(p->mode_prop->name, "link-status")) {
|
|
|
|
if (p->value == DRM_MODE_LINK_STATUS_BAD) {
|
|
|
|
xf86CrtcPtr crtc = output->crtc;
|
|
|
|
if (!crtc)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* the connector got a link failure, re-set the current mode */
|
|
|
|
drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
|
|
|
|
crtc->x, crtc->y);
|
|
|
|
|
|
|
|
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
|
|
|
|
"hotplug event: connector %u's link-state is BAD, "
|
|
|
|
"tried resetting the current mode. You may be left"
|
|
|
|
"with a black screen if this fails...\n",
|
|
|
|
drmmode_output->mode_output->connector_id);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2017-04-10 15:48:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-28 08:35:21 +01:00
|
|
|
mode_res = drmModeGetResources(drmmode->fd);
|
|
|
|
if (!mode_res)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (mode_res->count_crtcs != config->num_crtc) {
|
2020-02-04 07:02:06 +01:00
|
|
|
/* this triggers with Zaphod mode where we don't currently support connector hotplug or MST. */
|
2015-01-28 08:35:21 +01:00
|
|
|
goto out_free_res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* figure out if we have gotten rid of any connectors
|
|
|
|
traverse old output list looking for outputs */
|
|
|
|
for (i = 0; i < config->num_output; i++) {
|
|
|
|
xf86OutputPtr output = config->output[i];
|
|
|
|
drmmode_output_private_ptr drmmode_output;
|
|
|
|
|
|
|
|
drmmode_output = output->driver_private;
|
|
|
|
found = FALSE;
|
|
|
|
for (j = 0; j < mode_res->count_connectors; j++) {
|
|
|
|
if (mode_res->connectors[j] == drmmode_output->output_id) {
|
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
drmModeFreeConnector(drmmode_output->mode_output);
|
|
|
|
drmmode_output->mode_output = NULL;
|
|
|
|
drmmode_output->output_id = -1;
|
|
|
|
|
|
|
|
changed = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find new output ids we don't have outputs for */
|
|
|
|
for (i = 0; i < mode_res->count_connectors; i++) {
|
|
|
|
found = FALSE;
|
|
|
|
|
|
|
|
for (j = 0; j < config->num_output; j++) {
|
|
|
|
xf86OutputPtr output = config->output[j];
|
|
|
|
drmmode_output_private_ptr drmmode_output;
|
|
|
|
|
|
|
|
drmmode_output = output->driver_private;
|
|
|
|
if (mode_res->connectors[i] == drmmode_output->output_id) {
|
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
changed = TRUE;
|
2015-07-22 04:56:13 +02:00
|
|
|
drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
|
2015-01-28 08:35:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (changed) {
|
|
|
|
RRSetChanged(xf86ScrnToScreen(scrn));
|
|
|
|
RRTellChanged(xf86ScrnToScreen(scrn));
|
|
|
|
}
|
|
|
|
|
|
|
|
out_free_res:
|
2020-02-04 07:02:06 +01:00
|
|
|
|
|
|
|
/* Check to see if a lessee has disappeared */
|
|
|
|
drmmode_validate_leases(scrn);
|
|
|
|
|
2015-01-28 08:35:21 +01:00
|
|
|
drmModeFreeResources(mode_res);
|
|
|
|
out:
|
2014-10-08 09:39:15 +02:00
|
|
|
RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
2017-04-10 15:48:21 +02:00
|
|
|
|
|
|
|
#undef DRM_MODE_LINK_STATUS_BAD
|
|
|
|
#undef DRM_MODE_LINK_STATUS_GOOD
|
|
|
|
|
2011-09-29 12:49:26 +02:00
|
|
|
#endif
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
void
|
|
|
|
drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-11-28 11:20:49 +01:00
|
|
|
#ifdef CONFIG_UDEV_KMS
|
2014-10-08 09:39:15 +02:00
|
|
|
struct udev *u;
|
|
|
|
struct udev_monitor *mon;
|
|
|
|
|
|
|
|
u = udev_new();
|
|
|
|
if (!u)
|
|
|
|
return;
|
|
|
|
mon = udev_monitor_new_from_netlink(u, "udev");
|
|
|
|
if (!mon) {
|
|
|
|
udev_unref(u);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (udev_monitor_filter_add_match_subsystem_devtype(mon,
|
|
|
|
"drm",
|
|
|
|
"drm_minor") < 0 ||
|
|
|
|
udev_monitor_enable_receiving(mon) < 0) {
|
|
|
|
udev_monitor_unref(mon);
|
|
|
|
udev_unref(u);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmmode->uevent_handler =
|
|
|
|
xf86AddGeneralHandler(udev_monitor_get_fd(mon),
|
|
|
|
drmmode_handle_uevents, drmmode);
|
|
|
|
|
|
|
|
drmmode->uevent_monitor = mon;
|
2011-09-29 12:49:26 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
void
|
|
|
|
drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-11-28 11:20:49 +01:00
|
|
|
#ifdef CONFIG_UDEV_KMS
|
2014-10-08 09:39:15 +02:00
|
|
|
if (drmmode->uevent_handler) {
|
|
|
|
struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
|
|
|
|
|
|
|
|
xf86RemoveGeneralHandler(drmmode->uevent_handler);
|
2011-09-29 12:49:26 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
udev_monitor_unref(drmmode->uevent_monitor);
|
|
|
|
udev_unref(u);
|
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create front and cursor BOs */
|
2014-10-08 09:39:15 +02:00
|
|
|
Bool
|
|
|
|
drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
modesettingPtr ms = modesettingPTR(pScrn);
|
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
|
|
|
|
int width;
|
|
|
|
int height;
|
2015-07-22 18:14:06 +02:00
|
|
|
int bpp = ms->drmmode.kbpp;
|
2014-10-08 09:39:15 +02:00
|
|
|
int i;
|
|
|
|
int cpp = (bpp + 7) / 8;
|
|
|
|
|
|
|
|
width = pScrn->virtualX;
|
|
|
|
height = pScrn->virtualY;
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp))
|
2014-10-08 09:39:15 +02:00
|
|
|
return FALSE;
|
2014-12-10 00:20:44 +01:00
|
|
|
pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp;
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
width = ms->cursor_width;
|
|
|
|
height = ms->cursor_height;
|
|
|
|
bpp = 32;
|
|
|
|
for (i = 0; i < xf86_config->num_crtc; i++) {
|
|
|
|
xf86CrtcPtr crtc = xf86_config->crtc[i];
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
drmmode_crtc->cursor_bo =
|
|
|
|
dumb_bo_create(drmmode->fd, width, height, bpp);
|
|
|
|
}
|
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
void *
|
|
|
|
drmmode_map_front_bo(drmmode_ptr drmmode)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2015-01-14 00:08:36 +01:00
|
|
|
return drmmode_bo_map(drmmode, &drmmode->front_bo);
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
void *
|
2020-07-05 23:00:50 +02:00
|
|
|
drmmode_map_secondary_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv)
|
2012-07-19 06:12:59 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
int ret;
|
2012-07-19 06:12:59 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
if (ppriv->backing_bo->ptr)
|
|
|
|
return ppriv->backing_bo->ptr;
|
2012-07-19 06:12:59 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
ret = dumb_bo_map(drmmode->fd, ppriv->backing_bo);
|
|
|
|
if (ret)
|
|
|
|
return NULL;
|
2012-07-19 06:12:59 +02:00
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
return ppriv->backing_bo->ptr;
|
2012-07-19 06:12:59 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
Bool
|
|
|
|
drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
|
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
for (i = 0; i < xf86_config->num_crtc; i++) {
|
|
|
|
xf86CrtcPtr crtc = xf86_config->crtc[i];
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor_bo);
|
|
|
|
if (ret)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 09:39:15 +02:00
|
|
|
void
|
|
|
|
drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
|
2011-09-29 12:49:26 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (drmmode->fb_id) {
|
|
|
|
drmModeRmFB(drmmode->fd, drmmode->fb_id);
|
|
|
|
drmmode->fb_id = 0;
|
|
|
|
}
|
|
|
|
|
2014-12-10 00:20:44 +01:00
|
|
|
drmmode_bo_destroy(drmmode, &drmmode->front_bo);
|
2014-10-08 09:39:15 +02:00
|
|
|
|
|
|
|
for (i = 0; i < xf86_config->num_crtc; i++) {
|
|
|
|
xf86CrtcPtr crtc = xf86_config->crtc[i];
|
|
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
|
|
|
|
|
|
dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
|
|
|
|
}
|
2011-09-29 12:49:26 +02:00
|
|
|
}
|
2012-05-01 18:12:29 +02:00
|
|
|
|
|
|
|
/* ugly workaround to see if we can create 32bpp */
|
2014-10-08 09:39:15 +02:00
|
|
|
void
|
|
|
|
drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int *depth,
|
|
|
|
int *bpp)
|
2012-05-01 18:12:29 +02:00
|
|
|
{
|
2014-10-08 09:39:15 +02:00
|
|
|
drmModeResPtr mode_res;
|
|
|
|
uint64_t value;
|
|
|
|
struct dumb_bo *bo;
|
|
|
|
uint32_t fb_id;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* 16 is fine */
|
|
|
|
ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_PREFERRED_DEPTH, &value);
|
|
|
|
if (!ret && (value == 16 || value == 8)) {
|
|
|
|
*depth = value;
|
|
|
|
*bpp = value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*depth = 24;
|
|
|
|
mode_res = drmModeGetResources(drmmode->fd);
|
|
|
|
if (!mode_res)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (mode_res->min_width == 0)
|
|
|
|
mode_res->min_width = 1;
|
|
|
|
if (mode_res->min_height == 0)
|
|
|
|
mode_res->min_height = 1;
|
|
|
|
/*create a bo */
|
|
|
|
bo = dumb_bo_create(drmmode->fd, mode_res->min_width, mode_res->min_height,
|
|
|
|
32);
|
|
|
|
if (!bo) {
|
|
|
|
*bpp = 24;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = drmModeAddFB(drmmode->fd, mode_res->min_width, mode_res->min_height,
|
|
|
|
24, 32, bo->pitch, bo->handle, &fb_id);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
*bpp = 24;
|
|
|
|
dumb_bo_destroy(drmmode->fd, bo);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeRmFB(drmmode->fd, fb_id);
|
|
|
|
*bpp = 32;
|
|
|
|
|
|
|
|
dumb_bo_destroy(drmmode->fd, bo);
|
|
|
|
out:
|
|
|
|
drmModeFreeResources(mode_res);
|
|
|
|
return;
|
2012-05-01 18:12:29 +02:00
|
|
|
}
|
2019-06-24 21:46:26 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We hook the screen's cursor-sprite (swcursor) functions to see if a swcursor
|
2020-07-05 22:07:33 +02:00
|
|
|
* is active. When a swcursor is active we disable page-flipping.
|
2019-06-24 21:46:26 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
static void drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,
|
|
|
|
ScrnInfoPtr scrn, int x, int y)
|
|
|
|
{
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
CursorPtr cursor = sprite_priv->cursor;
|
|
|
|
Bool sprite_visible = sprite_priv->sprite_visible;
|
|
|
|
|
|
|
|
if (cursor) {
|
|
|
|
x -= cursor->bits->xhot;
|
|
|
|
y -= cursor->bits->yhot;
|
|
|
|
|
|
|
|
sprite_priv->sprite_visible =
|
|
|
|
x < scrn->virtualX && y < scrn->virtualY &&
|
|
|
|
(x + cursor->bits->width > 0) &&
|
|
|
|
(y + cursor->bits->height > 0);
|
|
|
|
} else {
|
|
|
|
sprite_priv->sprite_visible = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ms->drmmode.sprites_visible += sprite_priv->sprite_visible - sprite_visible;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
|
|
|
|
CursorPtr pCursor, int x, int y)
|
|
|
|
{
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
|
|
|
|
|
|
|
|
sprite_priv->cursor = pCursor;
|
|
|
|
drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
|
|
|
|
|
|
|
|
ms->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
|
|
|
|
int x, int y)
|
|
|
|
{
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
|
|
|
|
|
|
|
|
drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
|
|
|
|
|
|
|
|
ms->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
|
|
|
|
ScreenPtr pScreen,
|
|
|
|
CursorPtr pCursor)
|
|
|
|
{
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
|
|
|
|
return ms->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
|
|
|
|
ScreenPtr pScreen,
|
|
|
|
CursorPtr pCursor)
|
|
|
|
{
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
|
|
|
|
return ms->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
|
|
|
|
ScreenPtr pScreen)
|
|
|
|
{
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
|
|
|
|
return ms->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
|
|
|
|
ScreenPtr pScreen)
|
|
|
|
{
|
|
|
|
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
|
|
|
|
modesettingPtr ms = modesettingPTR(scrn);
|
|
|
|
|
|
|
|
ms->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
|
|
|
|
}
|
|
|
|
|
|
|
|
miPointerSpriteFuncRec drmmode_sprite_funcs = {
|
|
|
|
.RealizeCursor = drmmode_sprite_realize_realize_cursor,
|
|
|
|
.UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
|
|
|
|
.SetCursor = drmmode_sprite_set_cursor,
|
|
|
|
.MoveCursor = drmmode_sprite_move_cursor,
|
|
|
|
.DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
|
|
|
|
.DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
|
|
|
|
};
|