456 lines
15 KiB
C
456 lines
15 KiB
C
/*
|
|
* Copyright © 2013 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 <dix-config.h>
|
|
|
|
#include "dix/dix_priv.h"
|
|
|
|
#include "present_priv.h"
|
|
#include "randrstr_priv.h"
|
|
#include <protocol-versions.h>
|
|
|
|
static int
|
|
proc_present_query_version(ClientPtr client)
|
|
{
|
|
REQUEST(xPresentQueryVersionReq);
|
|
xPresentQueryVersionReply rep = {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.majorVersion = SERVER_PRESENT_MAJOR_VERSION,
|
|
.minorVersion = SERVER_PRESENT_MINOR_VERSION
|
|
};
|
|
|
|
REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
|
|
/* From presentproto:
|
|
*
|
|
* The client sends the highest supported version to the server
|
|
* and the server sends the highest version it supports, but no
|
|
* higher than the requested version.
|
|
*/
|
|
|
|
if (rep.majorVersion > stuff->majorVersion ||
|
|
rep.minorVersion > stuff->minorVersion) {
|
|
rep.majorVersion = stuff->majorVersion;
|
|
rep.minorVersion = stuff->minorVersion;
|
|
}
|
|
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swapl(&rep.majorVersion);
|
|
swapl(&rep.minorVersion);
|
|
}
|
|
WriteToClient(client, sizeof(rep), &rep);
|
|
return Success;
|
|
}
|
|
|
|
#define VERIFY_FENCE_OR_NONE(fence_ptr, fence_id, client, access) do { \
|
|
if ((fence_id) == None) \
|
|
(fence_ptr) = NULL; \
|
|
else { \
|
|
int __rc__ = SyncVerifyFence(&fence_ptr, fence_id, client, access); \
|
|
if (__rc__ != Success) \
|
|
return __rc__; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define VERIFY_CRTC_OR_NONE(crtc_ptr, crtc_id, client, access) do { \
|
|
if ((crtc_id) == None) \
|
|
(crtc_ptr) = NULL; \
|
|
else { \
|
|
VERIFY_RR_CRTC(crtc_id, crtc_ptr, access); \
|
|
} \
|
|
} while (0)
|
|
|
|
static int
|
|
proc_present_pixmap_common(ClientPtr client,
|
|
Window req_window,
|
|
Pixmap req_pixmap,
|
|
CARD32 req_serial,
|
|
CARD32 req_valid,
|
|
CARD32 req_update,
|
|
INT16 req_x_off,
|
|
INT16 req_y_off,
|
|
CARD32 req_target_crtc,
|
|
XSyncFence req_wait_fence,
|
|
XSyncFence req_idle_fence,
|
|
#ifdef DRI3
|
|
struct dri3_syncobj *acquire_syncobj,
|
|
struct dri3_syncobj *release_syncobj,
|
|
CARD64 req_acquire_point,
|
|
CARD64 req_release_point,
|
|
#endif /* DRI3 */
|
|
CARD32 req_options,
|
|
CARD64 req_target_msc,
|
|
CARD64 req_divisor,
|
|
CARD64 req_remainder,
|
|
size_t base_req_size,
|
|
xPresentNotify *req_notifies)
|
|
{
|
|
WindowPtr window;
|
|
PixmapPtr pixmap;
|
|
RegionPtr valid = NULL;
|
|
RegionPtr update = NULL;
|
|
RRCrtcPtr target_crtc;
|
|
SyncFence *wait_fence;
|
|
SyncFence *idle_fence;
|
|
int nnotifies;
|
|
present_notify_ptr notifies = NULL;
|
|
int ret;
|
|
|
|
ret = dixLookupWindow(&window, req_window, client, DixWriteAccess);
|
|
if (ret != Success)
|
|
return ret;
|
|
ret = dixLookupResourceByType((void **) &pixmap, req_pixmap, X11_RESTYPE_PIXMAP, client, DixReadAccess);
|
|
if (ret != Success)
|
|
return ret;
|
|
|
|
if (window->drawable.depth != pixmap->drawable.depth)
|
|
return BadMatch;
|
|
|
|
VERIFY_REGION_OR_NONE(valid, req_valid, client, DixReadAccess);
|
|
VERIFY_REGION_OR_NONE(update, req_update, client, DixReadAccess);
|
|
|
|
VERIFY_CRTC_OR_NONE(target_crtc, req_target_crtc, client, DixReadAccess);
|
|
|
|
VERIFY_FENCE_OR_NONE(wait_fence, req_wait_fence, client, DixReadAccess);
|
|
VERIFY_FENCE_OR_NONE(idle_fence, req_idle_fence, client, DixWriteAccess);
|
|
|
|
if (req_options & ~(PresentAllOptions)) {
|
|
client->errorValue = req_options;
|
|
return BadValue;
|
|
}
|
|
|
|
/*
|
|
* Check to see if remainder is sane
|
|
*/
|
|
if (req_divisor == 0) {
|
|
if (req_remainder != 0) {
|
|
client->errorValue = (CARD32)req_remainder;
|
|
return BadValue;
|
|
}
|
|
} else {
|
|
if (req_remainder >= req_divisor) {
|
|
client->errorValue = (CARD32)req_remainder;
|
|
return BadValue;
|
|
}
|
|
}
|
|
|
|
nnotifies = (client->req_len << 2) - base_req_size;
|
|
if (nnotifies % sizeof (xPresentNotify))
|
|
return BadLength;
|
|
|
|
nnotifies /= sizeof (xPresentNotify);
|
|
if (nnotifies) {
|
|
ret = present_create_notifies(client, nnotifies, req_notifies, ¬ifies);
|
|
if (ret != Success)
|
|
return ret;
|
|
}
|
|
|
|
ret = present_pixmap(window, pixmap, req_serial,
|
|
valid, update, req_x_off, req_y_off, target_crtc,
|
|
wait_fence, idle_fence,
|
|
#ifdef DRI3
|
|
acquire_syncobj, release_syncobj,
|
|
req_acquire_point, req_release_point,
|
|
#endif /* DRI3 */
|
|
req_options, req_target_msc, req_divisor, req_remainder,
|
|
notifies, nnotifies);
|
|
|
|
if (ret != Success)
|
|
present_destroy_notifies(notifies, nnotifies);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
proc_present_pixmap(ClientPtr client)
|
|
{
|
|
REQUEST(xPresentPixmapReq);
|
|
REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
|
|
return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial,
|
|
stuff->valid, stuff->update, stuff->x_off, stuff->y_off,
|
|
stuff->target_crtc,
|
|
stuff->wait_fence, stuff->idle_fence,
|
|
#ifdef DRI3
|
|
None, None, 0, 0,
|
|
#endif /* DRI3 */
|
|
stuff->options, stuff->target_msc,
|
|
stuff->divisor, stuff->remainder,
|
|
sizeof (xPresentPixmapReq),
|
|
(xPresentNotify *)(stuff + 1));
|
|
}
|
|
|
|
static int
|
|
proc_present_notify_msc(ClientPtr client)
|
|
{
|
|
REQUEST(xPresentNotifyMSCReq);
|
|
WindowPtr window;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
|
|
rc = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
/*
|
|
* Check to see if remainder is sane
|
|
*/
|
|
if (stuff->divisor == 0) {
|
|
if (stuff->remainder != 0) {
|
|
client->errorValue = (CARD32) stuff->remainder;
|
|
return BadValue;
|
|
}
|
|
} else {
|
|
if (stuff->remainder >= stuff->divisor) {
|
|
client->errorValue = (CARD32) stuff->remainder;
|
|
return BadValue;
|
|
}
|
|
}
|
|
|
|
return present_notify_msc(window, stuff->serial,
|
|
stuff->target_msc, stuff->divisor, stuff->remainder);
|
|
}
|
|
|
|
static int
|
|
proc_present_select_input (ClientPtr client)
|
|
{
|
|
REQUEST(xPresentSelectInputReq);
|
|
WindowPtr window;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xPresentSelectInputReq);
|
|
|
|
rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->eventMask & ~PresentAllEvents) {
|
|
client->errorValue = stuff->eventMask;
|
|
return BadValue;
|
|
}
|
|
return present_select_input(client, stuff->eid, window, stuff->eventMask);
|
|
}
|
|
|
|
static int
|
|
proc_present_query_capabilities (ClientPtr client)
|
|
{
|
|
REQUEST(xPresentQueryCapabilitiesReq);
|
|
xPresentQueryCapabilitiesReply rep = {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
};
|
|
WindowPtr window;
|
|
RRCrtcPtr crtc = NULL;
|
|
int r;
|
|
|
|
REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
|
|
r = dixLookupWindow(&window, stuff->target, client, DixGetAttrAccess);
|
|
switch (r) {
|
|
case Success:
|
|
crtc = present_get_crtc(window);
|
|
break;
|
|
case BadWindow:
|
|
VERIFY_RR_CRTC(stuff->target, crtc, DixGetAttrAccess);
|
|
break;
|
|
default:
|
|
return r;
|
|
}
|
|
|
|
rep.capabilities = present_query_capabilities(crtc);
|
|
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swapl(&rep.capabilities);
|
|
}
|
|
WriteToClient(client, sizeof(rep), &rep);
|
|
return Success;
|
|
}
|
|
|
|
#ifdef DRI3
|
|
static int
|
|
proc_present_pixmap_synced (ClientPtr client)
|
|
{
|
|
REQUEST(xPresentPixmapSyncedReq);
|
|
struct dri3_syncobj *acquire_syncobj;
|
|
struct dri3_syncobj *release_syncobj;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq);
|
|
VERIFY_DRI3_SYNCOBJ(stuff->acquire_syncobj, acquire_syncobj, DixWriteAccess);
|
|
VERIFY_DRI3_SYNCOBJ(stuff->release_syncobj, release_syncobj, DixWriteAccess);
|
|
|
|
if (stuff->acquire_point == 0 || stuff->release_point == 0 ||
|
|
(stuff->acquire_syncobj == stuff->release_syncobj &&
|
|
stuff->acquire_point >= stuff->release_point))
|
|
return BadValue;
|
|
|
|
return proc_present_pixmap_common(client, stuff->window, stuff->pixmap, stuff->serial,
|
|
stuff->valid, stuff->update, stuff->x_off, stuff->y_off,
|
|
stuff->target_crtc,
|
|
None, None,
|
|
acquire_syncobj, release_syncobj,
|
|
stuff->acquire_point, stuff->release_point,
|
|
stuff->options, stuff->target_msc,
|
|
stuff->divisor, stuff->remainder,
|
|
sizeof (xPresentPixmapSyncedReq),
|
|
(xPresentNotify *)(stuff + 1));
|
|
}
|
|
#endif /* DRI3 */
|
|
|
|
static int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = {
|
|
proc_present_query_version, /* 0 */
|
|
proc_present_pixmap, /* 1 */
|
|
proc_present_notify_msc, /* 2 */
|
|
proc_present_select_input, /* 3 */
|
|
proc_present_query_capabilities, /* 4 */
|
|
#ifdef DRI3
|
|
proc_present_pixmap_synced, /* 5 */
|
|
#endif /* DRI3 */
|
|
};
|
|
|
|
int
|
|
proc_present_dispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
if (stuff->data >= PresentNumberRequests || !proc_present_vector[stuff->data])
|
|
return BadRequest;
|
|
return (*proc_present_vector[stuff->data]) (client);
|
|
}
|
|
|
|
static int _X_COLD
|
|
sproc_present_query_version(ClientPtr client)
|
|
{
|
|
REQUEST(xPresentQueryVersionReq);
|
|
REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
|
|
|
|
swapl(&stuff->majorVersion);
|
|
swapl(&stuff->minorVersion);
|
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
|
}
|
|
|
|
static int _X_COLD
|
|
sproc_present_pixmap(ClientPtr client)
|
|
{
|
|
REQUEST(xPresentPixmapReq);
|
|
REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
|
|
|
|
swapl(&stuff->window);
|
|
swapl(&stuff->pixmap);
|
|
swapl(&stuff->valid);
|
|
swapl(&stuff->update);
|
|
swaps(&stuff->x_off);
|
|
swaps(&stuff->y_off);
|
|
swapll(&stuff->target_msc);
|
|
swapll(&stuff->divisor);
|
|
swapll(&stuff->remainder);
|
|
swapl(&stuff->idle_fence);
|
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
|
}
|
|
|
|
static int _X_COLD
|
|
sproc_present_notify_msc(ClientPtr client)
|
|
{
|
|
REQUEST(xPresentNotifyMSCReq);
|
|
REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
|
|
|
|
swapl(&stuff->window);
|
|
swapll(&stuff->target_msc);
|
|
swapll(&stuff->divisor);
|
|
swapll(&stuff->remainder);
|
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
|
}
|
|
|
|
static int _X_COLD
|
|
sproc_present_select_input (ClientPtr client)
|
|
{
|
|
REQUEST(xPresentSelectInputReq);
|
|
REQUEST_SIZE_MATCH(xPresentSelectInputReq);
|
|
|
|
swapl(&stuff->window);
|
|
swapl(&stuff->eventMask);
|
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
|
}
|
|
|
|
static int _X_COLD
|
|
sproc_present_query_capabilities (ClientPtr client)
|
|
{
|
|
REQUEST(xPresentQueryCapabilitiesReq);
|
|
REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
|
|
swapl(&stuff->target);
|
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
|
}
|
|
|
|
|
|
#ifdef DRI3
|
|
static int _X_COLD
|
|
sproc_present_pixmap_synced(ClientPtr client)
|
|
{
|
|
REQUEST(xPresentPixmapSyncedReq);
|
|
REQUEST_AT_LEAST_SIZE(xPresentPixmapSyncedReq);
|
|
|
|
swapl(&stuff->window);
|
|
|
|
swapl(&stuff->pixmap);
|
|
swapl(&stuff->serial);
|
|
|
|
swapl(&stuff->valid);
|
|
swapl(&stuff->update);
|
|
|
|
swaps(&stuff->x_off);
|
|
swaps(&stuff->y_off);
|
|
swapl(&stuff->target_crtc);
|
|
|
|
swapl(&stuff->acquire_syncobj);
|
|
swapl(&stuff->release_syncobj);
|
|
swapll(&stuff->acquire_point);
|
|
swapll(&stuff->release_point);
|
|
|
|
swapl(&stuff->options);
|
|
|
|
swapll(&stuff->target_msc);
|
|
swapll(&stuff->divisor);
|
|
swapll(&stuff->remainder);
|
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
|
}
|
|
#endif /* DRI3 */
|
|
|
|
static int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = {
|
|
sproc_present_query_version, /* 0 */
|
|
sproc_present_pixmap, /* 1 */
|
|
sproc_present_notify_msc, /* 2 */
|
|
sproc_present_select_input, /* 3 */
|
|
sproc_present_query_capabilities, /* 4 */
|
|
#ifdef DRI3
|
|
sproc_present_pixmap_synced, /* 5 */
|
|
#endif /* DRI3 */
|
|
};
|
|
|
|
int _X_COLD
|
|
sproc_present_dispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
if (stuff->data >= PresentNumberRequests || !sproc_present_vector[stuff->data])
|
|
return BadRequest;
|
|
return (*sproc_present_vector[stuff->data]) (client);
|
|
}
|