2007-08-23 11:53:02 +02:00
|
|
|
/*
|
|
|
|
* Xephyr - A kdrive X server thats runs in a host X window.
|
|
|
|
* Authored by Matthew Allum <mallum@openedhand.com>
|
|
|
|
*
|
|
|
|
* Copyright © 2007 OpenedHand Ltd
|
|
|
|
*
|
|
|
|
* 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 OpenedHand Ltd not be used in
|
|
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
|
|
* specific, written prior permission. OpenedHand Ltd makes no
|
|
|
|
* representations about the suitability of this software for any purpose. It
|
|
|
|
* is provided "as is" without express or implied warranty.
|
|
|
|
*
|
|
|
|
* OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
|
|
* EVENT SHALL OpenedHand Ltd 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.
|
|
|
|
*
|
|
|
|
* a lots of the content of this file has been adapted from the mesa source
|
|
|
|
* code.
|
|
|
|
* Authors:
|
|
|
|
* Dodji Seketeli <dodji@openedhand.com>
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <kdrive-config.h>
|
|
|
|
#endif
|
|
|
|
|
2008-07-23 01:00:26 +02:00
|
|
|
/*
|
|
|
|
* including some server headers (like kdrive-config.h)
|
|
|
|
* might define the macro _XSERVER64
|
|
|
|
* on 64 bits machines. That macro must _NOT_ be defined for Xlib
|
|
|
|
* client code, otherwise bad things happen.
|
|
|
|
* So let's undef that macro if necessary.
|
|
|
|
*/
|
|
|
|
#ifdef _XSERVER64
|
|
|
|
#undef _XSERVER64
|
|
|
|
#endif
|
|
|
|
|
2007-08-23 11:53:02 +02:00
|
|
|
#include <X11/Xlibint.h>
|
|
|
|
#include <GL/glx.h>
|
|
|
|
#include <GL/internal/glcore.h>
|
|
|
|
#include <GL/glxproto.h>
|
|
|
|
#include <GL/glxint.h>
|
|
|
|
#include "ephyrhostglx.h"
|
|
|
|
#define _HAVE_XALLOC_DECLS
|
|
|
|
#include "ephyrlog.h"
|
2007-08-30 23:54:49 +02:00
|
|
|
#include "hostx.h"
|
2007-08-23 11:53:02 +02:00
|
|
|
|
2007-08-28 15:55:05 +02:00
|
|
|
enum VisualConfRequestType {
|
|
|
|
EPHYR_GET_FB_CONFIG,
|
|
|
|
EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX,
|
|
|
|
EPHYR_GET_VISUAL_CONFIGS
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
static Bool ephyrHostGLXGetVisualConfigsInternal
|
|
|
|
(enum VisualConfRequestType a_type,
|
|
|
|
int32_t a_screen,
|
|
|
|
int32_t *a_num_visuals,
|
|
|
|
int32_t *a_num_props,
|
|
|
|
int32_t *a_props_buf_size,
|
|
|
|
int32_t **a_props_buf);
|
2007-08-23 11:53:02 +02:00
|
|
|
Bool
|
|
|
|
ephyrHostGLXGetMajorOpcode (int *a_opcode)
|
|
|
|
{
|
|
|
|
Bool is_ok=FALSE ;
|
|
|
|
Display *dpy=hostx_get_display () ;
|
|
|
|
static int opcode ;
|
|
|
|
int first_event_return=0, first_error_return=0;
|
|
|
|
|
|
|
|
EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
|
|
|
|
EPHYR_LOG ("enter\n") ;
|
|
|
|
if (!opcode) {
|
|
|
|
if (!XQueryExtension (dpy, GLX_EXTENSION_NAME, &opcode,
|
|
|
|
&first_event_return, &first_error_return)) {
|
|
|
|
EPHYR_LOG_ERROR ("XQueryExtension() failed\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*a_opcode = opcode ;
|
|
|
|
is_ok = TRUE ;
|
|
|
|
out:
|
|
|
|
EPHYR_LOG ("release\n") ;
|
|
|
|
return is_ok ;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
ephyrHostGLXQueryVersion (int *a_major, int *a_minor)
|
|
|
|
{
|
|
|
|
Bool is_ok = FALSE ;
|
|
|
|
Display *dpy = hostx_get_display () ;
|
2007-09-19 15:46:09 +02:00
|
|
|
int major_opcode=0;
|
|
|
|
xGLXQueryVersionReq *req=NULL;
|
|
|
|
xGLXQueryVersionReply reply;
|
2007-08-23 11:53:02 +02:00
|
|
|
|
|
|
|
EPHYR_RETURN_VAL_IF_FAIL (a_major && a_minor, FALSE) ;
|
|
|
|
EPHYR_LOG ("enter\n") ;
|
|
|
|
|
2007-09-19 15:46:09 +02:00
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
|
2007-08-23 11:53:02 +02:00
|
|
|
goto out ;
|
|
|
|
}
|
2007-09-19 15:46:09 +02:00
|
|
|
EPHYR_LOG ("major opcode: %d\n", major_opcode) ;
|
|
|
|
|
|
|
|
/* Send the glXQueryVersion request */
|
|
|
|
memset (&reply, 0, sizeof (reply)) ;
|
|
|
|
LockDisplay (dpy);
|
|
|
|
GetReq (GLXQueryVersion, req);
|
|
|
|
req->reqType = major_opcode;
|
|
|
|
req->glxCode = X_GLXQueryVersion;
|
|
|
|
req->majorVersion = 2;
|
|
|
|
req->minorVersion = 1;
|
|
|
|
_XReply(dpy, (xReply*) &reply, 0, False);
|
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
|
|
|
|
|
|
|
*a_major = reply.majorVersion ;
|
|
|
|
*a_minor = reply.minorVersion ;
|
|
|
|
|
|
|
|
EPHYR_LOG ("major:%d, minor:%d\n", *a_major, *a_minor) ;
|
2007-08-23 11:53:02 +02:00
|
|
|
|
|
|
|
is_ok = TRUE ;
|
|
|
|
out:
|
|
|
|
EPHYR_LOG ("leave\n") ;
|
|
|
|
return is_ok ;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GLX protocol structure for the ficticious "GXLGenericGetString" request.
|
|
|
|
*
|
|
|
|
* This is a non-existant protocol packet. It just so happens that all of
|
|
|
|
* the real protocol packets used to request a string from the server have
|
|
|
|
* an identical binary layout. The only difference between them is the
|
|
|
|
* meaning of the \c for_whom field and the value of the \c glxCode.
|
2007-08-30 23:54:49 +02:00
|
|
|
* (this has been copied from the mesa source code)
|
2007-08-23 11:53:02 +02:00
|
|
|
*/
|
|
|
|
typedef struct GLXGenericGetString {
|
|
|
|
CARD8 reqType;
|
|
|
|
CARD8 glxCode;
|
|
|
|
CARD16 length B16;
|
|
|
|
CARD32 for_whom B32;
|
|
|
|
CARD32 name B32;
|
|
|
|
} xGLXGenericGetStringReq;
|
|
|
|
|
|
|
|
/* These defines are only needed to make the GetReq macro happy.
|
|
|
|
*/
|
|
|
|
#define sz_xGLXGenericGetStringReq 12
|
|
|
|
#define X_GLXGenericGetString 0
|
|
|
|
|
|
|
|
Bool
|
|
|
|
ephyrHostGLXGetStringFromServer (int a_screen_number,
|
|
|
|
int a_string_name,
|
2007-08-30 23:54:49 +02:00
|
|
|
enum EphyrHostGLXGetStringOps a_op,
|
2007-08-23 11:53:02 +02:00
|
|
|
char **a_string)
|
|
|
|
{
|
2007-08-30 23:54:49 +02:00
|
|
|
Bool is_ok=FALSE ;
|
2007-08-23 11:53:02 +02:00
|
|
|
Display *dpy = hostx_get_display () ;
|
2008-02-21 15:29:27 +01:00
|
|
|
int default_screen = DefaultScreen (dpy);
|
2007-08-23 11:53:02 +02:00
|
|
|
xGLXGenericGetStringReq *req=NULL;
|
|
|
|
xGLXSingleReply reply;
|
2007-08-30 23:54:49 +02:00
|
|
|
int length=0, numbytes=0, major_opcode=0, get_string_op=0;
|
2007-08-23 11:53:02 +02:00
|
|
|
|
|
|
|
EPHYR_RETURN_VAL_IF_FAIL (dpy && a_string, FALSE) ;
|
|
|
|
|
|
|
|
EPHYR_LOG ("enter\n") ;
|
2007-08-30 23:54:49 +02:00
|
|
|
switch (a_op) {
|
|
|
|
case EPHYR_HOST_GLX_QueryServerString:
|
|
|
|
get_string_op = X_GLXQueryServerString;
|
|
|
|
break ;
|
|
|
|
case EPHYR_HOST_GLX_GetString:
|
|
|
|
get_string_op = X_GLsop_GetString;
|
2007-08-31 16:53:18 +02:00
|
|
|
EPHYR_LOG ("Going to glXGetString. strname:%#x, ctxttag:%d\n",
|
|
|
|
a_string_name, a_screen_number) ;
|
2007-08-30 23:54:49 +02:00
|
|
|
break ;
|
|
|
|
default:
|
|
|
|
EPHYR_LOG_ERROR ("unknown EphyrHostGLXGetStringOp:%d\n", a_op) ;
|
|
|
|
goto out ;
|
|
|
|
}
|
2007-08-23 11:53:02 +02:00
|
|
|
|
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
|
2007-08-30 23:54:49 +02:00
|
|
|
goto out ;
|
2007-08-23 11:53:02 +02:00
|
|
|
}
|
|
|
|
EPHYR_LOG ("major opcode: %d\n", major_opcode) ;
|
|
|
|
|
|
|
|
LockDisplay (dpy);
|
|
|
|
|
|
|
|
/* All of the GLX protocol requests for getting a string from the server
|
|
|
|
* look the same. The exact meaning of the a_for_whom field is usually
|
|
|
|
* either the screen number (for glXQueryServerString) or the context tag
|
|
|
|
* (for GLXSingle).
|
|
|
|
*/
|
|
|
|
GetReq (GLXGenericGetString, req);
|
|
|
|
req->reqType = major_opcode;
|
2007-08-30 23:54:49 +02:00
|
|
|
req->glxCode = get_string_op;
|
2008-02-21 15:29:27 +01:00
|
|
|
req->for_whom = default_screen;
|
2007-08-23 11:53:02 +02:00
|
|
|
req->name = a_string_name;
|
|
|
|
|
|
|
|
_XReply (dpy, (xReply *)&reply, 0, False);
|
|
|
|
|
|
|
|
length = reply.length * 4;
|
2008-02-21 15:29:27 +01:00
|
|
|
if (!length) {
|
|
|
|
numbytes = 0;
|
|
|
|
} else {
|
|
|
|
numbytes = reply.size;
|
|
|
|
}
|
2007-08-31 16:53:18 +02:00
|
|
|
EPHYR_LOG ("going to get a string of size:%d\n", numbytes) ;
|
2007-08-23 11:53:02 +02:00
|
|
|
|
2007-08-31 14:43:39 +02:00
|
|
|
*a_string = (char *) Xmalloc (numbytes +1);
|
|
|
|
if (!a_string) {
|
|
|
|
EPHYR_LOG_ERROR ("allocation failed\n") ;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset (*a_string, 0, numbytes+1) ;
|
|
|
|
if (_XRead (dpy, *a_string, numbytes)) {
|
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
|
|
|
EPHYR_LOG_ERROR ("read failed\n") ;
|
|
|
|
goto out ;
|
2007-08-23 11:53:02 +02:00
|
|
|
}
|
2007-08-31 14:43:39 +02:00
|
|
|
length -= numbytes;
|
2007-08-23 11:53:02 +02:00
|
|
|
_XEatData (dpy, length) ;
|
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
2007-08-31 16:53:18 +02:00
|
|
|
EPHYR_LOG ("strname:%#x, strvalue:'%s', strlen:%d\n",
|
|
|
|
a_string_name, *a_string, numbytes) ;
|
2007-08-23 11:53:02 +02:00
|
|
|
|
2007-08-30 23:54:49 +02:00
|
|
|
is_ok = TRUE ;
|
|
|
|
out:
|
2007-08-23 11:53:02 +02:00
|
|
|
EPHYR_LOG ("leave\n") ;
|
2007-08-30 23:54:49 +02:00
|
|
|
return is_ok ;
|
2007-08-23 11:53:02 +02:00
|
|
|
}
|
|
|
|
|
2007-08-28 15:55:05 +02:00
|
|
|
static Bool
|
|
|
|
ephyrHostGLXGetVisualConfigsInternal (enum VisualConfRequestType a_type,
|
|
|
|
int32_t a_screen,
|
|
|
|
int32_t *a_num_visuals,
|
|
|
|
int32_t *a_num_props,
|
|
|
|
int32_t *a_props_buf_size,
|
|
|
|
int32_t **a_props_buf)
|
2007-08-23 11:53:02 +02:00
|
|
|
{
|
|
|
|
Bool is_ok = FALSE ;
|
|
|
|
Display *dpy = hostx_get_display () ;
|
|
|
|
xGLXGetVisualConfigsReq *req;
|
|
|
|
xGLXGetFBConfigsReq *fb_req;
|
|
|
|
xGLXVendorPrivateWithReplyReq *vpreq;
|
|
|
|
xGLXGetFBConfigsSGIXReq *sgi_req;
|
|
|
|
xGLXGetVisualConfigsReply reply;
|
|
|
|
char *server_glx_version=NULL,
|
|
|
|
*server_glx_extensions=NULL ;
|
|
|
|
int j=0,
|
|
|
|
screens=0,
|
|
|
|
major_opcode=0,
|
|
|
|
num_props=0,
|
|
|
|
num_visuals=0,
|
|
|
|
props_buf_size=0,
|
|
|
|
props_per_visual_size=0;
|
|
|
|
int32_t *props_buf=NULL;
|
|
|
|
|
|
|
|
EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
|
|
|
|
|
|
|
|
screens = ScreenCount (dpy);
|
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get opcode\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
|
|
|
|
LockDisplay(dpy);
|
2007-08-28 15:55:05 +02:00
|
|
|
switch (a_type) {
|
|
|
|
case EPHYR_GET_FB_CONFIG:
|
2007-08-23 11:53:02 +02:00
|
|
|
GetReq(GLXGetFBConfigs,fb_req);
|
|
|
|
fb_req->reqType = major_opcode;
|
|
|
|
fb_req->glxCode = X_GLXGetFBConfigs;
|
Xephyr: port XV/GL stuff of the new multiscreen architecture
We can now launch GL or XV apps in any of the
Xephyr screens we want.
* hw/kdrive/ephyr/hostx.c,h:
(hostx_get_window):
(hostx_create_window): make these functions be screen
number aware.
* hw/kdrive/ephyr/XF86dri.c : fix some compiler warnings.
* hw/kdrive/ephyr/ephyrdri.c:
(ephyrDRIQueryDirectRenderingCapable),
(ephyrDRIOpenConnection),
(ephyrDRIAuthConnection),
(ephyrDRICloseConnection),
(ephyrDRIGetClientDriverName),
(ephyrDRICreateContext),
(ephyrDRIDestroyContext),
(ephyrDRICreateDrawable),
(ephyrDRIGetDrawableInfo),
(ephyrDRIGetDeviceInfo): in all those functions, don't forward
the screen number we receive - from the client - to the host X.
We (Xephyr) are always targetting the same X display screen, which is
the one Xephyr got launched against. So we enforce that in the code.
* hw/kdrive/ephyr/ephyrdriext.c:
(EphyrMirrorHostVisuals): make this duplicate the visuals of the host X
default screen into a given Xephyr screen. This way we have a chance
to update the visuals of all Xephyr screen to make them mirror those
of the host X.
(many other places): specify screen number where required by the api
change in hostx.h.
* hw/kdrive/ephyr/ephyrglxext.c: specify screen number where required
by the api change in hostx.h
* hw/kdrive/ephyr/ephyrhostglx.c: don't forward the screen number we
receive - from the client - to the host X.
We (Xephyr) are always targetting the same
X display screen, which is
the one Xephyr got launched against. So we enforce that in the code.
* hw/kdrive/ephyr/ephyrhostvideo.c,h: take in account the screen number received
from the client app. This is useful to know on which Xephyr screen we
need to display video stuff.
* hw/kdrive/ephyr/ephyrvideo.c: update this to reflect the API change
in hw/kdrive/ephyr/ephyrhostvideo.h.
(ephyrSetPortAttribute): when parameters are not valid
- they exceed their validity range - send them to the host anyway
and do not return an error to clients.
Some host expose buggy validity range, so rejecting client for that
is too harsh.
2007-10-03 13:03:34 +02:00
|
|
|
fb_req->screen = DefaultScreen (dpy);
|
2007-08-23 11:53:02 +02:00
|
|
|
break;
|
|
|
|
|
2007-08-28 15:55:05 +02:00
|
|
|
case EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX:
|
2007-08-23 11:53:02 +02:00
|
|
|
GetReqExtra(GLXVendorPrivateWithReply,
|
2007-08-28 15:55:05 +02:00
|
|
|
sz_xGLXGetFBConfigsSGIXReq
|
|
|
|
-
|
|
|
|
sz_xGLXVendorPrivateWithReplyReq,
|
|
|
|
vpreq);
|
2007-08-23 11:53:02 +02:00
|
|
|
sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq;
|
|
|
|
sgi_req->reqType = major_opcode;
|
|
|
|
sgi_req->glxCode = X_GLXVendorPrivateWithReply;
|
|
|
|
sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX;
|
Xephyr: port XV/GL stuff of the new multiscreen architecture
We can now launch GL or XV apps in any of the
Xephyr screens we want.
* hw/kdrive/ephyr/hostx.c,h:
(hostx_get_window):
(hostx_create_window): make these functions be screen
number aware.
* hw/kdrive/ephyr/XF86dri.c : fix some compiler warnings.
* hw/kdrive/ephyr/ephyrdri.c:
(ephyrDRIQueryDirectRenderingCapable),
(ephyrDRIOpenConnection),
(ephyrDRIAuthConnection),
(ephyrDRICloseConnection),
(ephyrDRIGetClientDriverName),
(ephyrDRICreateContext),
(ephyrDRIDestroyContext),
(ephyrDRICreateDrawable),
(ephyrDRIGetDrawableInfo),
(ephyrDRIGetDeviceInfo): in all those functions, don't forward
the screen number we receive - from the client - to the host X.
We (Xephyr) are always targetting the same X display screen, which is
the one Xephyr got launched against. So we enforce that in the code.
* hw/kdrive/ephyr/ephyrdriext.c:
(EphyrMirrorHostVisuals): make this duplicate the visuals of the host X
default screen into a given Xephyr screen. This way we have a chance
to update the visuals of all Xephyr screen to make them mirror those
of the host X.
(many other places): specify screen number where required by the api
change in hostx.h.
* hw/kdrive/ephyr/ephyrglxext.c: specify screen number where required
by the api change in hostx.h
* hw/kdrive/ephyr/ephyrhostglx.c: don't forward the screen number we
receive - from the client - to the host X.
We (Xephyr) are always targetting the same
X display screen, which is
the one Xephyr got launched against. So we enforce that in the code.
* hw/kdrive/ephyr/ephyrhostvideo.c,h: take in account the screen number received
from the client app. This is useful to know on which Xephyr screen we
need to display video stuff.
* hw/kdrive/ephyr/ephyrvideo.c: update this to reflect the API change
in hw/kdrive/ephyr/ephyrhostvideo.h.
(ephyrSetPortAttribute): when parameters are not valid
- they exceed their validity range - send them to the host anyway
and do not return an error to clients.
Some host expose buggy validity range, so rejecting client for that
is too harsh.
2007-10-03 13:03:34 +02:00
|
|
|
sgi_req->screen = DefaultScreen (dpy);
|
2007-08-23 11:53:02 +02:00
|
|
|
break;
|
|
|
|
|
2007-08-28 15:55:05 +02:00
|
|
|
case EPHYR_GET_VISUAL_CONFIGS:
|
2007-08-23 11:53:02 +02:00
|
|
|
GetReq(GLXGetVisualConfigs,req);
|
|
|
|
req->reqType = major_opcode;
|
|
|
|
req->glxCode = X_GLXGetVisualConfigs;
|
Xephyr: port XV/GL stuff of the new multiscreen architecture
We can now launch GL or XV apps in any of the
Xephyr screens we want.
* hw/kdrive/ephyr/hostx.c,h:
(hostx_get_window):
(hostx_create_window): make these functions be screen
number aware.
* hw/kdrive/ephyr/XF86dri.c : fix some compiler warnings.
* hw/kdrive/ephyr/ephyrdri.c:
(ephyrDRIQueryDirectRenderingCapable),
(ephyrDRIOpenConnection),
(ephyrDRIAuthConnection),
(ephyrDRICloseConnection),
(ephyrDRIGetClientDriverName),
(ephyrDRICreateContext),
(ephyrDRIDestroyContext),
(ephyrDRICreateDrawable),
(ephyrDRIGetDrawableInfo),
(ephyrDRIGetDeviceInfo): in all those functions, don't forward
the screen number we receive - from the client - to the host X.
We (Xephyr) are always targetting the same X display screen, which is
the one Xephyr got launched against. So we enforce that in the code.
* hw/kdrive/ephyr/ephyrdriext.c:
(EphyrMirrorHostVisuals): make this duplicate the visuals of the host X
default screen into a given Xephyr screen. This way we have a chance
to update the visuals of all Xephyr screen to make them mirror those
of the host X.
(many other places): specify screen number where required by the api
change in hostx.h.
* hw/kdrive/ephyr/ephyrglxext.c: specify screen number where required
by the api change in hostx.h
* hw/kdrive/ephyr/ephyrhostglx.c: don't forward the screen number we
receive - from the client - to the host X.
We (Xephyr) are always targetting the same
X display screen, which is
the one Xephyr got launched against. So we enforce that in the code.
* hw/kdrive/ephyr/ephyrhostvideo.c,h: take in account the screen number received
from the client app. This is useful to know on which Xephyr screen we
need to display video stuff.
* hw/kdrive/ephyr/ephyrvideo.c: update this to reflect the API change
in hw/kdrive/ephyr/ephyrhostvideo.h.
(ephyrSetPortAttribute): when parameters are not valid
- they exceed their validity range - send them to the host anyway
and do not return an error to clients.
Some host expose buggy validity range, so rejecting client for that
is too harsh.
2007-10-03 13:03:34 +02:00
|
|
|
req->screen = DefaultScreen (dpy);
|
2007-08-23 11:53:02 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_XReply(dpy, (xReply*) &reply, 0, False)) {
|
|
|
|
EPHYR_LOG_ERROR ("unknown error\n") ;
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
if (!reply.numVisuals) {
|
|
|
|
EPHYR_LOG_ERROR ("screen does not support GL rendering\n") ;
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
num_visuals = reply.numVisuals ;
|
|
|
|
|
|
|
|
/* FIXME: Is the __GLX_MIN_CONFIG_PROPS test correct for
|
|
|
|
* FIXME: FBconfigs?
|
|
|
|
*/
|
|
|
|
/* Check number of properties */
|
|
|
|
num_props = reply.numProps;
|
|
|
|
if ((num_props < __GLX_MIN_CONFIG_PROPS) ||
|
|
|
|
(num_props > __GLX_MAX_CONFIG_PROPS)) {
|
|
|
|
/* Huh? Not in protocol defined limits. Punt */
|
|
|
|
EPHYR_LOG_ERROR ("got a bad reply to request\n") ;
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
|
2007-08-28 15:55:05 +02:00
|
|
|
if (a_type != EPHYR_GET_VISUAL_CONFIGS) {
|
2007-08-23 11:53:02 +02:00
|
|
|
num_props *= 2;
|
|
|
|
}
|
|
|
|
props_per_visual_size = num_props * __GLX_SIZE_INT32;
|
|
|
|
props_buf_size = props_per_visual_size * reply.numVisuals;
|
|
|
|
props_buf = malloc (props_buf_size) ;
|
|
|
|
for (j = 0; j < reply.numVisuals; j++) {
|
|
|
|
if (_XRead (dpy,
|
2007-08-28 15:55:05 +02:00
|
|
|
&((char*)props_buf)[j*props_per_visual_size],
|
2007-08-23 11:53:02 +02:00
|
|
|
props_per_visual_size) != Success) {
|
|
|
|
EPHYR_LOG_ERROR ("read failed\n") ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
UnlockDisplay(dpy);
|
|
|
|
|
|
|
|
*a_num_visuals = num_visuals ;
|
2007-08-28 15:55:05 +02:00
|
|
|
*a_num_props = reply.numProps ;
|
2007-08-23 11:53:02 +02:00
|
|
|
*a_props_buf_size = props_buf_size ;
|
|
|
|
*a_props_buf = props_buf ;
|
|
|
|
is_ok = TRUE ;
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (server_glx_version) {
|
|
|
|
XFree (server_glx_version) ;
|
|
|
|
server_glx_version = NULL ;
|
|
|
|
}
|
|
|
|
if (server_glx_extensions) {
|
|
|
|
XFree (server_glx_extensions) ;
|
|
|
|
server_glx_extensions = NULL ;
|
|
|
|
}
|
|
|
|
SyncHandle () ;
|
|
|
|
return is_ok;
|
|
|
|
}
|
|
|
|
|
2007-08-28 15:55:05 +02:00
|
|
|
Bool
|
|
|
|
ephyrHostGLXGetVisualConfigs (int32_t a_screen,
|
|
|
|
int32_t *a_num_visuals,
|
|
|
|
int32_t *a_num_props,
|
|
|
|
int32_t *a_props_buf_size,
|
|
|
|
int32_t **a_props_buf)
|
|
|
|
{
|
|
|
|
Bool is_ok = FALSE;
|
|
|
|
|
|
|
|
EPHYR_LOG ("enter\n") ;
|
|
|
|
is_ok = ephyrHostGLXGetVisualConfigsInternal (EPHYR_GET_VISUAL_CONFIGS,
|
|
|
|
a_screen,
|
|
|
|
a_num_visuals,
|
|
|
|
a_num_props,
|
|
|
|
a_props_buf_size,
|
|
|
|
a_props_buf) ;
|
|
|
|
|
|
|
|
EPHYR_LOG ("leave:%d\n", is_ok) ;
|
|
|
|
return is_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
ephyrHostGLXVendorPrivGetFBConfigsSGIX (int a_screen,
|
|
|
|
int32_t *a_num_visuals,
|
|
|
|
int32_t *a_num_props,
|
|
|
|
int32_t *a_props_buf_size,
|
|
|
|
int32_t **a_props_buf)
|
|
|
|
{
|
|
|
|
Bool is_ok=FALSE ;
|
|
|
|
EPHYR_LOG ("enter\n") ;
|
|
|
|
is_ok = ephyrHostGLXGetVisualConfigsInternal
|
|
|
|
(EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX,
|
|
|
|
a_screen,
|
|
|
|
a_num_visuals,
|
|
|
|
a_num_props,
|
|
|
|
a_props_buf_size,
|
|
|
|
a_props_buf) ;
|
|
|
|
EPHYR_LOG ("leave\n") ;
|
|
|
|
return is_ok ;
|
|
|
|
}
|
|
|
|
|
2007-08-23 11:53:02 +02:00
|
|
|
Bool
|
|
|
|
ephyrHostGLXSendClientInfo (int32_t a_major, int32_t a_minor,
|
|
|
|
const char* a_extension_list)
|
|
|
|
{
|
|
|
|
Bool is_ok = FALSE ;
|
|
|
|
Display *dpy = hostx_get_display () ;
|
|
|
|
xGLXClientInfoReq *req;
|
|
|
|
int size;
|
|
|
|
int32_t major_opcode=0 ;
|
|
|
|
|
|
|
|
EPHYR_RETURN_VAL_IF_FAIL (dpy && a_extension_list, FALSE) ;
|
|
|
|
|
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
|
|
|
|
LockDisplay (dpy);
|
|
|
|
|
|
|
|
GetReq (GLXClientInfo,req);
|
|
|
|
req->reqType = major_opcode;
|
|
|
|
req->glxCode = X_GLXClientInfo;
|
|
|
|
req->major = a_major;
|
|
|
|
req->minor = a_minor;
|
|
|
|
|
|
|
|
size = strlen (a_extension_list) + 1;
|
|
|
|
req->length += (size + 3) >> 2;
|
|
|
|
req->numbytes = size;
|
|
|
|
Data (dpy, a_extension_list, size);
|
|
|
|
|
2007-08-31 14:43:39 +02:00
|
|
|
UnlockDisplay(dpy);
|
|
|
|
SyncHandle();
|
|
|
|
|
2007-08-23 11:53:02 +02:00
|
|
|
is_ok=TRUE ;
|
|
|
|
|
|
|
|
out:
|
|
|
|
return is_ok ;
|
|
|
|
}
|
|
|
|
|
2007-08-30 23:54:49 +02:00
|
|
|
Bool
|
|
|
|
ephyrHostGLXCreateContext (int a_screen,
|
|
|
|
int a_visual_id,
|
|
|
|
int a_context_id,
|
|
|
|
int a_share_list_ctxt_id,
|
|
|
|
Bool a_direct)
|
|
|
|
{
|
|
|
|
Bool is_ok = FALSE;
|
|
|
|
Display *dpy = hostx_get_display ();
|
|
|
|
int major_opcode=0, remote_context_id=0;
|
|
|
|
xGLXCreateContextReq *req;
|
|
|
|
|
|
|
|
EPHYR_LOG ("enter. screen:%d, visual:%d, contextid:%d, direct:%d\n",
|
|
|
|
a_screen, a_visual_id, a_context_id, a_direct) ;
|
|
|
|
|
|
|
|
if (!hostx_allocate_resource_id_peer (a_context_id, &remote_context_id)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to peer the context id %d host X",
|
|
|
|
remote_context_id) ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
|
|
|
|
LockDisplay (dpy) ;
|
|
|
|
|
|
|
|
/* Send the glXCreateContext request */
|
|
|
|
GetReq(GLXCreateContext,req);
|
|
|
|
req->reqType = major_opcode;
|
|
|
|
req->glxCode = X_GLXCreateContext;
|
|
|
|
req->context = remote_context_id;
|
|
|
|
req->visual = a_visual_id;
|
Xephyr: port XV/GL stuff of the new multiscreen architecture
We can now launch GL or XV apps in any of the
Xephyr screens we want.
* hw/kdrive/ephyr/hostx.c,h:
(hostx_get_window):
(hostx_create_window): make these functions be screen
number aware.
* hw/kdrive/ephyr/XF86dri.c : fix some compiler warnings.
* hw/kdrive/ephyr/ephyrdri.c:
(ephyrDRIQueryDirectRenderingCapable),
(ephyrDRIOpenConnection),
(ephyrDRIAuthConnection),
(ephyrDRICloseConnection),
(ephyrDRIGetClientDriverName),
(ephyrDRICreateContext),
(ephyrDRIDestroyContext),
(ephyrDRICreateDrawable),
(ephyrDRIGetDrawableInfo),
(ephyrDRIGetDeviceInfo): in all those functions, don't forward
the screen number we receive - from the client - to the host X.
We (Xephyr) are always targetting the same X display screen, which is
the one Xephyr got launched against. So we enforce that in the code.
* hw/kdrive/ephyr/ephyrdriext.c:
(EphyrMirrorHostVisuals): make this duplicate the visuals of the host X
default screen into a given Xephyr screen. This way we have a chance
to update the visuals of all Xephyr screen to make them mirror those
of the host X.
(many other places): specify screen number where required by the api
change in hostx.h.
* hw/kdrive/ephyr/ephyrglxext.c: specify screen number where required
by the api change in hostx.h
* hw/kdrive/ephyr/ephyrhostglx.c: don't forward the screen number we
receive - from the client - to the host X.
We (Xephyr) are always targetting the same
X display screen, which is
the one Xephyr got launched against. So we enforce that in the code.
* hw/kdrive/ephyr/ephyrhostvideo.c,h: take in account the screen number received
from the client app. This is useful to know on which Xephyr screen we
need to display video stuff.
* hw/kdrive/ephyr/ephyrvideo.c: update this to reflect the API change
in hw/kdrive/ephyr/ephyrhostvideo.h.
(ephyrSetPortAttribute): when parameters are not valid
- they exceed their validity range - send them to the host anyway
and do not return an error to clients.
Some host expose buggy validity range, so rejecting client for that
is too harsh.
2007-10-03 13:03:34 +02:00
|
|
|
req->screen = DefaultScreen (dpy);
|
2007-08-30 23:54:49 +02:00
|
|
|
req->shareList = a_share_list_ctxt_id;
|
|
|
|
req->isDirect = a_direct;
|
|
|
|
|
2007-08-31 14:43:39 +02:00
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
|
|
|
|
2007-08-30 23:54:49 +02:00
|
|
|
is_ok = TRUE ;
|
|
|
|
|
|
|
|
out:
|
|
|
|
EPHYR_LOG ("leave\n") ;
|
|
|
|
return is_ok ;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
ephyrHostDestroyContext (int a_ctxt_id)
|
|
|
|
{
|
|
|
|
Bool is_ok=FALSE;
|
|
|
|
Display *dpy=hostx_get_display ();
|
|
|
|
int major_opcode=0, remote_ctxt_id=0 ;
|
|
|
|
xGLXDestroyContextReq *req=NULL;
|
|
|
|
|
|
|
|
EPHYR_LOG ("enter:%d\n", a_ctxt_id) ;
|
|
|
|
|
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
if (!hostx_get_resource_id_peer (a_ctxt_id, &remote_ctxt_id)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get remote glx ctxt id\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
EPHYR_LOG ("host context id:%d\n", remote_ctxt_id) ;
|
|
|
|
|
|
|
|
LockDisplay (dpy);
|
|
|
|
GetReq (GLXDestroyContext,req);
|
|
|
|
req->reqType = major_opcode;
|
|
|
|
req->glxCode = X_GLXDestroyContext;
|
|
|
|
req->context = remote_ctxt_id;
|
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
|
|
|
|
|
|
|
is_ok = TRUE ;
|
|
|
|
|
|
|
|
out:
|
|
|
|
EPHYR_LOG ("leave\n") ;
|
|
|
|
return is_ok ;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
ephyrHostGLXMakeCurrent (int a_drawable,
|
|
|
|
int a_glx_ctxt_id,
|
|
|
|
int a_old_ctxt_tag,
|
|
|
|
int *a_ctxt_tag)
|
|
|
|
{
|
|
|
|
Bool is_ok=FALSE ;
|
|
|
|
Display *dpy = hostx_get_display () ;
|
|
|
|
int32_t major_opcode=0 ;
|
|
|
|
int remote_glx_ctxt_id=0 ;
|
|
|
|
xGLXMakeCurrentReq *req;
|
|
|
|
xGLXMakeCurrentReply reply;
|
|
|
|
|
|
|
|
EPHYR_RETURN_VAL_IF_FAIL (a_ctxt_tag, FALSE) ;
|
|
|
|
|
|
|
|
EPHYR_LOG ("enter. drawable:%d, context:%d, oldtag:%d\n",
|
|
|
|
a_drawable, a_glx_ctxt_id, a_old_ctxt_tag) ;
|
|
|
|
|
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
if (!hostx_get_resource_id_peer (a_glx_ctxt_id, &remote_glx_ctxt_id)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get remote glx ctxt id\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
|
|
|
|
LockDisplay (dpy);
|
|
|
|
|
|
|
|
GetReq (GLXMakeCurrent,req);
|
|
|
|
req->reqType = major_opcode;
|
|
|
|
req->glxCode = X_GLXMakeCurrent;
|
|
|
|
req->drawable = a_drawable;
|
|
|
|
req->context = remote_glx_ctxt_id;
|
|
|
|
req->oldContextTag = a_old_ctxt_tag;
|
|
|
|
|
|
|
|
memset (&reply, 0, sizeof (reply)) ;
|
|
|
|
if (!_XReply (dpy, (xReply*)&reply, 0, False)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get reply from host\n") ;
|
2007-08-31 14:43:39 +02:00
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
2007-08-30 23:54:49 +02:00
|
|
|
goto out ;
|
|
|
|
}
|
2007-08-31 14:43:39 +02:00
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
2007-08-30 23:54:49 +02:00
|
|
|
*a_ctxt_tag = reply.contextTag ;
|
2007-08-31 16:53:18 +02:00
|
|
|
EPHYR_LOG ("context tag:%d\n", *a_ctxt_tag) ;
|
2007-08-30 23:54:49 +02:00
|
|
|
is_ok = TRUE ;
|
|
|
|
|
|
|
|
out:
|
|
|
|
EPHYR_LOG ("leave\n") ;
|
|
|
|
return is_ok ;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define X_GLXSingle 0
|
|
|
|
|
|
|
|
#define __EPHYR_GLX_SINGLE_PUT_CHAR(offset,a) \
|
|
|
|
*((INT8 *) (pc + offset)) = a
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_PUT_SHORT(offset,a) \
|
|
|
|
*((INT16 *) (pc + offset)) = a
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_PUT_LONG(offset,a) \
|
|
|
|
*((INT32 *) (pc + offset)) = a
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_PUT_FLOAT(offset,a) \
|
|
|
|
*((FLOAT32 *) (pc + offset)) = a
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_READ_XREPLY() \
|
|
|
|
(void) _XReply(dpy, (xReply*) &reply, 0, False)
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_GET_RETVAL(a,cast) \
|
|
|
|
a = (cast) reply.retval
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_GET_SIZE(a) \
|
|
|
|
a = (GLint) reply.size
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_GET_CHAR(p) \
|
|
|
|
*p = *(GLbyte *)&reply.pad3;
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_GET_SHORT(p) \
|
|
|
|
*p = *(GLshort *)&reply.pad3;
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_GET_LONG(p) \
|
|
|
|
*p = *(GLint *)&reply.pad3;
|
|
|
|
|
|
|
|
#define EPHYR_GLX_SINGLE_GET_FLOAT(p) \
|
|
|
|
*p = *(GLfloat *)&reply.pad3;
|
|
|
|
|
|
|
|
Bool
|
|
|
|
ephyrHostGetIntegerValue (int a_current_context_tag, int a_int, int *a_val)
|
|
|
|
{
|
|
|
|
Bool is_ok=FALSE;
|
|
|
|
Display *dpy = hostx_get_display () ;
|
|
|
|
int major_opcode=0, size=0;
|
|
|
|
xGLXSingleReq *req=NULL;
|
|
|
|
xGLXSingleReply reply;
|
|
|
|
unsigned char* pc=NULL ;
|
|
|
|
|
|
|
|
EPHYR_RETURN_VAL_IF_FAIL (a_val, FALSE) ;
|
|
|
|
|
|
|
|
EPHYR_LOG ("enter\n") ;
|
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
LockDisplay (dpy) ;
|
|
|
|
GetReqExtra (GLXSingle, 4, req) ;
|
|
|
|
req->reqType = major_opcode ;
|
|
|
|
req->glxCode = X_GLsop_GetIntegerv ;
|
|
|
|
req->contextTag = a_current_context_tag;
|
|
|
|
pc = ((unsigned char *)(req) + sz_xGLXSingleReq) ;
|
|
|
|
EPHYR_GLX_SINGLE_PUT_LONG (0, a_int) ;
|
|
|
|
EPHYR_GLX_SINGLE_READ_XREPLY () ;
|
|
|
|
EPHYR_GLX_SINGLE_GET_SIZE (size) ;
|
|
|
|
if (!size) {
|
|
|
|
UnlockDisplay (dpy) ;
|
|
|
|
SyncHandle () ;
|
|
|
|
EPHYR_LOG_ERROR ("X_GLsop_GetIngerv failed\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
EPHYR_GLX_SINGLE_GET_LONG (a_val) ;
|
|
|
|
UnlockDisplay (dpy) ;
|
|
|
|
SyncHandle () ;
|
|
|
|
is_ok = TRUE ;
|
|
|
|
|
|
|
|
out:
|
|
|
|
EPHYR_LOG ("leave\n") ;
|
|
|
|
return is_ok ;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
|
|
ephyrHostIsContextDirect (int a_ctxt_id,
|
|
|
|
int *a_is_direct)
|
|
|
|
{
|
|
|
|
Bool is_ok=FALSE;
|
|
|
|
Display *dpy = hostx_get_display () ;
|
|
|
|
xGLXIsDirectReq *req=NULL;
|
|
|
|
xGLXIsDirectReply reply;
|
|
|
|
int major_opcode=0, remote_glx_ctxt_id=0;
|
|
|
|
|
|
|
|
EPHYR_LOG ("enter\n") ;
|
|
|
|
if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get major opcode\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
if (!hostx_get_resource_id_peer (a_ctxt_id, &remote_glx_ctxt_id)) {
|
|
|
|
EPHYR_LOG_ERROR ("failed to get remote glx ctxt id\n") ;
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
memset (&reply, 0, sizeof (reply)) ;
|
|
|
|
|
|
|
|
/* Send the glXIsDirect request */
|
|
|
|
LockDisplay (dpy);
|
|
|
|
GetReq (GLXIsDirect,req);
|
|
|
|
req->reqType = major_opcode;
|
|
|
|
req->glxCode = X_GLXIsDirect;
|
|
|
|
req->context = remote_glx_ctxt_id;
|
|
|
|
if (!_XReply (dpy, (xReply*) &reply, 0, False)) {
|
|
|
|
EPHYR_LOG_ERROR ("fail in reading reply from host\n") ;
|
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
|
|
|
goto out ;
|
|
|
|
}
|
|
|
|
UnlockDisplay (dpy);
|
|
|
|
SyncHandle ();
|
|
|
|
*a_is_direct = reply.isDirect ;
|
|
|
|
is_ok = TRUE ;
|
|
|
|
|
|
|
|
out:
|
|
|
|
EPHYR_LOG ("leave\n") ;
|
|
|
|
return is_ok ;
|
|
|
|
}
|