/* * Copyright © 2004 David Reveman * * 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 * David Reveman not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * David Reveman makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL DAVID REVEMAN 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. * * Author: David Reveman */ #ifdef HAVE_CONFIG_H # include "../config.h" #endif #include "glitz_glxint.h" #include extern glitz_gl_proc_address_list_t _glitz_glx_gl_proc_address; static void _glitz_glx_context_create (glitz_glx_screen_info_t *screen_info, XID visualid, GLXContext share_list, glitz_glx_context_t *context) { int vis_info_count, i; XVisualInfo *vis_infos; vis_infos = XGetVisualInfo (screen_info->display_info->display, 0, NULL, &vis_info_count); for (i = 0; i < vis_info_count; i++) { if (vis_infos[i].visual->visualid == visualid) break; } context->context = glXCreateContext (screen_info->display_info->display, &vis_infos[i], share_list, GLITZ_GL_TRUE); context->id = visualid; context->fbconfig = (GLXFBConfig) 0; XFree (vis_infos); } static void _glitz_glx_context_create_using_fbconfig (glitz_glx_screen_info_t *screen_info, XID fbconfigid, GLXContext share_list, glitz_glx_context_t *context) { GLXFBConfig *fbconfigs; int i, n_fbconfigs; XVisualInfo *vinfo = NULL; glitz_glx_static_proc_address_list_t *glx = &screen_info->glx; fbconfigs = glx->get_fbconfigs (screen_info->display_info->display, screen_info->screen, &n_fbconfigs); for (i = 0; i < n_fbconfigs; i++) { int value; glx->get_fbconfig_attrib (screen_info->display_info->display, fbconfigs[i], GLX_FBCONFIG_ID, &value); if (value == (int) fbconfigid) break; } if (i < n_fbconfigs) vinfo = glx->get_visual_from_fbconfig (screen_info->display_info->display, fbconfigs[i]); context->id = fbconfigid; if (vinfo) { context->context = glXCreateContext (screen_info->display_info->display, vinfo, share_list, GLITZ_GL_TRUE); XFree (vinfo); } else if (glx->create_new_context) context->context = glx->create_new_context (screen_info->display_info->display, fbconfigs[i], GLX_RGBA_TYPE, share_list, GLITZ_GL_TRUE); if (context->context) context->fbconfig = fbconfigs[i]; else context->fbconfig = (GLXFBConfig) 0; if (fbconfigs) XFree (fbconfigs); } static glitz_context_t * _glitz_glx_create_context (void *abstract_drawable, glitz_drawable_format_t *format) { glitz_glx_drawable_t *drawable = (glitz_glx_drawable_t *) abstract_drawable; glitz_glx_screen_info_t *screen_info = drawable->screen_info; unsigned long format_id = screen_info->formats[format->id].u.uval; glitz_glx_context_t *context; context = malloc (sizeof (glitz_glx_context_t)); if (!context) return NULL; _glitz_context_init (&context->base, &drawable->base); if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_FBCONFIG_MASK) _glitz_glx_context_create_using_fbconfig (screen_info, format_id, screen_info->root_context, context); else _glitz_glx_context_create (screen_info, format_id, screen_info->root_context, context); return (glitz_context_t *) context; } static void _glitz_glx_context_destroy (void *abstract_context) { glitz_glx_context_t *context = (glitz_glx_context_t *) abstract_context; glitz_glx_drawable_t *drawable = (glitz_glx_drawable_t *) context->base.drawable; if (drawable->screen_info->display_info->thread_info->cctx == &context->base) { glXMakeCurrent (drawable->screen_info->display_info->display, None, NULL); drawable->screen_info->display_info->thread_info->cctx = NULL; } glXDestroyContext (drawable->screen_info->display_info->display, context->context); _glitz_context_fini (&context->base); free (context); } static void _glitz_glx_copy_context (void *abstract_src, void *abstract_dst, unsigned long mask) { glitz_glx_context_t *src = (glitz_glx_context_t *) abstract_src; glitz_glx_context_t *dst = (glitz_glx_context_t *) abstract_dst; glitz_glx_drawable_t *drawable = (glitz_glx_drawable_t *) src->base.drawable; glXCopyContext (drawable->screen_info->display_info->display, src->context, dst->context, mask); } static void _glitz_glx_make_current (void *abstract_drawable, void *abstract_context) { glitz_glx_context_t *context = (glitz_glx_context_t *) abstract_context; glitz_glx_drawable_t *drawable = (glitz_glx_drawable_t *) abstract_drawable; glitz_glx_display_info_t *display_info = drawable->screen_info->display_info; if (drawable->base.width != drawable->width || drawable->base.height != drawable->height) _glitz_glx_drawable_update_size (drawable, drawable->base.width, drawable->base.height); if ((glXGetCurrentContext () != context->context) || (glXGetCurrentDrawable () != drawable->drawable)) { if (display_info->thread_info->cctx) { glitz_context_t *ctx = display_info->thread_info->cctx; if (ctx->lose_current) ctx->lose_current (ctx->closure); } glXMakeCurrent (display_info->display, drawable->drawable, context->context); } display_info->thread_info->cctx = &context->base; } static void _glitz_glx_notify_dummy (void *abstract_drawable, glitz_surface_t *surface) {} static glitz_function_pointer_t _glitz_glx_context_get_proc_address (void *abstract_context, const char *name) { glitz_glx_context_t *context = (glitz_glx_context_t *) abstract_context; glitz_glx_drawable_t *drawable = (glitz_glx_drawable_t *) context->base.drawable; /* _glitz_glx_make_current (drawable, context, NULL); */ return glitz_glx_get_proc_address (name, drawable->screen_info); } glitz_glx_context_t * glitz_glx_context_get (glitz_glx_screen_info_t *screen_info, glitz_drawable_format_t *format) { glitz_glx_context_t *context; glitz_glx_context_t **contexts = screen_info->contexts; int index, n_contexts = screen_info->n_contexts; unsigned long format_id; for (; n_contexts; n_contexts--, contexts++) if ((*contexts)->id == screen_info->formats[format->id].u.uval) return *contexts; index = screen_info->n_contexts++; screen_info->contexts = realloc (screen_info->contexts, sizeof (glitz_glx_context_t *) * screen_info->n_contexts); if (!screen_info->contexts) return NULL; context = malloc (sizeof (glitz_glx_context_t)); if (!context) return NULL; screen_info->contexts[index] = context; format_id = screen_info->formats[format->id].u.uval; if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_FBCONFIG_MASK) _glitz_glx_context_create_using_fbconfig (screen_info, format_id, screen_info->root_context, context); else _glitz_glx_context_create (screen_info, format_id, screen_info->root_context, context); if (!screen_info->root_context) screen_info->root_context = context->context; context->backend.gl = &_glitz_glx_gl_proc_address; context->backend.create_pbuffer = glitz_glx_create_pbuffer; context->backend.destroy = glitz_glx_destroy; context->backend.push_current = glitz_glx_push_current; context->backend.pop_current = glitz_glx_pop_current; context->backend.attach_notify = _glitz_glx_notify_dummy; context->backend.detach_notify = _glitz_glx_notify_dummy; context->backend.swap_buffers = glitz_glx_swap_buffers; context->backend.copy_sub_buffer = glitz_glx_copy_sub_buffer; context->backend.create_context = _glitz_glx_create_context; context->backend.destroy_context = _glitz_glx_context_destroy; context->backend.copy_context = _glitz_glx_copy_context; context->backend.make_current = _glitz_glx_make_current; context->backend.get_proc_address = _glitz_glx_context_get_proc_address; context->backend.draw_buffer = _glitz_drawable_draw_buffer; context->backend.read_buffer = _glitz_drawable_read_buffer; context->backend.drawable_formats = NULL; context->backend.n_drawable_formats = 0; if (screen_info->n_formats) { int size; size = sizeof (glitz_int_drawable_format_t) * screen_info->n_formats; context->backend.drawable_formats = malloc (size); if (context->backend.drawable_formats) { memcpy (context->backend.drawable_formats, screen_info->formats, size); context->backend.n_drawable_formats = screen_info->n_formats; } } context->backend.texture_formats = NULL; context->backend.formats = NULL; context->backend.n_formats = 0; context->backend.program_map = &screen_info->program_map; context->backend.feature_mask = 0; context->initialized = 0; return context; } void glitz_glx_context_destroy (glitz_glx_screen_info_t *screen_info, glitz_glx_context_t *context) { if (context->backend.drawable_formats) free (context->backend.drawable_formats); if (context->backend.formats) free (context->backend.formats); if (context->backend.texture_formats) free (context->backend.texture_formats); glXDestroyContext (screen_info->display_info->display, context->context); free (context); } static void _glitz_glx_context_initialize (glitz_glx_screen_info_t *screen_info, glitz_glx_context_t *context) { const char *version; glitz_backend_init (&context->backend, glitz_glx_get_proc_address, (void *) screen_info); glitz_initiate_state (&_glitz_glx_gl_proc_address); version = (const char *) context->backend.gl->get_string (GLITZ_GL_VERSION); if (version) { /* Having trouble with TexSubImage2D to NPOT GL_TEXTURE_2D textures when using nvidia's binary driver. Seems like a driver issue, but I'm not sure yet. Turning of NPOT GL_TEXTURE_2D textures until this have been solved. */ if (strstr (version, "NVIDIA 61.11") || strstr (version, "NVIDIA 66.29")) { context->backend.feature_mask &= ~GLITZ_FEATURE_TEXTURE_NON_POWER_OF_TWO_MASK; } } if (screen_info->glx_feature_mask & GLITZ_GLX_FEATURE_COPY_SUB_BUFFER_MASK) context->backend.feature_mask |= GLITZ_FEATURE_COPY_SUB_BUFFER_MASK; context->initialized = 1; } static void _glitz_glx_context_make_current (glitz_glx_drawable_t *drawable, glitz_bool_t finish) { glitz_glx_display_info_t *display_info = drawable->screen_info->display_info; if (finish) { glFinish (); drawable->base.finished = 1; } if (display_info->thread_info->cctx) { glitz_context_t *ctx = display_info->thread_info->cctx; if (ctx->lose_current) ctx->lose_current (ctx->closure); display_info->thread_info->cctx = NULL; } glXMakeCurrent (display_info->display, drawable->drawable, drawable->context->context); drawable->base.update_all = 1; if (!drawable->context->initialized) _glitz_glx_context_initialize (drawable->screen_info, drawable->context); } static void _glitz_glx_context_update (glitz_glx_drawable_t *drawable, glitz_constraint_t constraint, glitz_bool_t *restore_state) { glitz_glx_display_info_t *dinfo = drawable->screen_info->display_info; GLXContext context = NULL; if (restore_state && constraint == GLITZ_ANY_CONTEXT_CURRENT) { if (dinfo->thread_info->cctx) { *restore_state = 1; return; } } drawable->base.flushed = drawable->base.finished = 0; switch (constraint) { case GLITZ_NONE: break; case GLITZ_ANY_CONTEXT_CURRENT: if (!dinfo->thread_info->cctx) context = glXGetCurrentContext (); if (context == (GLXContext) 0) _glitz_glx_context_make_current (drawable, 0); break; case GLITZ_CONTEXT_CURRENT: if (!dinfo->thread_info->cctx) context = glXGetCurrentContext (); if (context != drawable->context->context) _glitz_glx_context_make_current (drawable, (context)? 1: 0); break; case GLITZ_DRAWABLE_CURRENT: if (!dinfo->thread_info->cctx) context = glXGetCurrentContext (); if (drawable->base.width != drawable->width || drawable->base.height != drawable->height) _glitz_glx_drawable_update_size (drawable, drawable->base.width, drawable->base.height); if ((context != drawable->context->context) || (glXGetCurrentDrawable () != drawable->drawable)) _glitz_glx_context_make_current (drawable, (context)? 1: 0); break; } } glitz_bool_t glitz_glx_push_current (void *abstract_drawable, glitz_surface_t *surface, glitz_constraint_t constraint, glitz_bool_t *restore_state) { glitz_glx_drawable_t *drawable = (glitz_glx_drawable_t *) abstract_drawable; glitz_glx_context_info_t *context_info; int index; if (restore_state) *restore_state = 0; index = drawable->screen_info->context_stack_size++; context_info = &drawable->screen_info->context_stack[index]; context_info->drawable = drawable; context_info->surface = surface; context_info->constraint = constraint; _glitz_glx_context_update (context_info->drawable, constraint, restore_state); return 1; } glitz_surface_t * glitz_glx_pop_current (void *abstract_drawable) { glitz_glx_drawable_t *drawable = (glitz_glx_drawable_t *) abstract_drawable; glitz_glx_context_info_t *context_info = NULL; int index; drawable->screen_info->context_stack_size--; index = drawable->screen_info->context_stack_size - 1; context_info = &drawable->screen_info->context_stack[index]; if (context_info->drawable) _glitz_glx_context_update (context_info->drawable, context_info->constraint, NULL); if (context_info->constraint == GLITZ_DRAWABLE_CURRENT) return context_info->surface; return NULL; }