View Issue Details

IDProjectCategoryView StatusLast Update
0015715CommunityOCCT:Visualizationpublic2010-07-15 16:53
ReportersanAssigned Topsn 
PrioritynormalSeveritytrivial 
Status closedResolutionfixed 
OSAll 
Summary0015715: [OCC Forum] Bug in OpenGl_tXfm.c, function: loadTexFont
DescriptionThis bug comes from OCC forum:
http://www.opencascade.org/org/forum/thread_11016/
http://www.opencascade.org/org/forum/thread_11154/

There are two problems related to loadTexFont() function:

1. Win32 GDI resources (a font, a bitmap and a memory device context)
allocated in it are not released, that results in memory leaks. These
resourecs should be released at the end of the function.

2. Due to some reason, in multi-view applications loadTexFont() is called on
each 3D view update or at least on each change of teh active 3D view, instead
of using already created textures. Therefore, memory leaks resulted from
problem 1 above become critical. It is necessary to analyze why existing font
texture caching does not work properly, and correct it or accept texture
caching proposed by Forum (see below).

***

Original message posted by Jan Brüninghaus 2007-02-26 15:21

The MS Windows specific funtion loadTexFont in OpenGL_tXfm.c has a bug. It
only occurs, when there are more than one occ-window for an application open.

Test case:
- 2 occ-windows (in one application) with an importet cad-model
- moving the modell constantly around with AIS_InteractiveContext.SetLocation
and update the display with V3d_View.Redraw

What happens:
- for a short time everything works fine, but then there is suddenly a great
slow-down from one redraw to an other
- the taskmanager of windows displays, that there is _much_ cpu-time for the
kernel is used from this point on
- after a few minutes, the hole application crashs

The reason:
- the function loadTexFont in OpenGl_tXfm.c is called _very_ often
- windows ressources are created, but never freed (font, hDC, hBmp) so windows
runs out of ressources

The main problem is, that loadTexFont is called so often when using multiple
occ-windows. If font, hDC and hBmp is freed at the end of the function, the
hole animation slows down to a constant lower frame rate, since much time is
used by the kernel for creating and freeing the ressources.

Analyzing the function shows, that there are only two different fonts loaded.
So there is now need to call the loadTexFont thousands of times. As a quick
fix i added a statical list, that stores every loaded font, so that when
loadTexFont is called the second time for a font, only the list has to be
used. With this everything works.

Below is the changed function:

/*
* list to handle already loaded fonts
*/
struct font_cache_list {
     struct font_cache_list *next;
     TM_FONT_HANDLE *fontHandle;
     char *font_name;
     GLint tex_id;
};

