[Bug 3902] Unnormal slowness in Heroes 4 (X11DRV_BitBlt?)
http://bugs.winehq.org/show_bug.cgi?id=3902 ------- Additional Comments From giulian2003(a)hotmail.com 2006-06-02 04:27 ------- Hi Marty, I haven't made any patch because even though i obtained good results, i still had some problems (some bitmap areas didn't update right). Anyway, its easy to make the necesary changes, it will take you about half un hour, i will try to guide trough it: First of all, I've wrote an email to Robert Shearman asking for informations about DIBs - X Server sync and this is what he wrote me: Question: Hello, Could anyone give me some more info on X11DRV_CoerceDIBSection function and the logic behind using 'DIB_Status_GdiMod' and 'DIB_Status_AppMod' stats? I am trying to repair a bug (3902) that has to do with application waiting exccessivly on some locks and i am kind of lost ;( Any help would be greatly appreciated! Answer: That code is designed to keep DIBs sync'ed between applications and the X server. When the application does a Win32 GDI call then the state of the DIB gets set to DIB_Status_GdiMod and the memory that backs the DIB is set to no-access so that a page fault occurs if the application tries to read it. A handler detects this and downloads the DIB from the X server and sets the state to DIB_Status_None. In this state the DIB memory is set to read-only, so that a page fault occurs if the application tries to write it. The same handler also detects this and consequentially sets the DIB state to DIB_Status_AppMod and allows full access to the DIB memory. Now, the problem is this: If you look in the function X11DRV_DIB_Coerce() in 'wine- 0.9.x\dlls\x11drv\dib.c', you will notice that in some cases (InSync requested in status GdiMod, etc.) the function X11DRV_DIB_DoUpdateDIBSection() is called which syncronises ALL the bitmap. even though the previous function modified only a small area of the bitmap: static void X11DRV_DIB_DoUpdateDIBSection(X_PHYSBITMAP *physBitmap, BOOL toDIB) { BITMAP bitmap; GetObjectW( physBitmap->hbitmap, sizeof(bitmap), &bitmap ); X11DRV_DIB_DoCopyDIBSection(physBitmap, toDIB, physBitmap->colorMap, physBitmap->nColorMap, physBitmap->pixmap, 0, 0, 0, 0, bitmap.bmWidth, bitmap.bmHeight); } My ideea was this: In some cases is possible to know what area of the bitmap will get modified so a GDI function could memorise the rectangle to be modified! This way, the X11DRV_DIB_DoUpdateDIBSection() function could syncronise only the modified area of the bitmap instead of all the bitmap. In order to implement this, i made the following changes: - added a member to X_PHYSBITMAP structure in 'wine-0.9.3\dlls\x11drv\x11drv.h': //it has the purpose to memorise the current modifing rectangle for a certain bitmap XRectangle modified_rect; - added 2 functions in 'wine-0.9.x\dlls\x11drv\dib.c' designed for reading and setting the modifing rectangle: /*********************************************************************** * X11DRV_SetBoundRect */ void X11DRV_SetBoundRect(X_PHYSBITMAP *physBitmap, INT x, INT y, INT width, INT height) { XRectangle *t; INT xMin,yMin,xMax,yMax; if (!physBitmap) return; t = &(physBitmap->modified_rect); if ( t->width && t->height && /*already a valid rect inside*/ width && height ) /*not trying to invalidate rect*/ { //calculate the union of the two rectangles xMin = ((t->x < x)?t->x:x); yMin = ((t->y < y)?t->y:y); xMax = ((t->x + t->width > x + width)?(t->x + t->width):(x + width)); yMax = ((t->y + t->height > y + height)?(t->y + t->height):(y + height)); t->x = xMin; t->y = yMin; t->width = xMax - xMin; t->height = yMax - yMin; } else { t->x = x; t->y = y; t->width = width; t->height = height; } TRACE("(%p,%d,%d,%d,%d)\n", physBitmap->hbitmap, t->x, t->y, t->width, t->height); } /*********************************************************************** * X11DRV_GetBoundRect */ UINT X11DRV_GetBoundRect(X_PHYSBITMAP *physBitmap, INT *x, INT *y, INT *width, INT *height) { DIBSECTION dib; XRectangle *t; if (!physBitmap || GetObjectW( physBitmap->hbitmap, sizeof(dib), &dib ) != sizeof(dib)) { ERR("called for non-DIBSection!?\n"); return 1; } t = &(physBitmap->modified_rect); /* we should check for oversize values */ if ( (t->width > 0) && (t->height > 0) && (t->x < dib.dsBm.bmWidth) && (t->y < dib.dsBm.bmHeight) ) { *x = t->x; *y = t->y; if (t->x + t->width > dib.dsBm.bmWidth) *width = dib.dsBm.bmWidth - t->x; else *width = t->width; if (t->y + t->height > dib.dsBm.bmHeight) *height = dib.dsBm.bmHeight - t->y; else *height = t->height; } else { *x = 0; *y = 0; *width = dib.dsBm.bmWidth; *height = dib.dsBm.bmHeight; } TRACE("(%p,%d,%d,%d,%d)\n", physBitmap->hbitmap, *x, *y, *width, *height); return 0; } And finally, i modified the X11DRV_DIB_DoUpdateDIBSection() function in 'wine- 0.9.x\dlls\x11drv\dib.c' to take in consideration the modifing rectangle! static void X11DRV_DIB_DoUpdateDIBSection(X_PHYSBITMAP *physBitmap, BOOL toDIB) { INT x,y,width,height; if ( X11DRV_GetBoundRect(physBitmap,&x,&y,&width,&height) ) return; /*invalidate bound rect*/ X11DRV_SetBoundRect(physBitmap,0,0,0,0); X11DRV_DIB_DoCopyDIBSection(physBitmap, toDIB, physBitmap->colorMap, physBitmap->nColorMap, physBitmap->pixmap, x, y, x, y, width, height); } Now, a GDI function (for example BitBlt()) should be called like this: X11DRV_SetBoundRect(physDevDst->bitmap,xDst,yDst,width,height); X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE ); if (physDevDst != physDevSrc) { X11DRV_SetBoundRect(physDevSrc->bitmap,xSrc,ySrc,width,height); X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE ); } result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, width, height, rop ); if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE ); X11DRV_UnlockDIBSection( physDevDst, TRUE ); As i said, i obtained good results, but the bitmaps don't update right! ;( I think one of the problems is i didn't took into consideration the origines in X11DRV_PDEVICE struct when i call X11DRV_SetBoundRect(), moustly because i don't have a clear understanding about how things work! The members of the X11DRV_PDEVICE struct that i belive should be taken into consideration are: POINT org; /* DC origin relative to drawable */ POINT drawable_org; /* Origin of drawable relative to screen */ HRGN region; /* Device region (visible region & clip region) * Not sure if all of them or maybe only 'org'? If you have any more questions, please don't esitate to ask them... Iulian -- Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are on the CC list for the bug, or are watching someone who is.
participants (1)
-
Wine Bugs