226 lines
6.9 KiB
C
226 lines
6.9 KiB
C
/*
|
|
Copyright (c) 2009 Apple Inc.
|
|
|
|
Permission is hereby granted, free of charge, to any person
|
|
obtaining a copy of this software and associated documentation files
|
|
(the "Software"), to deal in the Software without restriction,
|
|
including without limitation the rights to use, copy, modify, merge,
|
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
|
and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
|
|
HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name(s) of the above
|
|
copyright holders shall not be used in advertising or otherwise to
|
|
promote the sale, use or other dealings in this Software without
|
|
prior written authorization.
|
|
*/
|
|
#include <assert.h>
|
|
#include "glxclient.h"
|
|
#include "apple_glx.h"
|
|
#include "appledri.h"
|
|
#include "apple_glx_drawable.h"
|
|
|
|
static bool surface_make_current(struct apple_glx_context *ac,
|
|
struct apple_glx_drawable *d);
|
|
|
|
static void surface_destroy(Display * dpy, struct apple_glx_drawable *d);
|
|
|
|
|
|
static struct apple_glx_drawable_callbacks callbacks = {
|
|
.type = APPLE_GLX_DRAWABLE_SURFACE,
|
|
.make_current = surface_make_current,
|
|
.destroy = surface_destroy
|
|
};
|
|
|
|
static void
|
|
update_viewport_and_scissor(Display * dpy, GLXDrawable drawable)
|
|
{
|
|
Window root;
|
|
int x, y;
|
|
unsigned int width = 0, height = 0, bd, depth;
|
|
|
|
XGetGeometry(dpy, drawable, &root, &x, &y, &width, &height, &bd, &depth);
|
|
|
|
apple_glapi_oglfw_viewport_scissor(0, 0, width, height);
|
|
}
|
|
|
|
static bool
|
|
surface_make_current(struct apple_glx_context *ac,
|
|
struct apple_glx_drawable *d)
|
|
{
|
|
struct apple_glx_surface *s = &d->types.surface;
|
|
xp_error error;
|
|
|
|
assert(APPLE_GLX_DRAWABLE_SURFACE == d->type);
|
|
|
|
apple_glx_diagnostic("%s: ac->context_obj %p s->surface_id %u\n",
|
|
__func__, (void *) ac->context_obj, s->surface_id);
|
|
|
|
error = xp_attach_gl_context(ac->context_obj, s->surface_id);
|
|
|
|
if (error) {
|
|
fprintf(stderr, "error: xp_attach_gl_context returned: %d\n", error);
|
|
return true;
|
|
}
|
|
|
|
|
|
if (!ac->made_current) {
|
|
/*
|
|
* The first time a new context is made current the glViewport
|
|
* and glScissor should be updated.
|
|
*/
|
|
update_viewport_and_scissor(ac->drawable->display,
|
|
ac->drawable->drawable);
|
|
ac->made_current = true;
|
|
}
|
|
|
|
apple_glx_diagnostic("%s: drawable 0x%lx\n", __func__, d->drawable);
|
|
|
|
return false;
|
|
}
|
|
|
|
static void
|
|
surface_destroy(Display * dpy, struct apple_glx_drawable *d)
|
|
{
|
|
struct apple_glx_surface *s = &d->types.surface;
|
|
|
|
apple_glx_diagnostic("%s: s->surface_id %u\n", __func__, s->surface_id);
|
|
|
|
xp_error error = xp_destroy_surface(s->surface_id);
|
|
|
|
if (error) {
|
|
fprintf(stderr, "xp_destroy_surface error: %d\n", (int) error);
|
|
}
|
|
|
|
/*
|
|
* Check if this surface destroy came from the surface being destroyed
|
|
* on the server. If s->pending_destroy is true, then it did, and
|
|
* we don't want to try to destroy the surface on the server.
|
|
*/
|
|
if (!s->pending_destroy) {
|
|
/*
|
|
* Warning: this causes other routines to be called (potentially)
|
|
* from surface_notify_handler. It's probably best to not have
|
|
* any locks at this point locked.
|
|
*/
|
|
XAppleDRIDestroySurface(d->display, DefaultScreen(d->display),
|
|
d->drawable);
|
|
|
|
apple_glx_diagnostic
|
|
("%s: destroyed a surface for drawable 0x%lx uid %u\n", __func__,
|
|
d->drawable, s->uid);
|
|
}
|
|
}
|
|
|
|
/* Return true if an error occurred. */
|
|
static bool
|
|
create_surface(Display * dpy, int screen, struct apple_glx_drawable *d)
|
|
{
|
|
struct apple_glx_surface *s = &d->types.surface;
|
|
unsigned int key[2];
|
|
xp_client_id id;
|
|
|
|
id = apple_glx_get_client_id();
|
|
if (0 == id)
|
|
return true;
|
|
|
|
assert(None != d->drawable);
|
|
|
|
s->pending_destroy = false;
|
|
|
|
if (XAppleDRICreateSurface(dpy, screen, d->drawable, id, key, &s->uid)) {
|
|
xp_error error;
|
|
|
|
error = xp_import_surface(key, &s->surface_id);
|
|
|
|
if (error) {
|
|
fprintf(stderr, "error: xp_import_surface returned: %d\n", error);
|
|
return true;
|
|
}
|
|
|
|
apple_glx_diagnostic("%s: created a surface for drawable 0x%lx"
|
|
" with uid %u\n", __func__, d->drawable, s->uid);
|
|
return false; /*success */
|
|
}
|
|
|
|
return true; /* unable to create a surface. */
|
|
}
|
|
|
|
/* Return true if an error occurred. */
|
|
/* This returns a referenced object via resultptr. */
|
|
bool
|
|
apple_glx_surface_create(Display * dpy, int screen,
|
|
GLXDrawable drawable,
|
|
struct apple_glx_drawable ** resultptr)
|
|
{
|
|
struct apple_glx_drawable *d;
|
|
|
|
if (apple_glx_drawable_create(dpy, screen, drawable, &d, &callbacks))
|
|
return true;
|
|
|
|
/* apple_glx_drawable_create creates a locked and referenced object. */
|
|
|
|
if (create_surface(dpy, screen, d)) {
|
|
d->unlock(d);
|
|
d->destroy(d);
|
|
return true;
|
|
}
|
|
|
|
*resultptr = d;
|
|
|
|
d->unlock(d);
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* All surfaces are reference counted, and surfaces are only created
|
|
* when the window is made current. When all contexts no longer reference
|
|
* a surface drawable the apple_glx_drawable gets destroyed, and thus
|
|
* its surface is destroyed.
|
|
*
|
|
* However we can make the destruction occur a bit sooner by setting
|
|
* pending_destroy, which is then checked for in glViewport by
|
|
* apple_glx_context_update.
|
|
*/
|
|
void
|
|
apple_glx_surface_destroy(unsigned int uid)
|
|
{
|
|
struct apple_glx_drawable *d;
|
|
|
|
d = apple_glx_drawable_find_by_uid(uid, APPLE_GLX_DRAWABLE_REFERENCE
|
|
| APPLE_GLX_DRAWABLE_LOCK);
|
|
|
|
if (d) {
|
|
d->types.surface.pending_destroy = true;
|
|
d->release(d);
|
|
|
|
/*
|
|
* We release 2 references to the surface. One was acquired by
|
|
* the find, and the other was leftover from a context, or
|
|
* the surface being displayed, so the destroy() will decrease it
|
|
* once more.
|
|
*
|
|
* If the surface is in a context, it will take one d->destroy(d);
|
|
* to actually destroy it when the pending_destroy is processed
|
|
* by a glViewport callback (see apple_glx_context_update()).
|
|
*/
|
|
if (!d->destroy(d)) {
|
|
/* apple_glx_drawable_find_by_uid returns a locked drawable */
|
|
d->unlock(d);
|
|
}
|
|
}
|
|
}
|