Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  Copyright (c) 2008, 2009 Apple Inc.
  3.  
  4.  Permission is hereby granted, free of charge, to any person
  5.  obtaining a copy of this software and associated documentation files
  6.  (the "Software"), to deal in the Software without restriction,
  7.  including without limitation the rights to use, copy, modify, merge,
  8.  publish, distribute, sublicense, and/or sell copies of the Software,
  9.  and to permit persons to whom the Software is furnished to do so,
  10.  subject to the following conditions:
  11.  
  12.  The above copyright notice and this permission notice shall be
  13.  included in all copies or substantial portions of the Software.
  14.  
  15.  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16.  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17.  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18.  NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
  19.  HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  20.  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21.  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  DEALINGS IN THE SOFTWARE.
  23.  
  24.  Except as contained in this notice, the name(s) of the above
  25.  copyright holders shall not be used in advertising or otherwise to
  26.  promote the sale, use or other dealings in this Software without
  27.  prior written authorization.
  28. */
  29.  
  30. #include <stdbool.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <limits.h>
  34. #include <assert.h>
  35. #include <pthread.h>
  36.  
  37. #include <fcntl.h>
  38. #include <sys/mman.h>
  39. #include <unistd.h>
  40.  
  41. // Get the newer glext.h first
  42. #include <GL/gl.h>
  43. #include <GL/glext.h>
  44.  
  45. #include <OpenGL/CGLTypes.h>
  46. #include <OpenGL/CGLCurrent.h>
  47. #include <OpenGL/OpenGL.h>
  48.  
  49. #include "glxclient.h"
  50.  
  51. #include "apple_glx.h"
  52. #include "apple_glx_context.h"
  53. #include "appledri.h"
  54. #include "apple_visual.h"
  55. #include "apple_cgl.h"
  56. #include "apple_glx_drawable.h"
  57.  
  58. static pthread_mutex_t context_lock = PTHREAD_MUTEX_INITIALIZER;
  59.  
  60. /*
  61.  * This should be locked on creation and destruction of the
  62.  * apple_glx_contexts.
  63.  *
  64.  * It's also locked when the surface_notify_handler is searching
  65.  * for a uid associated with a surface.
  66.  */
  67. static struct apple_glx_context *context_list = NULL;
  68.  
  69. /* This guards the context_list above. */
  70. static void
  71. lock_context_list(void)
  72. {
  73.    int err;
  74.  
  75.    err = pthread_mutex_lock(&context_lock);
  76.  
  77.    if (err) {
  78.       fprintf(stderr, "pthread_mutex_lock failure in %s: %d\n",
  79.               __func__, err);
  80.       abort();
  81.    }
  82. }
  83.  
  84. static void
  85. unlock_context_list(void)
  86. {
  87.    int err;
  88.  
  89.    err = pthread_mutex_unlock(&context_lock);
  90.  
  91.    if (err) {
  92.       fprintf(stderr, "pthread_mutex_unlock failure in %s: %d\n",
  93.               __func__, err);
  94.       abort();
  95.    }
  96. }
  97.  
  98. static bool
  99. is_context_valid(struct apple_glx_context *ac)
  100. {
  101.    struct apple_glx_context *i;
  102.  
  103.    lock_context_list();
  104.  
  105.    for (i = context_list; i; i = i->next) {
  106.       if (ac == i) {
  107.          unlock_context_list();
  108.          return true;
  109.       }
  110.    }
  111.  
  112.    unlock_context_list();
  113.  
  114.    return false;
  115. }
  116.  
  117. /* This creates an apple_private_context struct.  
  118.  *
  119.  * It's typically called to save the struct in a GLXContext.
  120.  *
  121.  * This is also where the CGLContextObj is created, and the CGLPixelFormatObj.
  122.  */
  123. bool
  124. apple_glx_create_context(void **ptr, Display * dpy, int screen,
  125.                          const void *mode, void *sharedContext,
  126.                          int *errorptr, bool * x11errorptr)
  127. {
  128.    struct apple_glx_context *ac;
  129.    struct apple_glx_context *sharedac = sharedContext;
  130.    CGLError error;
  131.  
  132.    *ptr = NULL;
  133.  
  134.    ac = malloc(sizeof *ac);
  135.  
  136.    if (NULL == ac) {
  137.       *errorptr = BadAlloc;
  138.       *x11errorptr = true;
  139.       return true;
  140.    }
  141.  
  142.    if (sharedac && !is_context_valid(sharedac)) {
  143.       *errorptr = GLXBadContext;
  144.       *x11errorptr = false;
  145.       return true;
  146.    }
  147.  
  148.    ac->context_obj = NULL;
  149.    ac->pixel_format_obj = NULL;
  150.    ac->drawable = NULL;
  151.    ac->thread_id = pthread_self();
  152.    ac->screen = screen;
  153.    ac->double_buffered = false;
  154.    ac->uses_stereo = false;
  155.    ac->need_update = false;
  156.    ac->is_current = false;
  157.    ac->made_current = false;
  158.    ac->last_surface_window = None;
  159.  
  160.    apple_visual_create_pfobj(&ac->pixel_format_obj, mode,
  161.                              &ac->double_buffered, &ac->uses_stereo,
  162.                              /*offscreen */ false);
  163.  
  164.    error = apple_cgl.create_context(ac->pixel_format_obj,
  165.                                     sharedac ? sharedac->context_obj : NULL,
  166.                                     &ac->context_obj);
  167.  
  168.  
  169.    if (error) {
  170.       (void) apple_cgl.destroy_pixel_format(ac->pixel_format_obj);
  171.  
  172.       free(ac);
  173.  
  174.       if (kCGLBadMatch == error) {
  175.          *errorptr = BadMatch;
  176.          *x11errorptr = true;
  177.       }
  178.       else {
  179.          *errorptr = GLXBadContext;
  180.          *x11errorptr = false;
  181.       }
  182.  
  183.       if (getenv("LIBGL_DIAGNOSTIC"))
  184.          fprintf(stderr, "error: %s\n", apple_cgl.error_string(error));
  185.  
  186.       return true;
  187.    }
  188.  
  189.    /* The context creation succeeded, so we can link in the new context. */
  190.    lock_context_list();
  191.  
  192.    if (context_list)
  193.       context_list->previous = ac;
  194.  
  195.    ac->previous = NULL;
  196.    ac->next = context_list;
  197.    context_list = ac;
  198.  
  199.    *ptr = ac;
  200.  
  201.    apple_glx_diagnostic("%s: ac %p ac->context_obj %p\n",
  202.                         __func__, (void *) ac, (void *) ac->context_obj);
  203.  
  204.    unlock_context_list();
  205.  
  206.    return false;
  207. }
  208.  
  209. void
  210. apple_glx_destroy_context(void **ptr, Display * dpy)
  211. {
  212.    struct apple_glx_context *ac = *ptr;
  213.  
  214.    if (NULL == ac)
  215.       return;
  216.  
  217.    apple_glx_diagnostic("%s: ac %p ac->context_obj %p\n",
  218.                         __func__, (void *) ac, (void *) ac->context_obj);
  219.  
  220.    if (apple_cgl.get_current_context() == ac->context_obj) {
  221.       apple_glx_diagnostic("%s: context ac->context_obj %p "
  222.                            "is still current!\n", __func__,
  223.                            (void *) ac->context_obj);
  224.       if (apple_cgl.set_current_context(NULL)) {
  225.          abort();
  226.       }
  227.    }
  228.  
  229.    /* Remove ac from the context_list as soon as possible. */
  230.    lock_context_list();
  231.  
  232.    if (ac->previous) {
  233.       ac->previous->next = ac->next;
  234.    }
  235.    else {
  236.       context_list = ac->next;
  237.    }
  238.  
  239.    if (ac->next) {
  240.       ac->next->previous = ac->previous;
  241.    }
  242.  
  243.    unlock_context_list();
  244.  
  245.  
  246.    if (apple_cgl.clear_drawable(ac->context_obj)) {
  247.       fprintf(stderr, "error: while clearing drawable!\n");
  248.       abort();
  249.    }
  250.  
  251.    /*
  252.     * This potentially causes surface_notify_handler to be called in
  253.     * apple_glx.c...
  254.     * We can NOT have a lock held at this point.  It would result in
  255.     * an abort due to an attempted deadlock.  This is why we earlier
  256.     * removed the ac pointer from the double-linked list.
  257.     */
  258.    if (ac->drawable) {
  259.       ac->drawable->destroy(ac->drawable);
  260.    }
  261.  
  262.    if (apple_cgl.destroy_pixel_format(ac->pixel_format_obj)) {
  263.       fprintf(stderr, "error: destroying pixel format in %s\n", __func__);
  264.       abort();
  265.    }
  266.  
  267.    if (apple_cgl.destroy_context(ac->context_obj)) {
  268.       fprintf(stderr, "error: destroying context_obj in %s\n", __func__);
  269.       abort();
  270.    }
  271.  
  272.    free(ac);
  273.  
  274.    *ptr = NULL;
  275.  
  276.    apple_glx_garbage_collect_drawables(dpy);
  277. }
  278.  
  279.  
  280. /* Return true if an error occured. */
  281. bool
  282. apple_glx_make_current_context(Display * dpy, void *oldptr, void *ptr,
  283.                                GLXDrawable drawable)
  284. {
  285.    struct apple_glx_context *oldac = oldptr;
  286.    struct apple_glx_context *ac = ptr;
  287.    struct apple_glx_drawable *newagd = NULL;
  288.    CGLError cglerr;
  289.    bool same_drawable = false;
  290.  
  291. #if 0
  292.    apple_glx_diagnostic("%s: oldac %p ac %p drawable 0x%lx\n",
  293.                         __func__, (void *) oldac, (void *) ac, drawable);
  294.  
  295.    apple_glx_diagnostic("%s: oldac->context_obj %p ac->context_obj %p\n",
  296.                         __func__,
  297.                         (void *) (oldac ? oldac->context_obj : NULL),
  298.                         (void *) (ac ? ac->context_obj : NULL));
  299. #endif
  300.  
  301.    /* This a common path for GLUT and other apps, so special case it. */
  302.    if (ac && ac->drawable && ac->drawable->drawable == drawable) {
  303.       same_drawable = true;
  304.  
  305.       if (ac->is_current)
  306.          return false;
  307.    }
  308.  
  309.    /* Reset the is_current state of the old context, if non-NULL. */
  310.    if (oldac && (ac != oldac))
  311.       oldac->is_current = false;
  312.  
  313.    if (NULL == ac) {
  314.       /*Clear the current context for this thread. */
  315.       apple_cgl.set_current_context(NULL);
  316.  
  317.       if (oldac) {
  318.          oldac->is_current = false;
  319.  
  320.          if (oldac->drawable) {
  321.             oldac->drawable->destroy(oldac->drawable);
  322.             oldac->drawable = NULL;
  323.          }
  324.  
  325.          /* Invalidate this to prevent surface recreation. */
  326.          oldac->last_surface_window = None;
  327.       }
  328.  
  329.       return false;
  330.    }
  331.  
  332.    if (None == drawable) {
  333.       bool error = false;
  334.  
  335.       /* Clear the current drawable for this context_obj. */
  336.  
  337.       if (apple_cgl.set_current_context(ac->context_obj))
  338.          error = true;
  339.  
  340.       if (apple_cgl.clear_drawable(ac->context_obj))
  341.          error = true;
  342.  
  343.       if (ac->drawable) {
  344.          ac->drawable->destroy(ac->drawable);
  345.          ac->drawable = NULL;
  346.       }
  347.  
  348.       /* Invalidate this to prevent surface recreation. */
  349.       ac->last_surface_window = None;
  350.  
  351.       apple_glx_diagnostic("%s: drawable is None, error is: %d\n",
  352.                            __func__, error);
  353.  
  354.       return error;
  355.    }
  356.  
  357.    /* This is an optimisation to avoid searching for the current drawable. */
  358.    if (ac->drawable && ac->drawable->drawable == drawable) {
  359.       newagd = ac->drawable;
  360.    }
  361.    else {
  362.       /* Find the drawable if possible, and retain a reference to it. */
  363.       newagd =
  364.          apple_glx_drawable_find(drawable, APPLE_GLX_DRAWABLE_REFERENCE);
  365.    }
  366.  
  367.    /*
  368.     * Try to destroy the old drawable, so long as the new one
  369.     * isn't the old.
  370.     */
  371.    if (ac->drawable && !same_drawable) {
  372.       ac->drawable->destroy(ac->drawable);
  373.       ac->drawable = NULL;
  374.    }
  375.  
  376.    if (NULL == newagd) {
  377.       if (apple_glx_surface_create(dpy, ac->screen, drawable, &newagd))
  378.          return true;
  379.  
  380.       /* The drawable is referenced once by apple_glx_surface_create. */
  381.  
  382.       /*
  383.        * FIXME: We actually need 2 references to prevent premature surface
  384.        * destruction.  The problem is that the surface gets destroyed in
  385.        * the case of the context being reused for another window, and
  386.        * we then lose the surface contents.  Wait for destruction of a
  387.        * window to destroy a surface.
  388.        *
  389.        * Note: this may leave around surfaces we don't want around, if
  390.        * say we are using X for raster drawing after OpenGL rendering,
  391.        * but it will be compatible with the old libGL's behavior.
  392.        *
  393.        * Someday the X11 and OpenGL rendering must be unified at some
  394.        * layer.  I suspect we can do that via shared memory and
  395.        * multiple threads in the X server (1 for each context created
  396.        * by a client).  This would also allow users to render from
  397.        * multiple clients to the same OpenGL surface.  In fact it could
  398.        * all be OpenGL.
  399.        *
  400.        */
  401.       newagd->reference(newagd);
  402.  
  403.       /* Save the new drawable with the context structure. */
  404.       ac->drawable = newagd;
  405.    }
  406.    else {
  407.       /* We are reusing an existing drawable structure. */
  408.  
  409.       if (same_drawable) {
  410.          assert(ac->drawable == newagd);
  411.          /* The drawable_find above retained a reference for us. */
  412.       }
  413.       else {
  414.          ac->drawable = newagd;
  415.       }
  416.    }
  417.  
  418.    /*
  419.     * Avoid this costly path if this is the same drawable and the
  420.     * context is already current.
  421.     */
  422.  
  423.    if (same_drawable && ac->is_current) {
  424.       apple_glx_diagnostic("same_drawable and ac->is_current\n");
  425.       return false;
  426.    }
  427.  
  428.    cglerr = apple_cgl.set_current_context(ac->context_obj);
  429.  
  430.    if (kCGLNoError != cglerr) {
  431.       fprintf(stderr, "set current error: %s\n",
  432.               apple_cgl.error_string(cglerr));
  433.       return true;
  434.    }
  435.  
  436.    ac->is_current = true;
  437.  
  438.    assert(NULL != ac->context_obj);
  439.    assert(NULL != ac->drawable);
  440.  
  441.    ac->thread_id = pthread_self();
  442.  
  443.    /* This will be set if the pending_destroy code indicates it should be: */
  444.    ac->last_surface_window = None;
  445.  
  446.    switch (ac->drawable->type) {
  447.    case APPLE_GLX_DRAWABLE_PBUFFER:
  448.    case APPLE_GLX_DRAWABLE_SURFACE:
  449.    case APPLE_GLX_DRAWABLE_PIXMAP:
  450.       if (ac->drawable->callbacks.make_current) {
  451.          if (ac->drawable->callbacks.make_current(ac, ac->drawable))
  452.             return true;
  453.       }
  454.       break;
  455.  
  456.    default:
  457.       fprintf(stderr, "internal error: invalid drawable type: %d\n",
  458.               ac->drawable->type);
  459.       abort();
  460.    }
  461.  
  462.    return false;
  463. }
  464.  
  465. bool
  466. apple_glx_is_current_drawable(Display * dpy, void *ptr, GLXDrawable drawable)
  467. {
  468.    struct apple_glx_context *ac = ptr;
  469.  
  470.    if (ac->drawable && ac->drawable->drawable == drawable) {
  471.       return true;
  472.    }
  473.    else if (NULL == ac->drawable && None != ac->last_surface_window) {
  474.       apple_glx_context_update(dpy, ac);
  475.  
  476.       return (ac->drawable && ac->drawable->drawable == drawable);
  477.    }
  478.  
  479.    return false;
  480. }
  481.  
  482. bool
  483. apple_glx_copy_context(void *currentptr, void *srcptr, void *destptr,
  484.                        unsigned long mask, int *errorptr, bool * x11errorptr)
  485. {
  486.    struct apple_glx_context *src, *dest;
  487.    CGLError err;
  488.  
  489.    src = srcptr;
  490.    dest = destptr;
  491.  
  492.    if (src->screen != dest->screen) {
  493.       *errorptr = BadMatch;
  494.       *x11errorptr = true;
  495.       return true;
  496.    }
  497.  
  498.    if (dest == currentptr || dest->is_current) {
  499.       *errorptr = BadAccess;
  500.       *x11errorptr = true;
  501.       return true;
  502.    }
  503.  
  504.    /*
  505.     * If srcptr is the current context then we should do an implicit glFlush.
  506.     */
  507.    if (currentptr == srcptr)
  508.       glFlush();
  509.  
  510.    err = apple_cgl.copy_context(src->context_obj, dest->context_obj,
  511.                                 (GLbitfield) mask);
  512.  
  513.    if (kCGLNoError != err) {
  514.       *errorptr = GLXBadContext;
  515.       *x11errorptr = false;
  516.       return true;
  517.    }
  518.  
  519.    return false;
  520. }
  521.  
  522. /*
  523.  * The value returned is the total number of contexts set to update.
  524.  * It's meant for debugging/introspection.
  525.  */
  526. int
  527. apple_glx_context_surface_changed(unsigned int uid, pthread_t caller)
  528. {
  529.    struct apple_glx_context *ac;
  530.    int updated = 0;
  531.  
  532.    lock_context_list();
  533.  
  534.    for (ac = context_list; ac; ac = ac->next) {
  535.       if (ac->drawable && APPLE_GLX_DRAWABLE_SURFACE == ac->drawable->type
  536.           && ac->drawable->types.surface.uid == uid) {
  537.  
  538.          if (caller == ac->thread_id) {
  539.             apple_glx_diagnostic("caller is the same thread for uid %u\n",
  540.                                  uid);
  541.  
  542.             xp_update_gl_context(ac->context_obj);
  543.          }
  544.          else {
  545.             ac->need_update = true;
  546.             ++updated;
  547.          }
  548.       }
  549.    }
  550.  
  551.    unlock_context_list();
  552.  
  553.    return updated;
  554. }
  555.  
  556. void
  557. apple_glx_context_update(Display * dpy, void *ptr)
  558. {
  559.    struct apple_glx_context *ac = ptr;
  560.  
  561.    if (NULL == ac->drawable && None != ac->last_surface_window) {
  562.       bool failed;
  563.  
  564.       /* Attempt to recreate the surface for a destroyed drawable. */
  565.       failed =
  566.          apple_glx_make_current_context(dpy, ac, ac, ac->last_surface_window);
  567.  
  568.       apple_glx_diagnostic("%s: surface recreation failed? %s\n", __func__,
  569.                            failed ? "YES" : "NO");
  570.    }
  571.  
  572.    if (ac->need_update) {
  573.       xp_update_gl_context(ac->context_obj);
  574.       ac->need_update = false;
  575.  
  576.       apple_glx_diagnostic("%s: updating context %p\n", __func__, ptr);
  577.    }
  578.  
  579.    if (ac->drawable && APPLE_GLX_DRAWABLE_SURFACE == ac->drawable->type
  580.        && ac->drawable->types.surface.pending_destroy) {
  581.       apple_glx_diagnostic("%s: clearing drawable %p\n", __func__, ptr);
  582.       apple_cgl.clear_drawable(ac->context_obj);
  583.  
  584.       if (ac->drawable) {
  585.          struct apple_glx_drawable *d;
  586.  
  587.          apple_glx_diagnostic("%s: attempting to destroy drawable %p\n",
  588.                               __func__, ptr);
  589.          apple_glx_diagnostic("%s: ac->drawable->drawable is 0x%lx\n",
  590.                               __func__, ac->drawable->drawable);
  591.  
  592.          d = ac->drawable;
  593.  
  594.          ac->last_surface_window = d->drawable;
  595.  
  596.          ac->drawable = NULL;
  597.  
  598.          /*
  599.           * This will destroy the surface drawable if there are
  600.           * no references to it.  
  601.           * It also subtracts 1 from the reference_count.
  602.           * If there are references to it, then it's probably made
  603.           * current in another context.
  604.           */
  605.          d->destroy(d);
  606.       }
  607.    }
  608. }
  609.  
  610. bool
  611. apple_glx_context_uses_stereo(void *ptr)
  612. {
  613.    struct apple_glx_context *ac = ptr;
  614.  
  615.    return ac->uses_stereo;
  616. }
  617.