diff options
Diffstat (limited to 'hw/kdrive/ephyr/ephyrhostglx.c')
-rw-r--r-- | hw/kdrive/ephyr/ephyrhostglx.c | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/hw/kdrive/ephyr/ephyrhostglx.c b/hw/kdrive/ephyr/ephyrhostglx.c new file mode 100644 index 000000000..5d9a482e8 --- /dev/null +++ b/hw/kdrive/ephyr/ephyrhostglx.c @@ -0,0 +1,687 @@ +/* + * 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 + +#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" +#include "hostx.h" + +#ifdef XEPHYR_DRI +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); +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 () ; + int major_opcode=0; + xGLXQueryVersionReq *req=NULL; + xGLXQueryVersionReply reply; + + EPHYR_RETURN_VAL_IF_FAIL (a_major && a_minor, FALSE) ; + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) { + EPHYR_LOG_ERROR ("failed to get major opcode\n") ; + goto out ; + } + 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) ; + + 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. + * (this has been copied from the mesa source code) + */ +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, + enum EphyrHostGLXGetStringOps a_op, + char **a_string) +{ + Bool is_ok=FALSE ; + Display *dpy = hostx_get_display () ; + xGLXGenericGetStringReq *req=NULL; + xGLXSingleReply reply; + int length=0, numbytes=0, major_opcode=0, get_string_op=0; + + EPHYR_RETURN_VAL_IF_FAIL (dpy && a_string, FALSE) ; + + EPHYR_LOG ("enter\n") ; + 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; + EPHYR_LOG ("Going to glXGetString. strname:%#x, ctxttag:%d\n", + a_string_name, a_screen_number) ; + break ; + default: + EPHYR_LOG_ERROR ("unknown EphyrHostGLXGetStringOp:%d\n", a_op) ; + goto out ; + } + + if (!ephyrHostGLXGetMajorOpcode (&major_opcode)) { + EPHYR_LOG_ERROR ("failed to get major opcode\n") ; + goto out ; + } + 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; + req->glxCode = get_string_op; + req->for_whom = DefaultScreen (dpy); + req->name = a_string_name; + + _XReply (dpy, (xReply *)&reply, 0, False); + + length = reply.length * 4; + numbytes = reply.size; + EPHYR_LOG ("going to get a string of size:%d\n", numbytes) ; + + *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 ; + } + length -= numbytes; + _XEatData (dpy, length) ; + UnlockDisplay (dpy); + SyncHandle (); + EPHYR_LOG ("strname:%#x, strvalue:'%s', strlen:%d\n", + a_string_name, *a_string, numbytes) ; + + is_ok = TRUE ; +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +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) +{ + 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); + switch (a_type) { + case EPHYR_GET_FB_CONFIG: + GetReq(GLXGetFBConfigs,fb_req); + fb_req->reqType = major_opcode; + fb_req->glxCode = X_GLXGetFBConfigs; + fb_req->screen = DefaultScreen (dpy); + break; + + case EPHYR_VENDOR_PRIV_GET_FB_CONFIG_SGIX: + GetReqExtra(GLXVendorPrivateWithReply, + sz_xGLXGetFBConfigsSGIXReq + - + sz_xGLXVendorPrivateWithReplyReq, + vpreq); + sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq; + sgi_req->reqType = major_opcode; + sgi_req->glxCode = X_GLXVendorPrivateWithReply; + sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX; + sgi_req->screen = DefaultScreen (dpy); + break; + + case EPHYR_GET_VISUAL_CONFIGS: + GetReq(GLXGetVisualConfigs,req); + req->reqType = major_opcode; + req->glxCode = X_GLXGetVisualConfigs; + req->screen = DefaultScreen (dpy); + 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 ; + } + + if (a_type != EPHYR_GET_VISUAL_CONFIGS) { + 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, + &((char*)props_buf)[j*props_per_visual_size], + props_per_visual_size) != Success) { + EPHYR_LOG_ERROR ("read failed\n") ; + } + } + UnlockDisplay(dpy); + + *a_num_visuals = num_visuals ; + *a_num_props = reply.numProps ; + *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; +} + +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 ; +} + +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); + + UnlockDisplay(dpy); + SyncHandle(); + + is_ok=TRUE ; + +out: + return is_ok ; +} + +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; + req->screen = DefaultScreen (dpy); + req->shareList = a_share_list_ctxt_id; + req->isDirect = a_direct; + + UnlockDisplay (dpy); + SyncHandle (); + + 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") ; + UnlockDisplay (dpy); + SyncHandle (); + goto out ; + } + UnlockDisplay (dpy); + SyncHandle (); + *a_ctxt_tag = reply.contextTag ; + EPHYR_LOG ("context tag:%d\n", *a_ctxt_tag) ; + 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 ; +} + +#endif /*XEPHYR_DRI*/ + |