/* * 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 names 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. * * Based on glx code by David Reveman * * Contributors: * Tor Lillqvist * Vladimir Vukicevic * */ #ifdef HAVE_CONFIG_H # include "../config.h" #endif #include "glitz_wglint.h" #include #include #include #include #include void glitz_wgl_print_win32_error_string (int error_code) { char *msg = NULL; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, 0, (LPTSTR) &msg, 0, NULL); if (msg != NULL) fprintf (stderr, "%s", msg); else fprintf (stderr, "Unknown error code %d", error_code); LocalFree (msg); } void glitz_wgl_win32_api_failed (const char *api) { fprintf (stderr, "%s failed: ", api); glitz_wgl_print_win32_error_string (GetLastError ()); fprintf (stderr, "\n"); } glitz_gl_proc_address_list_t _glitz_wgl_gl_proc_address = { /* core */ (glitz_gl_enable_t) glEnable, (glitz_gl_disable_t) glDisable, (glitz_gl_get_error_t) glGetError, (glitz_gl_get_string_t) glGetString, (glitz_gl_enable_client_state_t) glEnableClientState, (glitz_gl_disable_client_state_t) glDisableClientState, (glitz_gl_vertex_pointer_t) glVertexPointer, (glitz_gl_tex_coord_pointer_t) glTexCoordPointer, (glitz_gl_draw_arrays_t) glDrawArrays, (glitz_gl_tex_env_f_t) glTexEnvf, (glitz_gl_tex_env_fv_t) glTexEnvfv, (glitz_gl_tex_gen_i_t) glTexGeni, (glitz_gl_tex_gen_fv_t) glTexGenfv, (glitz_gl_color_4us_t) glColor4us, (glitz_gl_color_4f_t) glColor4f, (glitz_gl_scissor_t) glScissor, (glitz_gl_blend_func_t) glBlendFunc, (glitz_gl_clear_t) glClear, (glitz_gl_clear_color_t) glClearColor, (glitz_gl_clear_stencil_t) glClearStencil, (glitz_gl_stencil_func_t) glStencilFunc, (glitz_gl_stencil_op_t) glStencilOp, (glitz_gl_push_attrib_t) glPushAttrib, (glitz_gl_pop_attrib_t) glPopAttrib, (glitz_gl_matrix_mode_t) glMatrixMode, (glitz_gl_push_matrix_t) glPushMatrix, (glitz_gl_pop_matrix_t) glPopMatrix, (glitz_gl_load_identity_t) glLoadIdentity, (glitz_gl_load_matrix_f_t) glLoadMatrixf, (glitz_gl_depth_range_t) glDepthRange, (glitz_gl_viewport_t) glViewport, (glitz_gl_raster_pos_2f_t) glRasterPos2f, (glitz_gl_bitmap_t) glBitmap, (glitz_gl_read_buffer_t) glReadBuffer, (glitz_gl_draw_buffer_t) glDrawBuffer, (glitz_gl_copy_pixels_t) glCopyPixels, (glitz_gl_flush_t) glFlush, (glitz_gl_finish_t) glFinish, (glitz_gl_pixel_store_i_t) glPixelStorei, (glitz_gl_ortho_t) glOrtho, (glitz_gl_scale_f_t) glScalef, (glitz_gl_translate_f_t) glTranslatef, (glitz_gl_hint_t) glHint, (glitz_gl_depth_mask_t) glDepthMask, (glitz_gl_polygon_mode_t) glPolygonMode, (glitz_gl_shade_model_t) glShadeModel, (glitz_gl_color_mask_t) glColorMask, (glitz_gl_read_pixels_t) glReadPixels, (glitz_gl_get_tex_image_t) glGetTexImage, (glitz_gl_tex_sub_image_2d_t) glTexSubImage2D, (glitz_gl_gen_textures_t) glGenTextures, (glitz_gl_delete_textures_t) glDeleteTextures, (glitz_gl_bind_texture_t) glBindTexture, (glitz_gl_tex_image_2d_t) glTexImage2D, (glitz_gl_tex_parameter_i_t) glTexParameteri, (glitz_gl_tex_parameter_fv_t) glTexParameterfv, (glitz_gl_get_tex_level_parameter_iv_t) glGetTexLevelParameteriv, (glitz_gl_copy_tex_sub_image_2d_t) glCopyTexSubImage2D, (glitz_gl_get_integer_v_t) glGetIntegerv, /* extensions */ (glitz_gl_blend_color_t) 0, (glitz_gl_active_texture_t) 0, (glitz_gl_client_active_texture_t) 0, (glitz_gl_multi_draw_arrays_t) 0, (glitz_gl_gen_programs_t) 0, (glitz_gl_delete_programs_t) 0, (glitz_gl_program_string_t) 0, (glitz_gl_bind_program_t) 0, (glitz_gl_program_local_param_4fv_t) 0, (glitz_gl_get_program_iv_t) 0, (glitz_gl_gen_buffers_t) 0, (glitz_gl_delete_buffers_t) 0, (glitz_gl_bind_buffer_t) 0, (glitz_gl_buffer_data_t) 0, (glitz_gl_buffer_sub_data_t) 0, (glitz_gl_get_buffer_sub_data_t) 0, (glitz_gl_map_buffer_t) 0, (glitz_gl_unmap_buffer_t) 0, (glitz_gl_gen_framebuffers_t) 0, (glitz_gl_delete_framebuffers_t) 0, (glitz_gl_bind_framebuffer_t) 0, (glitz_gl_framebuffer_renderbuffer_t) 0, (glitz_gl_framebuffer_texture_2d_t) 0, (glitz_gl_check_framebuffer_status_t) 0, (glitz_gl_gen_renderbuffers_t) 0, (glitz_gl_delete_renderbuffers_t) 0, (glitz_gl_bind_renderbuffer_t) 0, (glitz_gl_renderbuffer_storage_t) 0, (glitz_gl_get_renderbuffer_parameter_iv_t) 0 }; glitz_function_pointer_t glitz_wgl_get_proc_address (const char *name, void *closure) { glitz_wgl_screen_info_t *screen_info = (glitz_wgl_screen_info_t *) closure; glitz_wgl_thread_info_t *info = screen_info->thread_info; glitz_function_pointer_t address = (glitz_function_pointer_t) wglGetProcAddress (name); if (!address && info->gl_library) { /* Not sure whether this has any use at all... */ if (!info->dlhand) info->dlhand = LoadLibrary (info->gl_library); if (info->dlhand) { address = (glitz_function_pointer_t) GetProcAddress (info->dlhand, name); } } return address; } static void _glitz_wgl_proc_address_lookup (glitz_wgl_screen_info_t *screen_info) { screen_info->wgl.get_pixel_format_attrib_iv = (glitz_wgl_get_pixel_format_attrib_iv_t) glitz_wgl_get_proc_address ("wglGetPixelFormatAttribivARB", screen_info); screen_info->wgl.choose_pixel_format = (glitz_wgl_choose_pixel_format_t) glitz_wgl_get_proc_address ("wglChoosePixelFormatARB", screen_info); screen_info->wgl.create_pbuffer = (glitz_wgl_create_pbuffer_t) glitz_wgl_get_proc_address ("wglCreatePbufferARB", screen_info); screen_info->wgl.get_pbuffer_dc = (glitz_wgl_get_pbuffer_dc_t) glitz_wgl_get_proc_address ("wglGetPbufferDCARB", screen_info); screen_info->wgl.release_pbuffer_dc = (glitz_wgl_release_pbuffer_dc_t) glitz_wgl_get_proc_address ("wglReleasePbufferDCARB", screen_info); screen_info->wgl.destroy_pbuffer = (glitz_wgl_destroy_pbuffer_t) glitz_wgl_get_proc_address ("wglDestroyPbufferARB", screen_info); screen_info->wgl.query_pbuffer = (glitz_wgl_query_pbuffer_t) glitz_wgl_get_proc_address ("wglQueryPbufferARB", screen_info); screen_info->wgl.make_context_current = (glitz_wgl_make_context_current_t) glitz_wgl_get_proc_address ("wglMakeContextCurrentARB", screen_info); if ((!screen_info->wgl.create_pbuffer) || (!screen_info->wgl.destroy_pbuffer) || (!screen_info->wgl.query_pbuffer)) screen_info->wgl_feature_mask &= ~GLITZ_WGL_FEATURE_PBUFFER_MASK; } static void _glitz_wgl_screen_destroy (glitz_wgl_screen_info_t *screen_info); static void _glitz_wgl_thread_info_init (glitz_wgl_thread_info_t *thread_info) { thread_info->screen = NULL; thread_info->gl_library = NULL; thread_info->dlhand = NULL; thread_info->cctx = NULL; } static void _glitz_wgl_thread_info_fini (glitz_wgl_thread_info_t *thread_info) { _glitz_wgl_screen_destroy (thread_info->screen); thread_info->screen = NULL; if (thread_info->gl_library) { free (thread_info->gl_library); thread_info->gl_library = NULL; } if (thread_info->dlhand) { FreeLibrary (thread_info->dlhand); thread_info->dlhand = NULL; } } static int tsd_initialized = 0; static DWORD info_tsd; static void _glitz_wgl_thread_info_destroy (glitz_wgl_thread_info_t *thread_info) { TlsSetValue (info_tsd, NULL); if (thread_info) { _glitz_wgl_thread_info_fini (thread_info); free (thread_info); } } static glitz_wgl_thread_info_t * _glitz_wgl_thread_info_get_inner (void) { glitz_wgl_thread_info_t *thread_info; void *p; if (!tsd_initialized) { info_tsd = TlsAlloc (); tsd_initialized = 1; } p = TlsGetValue (info_tsd); if (p == NULL) { thread_info = malloc (sizeof (glitz_wgl_thread_info_t)); _glitz_wgl_thread_info_init (thread_info); TlsSetValue (info_tsd, thread_info); } else thread_info = (glitz_wgl_thread_info_t *) p; return thread_info; } static glitz_wgl_thread_info_t * _glitz_wgl_thread_info_get (const char *gl_library) { glitz_wgl_thread_info_t *thread_info = _glitz_wgl_thread_info_get_inner (); if (gl_library) { int len = strlen (gl_library); if (thread_info->gl_library) { free (thread_info->gl_library); thread_info->gl_library = NULL; } thread_info->gl_library = malloc (len + 1); if (thread_info->gl_library) { memcpy (thread_info->gl_library, gl_library, len); thread_info->gl_library[len] = '\0'; } } return thread_info; } int glitz_wgl_thread_starter (const glitz_wgl_thread_starter_arg_t *arg) { glitz_wgl_thread_info_t *thread_info; int retval; retval = (*arg->user_thread_function) (arg->user_thread_function_arg); if (tsd_initialized) { thread_info = (glitz_wgl_thread_info_t *) TlsGetValue (info_tsd); _glitz_wgl_thread_info_fini (thread_info); free (thread_info); } return retval; } static void _glitz_wgl_create_root_context (glitz_wgl_screen_info_t *screen_info) { WNDCLASSEX wcl; ATOM klass; static PIXELFORMATDESCRIPTOR pfd = { sizeof (PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; int pixel_format; wcl.cbSize = sizeof (wcl); wcl.style = 0; wcl.lpfnWndProc = DefWindowProc; wcl.cbClsExtra = 0; wcl.cbWndExtra = 0; wcl.hInstance = GetModuleHandle (NULL); wcl.hIcon = NULL; wcl.hCursor = LoadCursor (NULL, IDC_ARROW); wcl.hbrBackground = NULL; wcl.lpszMenuName = NULL; wcl.lpszClassName = "glitz-wgl-root-window-class"; wcl.hIconSm = NULL; klass = RegisterClassEx (&wcl); if (!klass) { exit (1); } screen_info->root_window = CreateWindowEx (0, (LPCTSTR) (DWORD) klass, "glitz-wgl-root-window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, GetDesktopWindow (), NULL, GetModuleHandle (NULL), NULL); screen_info->root_dc = GetDC (screen_info->root_window); pixel_format = ChoosePixelFormat (screen_info->root_dc, &pfd); if (pixel_format != 0) { SetPixelFormat (screen_info->root_dc, pixel_format, &pfd); screen_info->root_context = wglCreateContext (screen_info->root_dc); wglMakeCurrent (screen_info->root_dc, screen_info->root_context); } else { screen_info->root_context = NULL; } } glitz_wgl_screen_info_t * glitz_wgl_screen_info_get (void) { static glitz_wgl_screen_info_t *screen_info = NULL; const char *gl_version; if (screen_info != NULL) return screen_info; screen_info = malloc (sizeof (glitz_wgl_screen_info_t)); screen_info->drawables = 0; screen_info->formats = NULL; screen_info->format_ids = NULL; screen_info->n_formats = 0; screen_info->contexts = NULL; screen_info->n_contexts = 0; memset (&screen_info->wgl, 0, sizeof (glitz_wgl_static_proc_address_list_t)); glitz_program_map_init (&screen_info->program_map); _glitz_wgl_create_root_context (screen_info); gl_version = glGetString (GL_VERSION); screen_info->wgl_version = 1; /* Can't use atof(), as GL_VERSION might always use a decimal period, * but atof() looks for the locale-specific decimal separator. */ if (gl_version != NULL && gl_version[0]) { int whole_part; int n; if (sscanf (gl_version, "%d%n", &whole_part, &n) == 1 && (gl_version[n] == '.' || gl_version[n] == ',')) { double fraction = 0.1; screen_info->wgl_version = whole_part; while (isdigit (gl_version[n+1])) { screen_info->wgl_version += (gl_version[n+1] - '0') * fraction; fraction /= 10; n++; } } } screen_info->wgl_feature_mask = 0; screen_info->thread_info = _glitz_wgl_thread_info_get_inner (); screen_info->thread_info->screen = screen_info; _glitz_wgl_thread_info_get (NULL); glitz_wgl_query_extensions (screen_info, screen_info->wgl_version); _glitz_wgl_proc_address_lookup (screen_info); glitz_wgl_query_formats (screen_info); screen_info->context_stack_size = 1; screen_info->context_stack->drawable = NULL; screen_info->context_stack->surface = NULL; screen_info->context_stack->constraint = GLITZ_NONE; return screen_info; } static void _glitz_wgl_screen_destroy (glitz_wgl_screen_info_t *screen_info) { int i; if (screen_info->root_context) { wglMakeCurrent (NULL, NULL); } for (i = 0; i < screen_info->n_contexts; i++) glitz_wgl_context_destroy (screen_info, screen_info->contexts[i]); if (screen_info->contexts) free (screen_info->contexts); if (screen_info->formats) free (screen_info->formats); if (screen_info->format_ids) free (screen_info->format_ids); if (screen_info->root_context) { wglDeleteContext (screen_info->root_context); } if (screen_info->root_dc) { DeleteDC (screen_info->root_dc); } if (screen_info->root_window) { DestroyWindow (screen_info->root_window); } free (screen_info); } void glitz_wgl_init (const char *gl_library) { _glitz_wgl_thread_info_get (gl_library); } void glitz_wgl_fini (void) { glitz_wgl_thread_info_t *info = _glitz_wgl_thread_info_get (NULL); _glitz_wgl_thread_info_destroy (info); }