randr: Add per-crtc pixmaps

This adds new driver hooks to allocate scanout pixmaps and
changes the mode setting APIs to pass the new scanout pixmaps
along from DIX. DIX is responsible for reference counting the pixmaps
by tracking them through RRCrtcNotify.

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Aaron Plattner <aplattner@nvidia.com>
This commit is contained in:
Keith Packard 2010-12-03 13:00:46 -08:00
commit 82612045e1
11 changed files with 355 additions and 20 deletions

View file

@ -16,6 +16,7 @@ librandr_la_SOURCES = \
rrinfo.c \
rrmode.c \
rroutput.c \
rrpixmap.c \
rrpointer.c \
rrproperty.c \
rrscreen.c \

View file

@ -66,7 +66,8 @@ miRRSetCrtcConfig(RRCrtcConfigPtr crtc_config)
y,
crtc_config->rotation,
crtc_config->numOutputs,
crtc_config->outputs);
crtc_config->outputs,
crtc_config->pixmap);
}
Bool

View file

@ -98,6 +98,7 @@ RRCloseScreen (int i, ScreenPtr pScreen)
free(pScrPriv->crtcs);
free(pScrPriv->outputs);
free(pScrPriv->scanout_info);
free(pScrPriv);
RRNScreens -= 1; /* ok, one fewer screen with RandR running */
return (*pScreen->CloseScreen) (i, pScreen);
@ -248,6 +249,8 @@ Bool RRScreenInit(ScreenPtr pScreen)
pScrPriv->rrCrtcSet = NULL;
pScrPriv->rrCrtcSetGamma = NULL;
#endif
pScrPriv->scanout_info = NULL;
pScrPriv->n_scanout_info = 0;
#if RANDR_10_INTERFACE
pScrPriv->rrSetConfig = 0;
pScrPriv->rotations = RR_Rotate_0;
@ -482,6 +485,18 @@ RRVerticalRefresh (xRRModeInfo *mode)
return (CARD16) refresh;
}
RRScanoutPixmapInfo *
RRQueryScanoutPixmapInfo(ScreenPtr screen, int *n_info)
{
rrScrPriv(screen);
if (!pScrPriv->scanout_info && pScrPriv->rrQueryScanoutPixmaps)
pScrPriv->scanout_info = pScrPriv->rrQueryScanoutPixmaps(screen,
&pScrPriv->n_scanout_info);
*n_info = pScrPriv->n_scanout_info;
return pScrPriv->scanout_info;
}
static int
ProcRRDispatch (ClientPtr client)
{

View file

@ -123,6 +123,7 @@ struct _rrCrtc {
CARD16 *gammaGreen;
void *devPrivate;
Bool transforms;
PixmapPtr scanoutPixmap;
RRTransformRec client_pending_transform;
RRTransformRec client_current_transform;
PictTransform client_sprite_position_transform;
@ -198,7 +199,8 @@ typedef Bool (*RRCrtcSetProcPtr) (ScreenPtr pScreen,
int y,
Rotation rotation,
int numOutputs,
RROutputPtr *outputs);
RROutputPtr *outputs,
PixmapPtr scanout_pixmap);
typedef Bool (*RRCrtcSetGammaProcPtr) (ScreenPtr pScreen,
RRCrtcPtr crtc);
@ -264,6 +266,20 @@ typedef Bool (*RRSetConfigProcPtr) (ScreenPtr pScreen,
#endif
typedef struct {
PictFormatPtr format;
int maxWidth, maxHeight;
int depth;
Rotation rotations;
} RRScanoutPixmapInfo;
typedef RRScanoutPixmapInfo *(*RRQueryScanoutPixmapsPtr) (ScreenPtr pScreen,
int *num_info);
typedef PixmapPtr (*RRCreateScanoutPixmapPtr) (ScreenPtr pScreen,
int width, int height, int depth,
Rotation rotations,
PictFormatPtr format);
typedef void (*RRSetCrtcSpriteTransformPtr) (ScreenPtr pScreen,
RRCrtcPtr randr_crtc,
@ -303,6 +319,8 @@ typedef struct _rrScrPriv {
RRGetPanningProcPtr rrGetPanning;
RRSetPanningProcPtr rrSetPanning;
#endif
RRQueryScanoutPixmapsPtr rrQueryScanoutPixmaps;
RRCreateScanoutPixmapPtr rrCreateScanoutPixmap;
RRSetCrtcSpriteTransformPtr rrSetCrtcSpriteTransform;
RRGetCrtcSpriteTransformPtr rrGetCrtcSpriteTransform;
RRSetCrtcConfigsPtr rrSetCrtcConfigs;
@ -333,6 +351,8 @@ typedef struct _rrScrPriv {
/* Last known pointer position */
RRCrtcPtr pointerCrtc;
RRScanoutPixmapInfo *scanout_info;
int n_scanout_info;
#ifdef RANDR_10_INTERFACE
/*
* Configuration information
@ -347,6 +367,7 @@ typedef struct _rrScrPriv {
int rate;
int size;
#endif
} rrScrPrivRec, *rrScrPrivPtr;
extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec;
@ -521,6 +542,9 @@ RRGetRotation (ScreenPtr pScreen);
extern _X_EXPORT CARD16
RRVerticalRefresh (xRRModeInfo *mode);
extern _X_EXPORT RRScanoutPixmapInfo *
RRQueryScanoutPixmapInfo(ScreenPtr screen, int *n_info);
#ifdef RANDR_10_INTERFACE
/*
* This is the old interface, deprecated but left
@ -599,7 +623,8 @@ RRCrtcNotify (RRCrtcPtr crtc,
Rotation rotation,
RRTransformPtr transform,
int numOutputs,
RROutputPtr *outputs);
RROutputPtr *outputs,
PixmapPtr scanoutPixmap);
extern _X_EXPORT void
RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc);
@ -614,7 +639,8 @@ RRCrtcSet (RRCrtcPtr crtc,
int y,
Rotation rotation,
int numOutput,
RROutputPtr *outputs);
RROutputPtr *outputs,
PixmapPtr scanout_pixmap);
/*
* Request that the Crtc gamma be changed
@ -643,6 +669,10 @@ RRCrtcGammaGet(RRCrtcPtr crtc);
extern _X_EXPORT Bool
RRCrtcGammaNotify (RRCrtcPtr crtc);
void
RRModeGetScanoutSize (RRModePtr mode, struct pixman_f_transform *transform,
int *width, int *height);
/*
* Set the size of the gamma table at server startup time
*/
@ -777,12 +807,24 @@ RRCrtcSpriteTransformSet(RRCrtcPtr crtc,
struct pict_f_transform *f_position_transform,
struct pict_f_transform *f_image_transform);
int
ProcRRQueryScanoutPixmaps (ClientPtr client);
int
ProcRRCreateScanoutPixmap (ClientPtr client);
int
ProcRRSetCrtcPixmapConfig (ClientPtr client);
int
ProcRRSetCrtcSpriteTransform (ClientPtr client);
int
ProcRRGetCrtcSpriteTransform (ClientPtr client);
int
ProcRRSetCrtcConfigs (ClientPtr client);
/* rrdispatch.c */
extern _X_EXPORT Bool
RRClientKnowsRates (ClientPtr pClient);

View file

@ -138,7 +138,8 @@ RRCrtcNotify (RRCrtcPtr crtc,
Rotation rotation,
RRTransformPtr transform,
int numOutputs,
RROutputPtr *outputs)
RROutputPtr *outputs,
PixmapPtr scanoutPixmap)
{
int i, j;
@ -236,6 +237,15 @@ RRCrtcNotify (RRCrtcPtr crtc,
RRCrtcChanged (crtc, TRUE);
}
if (scanoutPixmap != crtc->scanoutPixmap)
{
if (scanoutPixmap)
++scanoutPixmap->refcnt;
if (crtc->scanoutPixmap)
(*crtc->scanoutPixmap->drawable.pScreen->DestroyPixmap) (crtc->scanoutPixmap);
crtc->scanoutPixmap = scanoutPixmap;
}
if (crtc->changed && mode)
{
RRTransformCompute (x, y,
@ -312,7 +322,8 @@ RRCrtcSet (RRCrtcPtr crtc,
int y,
Rotation rotation,
int numOutputs,
RROutputPtr *outputs)
RROutputPtr *outputs,
PixmapPtr scanout_pixmap)
{
ScreenPtr pScreen = crtc->pScreen;
Bool ret = FALSE;
@ -326,7 +337,8 @@ RRCrtcSet (RRCrtcPtr crtc,
crtc->numOutputs == numOutputs &&
!memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
!RRCrtcPendingProperties (crtc) &&
!RRCrtcPendingTransform (crtc))
!RRCrtcPendingTransform (crtc) &&
crtc->scanoutPixmap == scanout_pixmap)
{
ret = TRUE;
}
@ -336,7 +348,7 @@ RRCrtcSet (RRCrtcPtr crtc,
if (pScrPriv->rrCrtcSet)
{
ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
rotation, numOutputs, outputs);
rotation, numOutputs, outputs, scanout_pixmap);
}
else
#endif
@ -349,7 +361,7 @@ RRCrtcSet (RRCrtcPtr crtc,
if (!mode)
{
RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL);
RRCrtcNotify (crtc, NULL, x, y, rotation, NULL, 0, NULL, scanout_pixmap);
ret = TRUE;
}
else
@ -375,7 +387,7 @@ RRCrtcSet (RRCrtcPtr crtc,
*/
if (ret)
{
RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs);
RRCrtcNotify (crtc, mode, x, y, rotation, NULL, 1, outputs, scanout_pixmap);
RRScreenSizeNotify (pScreen);
}
}
@ -573,7 +585,10 @@ RRCrtcGammaNotify (RRCrtcPtr crtc)
return TRUE; /* not much going on here */
}
static void
/*
* Compute overall scanout buffer requirements for the specified mode
*/
void
RRModeGetScanoutSize (RRModePtr mode, struct pixman_f_transform *transform,
int *width, int *height)
{
@ -1049,7 +1064,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
}
if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
rotation, numOutputs, outputs))
rotation, numOutputs, outputs, NULL))
{
rep.status = RRSetConfigFailed;
goto sendReply;

View file

@ -168,7 +168,7 @@ RRScanOldConfig (ScreenPtr pScreen, Rotation rotations)
/* notice current mode */
if (newMode)
RRCrtcNotify (crtc, newMode, 0, 0, pScrPriv->rotation,
NULL, 1, &output);
NULL, 1, &output, NULL);
}
#endif

