From fad230827c3293da9fb99540e88d50b990abc8c9 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Mon, 10 May 2004 15:49:16 +0000 Subject: Suppressed all OutputDebugString traces. Fixed the GL redrawing problem occuring under Windows after a window move and under Linux when the window was clipped by the screen border. The graphic context is freed when no longer needed, (no more zinc windows on a given display). This code is suspended on Linux because of a problem (perhaps in nvidia driver) causing a random) crash of the server. Fixed under Windows the problem of activating a GL context for freeing resources after the destruction of a widget. Now a list of active widgets is kept and the code activate a remaining widget in the same context. Fixed default GL font loading. --- generic/tkZinc.c | 249 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 157 insertions(+), 92 deletions(-) (limited to 'generic/tkZinc.c') diff --git a/generic/tkZinc.c b/generic/tkZinc.c index 706c399..ef92355 100644 --- a/generic/tkZinc.c +++ b/generic/tkZinc.c @@ -148,10 +148,6 @@ static int ZnGLAttribs[] = { #endif #endif -#ifdef _WIN32 - char msg[256]; -#endif - /* * Temporary object lists */ @@ -914,54 +910,63 @@ ZnGetGLContext(Display *dpy) } ZnGLContextEntry * -ZnGLMakeCurrent(Display *dpy, - Tk_Window win) +ZnGLMakeCurrent(Display *dpy, + ZnWInfo *wi) { ZnGLContextEntry *ce; ce = ZnGetGLContext(dpy); #ifdef _WIN32 - if (win) { - ce->hwnd = Tk_GetHWND(Tk_WindowId(win)); + if (!wi) { + /* Get a zinc widget from the context struct + * for this display. If no more are left, + * returns, nothing can be done. This can + * happend only when freeing images or fonts + * after the last zinc on a given display has + * been deleted. In this case the context has + * been already deleted, freeing all resources + * including textures. + */ + return NULL; } + ce->hwnd = Tk_GetHWND(Tk_WindowId(wi->win)); ce->hdc = GetDC(ce->hwnd); SetPixelFormat(ce->hdc, ce->ipixel, &ce->pfd); - /*sprintf(msg, "hdc used: %d\n", ce->hdc); - OutputDebugString(msg); - if (wglMakeCurrent(ce->hdc, ce->context)) { - OutputDebugString("make current ok\n"); + if (!wglMakeCurrent(ce->hdc, ce->context)) { + fprintf(stderr, "Can't make the GL context current: %d\n", GetLastError()); } - else { - sprintf(msg, "erreur %d\n", GetLastError()); - OutputDebugString(msg); - }*/ - wglMakeCurrent(ce->hdc, ce->context); #else - glXMakeCurrent(dpy, win?Tk_WindowId(win):DefaultRootWindow(dpy), + glXMakeCurrent(dpy, wi?Tk_WindowId(wi->win):DefaultRootWindow(dpy), ce->context); #endif return ce; } -#ifdef _WIN32 void ZnGLReleaseContext(ZnGLContextEntry *ce) { - wglMakeCurrent(NULL, NULL); - ReleaseDC(ce->hwnd, ce->hdc); -} + if (ce) { +#ifdef _WIN32 + wglMakeCurrent(NULL, NULL); + ReleaseDC(ce->hwnd, ce->hdc); +#else + /*glXMakeCurrent(ce->dpy, None, NULL);*/ #endif + } +} static void ZnGLSwapBuffers(ZnGLContextEntry *ce, - Tk_Window win) + ZnWInfo *wi) { + if (ce) { #ifdef _WIN32 - SwapBuffers(ce->hdc); + SwapBuffers(ce->hdc); #else - glXSwapBuffers(ce->dpy, Tk_WindowId(win)); -#endif + glXSwapBuffers(ce->dpy, Tk_WindowId(wi->win)); +#endif + } } #endif @@ -980,19 +985,21 @@ InitRendering(ZnWInfo *wi) /* * Look for a matching context already available. */ - Tk_MakeWindowExist(wi->win); ce = ZnGetGLContext(wi->dpy); if (ce) { gl_context = ce->context; ce->hwnd = Tk_GetHWND(Tk_WindowId(wi->win)); ce->hdc = GetDC(ce->hwnd); + ZnListAdd(ce->widgets, &wi, ZnListTail); SetPixelFormat(ce->hdc, ce->ipixel, &ce->pfd); } else { ce = ZnMalloc(sizeof(ZnGLContextEntry)); ce->hwnd = Tk_GetHWND(Tk_WindowId(wi->win)); ce->hdc = GetDC(ce->hwnd); - + ce->widgets = ZnListNew(1, sizeof(ZnWInfo *)); + ZnListAdd(ce->widgets, &wi, ZnListTail); + memset(&ce->pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); ce->pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); ce->pfd.nVersion = 1; @@ -1005,16 +1012,14 @@ InitRendering(ZnWInfo *wi) ce->pfd.cStencilBits = 8; ce->pfd.iLayerType = PFD_MAIN_PLANE; ce->ipixel = ChoosePixelFormat(ce->hdc, &ce->pfd); - /*sprintf(msg, "ipixel=%d dwFlags=0x%x req=0x%x iPixelType=%d hdc=%d\n", + /*printf("ipixel=%d dwFlags=0x%x req=0x%x iPixelType=%d hdc=%d\n", ce->ipixel, ce->pfd.dwFlags, PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER, ce->pfd.iPixelType==PFD_TYPE_RGBA, - ce->hdc); - OutputDebugString(msg);*/ + ce->hdc);*/ if (!ce->ipixel) { fprintf(stderr, "ChoosePixelFormat failed\n"); - OutputDebugString("ChoosePixelFormat failed\n"); } if (SetPixelFormat(ce->hdc, ce->ipixel, &ce->pfd) == TRUE) { @@ -1030,7 +1035,6 @@ InitRendering(ZnWInfo *wi) } else { fprintf(stderr, "wglCreateContext failed\n"); - OutputDebugString("wglCreateContext failed\n"); ZnFree(ce); } } @@ -1059,6 +1063,7 @@ InitRendering(ZnWInfo *wi) gl_context = ce->context; gl_visual = ce->visual; colormap = ce->colormap; + ZnListAdd(ce->widgets, &wi, ZnListTail); } else { int val; @@ -1088,6 +1093,8 @@ InitRendering(ZnWInfo *wi) ce->max_point_width = 1; ce->next = gl_contexts; gl_contexts = ce; + ce->widgets = ZnListNew(1, sizeof(ZnWInfo *)); + ZnListAdd(ce->widgets, &wi, ZnListTail); if (ISSET(wi->flags, ZN_PRINT_CONFIG)) { fprintf(stderr, " Visual : 0x%x, ", @@ -1119,7 +1126,7 @@ InitRendering(ZnWInfo *wi) } # endif /* _WIN32 */ - ce = ZnGLMakeCurrent(wi->dpy, wi->win); + ce = ZnGLMakeCurrent(wi->dpy, wi); glGetFloatv(ZN_GL_LINE_WIDTH_RANGE, r); ce->max_line_width = r[1]; glGetFloatv(ZN_GL_POINT_SIZE_RANGE, r); @@ -1144,13 +1151,6 @@ InitRendering(ZnWInfo *wi) ce->max_tex_size); } - if (!wi->font_tfi) { - wi->font_tfi = ZnGetTexFont(wi, wi->font); - } - if (!wi->map_font_tfi) { - wi->map_font_tfi = ZnGetTexFont(wi, wi->map_text_font); - } - ZnGLReleaseContext(ce); } #endif /* GL */ @@ -6493,14 +6493,14 @@ Configure(Tcl_Interp *interp,/* Used for error reporting. */ if (CONFIG_PROBE(FONT_SPEC) || !wi->font_tfi) { if (wi->font_tfi) { ZnFreeTexFont(wi->font_tfi); - wi->font_tfi = NULL; } + wi->font_tfi = ZnGetTexFont(wi, wi->font); } if (CONFIG_PROBE(MAP_TEXT_FONT_SPEC) || !wi->map_font_tfi) { if (wi->map_font_tfi) { ZnFreeTexFont(wi->map_font_tfi); - wi->map_font_tfi = NULL; } + wi->map_font_tfi = ZnGetTexFont(wi, wi->map_text_font); } #endif @@ -6776,14 +6776,14 @@ Configure(Tcl_Interp *interp,/* Used for error reporting. */ if ((mask & CONFIG_FONT) || !wi->font_tfi) { if (wi->font_tfi) { ZnFreeTexFont(wi->font_tfi); - wi->font_tfi = NULL; } + wi->font_tfi = ZnGetTexFont(wi, wi->font); } if ((mask & CONFIG_MAP_FONT) || !wi->map_font_tfi) { if (wi->map_font_tfi) { ZnFreeTexFont(wi->map_font_tfi); - wi->map_font_tfi = NULL; } + wi->map_font_tfi = ZnGetTexFont(wi, wi->map_text_font); } #endif @@ -7036,6 +7036,17 @@ Focus(ZnWInfo *wi, *---------------------------------------------------------------------- */ static void +TopEvent(ClientData client_data, /* Information about widget. */ + XEvent *event) +{ + ZnWInfo *wi = (ZnWInfo *) client_data; + if (event->type == ConfigureNotify) { + /*printf("Window moved\n");*/ + SET(wi->flags, ZN_CONFIGURE_EVENT); + } +} + +static void Event(ClientData client_data, /* Information about widget. */ XEvent *event) /* Information about event. */ { @@ -7047,13 +7058,13 @@ Event(ClientData client_data, /* Information about widget. */ event->type == MapNotify ? "MAP": event->type == Expose? "EXPOSE" : event->type == ConfigureNotify ? "CONFIGURE" : + event->type == VisibilityNotify ? "VISIBILITY" : event->type == DestroyNotify ? "DESTROY" : "??", event->type);*/ if (event->type == MapNotify) { SET(wi->flags, ZN_CONFIGURE_EVENT); if (!wi->gc) { SET(wi->flags, ZN_REALIZED); - /*OutputDebugString("MAP\n");*/ InitRendering(wi); /* @@ -7078,12 +7089,19 @@ Event(ClientData client_data, /* Information about widget. */ } success = XQueryTree(wi->dpy, Tk_WindowId(top_level), &root, &parent, &children, &num_children); - if (root == parent) { + if (!success || (root == parent)) { wi->real_top = Tk_WindowId(top_level); } else { wi->real_top = parent; } + /* + * Needed under glx to suspend update with scissors after + * a move to synchronise the two buffers. Fix a refresh + * bug when the window is partially clipped by the display + * border. Can be usefull under Windows too. + */ + Tk_CreateEventHandler(top_level, StructureNotifyMask, TopEvent, (ClientData) wi); if (children && success) { XFree(children); } @@ -7120,10 +7138,6 @@ Event(ClientData client_data, /* Information about widget. */ * if we are done adding exposed parts. */ ZnAddBBoxToBBox(&wi->exposed_area, &bbox); - /*sprintf(msg, "EXPOSE %g %g %g %g\n", - wi->exposed_area.orig.x, wi->exposed_area.orig.y, - wi->exposed_area.corner.x, wi->exposed_area.corner.y); - OutputDebugString(msg);*/ if (/*(((XExposeEvent*) event)->count == 0) &&*/ !ZnIsEmptyBBox(&wi->exposed_area)) { ZnNeedRedisplay(wi); @@ -7224,6 +7238,7 @@ Event(ClientData client_data, /* Information about widget. */ event->type == MapNotify ? "MAP": event->type == Expose? "EXPOSE" : event->type == ConfigureNotify ? "CONFIGURE" : + event->type == VisibilityNotify ? "VISIBILITY" : event->type == DestroyNotify ? "DESTROY" : "??");*/ } @@ -7710,19 +7725,6 @@ Bind(ClientData client_data, /* Information about widget. */ } else if ((event->type == EnterNotify) || (event->type == LeaveNotify)) { -#if defined(_WIN32) && defined(GL) - /* Only needed on Windows to help get the display right - * after a window move. It also helps with the first redraw - * after window creation. - */ - ZnBBox bbox; - - bbox.orig.x = bbox.orig.y = 0; - bbox.corner.x = Tk_Width(wi->win); - bbox.corner.y = Tk_Height(wi->win); - ZnDamage(wi, &bbox); -#endif - wi->state = event->xcrossing.state; PickCurrentItem(wi, event); goto done; @@ -7937,12 +7939,15 @@ static void Destroy(char *mem_ptr) /* Info about the widget. */ { ZnWInfo *wi = (ZnWInfo *) mem_ptr; - unsigned int num; + unsigned int num, i; Tcl_HashSearch search; Tcl_HashEntry *entry; +#ifdef GL + ZnGLContextEntry *ce; + ZnWInfo **wip; +#endif /*printf("Destroy begining\n");*/ - /*OutputDebugString("Destroy begining\n");*/ /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case win @@ -7975,24 +7980,6 @@ Destroy(char *mem_ptr) /* Info about the widget. */ Tcl_CancelIdleCall(Redisplay, (ClientData) wi); } -#ifdef GL - if (wi->font_tfi) { - ZnFreeTexFont(wi->font_tfi); - wi->font_tfi = NULL; - } - if (wi->map_font_tfi) { - ZnFreeTexFont(wi->map_font_tfi); - wi->map_font_tfi = NULL; - } -#endif - /* - if (wi->font) { - Tk_FreeFont(wi->font); - } - if (wi->map_text_font) { - Tk_FreeFont(wi->map_text_font); - }*/ - for (num = 0; num < ZN_NUM_ALPHA_STEPS; num++) { if (wi->alpha_stipples[num] != None) { Tk_FreeBitmap(wi->dpy, wi->alpha_stipples[num]); @@ -8071,6 +8058,72 @@ Destroy(char *mem_ptr) /* Info about the widget. */ Tk_FreeConfigOptions((char *) wi, wi->opt_table, wi->win); #endif +#ifdef GL + if (wi->font_tfi) { + ZnFreeTexFont(wi->font_tfi); + wi->font_tfi = NULL; + } + if (wi->map_font_tfi) { + ZnFreeTexFont(wi->map_font_tfi); + wi->map_font_tfi = NULL; + } + /* + * Remove the widget from the context list and + * free the context if no more widgets are active. + */ + ce = ZnGetGLContext(wi->dpy); + if (ce) { + wip = ZnListArray(ce->widgets); + num = ZnListSize(ce->widgets); + for (i = 0; i < num; i++, wip++) { + if (*wip == wi) { + ZnListDelete(ce->widgets, i); + } + } + /* + * This code cause spurious X11 server reboots + * with nvidia drivers (not tested with others + * though). Thus it has been limited to WIN for + * the time being. + */ +#ifdef _WIN32 + if (ZnListSize(ce->widgets) == 0) { + ZnGLContextEntry *prev, *next; + /*printf("Freeing a GL context\n");*/ + if (ce == gl_contexts) { + gl_contexts = ce->next; + } + else { + for (prev = gl_contexts, next = gl_contexts->next; next; + prev = next, next = next->next) { + if (next == ce) { + prev->next = next->next; + break; + } + } + } +#ifdef _WIN32 + ZnGLReleaseContext(ce); + wglDeleteContext(ce->context); +#else + glXDestroyContext(ce->dpy, ce->context); + XFreeColormap(ce->dpy, ce->colormap); + XFree(ce->visual); +#endif + ZnListFree(ce->widgets); + ZnFree(ce); + } +#endif + } +#endif + /* + if (wi->font) { + Tk_FreeFont(wi->font); + } + if (wi->map_text_font) { + Tk_FreeFont(wi->map_text_font); + }*/ + /* * Should be empty by now. */ @@ -8084,7 +8137,6 @@ Destroy(char *mem_ptr) /* Info about the widget. */ ZnFree(wi); /*printf("Destroy ending\n");*/ - /*OutputDebugString("Destroy ending\n");*/ } @@ -8193,12 +8245,10 @@ Update(ZnWInfo *wi) ZnGroupSetCallOm(wi->om_group, False); } #endif - /*OutputDebugString("Update Begin\n");*/ if (ISSET(wi->top_group->inv_flags, ZN_COORDS_FLAG) || ISSET(wi->top_group->inv_flags, ZN_TRANSFO_FLAG)) { wi->top_group->class->ComputeCoordinates(wi->top_group, False); } - /*OutputDebugString("Update End\n");*/ } @@ -8222,9 +8272,15 @@ Repair(ZnWInfo *wi) int int_height = Tk_Height(wi->win); ZnGLContextEntry *ce; + /*SET(wi->flags, ZN_CONFIGURE_EVENT);*/ if (wi->render) { - ZnGLWaitX(); #ifdef GL + /* Load deferred font glyphs just before making the context + * current. Mandatory under Windows (probably due to hdc use conflict). + */ + ZnGetDeferredGLGlyphs(); + + ZnGLWaitX(); #ifdef GL_DAMAGE if (ISCLEAR(wi->flags, ZN_CONFIGURE_EVENT)) { ClampDamageArea(wi); @@ -8238,9 +8294,8 @@ Repair(ZnWInfo *wi) } #endif - /*sprintf(msg, "Repair, scissors: %d\n", ISCLEAR(wi->flags, ZN_CONFIGURE_EVENT)); - OutputDebugString(msg);*/ - ce = ZnGLMakeCurrent(wi->dpy, wi->win); + /*printf("Repair, scissors: %d\n", ISCLEAR(wi->flags, ZN_CONFIGURE_EVENT));*/ + ce = ZnGLMakeCurrent(wi->dpy, wi); glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); #if 0 @@ -8286,6 +8341,7 @@ Repair(ZnWInfo *wi) (int) (wi->damaged_area.corner.y - wi->damaged_area.orig.y)); } else { + glDisable(GL_SCISSOR_TEST); wi->damaged_area.orig.x = wi->damaged_area.orig.y = wi->inset; wi->damaged_area.corner.x = int_width-wi->inset; wi->damaged_area.corner.y = int_height-wi->inset; @@ -8379,7 +8435,16 @@ Repair(ZnWInfo *wi) } /* Switch the GL buffers. */ - ZnGLSwapBuffers(ce, wi->win); + /* The scissor test might be needed under windows, should be tested. + * Symptom: when moving the window, the buffer switch results in a + * shifted display all around the damaged area. + */ +#ifdef GL_DAMAGE + if (ISCLEAR(wi->flags, ZN_CONFIGURE_EVENT)) { + glEnable(GL_SCISSOR_TEST); + } +#endif + ZnGLSwapBuffers(ce, wi); /* * Wait the end of GL update if we need to synchronize -- cgit v1.1