static GLint loadTexFont(char* fontName, TM_FONT_HANDLE* fontHandle)
{
     static struct font_cache_list *font_list = NULL;
     struct font_cache_list *element = NULL;

     GLint tex_id = -1;
     HFONT font;
     HDC hMemDC, hDC = NULL;
     char str[2] = " ";
     int i, j, l, num, code;
     BITMAPINFO bi;
     HBITMAP hBmp, hOldBmp;
     const int spacing = 2; /* spacing between characters in a string */
     GLubyte fontBits [256 * 256 * 3]; /* font bitmap array: RGB */
     GLubyte ifontBits[256 * 256 * 2]; /* texture array: luminance and alpha */
     int charWidths[MAX_NB_CHARS];

     if (!fontHandle) {
          return tex_id;
     }

     /*
      * check if the font is already in the list
      */
     element = font_list;
     while (element != NULL && strcmp(fontName, element->font_name) != 0) {
          element = element->next;
     }
     if (element != NULL) {
          /*
           * can a fontHandle be deleted?
           * need to check out this...
           */
          fontHandle = element->fontHandle;
          return element->tex_id;
     }

     memset(fontHandle, 0, sizeof(TM_FONT_HANDLE));

     fontHandle->curRC = wglGetCurrentContext();
     fontHandle->texSize = 256;
     fontHandle->scale = 1.f;

     /* draw the font glyphs on the square bitmap */
     font = CreateFont(-16, /* Height Of Font*/
               0, /* Width Of Font*/
               0, /* Angle Of Escapement*/
               0, /* Orientation Angle*/
               FW_BOLD, /* Font Weight*/
               FALSE, /* Italic*/
               FALSE, /* Underline*/
               FALSE, /* Strikeout*/
               ANSI_CHARSET, /* Character Set Identifier*/
               OUT_TT_PRECIS, /* Output Precision*/
               CLIP_DEFAULT_PRECIS, /* Clipping Precision*/
               NONANTIALIASED_QUALITY, /* Output Quality*/
               FF_MODERN|DEFAULT_PITCH, /* Family And Pitch*/
               fontName); /* Font Name*/

     hDC = wglGetCurrentDC();
     hMemDC = CreateCompatibleDC(hDC);
     hBmp = CreateCompatibleBitmap(hDC, fontHandle->texSize, fontHandle-
>texSize);
     hOldBmp = (HBITMAP)SelectObject(hMemDC, hBmp);
     SelectObject(hMemDC, font);
     SetTextColor(hMemDC, RGB(255, 255, 255));
     SetBkColor (hMemDC, RGB(0, 0, 0));
     GetCharWidth32(hDC, 0, MAX_NB_CHARS - 1, charWidths);

     for (i = 0; i < 16; i++) {
          for (j = 0; j < 16; j++) {
               code = i * 16 + j;
               str[0] = (char)code;
               l = strlen(str);
               TextOut(hMemDC, j * CHAR_SIZE, i * CHAR_SIZE, str, l);
               /* calculate advance ratio for each character */
               fontHandle->charRatios[code] = (float) (charWidths[code] +
spacing) / (float) CHAR_SIZE;
          }
     }

     /* retrieve the font bitmap */
     memset(&bi, 0, sizeof(BITMAPINFOHEADER));
     bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
     bi.bmiHeader.biPlanes = 1;
     bi.bmiHeader.biBitCount = 24;
     bi.bmiHeader.biHeight = -fontHandle->texSize;
     bi.bmiHeader.biWidth = fontHandle->texSize;
     bi.bmiHeader.biCompression = BI_RGB;
     SelectObject(hMemDC, hOldBmp);
     num = GetDIBits(hMemDC, hBmp, 0, fontHandle->texSize, fontBits, &bi,
DIB_RGB_COLORS);

     /* prepare an array of alpha and luminance values */
     for (i = 0; i < fontHandle->texSize; i++) {
          for(j = 0; j < fontHandle->texSize; j++) {
               ifontBits[(i * fontHandle->texSize + j) * 2] = fontBits[(i *
fontHandle->texSize + j) * 3];
               ifontBits[(i * fontHandle->texSize + j) * 2 + 1] = fontBits[(i
* fontHandle->texSize + j) * 3];
          }
     }

     /* create the font texture */
     glGenTextures(1, &tex_id);
     glBindTexture(GL_TEXTURE_2D, tex_id);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
               GL_REPEAT);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
               GL_NEAREST);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
               GL_NEAREST);

     glTexImage2D(GL_TEXTURE_2D,
               0,
               GL_INTENSITY,
               fontHandle->texSize,
               fontHandle->texSize,
               0,
               GL_LUMINANCE_ALPHA,
               GL_UNSIGNED_BYTE,
               ifontBits);

     fontHandle->textureId = tex_id;

     /*
      * add the new font to the list
      */
     element = (struct font_cache_list *) malloc(sizeof(struct
font_cache_list));
     element->next = NULL;
     element->font_name = fontName;
     element->fontHandle = fontHandle;
     element->tex_id = tex_id;
     if (font_list == NULL) {
          font_list = element;
     } else {
          struct font_cache_list *last_element = font_list;
          while (last_element->next != NULL) {
               last_element = last_element->next;
          }
          last_element->next = element;
     }

     /*
      * free windows ressources
      */
     DeleteObject(font);
     DeleteObject(hBmp);
     DeleteDC(hMemDC);

     return tex_id;
}

***

Ashish 2007-03-26 16:59
I have MDI application where i need to open multiple views to show different
shapes. When i toggle between different views of my application GDI object
count keeps on incresing. Also, when i close one view GDI count should decrese
by the amount it had increased before opening the view, but it doesn't
decrese. That means GDI objects are not being released properly.

Ashish
 
 
 
 Ashish 2007-03-27 08:27
Same problem persist in OCC 6.2.... When I use OCC5.2 everything works fine.
Since i wanted to use textured shape functionality of 6.1, i switched to 6.1
and found GDI object leaks(can be seen in task manager).

To get this problem one can open any sample(i used topologyprimitives) and
create new frame using main frame menu(Window >> New Window). Then after
creating some shapes(say box in topologyprimitives sample), toggle between two
views. You can find that on every redraw call new GDi objects are created and
old ones are left without being released.

Can anybody suggest me the way to solve this problem? It leads to seroud
refresh problem in my application.

TIA
Ashish
TagsNo tags attached.
Test case number

Activities

There are no notes attached to this issue.

Issue History

Date Modified Username Field Change
2008-10-03 13:04 bugmaster groupset1 => 4096
2008-10-03 13:04 bugmaster Customer => Community
2008-10-03 13:04 bugmaster Assigned To bugmaster => san
2008-10-03 13:04 bugmaster Status new => assigned
2008-10-06 17:55 san Assigned To san => psn
2008-11-07 16:12 psn OtherBugsDependingOnThis => 20205
2008-11-12 12:06 psn Status assigned => resolved
2010-07-15 16:53 bugmaster Status resolved => closed
2010-07-15 16:53 bugmaster Resolution @0@ => fixed
2011-08-02 11:24 bugmaster Category OCCT:VIZ => OCCT:Visualization