diff options
Diffstat (limited to 'src/glx/apple/apple_glx_surface.c')
-rw-r--r-- | src/glx/apple/apple_glx_surface.c | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/src/glx/apple/apple_glx_surface.c b/src/glx/apple/apple_glx_surface.c new file mode 100644 index 00000000000..6db2910a464 --- /dev/null +++ b/src/glx/apple/apple_glx_surface.c @@ -0,0 +1,224 @@ +/* + 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); + + glViewport(0, 0, width, height); + glScissor(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 occured. */ +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 occured. */ +/* 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()). + */ + d->destroy(d); + + d->unlock(d); + } +} |