154
randr/rrpixmap.c Normal file
View file

@ -0,0 +1,154 @@
/*
* Copyright © 2010 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "randrstr.h"
#include "xace.h"
int
ProcRRQueryScanoutPixmaps (ClientPtr client)
{
REQUEST(xRRQueryScanoutPixmapsReq);
xRRQueryScanoutPixmapsReply rep;
RRScanoutPixmapInfo *info;
xRRScanoutPixmapInfo *x_info;
int n_info;
int rc;
DrawablePtr drawable;
ScreenPtr screen;
rrScrPrivPtr screen_priv;
int n, s;
REQUEST_SIZE_MATCH(xRRQueryScanoutPixmapsReq);
rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixGetAttrAccess);
if (rc != Success) {
client->errorValue = stuff->drawable;
return rc;
}
screen = drawable->pScreen;
screen_priv = rrGetScrPriv(screen);
rep.type = X_Reply;
/* rep.status has already been filled in */
rep.length = 0;
rep.sequenceNumber = client->sequence;
info = RRQueryScanoutPixmapInfo(screen, &n_info);
x_info = calloc(n_info, sizeof (xRRScanoutPixmapInfo));
if (n_info && !x_info)
return BadAlloc;
rep.length += (n_info * sizeof (xRRScanoutPixmapInfo)) >> 2;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
}
for (s = 0; s < n_info; s++) {
x_info[s].format = info[s].format->id;
x_info[s].maxWidth = info[s].maxWidth;
x_info[s].maxHeight = info[s].maxHeight;
x_info[s].rotations = info[s].rotations;
if (client->swapped) {
swapl(&x_info[s].format, n);
swaps(&x_info[s].maxWidth, n);
swaps(&x_info[s].maxHeight, n);
swaps(&x_info[s].rotations, n);
}
}
WriteToClient(client, sizeof(rep), (char *)&rep);
if (n_info)
WriteToClient(client, n_info * sizeof (xRRScanoutPixmapInfo),
(char *) x_info);
return Success;
}
int
ProcRRCreateScanoutPixmap (ClientPtr client)
{
REQUEST(xRRCreateScanoutPixmapReq);
int rc;
DrawablePtr drawable;
ScreenPtr screen;
rrScrPrivPtr screen_priv;
PixmapPtr pixmap;
int n_info;
RRScanoutPixmapInfo *info;
int s;
REQUEST_SIZE_MATCH(xRRCreateScanoutPixmapReq);
client->errorValue = stuff->pid;
LEGAL_NEW_RESOURCE(stuff->pid, client);
rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixGetAttrAccess);
if (rc != Success) {
client->errorValue = stuff->drawable;
return rc;
}
screen = drawable->pScreen;
screen_priv = rrGetScrPriv(screen);
if (!screen_priv)
return BadValue;
info = RRQueryScanoutPixmapInfo(screen, &n_info);
for (s = 0; s < n_info; s++) {
if (info[s].format->id == stuff->format)
break;
}
if (s == n_info || !screen_priv->rrCreateScanoutPixmap) {
client->errorValue = stuff->format;
return BadValue;
}
info = &info[s];
if (!stuff->width || stuff->width > info->maxWidth) {
client->errorValue = stuff->width;
return BadValue;
}
if (!stuff->height || stuff->height > info->maxHeight) {
client->errorValue = stuff->height;
return BadValue;
}
if ((stuff->rotations & info->rotations) != stuff->rotations) {
client->errorValue = stuff->rotations;
return BadValue;
}
pixmap = screen_priv->rrCreateScanoutPixmap (screen,
stuff->width, stuff->height,
info->depth,
stuff->rotations,
info->format);
if (!pixmap)
return BadAlloc;
pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
pixmap->drawable.id = stuff->pid;
rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
pixmap, RT_NONE, NULL, DixCreateAccess);
if (rc != Success) {
screen->DestroyPixmap(pixmap);
return rc;
}
if (!AddResource(stuff->pid, RT_PIXMAP, pixmap))
return BadAlloc;
return Success;
}

View file

@ -794,8 +794,10 @@ ProcRRSetScreenConfig (ClientPtr client)
}
rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
if (rc != Success)
if (rc != Success) {
client->errorValue = stuff->drawable;
return rc;
}
pScreen = pDraw->pScreen;
@ -940,7 +942,7 @@ ProcRRSetScreenConfig (ClientPtr client)
for (c = 0; c < pScrPriv->numCrtcs; c++)
{
if (!RRCrtcSet (pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
0, NULL))
0, NULL, NULL))
{
rep.status = RRSetConfigFailed;
/* XXX recover from failure */
@ -956,7 +958,7 @@ ProcRRSetScreenConfig (ClientPtr client)
}
}
if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output))
if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output, NULL))
rep.status = RRSetConfigFailed;
else {
pScrPriv->lastSetTime = time;