13464ebd5Sriastradh/*
23464ebd5Sriastradh Copyright (c) 2009 Apple Inc.
33464ebd5Sriastradh
43464ebd5Sriastradh Permission is hereby granted, free of charge, to any person
53464ebd5Sriastradh obtaining a copy of this software and associated documentation files
63464ebd5Sriastradh (the "Software"), to deal in the Software without restriction,
73464ebd5Sriastradh including without limitation the rights to use, copy, modify, merge,
83464ebd5Sriastradh publish, distribute, sublicense, and/or sell copies of the Software,
93464ebd5Sriastradh and to permit persons to whom the Software is furnished to do so,
103464ebd5Sriastradh subject to the following conditions:
113464ebd5Sriastradh
123464ebd5Sriastradh The above copyright notice and this permission notice shall be
133464ebd5Sriastradh included in all copies or substantial portions of the Software.
143464ebd5Sriastradh
153464ebd5Sriastradh THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
163464ebd5Sriastradh EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
173464ebd5Sriastradh MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
183464ebd5Sriastradh NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
193464ebd5Sriastradh HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
203464ebd5Sriastradh WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
213464ebd5Sriastradh OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
223464ebd5Sriastradh DEALINGS IN THE SOFTWARE.
233464ebd5Sriastradh
243464ebd5Sriastradh Except as contained in this notice, the name(s) of the above
253464ebd5Sriastradh copyright holders shall not be used in advertising or otherwise to
263464ebd5Sriastradh promote the sale, use or other dealings in this Software without
273464ebd5Sriastradh prior written authorization.
283464ebd5Sriastradh*/
293464ebd5Sriastradh#include <assert.h>
303464ebd5Sriastradh#include "glxclient.h"
313464ebd5Sriastradh#include "apple_glx.h"
323464ebd5Sriastradh#include "appledri.h"
333464ebd5Sriastradh#include "apple_glx_drawable.h"
343464ebd5Sriastradh
353464ebd5Sriastradhstatic bool surface_make_current(struct apple_glx_context *ac,
363464ebd5Sriastradh                                 struct apple_glx_drawable *d);
373464ebd5Sriastradh
383464ebd5Sriastradhstatic void surface_destroy(Display * dpy, struct apple_glx_drawable *d);
393464ebd5Sriastradh
403464ebd5Sriastradh
413464ebd5Sriastradhstatic struct apple_glx_drawable_callbacks callbacks = {
423464ebd5Sriastradh   .type = APPLE_GLX_DRAWABLE_SURFACE,
433464ebd5Sriastradh   .make_current = surface_make_current,
443464ebd5Sriastradh   .destroy = surface_destroy
453464ebd5Sriastradh};
463464ebd5Sriastradh
473464ebd5Sriastradhstatic void
483464ebd5Sriastradhupdate_viewport_and_scissor(Display * dpy, GLXDrawable drawable)
493464ebd5Sriastradh{
503464ebd5Sriastradh   Window root;
513464ebd5Sriastradh   int x, y;
523464ebd5Sriastradh   unsigned int width = 0, height = 0, bd, depth;
533464ebd5Sriastradh
543464ebd5Sriastradh   XGetGeometry(dpy, drawable, &root, &x, &y, &width, &height, &bd, &depth);
553464ebd5Sriastradh
563464ebd5Sriastradh   apple_glapi_oglfw_viewport_scissor(0, 0, width, height);
573464ebd5Sriastradh}
583464ebd5Sriastradh
593464ebd5Sriastradhstatic bool
603464ebd5Sriastradhsurface_make_current(struct apple_glx_context *ac,
613464ebd5Sriastradh                     struct apple_glx_drawable *d)
623464ebd5Sriastradh{
633464ebd5Sriastradh   struct apple_glx_surface *s = &d->types.surface;
643464ebd5Sriastradh   xp_error error;
653464ebd5Sriastradh
663464ebd5Sriastradh   assert(APPLE_GLX_DRAWABLE_SURFACE == d->type);
673464ebd5Sriastradh
683464ebd5Sriastradh   apple_glx_diagnostic("%s: ac->context_obj %p s->surface_id %u\n",
693464ebd5Sriastradh                        __func__, (void *) ac->context_obj, s->surface_id);
703464ebd5Sriastradh
713464ebd5Sriastradh   error = xp_attach_gl_context(ac->context_obj, s->surface_id);
723464ebd5Sriastradh
733464ebd5Sriastradh   if (error) {
743464ebd5Sriastradh      fprintf(stderr, "error: xp_attach_gl_context returned: %d\n", error);
753464ebd5Sriastradh      return true;
763464ebd5Sriastradh   }
773464ebd5Sriastradh
783464ebd5Sriastradh
793464ebd5Sriastradh   if (!ac->made_current) {
803464ebd5Sriastradh      /*
813464ebd5Sriastradh       * The first time a new context is made current the glViewport
823464ebd5Sriastradh       * and glScissor should be updated.
833464ebd5Sriastradh       */
843464ebd5Sriastradh      update_viewport_and_scissor(ac->drawable->display,
853464ebd5Sriastradh                                  ac->drawable->drawable);
863464ebd5Sriastradh      ac->made_current = true;
873464ebd5Sriastradh   }
883464ebd5Sriastradh
893464ebd5Sriastradh   apple_glx_diagnostic("%s: drawable 0x%lx\n", __func__, d->drawable);
903464ebd5Sriastradh
913464ebd5Sriastradh   return false;
923464ebd5Sriastradh}
933464ebd5Sriastradh
943464ebd5Sriastradhstatic void
953464ebd5Sriastradhsurface_destroy(Display * dpy, struct apple_glx_drawable *d)
963464ebd5Sriastradh{
973464ebd5Sriastradh   struct apple_glx_surface *s = &d->types.surface;
983464ebd5Sriastradh
993464ebd5Sriastradh   apple_glx_diagnostic("%s: s->surface_id %u\n", __func__, s->surface_id);
1003464ebd5Sriastradh
1013464ebd5Sriastradh   xp_error error = xp_destroy_surface(s->surface_id);
1023464ebd5Sriastradh
1033464ebd5Sriastradh   if (error) {
1043464ebd5Sriastradh      fprintf(stderr, "xp_destroy_surface error: %d\n", (int) error);
1053464ebd5Sriastradh   }
1063464ebd5Sriastradh
1073464ebd5Sriastradh   /*
1083464ebd5Sriastradh    * Check if this surface destroy came from the surface being destroyed
1093464ebd5Sriastradh    * on the server.  If s->pending_destroy is true, then it did, and
1103464ebd5Sriastradh    * we don't want to try to destroy the surface on the server.
1113464ebd5Sriastradh    */
1123464ebd5Sriastradh   if (!s->pending_destroy) {
1133464ebd5Sriastradh      /*
1143464ebd5Sriastradh       * Warning: this causes other routines to be called (potentially)
1153464ebd5Sriastradh       * from surface_notify_handler.  It's probably best to not have
1163464ebd5Sriastradh       * any locks at this point locked.
1173464ebd5Sriastradh       */
1183464ebd5Sriastradh      XAppleDRIDestroySurface(d->display, DefaultScreen(d->display),
1193464ebd5Sriastradh                              d->drawable);
1203464ebd5Sriastradh
1213464ebd5Sriastradh      apple_glx_diagnostic
1223464ebd5Sriastradh         ("%s: destroyed a surface for drawable 0x%lx uid %u\n", __func__,
1233464ebd5Sriastradh          d->drawable, s->uid);
1243464ebd5Sriastradh   }
1253464ebd5Sriastradh}
1263464ebd5Sriastradh
12701e04c3fSmrg/* Return true if an error occurred. */
1283464ebd5Sriastradhstatic bool
1293464ebd5Sriastradhcreate_surface(Display * dpy, int screen, struct apple_glx_drawable *d)
1303464ebd5Sriastradh{
1313464ebd5Sriastradh   struct apple_glx_surface *s = &d->types.surface;
1323464ebd5Sriastradh   unsigned int key[2];
1333464ebd5Sriastradh   xp_client_id id;
1343464ebd5Sriastradh
1353464ebd5Sriastradh   id = apple_glx_get_client_id();
1363464ebd5Sriastradh   if (0 == id)
1373464ebd5Sriastradh      return true;
1383464ebd5Sriastradh
1393464ebd5Sriastradh   assert(None != d->drawable);
1403464ebd5Sriastradh
1413464ebd5Sriastradh   s->pending_destroy = false;
1423464ebd5Sriastradh
1433464ebd5Sriastradh   if (XAppleDRICreateSurface(dpy, screen, d->drawable, id, key, &s->uid)) {
1443464ebd5Sriastradh      xp_error error;
1453464ebd5Sriastradh
1463464ebd5Sriastradh      error = xp_import_surface(key, &s->surface_id);
1473464ebd5Sriastradh
1483464ebd5Sriastradh      if (error) {
1493464ebd5Sriastradh         fprintf(stderr, "error: xp_import_surface returned: %d\n", error);
1503464ebd5Sriastradh         return true;
1513464ebd5Sriastradh      }
1523464ebd5Sriastradh
1533464ebd5Sriastradh      apple_glx_diagnostic("%s: created a surface for drawable 0x%lx"
1543464ebd5Sriastradh                           " with uid %u\n", __func__, d->drawable, s->uid);
1553464ebd5Sriastradh      return false;             /*success */
1563464ebd5Sriastradh   }
1573464ebd5Sriastradh
1583464ebd5Sriastradh   return true;                 /* unable to create a surface. */
1593464ebd5Sriastradh}
1603464ebd5Sriastradh
16101e04c3fSmrg/* Return true if an error occurred. */
1623464ebd5Sriastradh/* This returns a referenced object via resultptr. */
1633464ebd5Sriastradhbool
1643464ebd5Sriastradhapple_glx_surface_create(Display * dpy, int screen,
1653464ebd5Sriastradh                         GLXDrawable drawable,
1663464ebd5Sriastradh                         struct apple_glx_drawable ** resultptr)
1673464ebd5Sriastradh{
1683464ebd5Sriastradh   struct apple_glx_drawable *d;
1693464ebd5Sriastradh
1703464ebd5Sriastradh   if (apple_glx_drawable_create(dpy, screen, drawable, &d, &callbacks))
1713464ebd5Sriastradh      return true;
1723464ebd5Sriastradh
1733464ebd5Sriastradh   /* apple_glx_drawable_create creates a locked and referenced object. */
1743464ebd5Sriastradh
1753464ebd5Sriastradh   if (create_surface(dpy, screen, d)) {
1763464ebd5Sriastradh      d->unlock(d);
1773464ebd5Sriastradh      d->destroy(d);
1783464ebd5Sriastradh      return true;
1793464ebd5Sriastradh   }
1803464ebd5Sriastradh
1813464ebd5Sriastradh   *resultptr = d;
1823464ebd5Sriastradh
1833464ebd5Sriastradh   d->unlock(d);
1843464ebd5Sriastradh
1853464ebd5Sriastradh   return false;
1863464ebd5Sriastradh}
1873464ebd5Sriastradh
1883464ebd5Sriastradh/*
1893464ebd5Sriastradh * All surfaces are reference counted, and surfaces are only created
1903464ebd5Sriastradh * when the window is made current.  When all contexts no longer reference
1913464ebd5Sriastradh * a surface drawable the apple_glx_drawable gets destroyed, and thus
1923464ebd5Sriastradh * its surface is destroyed.
1933464ebd5Sriastradh *
1943464ebd5Sriastradh * However we can make the destruction occur a bit sooner by setting
1953464ebd5Sriastradh * pending_destroy, which is then checked for in glViewport by
1963464ebd5Sriastradh * apple_glx_context_update.
1973464ebd5Sriastradh */
1983464ebd5Sriastradhvoid
1993464ebd5Sriastradhapple_glx_surface_destroy(unsigned int uid)
2003464ebd5Sriastradh{
2013464ebd5Sriastradh   struct apple_glx_drawable *d;
2023464ebd5Sriastradh
2033464ebd5Sriastradh   d = apple_glx_drawable_find_by_uid(uid, APPLE_GLX_DRAWABLE_REFERENCE
2043464ebd5Sriastradh                                      | APPLE_GLX_DRAWABLE_LOCK);
2053464ebd5Sriastradh
2063464ebd5Sriastradh   if (d) {
2073464ebd5Sriastradh      d->types.surface.pending_destroy = true;
2083464ebd5Sriastradh      d->release(d);
209af69d88dSmrg
2103464ebd5Sriastradh      /*
2113464ebd5Sriastradh       * We release 2 references to the surface.  One was acquired by
2123464ebd5Sriastradh       * the find, and the other was leftover from a context, or
2133464ebd5Sriastradh       * the surface being displayed, so the destroy() will decrease it
2143464ebd5Sriastradh       * once more.
2153464ebd5Sriastradh       *
2163464ebd5Sriastradh       * If the surface is in a context, it will take one d->destroy(d);
2173464ebd5Sriastradh       * to actually destroy it when the pending_destroy is processed
2183464ebd5Sriastradh       * by a glViewport callback (see apple_glx_context_update()).
2193464ebd5Sriastradh       */
220af69d88dSmrg      if (!d->destroy(d)) {
221af69d88dSmrg          /* apple_glx_drawable_find_by_uid returns a locked drawable */
222af69d88dSmrg          d->unlock(d);
223af69d88dSmrg      }
2243464ebd5Sriastradh   }
2253464ebd5Sriastradh}
226