mirror of
https://github.com/X11Libre/xf86-video-ati.git
synced 2026-03-24 01:24:43 +00:00
radeon/kms: add pageflip support
requires radeon drm 2.8.0 or higher Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Jerome Glisse <jglisse@redhat.com>
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#ifdef XF86DRM_MODE
|
||||
#include <sys/ioctl.h>
|
||||
#include "micmap.h"
|
||||
@@ -1279,6 +1280,25 @@ drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
|
||||
radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data);
|
||||
}
|
||||
|
||||
static void
|
||||
drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
|
||||
unsigned int tv_usec, void *event_data)
|
||||
{
|
||||
drmmode_ptr drmmode = event_data;
|
||||
|
||||
drmmode->flip_count--;
|
||||
if (drmmode->flip_count > 0)
|
||||
return;
|
||||
|
||||
drmModeRmFB(drmmode->fd, drmmode->old_fb_id);
|
||||
|
||||
if (drmmode->event_data == NULL)
|
||||
return;
|
||||
|
||||
radeon_dri2_flip_event_handler(frame, tv_sec, tv_usec, drmmode->event_data);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
drm_wakeup_handler(pointer data, int err, pointer p)
|
||||
{
|
||||
@@ -1322,8 +1342,9 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
|
||||
drmmode->flip_count = 0;
|
||||
drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
|
||||
drmmode->event_context.vblank_handler = drmmode_vblank_handler;
|
||||
drmmode->event_context.page_flip_handler = NULL;
|
||||
drmmode->event_context.page_flip_handler = drmmode_flip_handler;
|
||||
if (!pRADEONEnt->fd_wakeup_registered && info->dri->pKernelDRMVersion->version_minor >= 4) {
|
||||
drmmode->flip_count = 0;
|
||||
AddGeneralSocket(drmmode->fd);
|
||||
RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
|
||||
drm_wakeup_handler, drmmode);
|
||||
@@ -1563,4 +1584,71 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
|
||||
#endif
|
||||
}
|
||||
|
||||
Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data)
|
||||
{
|
||||
RADEONInfoPtr info = RADEONPTR(scrn);
|
||||
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
|
||||
drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
|
||||
drmmode_ptr drmmode = drmmode_crtc->drmmode;
|
||||
unsigned int pitch = scrn->displayWidth * info->CurrentLayout.pixel_bytes;
|
||||
int i, old_fb_id;
|
||||
uint32_t tiling_flags = 0;
|
||||
int height;
|
||||
|
||||
if (info->allowColorTiling) {
|
||||
if (info->ChipFamily >= CHIP_FAMILY_R600)
|
||||
tiling_flags |= RADEON_TILING_MICRO;
|
||||
else
|
||||
tiling_flags |= RADEON_TILING_MACRO;
|
||||
}
|
||||
|
||||
pitch = RADEON_ALIGN(pitch, drmmode_get_pitch_align(scrn, info->CurrentLayout.pixel_bytes, tiling_flags));
|
||||
height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags));
|
||||
|
||||
/*
|
||||
* Create a new handle for the back buffer
|
||||
*/
|
||||
old_fb_id = drmmode->fb_id;
|
||||
if (drmModeAddFB(drmmode->fd, scrn->virtualX, height,
|
||||
scrn->depth, scrn->bitsPerPixel, pitch,
|
||||
new_front->handle, &drmmode->fb_id))
|
||||
goto error_out;
|
||||
|
||||
/*
|
||||
* Queue flips on all enabled CRTCs
|
||||
* Note that if/when we get per-CRTC buffers, we'll have to update this.
|
||||
* Right now it assumes a single shared fb across all CRTCs, with the
|
||||
* kernel fixing up the offset of each CRTC as necessary.
|
||||
*
|
||||
* Also, flips queued on disabled or incorrectly configured displays
|
||||
* may never complete; this is a configuration error.
|
||||
*/
|
||||
for (i = 0; i < config->num_crtc; i++) {
|
||||
if (!config->crtc[i]->enabled)
|
||||
continue;
|
||||
|
||||
drmmode->event_data = data;
|
||||
drmmode->flip_count++;
|
||||
drmmode_crtc = config->crtc[i]->driver_private;
|
||||
if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
|
||||
drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, drmmode)) {
|
||||
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
|
||||
"flip queue failed: %s\n", strerror(errno));
|
||||
goto error_undo;
|
||||
}
|
||||
}
|
||||
|
||||
drmmode->old_fb_id = old_fb_id;
|
||||
return TRUE;
|
||||
|
||||
error_undo:
|
||||
drmModeRmFB(drmmode->fd, drmmode->fb_id);
|
||||
drmmode->fb_id = old_fb_id;
|
||||
|
||||
error_out:
|
||||
xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
|
||||
strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
typedef struct {
|
||||
int fd;
|
||||
unsigned fb_id;
|
||||
unsigned old_fb_id;
|
||||
drmModeResPtr mode_res;
|
||||
drmModeFBPtr mode_fb;
|
||||
int cpp;
|
||||
@@ -50,6 +51,7 @@ typedef struct {
|
||||
#endif
|
||||
drmEventContext event_context;
|
||||
int flip_count;
|
||||
void *event_data;
|
||||
} drmmode_rec, *drmmode_ptr;
|
||||
|
||||
typedef struct {
|
||||
@@ -99,6 +101,8 @@ extern int drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling);
|
||||
extern int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
|
||||
extern int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
|
||||
|
||||
Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1074,6 +1074,8 @@ typedef struct {
|
||||
struct radeon_bo *bicubic_bo;
|
||||
void *bicubic_memory;
|
||||
int bicubic_offset;
|
||||
/* kms pageflipping */
|
||||
Bool allowPageFlip;
|
||||
} RADEONInfoRec, *RADEONInfoPtr;
|
||||
|
||||
#define RADEONWaitForFifo(pScrn, entries) \
|
||||
|
||||
@@ -82,6 +82,10 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
|
||||
struct radeon_exa_pixmap_priv *driver_priv;
|
||||
int i, r, need_enlarge = 0;
|
||||
int flags = 0;
|
||||
unsigned front_width;
|
||||
|
||||
pixmap = screen->GetScreenPixmap(screen);
|
||||
front_width = pixmap->drawable.width;
|
||||
|
||||
buffers = calloc(count, sizeof *buffers);
|
||||
if (buffers == NULL) {
|
||||
@@ -162,12 +166,18 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
|
||||
drawable->depth,
|
||||
flags);
|
||||
|
||||
} else
|
||||
} else {
|
||||
unsigned aligned_width = drawable->width;
|
||||
|
||||
if (aligned_width == front_width)
|
||||
aligned_width = pScrn->virtualX;
|
||||
|
||||
pixmap = (*pScreen->CreatePixmap)(pScreen,
|
||||
drawable->width,
|
||||
aligned_width,
|
||||
drawable->height,
|
||||
drawable->depth,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (attachments[i] == DRI2BufferDepth) {
|
||||
@@ -206,6 +216,10 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
|
||||
struct radeon_exa_pixmap_priv *driver_priv;
|
||||
int r, need_enlarge = 0;
|
||||
int flags;
|
||||
unsigned front_width;
|
||||
|
||||
pixmap = pScreen->GetScreenPixmap(pScreen);
|
||||
front_width = pixmap->drawable.width;
|
||||
|
||||
buffers = calloc(1, sizeof *buffers);
|
||||
if (buffers == NULL) {
|
||||
@@ -287,12 +301,18 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
|
||||
(format != 0)?format:drawable->depth,
|
||||
flags);
|
||||
|
||||
} else
|
||||
} else {
|
||||
unsigned aligned_width = drawable->width;
|
||||
|
||||
if (aligned_width == front_width)
|
||||
aligned_width = pScrn->virtualX;
|
||||
|
||||
pixmap = (*pScreen->CreatePixmap)(pScreen,
|
||||
drawable->width,
|
||||
aligned_width,
|
||||
drawable->height,
|
||||
(format != 0)?format:drawable->depth,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (attachment == DRI2BufferDepth) {
|
||||
@@ -549,12 +569,98 @@ radeon_dri2_unref_buffer(BufferPtr buffer)
|
||||
}
|
||||
}
|
||||
|
||||
static Bool
|
||||
radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
|
||||
DrawablePtr draw, DRI2BufferPtr front,
|
||||
DRI2BufferPtr back, DRI2SwapEventPtr func,
|
||||
void *data)
|
||||
{
|
||||
struct dri2_buffer_priv *back_priv;
|
||||
struct radeon_exa_pixmap_priv *exa_priv;
|
||||
DRI2FrameEventPtr flip_info;
|
||||
|
||||
flip_info = calloc(1, sizeof(DRI2FrameEventRec));
|
||||
if (!flip_info)
|
||||
return FALSE;
|
||||
|
||||
flip_info->drawable_id = draw->id;
|
||||
flip_info->client = client;
|
||||
flip_info->type = DRI2_SWAP;
|
||||
flip_info->event_complete = func;
|
||||
flip_info->event_data = data;
|
||||
xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
|
||||
"%s:%d fevent[%p]\n", __func__, __LINE__, flip_info);
|
||||
|
||||
/* Page flip the full screen buffer */
|
||||
back_priv = back->driverPrivate;
|
||||
exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap);
|
||||
return radeon_do_pageflip(scrn, exa_priv->bo, flip_info);
|
||||
}
|
||||
|
||||
static Bool
|
||||
can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
|
||||
{
|
||||
struct dri2_buffer_priv *front_priv = front->driverPrivate;
|
||||
struct dri2_buffer_priv *back_priv = back->driverPrivate;
|
||||
PixmapPtr front_pixmap = front_priv->pixmap;
|
||||
PixmapPtr back_pixmap = back_priv->pixmap;
|
||||
|
||||
if (front_pixmap->drawable.width != back_pixmap->drawable.width)
|
||||
return FALSE;
|
||||
|
||||
if (front_pixmap->drawable.height != back_pixmap->drawable.height)
|
||||
return FALSE;
|
||||
|
||||
if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
|
||||
return FALSE;
|
||||
|
||||
if (front_pixmap->devKind != back_pixmap->devKind)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
radeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
|
||||
{
|
||||
struct dri2_buffer_priv *front_priv = front->driverPrivate;
|
||||
struct dri2_buffer_priv *back_priv = back->driverPrivate;
|
||||
struct radeon_exa_pixmap_priv *front_radeon, *back_radeon;
|
||||
ScreenPtr screen;
|
||||
RADEONInfoPtr info;
|
||||
struct radeon_bo *bo;
|
||||
int tmp;
|
||||
|
||||
/* Swap BO names so DRI works */
|
||||
tmp = front->name;
|
||||
front->name = back->name;
|
||||
back->name = tmp;
|
||||
|
||||
/* Swap pixmap bos */
|
||||
front_radeon = exaGetPixmapDriverPrivate(front_priv->pixmap);
|
||||
back_radeon = exaGetPixmapDriverPrivate(back_priv->pixmap);
|
||||
bo = back_radeon->bo;
|
||||
back_radeon->bo = front_radeon->bo;
|
||||
front_radeon->bo = bo;
|
||||
|
||||
/* Do we need to update the Screen? */
|
||||
screen = draw->pScreen;
|
||||
info = RADEONPTR(xf86Screens[screen->myNum]);
|
||||
if (front_radeon->bo == info->front_bo) {
|
||||
radeon_bo_unref(info->front_bo);
|
||||
info->front_bo = back_radeon->bo;
|
||||
radeon_bo_ref(info->front_bo);
|
||||
front_radeon = exaGetPixmapDriverPrivate(screen->GetScreenPixmap(screen));
|
||||
front_radeon->bo = bo;
|
||||
}
|
||||
}
|
||||
|
||||
void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
|
||||
unsigned int tv_usec, void *event_data)
|
||||
{
|
||||
DRI2FrameEventPtr event = event_data;
|
||||
RADEONInfoPtr info;
|
||||
DrawablePtr drawable;
|
||||
ClientPtr client;
|
||||
ScreenPtr screen;
|
||||
ScrnInfoPtr scrn;
|
||||
int status;
|
||||
@@ -563,7 +669,7 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
|
||||
RegionRec region;
|
||||
|
||||
if (!event->valid)
|
||||
goto cleanup;
|
||||
goto cleanup;
|
||||
|
||||
status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
|
||||
M_ANY, DixWriteAccess);
|
||||
@@ -572,25 +678,45 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
|
||||
|
||||
screen = drawable->pScreen;
|
||||
scrn = xf86Screens[screen->myNum];
|
||||
client = event->client;
|
||||
info = RADEONPTR(scrn);
|
||||
|
||||
switch (event->type) {
|
||||
case DRI2_FLIP:
|
||||
if (info->allowPageFlip &&
|
||||
DRI2CanFlip(drawable) &&
|
||||
can_exchange(event->front, event->back) &&
|
||||
radeon_dri2_schedule_flip(scrn,
|
||||
event->client,
|
||||
drawable,
|
||||
event->front,
|
||||
event->back,
|
||||
event->event_complete,
|
||||
event->event_data)) {
|
||||
radeon_dri2_exchange_buffers(drawable, event->front, event->back);
|
||||
break;
|
||||
}
|
||||
/* else fall through to exchange/blit */
|
||||
case DRI2_SWAP:
|
||||
box.x1 = 0;
|
||||
box.y1 = 0;
|
||||
box.x2 = drawable->width;
|
||||
box.y2 = drawable->height;
|
||||
REGION_INIT(pScreen, ®ion, &box, 0);
|
||||
radeon_dri2_copy_region(drawable, ®ion, event->front, event->back);
|
||||
swap_type = DRI2_BLIT_COMPLETE;
|
||||
if (DRI2CanExchange(drawable) &&
|
||||
can_exchange(event->front, event->back)) {
|
||||
radeon_dri2_exchange_buffers(drawable, event->front, event->back);
|
||||
swap_type = DRI2_EXCHANGE_COMPLETE;
|
||||
} else {
|
||||
box.x1 = 0;
|
||||
box.y1 = 0;
|
||||
box.x2 = drawable->width;
|
||||
box.y2 = drawable->height;
|
||||
REGION_INIT(pScreen, ®ion, &box, 0);
|
||||
radeon_dri2_copy_region(drawable, ®ion, event->front, event->back);
|
||||
swap_type = DRI2_BLIT_COMPLETE;
|
||||
}
|
||||
|
||||
DRI2SwapComplete(client, drawable, frame, tv_sec, tv_usec,
|
||||
DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec,
|
||||
swap_type, event->event_complete, event->event_data);
|
||||
|
||||
break;
|
||||
case DRI2_WAITMSC:
|
||||
DRI2WaitMSCComplete(client, drawable, frame, tv_sec, tv_usec);
|
||||
DRI2WaitMSCComplete(event->client, drawable, frame, tv_sec, tv_usec);
|
||||
break;
|
||||
default:
|
||||
/* Unknown type */
|
||||
@@ -638,7 +764,7 @@ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
|
||||
RADEONInfoPtr info = RADEONPTR(scrn);
|
||||
drmVBlank vbl;
|
||||
int ret;
|
||||
int crtc= radeon_dri2_drawable_crtc(draw);
|
||||
int crtc = radeon_dri2_drawable_crtc(draw);
|
||||
|
||||
/* Drawable not displayed, make up a value */
|
||||
if (crtc == -1) {
|
||||
@@ -796,6 +922,47 @@ out_complete:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
|
||||
unsigned int tv_usec, void *event_data)
|
||||
{
|
||||
DRI2FrameEventPtr flip = event_data;
|
||||
DrawablePtr drawable;
|
||||
ScreenPtr screen;
|
||||
ScrnInfoPtr scrn;
|
||||
int status;
|
||||
PixmapPtr pixmap;
|
||||
|
||||
status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient,
|
||||
M_ANY, DixWriteAccess);
|
||||
if (status != Success) {
|
||||
free(flip);
|
||||
return;
|
||||
}
|
||||
|
||||
screen = drawable->pScreen;
|
||||
scrn = xf86Screens[screen->myNum];
|
||||
|
||||
pixmap = screen->GetScreenPixmap(screen);
|
||||
xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
|
||||
"%s:%d fevent[%p] width %d pitch %d (/4 %d)\n",
|
||||
__func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4);
|
||||
|
||||
/* We assume our flips arrive in order, so we don't check the frame */
|
||||
switch (flip->type) {
|
||||
case DRI2_SWAP:
|
||||
DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
|
||||
DRI2_FLIP_COMPLETE, flip->event_complete,
|
||||
flip->event_data);
|
||||
break;
|
||||
default:
|
||||
xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__);
|
||||
/* Unknown type */
|
||||
break;
|
||||
}
|
||||
|
||||
free(flip);
|
||||
}
|
||||
|
||||
/*
|
||||
* ScheduleSwap is responsible for requesting a DRM vblank event for the
|
||||
* appropriate frame.
|
||||
@@ -883,6 +1050,15 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
|
||||
}
|
||||
|
||||
current_msc = vbl.reply.sequence;
|
||||
|
||||
/* Flips need to be submitted one frame before */
|
||||
if (info->allowPageFlip &&
|
||||
DRI2CanFlip(draw) &&
|
||||
can_exchange(front, back)) {
|
||||
swap_type = DRI2_FLIP;
|
||||
flip = 1;
|
||||
}
|
||||
|
||||
swap_info->type = swap_type;
|
||||
|
||||
/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
|
||||
@@ -899,9 +1075,6 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
|
||||
*/
|
||||
if (divisor == 0 || current_msc < *target_msc) {
|
||||
vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
|
||||
if (crtc > 0)
|
||||
vbl.request.type |= DRM_VBLANK_SECONDARY;
|
||||
|
||||
/* If non-pageflipping, but blitting/exchanging, we need to use
|
||||
* DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
|
||||
* on.
|
||||
|
||||
@@ -44,5 +44,7 @@ xf86CrtcPtr radeon_covering_crtc(ScrnInfoPtr pScrn, BoxPtr box,
|
||||
xf86CrtcPtr desired, BoxPtr crtc_box_ret);
|
||||
void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
|
||||
unsigned int tv_usec, void *event_data);
|
||||
void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
|
||||
unsigned int tv_usec, void *event_data);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -70,6 +70,7 @@ const OptionInfoRec RADEONOptions_KMS[] = {
|
||||
{ OPTION_EXA_VSYNC, "EXAVSync", OPTV_BOOLEAN, {0}, FALSE },
|
||||
{ OPTION_EXA_PIXMAPS, "EXAPixmaps", OPTV_BOOLEAN, {0}, FALSE },
|
||||
{ OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE },
|
||||
{ OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE },
|
||||
{ -1, NULL, OPTV_NONE, {0}, FALSE }
|
||||
};
|
||||
|
||||
@@ -620,6 +621,13 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"KMS Color Tiling: %sabled\n", info->allowColorTiling ? "en" : "dis");
|
||||
|
||||
if (info->dri->pKernelDRMVersion->version_minor >= 8) {
|
||||
info->allowPageFlip = xf86ReturnOptValBool(info->Options,
|
||||
OPTION_PAGE_FLIP, TRUE);
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis");
|
||||
}
|
||||
|
||||
if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n");
|
||||
goto fail;
|
||||
|
||||
Reference in New Issue
Block a user