If DGA is not available, Wine falls back to creating offscreen primary surface and blitting all changes to the screen. It knows which part of the surface might have changed by watching unlock calls.
However, as Jukka Heinonen pointed out in his message posted on 17.10.2001, the update logic in asynchronous mode (when SYNC_UPDATE is not defined, which is the default) is broken: "(...)if more than one lock/unlock pair happens between update thread blits, display might not be updated correctly". Synchronous mode on the other hand, causes applications, which constantly lock and unlock big areas just to change a few pixels, run very slow.
As this bug prevents me from playing "Warlords: Battlecry", I decided to do something about it.
Here are my changes:
- User_add_dirty_rect is now an asynchronous equivalent of User_copy_to_screen. It adds the rectangle to the list of dirty rectangles and signal the update thread that there is some work to do. - update thread calls User_get_dirty_rect to iterate over the list of dirty rectangles - current "naïve" algoritm keeps only one rectangle which is a union of all dirty rectangles, so it tends to redraw too much, but better algoritms may be implemented - removed now unused lastlockrect variable, and the code which updates it
I attached the patch for your reviews, comments, suggestions.
The game is almost playable now, there are remaining issues with DirectMusic (must be run with NODIRECTMUSIC switch or crashes) and windows managers (kwin cannot raise the window, metacity complains that the window attributes do not make sense).
On Wed, 21 Jan 2004 06:36:09 +0100, Piotr Pawlow wrote:
windows managers (kwin cannot raise the window, metacity complains that the window attributes do not make sense).
Metacity is normally a good barometer of whether we got WM stuff correct. What errors do you see exactly? Are we created unmanaged windows here, or are they managed but with screwed up NETWM attributes?
On Wednesday 21 January 2004 12:53, Mike Hearn wrote:
Metacity is normally a good barometer of whether we got WM stuff correct. What errors do you see exactly? Are we created unmanaged windows here, or are they managed but with screwed up NETWM attributes?
Metacity displays two messages:
#v+ Window manager warning: Window 0x3200004 (Warlords B) sets an MWM hint indicating it isn't resizable, but sets min size 1 x 1 and max size 2147483647 x 2147483647; this doesn't make much sense. Window manager warning: Window 0x3400009 () sets an MWM hint indicating it isn't resizable, but sets min size 1 x 1 and max size 2147483647 x 2147483647; this doesn't make much sense. #v-
With metacity the game starts, main screen appears for one second, then disappears and the screen remains black. The game is running, I can hear sounds when I move the mouse, I can push buttons and exit the game, but I don't see anything. I can't switch windows with alt-tab. There is no music.
KWin does not say anything when I start the game. Main screen appears and does not disappear. Music plays. I can start and play the game, switching windows with alt-tab works, but when I switch to another window I can't go back. KWin says:
#v+ kwin: Raising: No support kwin: Raising: Refusing #v-
The game halts and music stops when I switch to another window, then when I switch back music starts playing again, but the window does not show up.
I created 3 logs with --debugmsg +x11drv: http://pp.siedziba.pl/tmp/wb/wb+x11drv-metacity.log - start the game and exit http://pp.siedziba.pl/tmp/wb/wb+x11drv-kwin.log - as above, with kwin http://pp.siedziba.pl/tmp/wb/wb+x11drv-kwin-switching_windows.log - start the game and switch windows 2 times
I don't understand much from these logs, but maybe you or someone else can spot a problem. One thing I noticed, is that with metacity the game does not draw anything, which is indicated by the lack of "fixme:ddraw:Main_DirectDraw_WaitForVerticalBlank" messages. I rerun the test with +bitblt to make sure. I guess the game thinks its window is inactive.
Here are my changes:
- User_add_dirty_rect is now an asynchronous equivalent of
User_copy_to_screen. It adds the rectangle to the list of dirty rectangles and signal the update thread that there is some work to do.
- update thread calls User_get_dirty_rect to iterate over the list of dirty
rectangles
- current "naïve" algoritm keeps only one rectangle which is a union of all
dirty rectangles, so it tends to redraw too much, but better algoritms may be implemented
- removed now unused lastlockrect variable, and the code which updates it
I attached the patch for your reviews, comments, suggestions.
The only comment I have on the patch is that you are using the rectangle from the 'User_DirectDrawSurface_unlock_update' code. The big problem here is that for old DirectX versions (versions 1 to 3), the lock rectangle was not repeated in the Unlock call (it was only present in the Lock code).
So, basically, you will always force a full redraw for these old DirectX versions. So, the best would be to add the dirty rectangles in the Lock calls (if we are not in READONLY mode).
A part from that, the patch looks nice.
Same comments as in my other mails about contributors :-)
Lionel
PS: all these dirty region handling should be factorized as I did the same kind of hacks in the D3D code to speed up transfer between 2D and 3D buffers.
On Monday 26 January 2004 22:44, Lionel Ulmer wrote:
The only comment I have on the patch is that you are using the rectangle from the 'User_DirectDrawSurface_unlock_update' code. The big problem here is that for old DirectX versions (versions 1 to 3), the lock rectangle was not repeated in the Unlock call (it was only present in the Lock code).
Oh, I see.
So, basically, you will always force a full redraw for these old DirectX versions. So, the best would be to add the dirty rectangles in the Lock calls (if we are not in READONLY mode).
Then I would be drawing rectangles which are not ready for a redraw yet. Does UnLock release only last lock or all locks on these old DX versions?
PS: all these dirty region handling should be factorized as I did the same kind of hacks in the D3D code to speed up transfer between 2D and 3D buffers.
OK, I will look in there too.
Then I would be drawing rectangles which are not ready for a redraw yet. Does UnLock release only last lock or all locks on these old DX versions?
Well, you need to store the rectangle at Lock time but only draw it at Unlock time. And I have no idea if any game ever does concurrent locks (so I have no idea how concurrent lock work).
But anyway, with the update thread, there is no guarantee to not flush on screen something that is not 'finished' (if the application locks rect A then unlocks it then relocks the same rectangle A and the update thread flushes on screen before the apps unlocks A, you will put on screen unfinished stuff).
So setting the rectangle dirty on Lock is not going to give us that much more garbage on screen than the usual stuff (and, moreover, this only is a problem on Windowed applications or on non-double buffered games (which COMI is the only example I know)).
Lionel
On Wednesday 04 February 2004 23:31, Lionel Ulmer wrote:
Well, you need to store the rectangle at Lock time but only draw it at Unlock time. And I have no idea if any game ever does concurrent locks (so I have no idea how concurrent lock work).
OK, so that is another thing to find out
So setting the rectangle dirty on Lock is not going to give us that much more garbage on screen than the usual stuff
There is a big difference between setting it Lock and on UnLock. Setting on UnLock is like saying: yeah, I know I may draw unfinished rectangles which you keep locked while I'm drawing, but I will fix them as soon as you finish and unlock them. But setting on Lock is like saying: I will draw this unfinished rectangle and I don't care to fix it later when it is finished.
The first method will in most cases cause no more than some tearing, the second will cause trails and other artifacts.
(and, moreover, this only is a problem on Windowed applications or on non-double buffered games (which COMI is the only example I know)).
Warlords Battlecry does not use double-buffering. It draws to an offscreen surface, then blits pieces of this surface to the front buffer. AFAIK the sequel does the same. Demos are here:
http://www.gamesdomain.co.uk/demos/demo/1130.html http://www.gamesdomain.co.uk/demos/demo/1587.html
ons, 04.02.2004 kl. 23.31 skrev Lionel Ulmer:
Then I would be drawing rectangles which are not ready for a redraw yet. Does UnLock release only last lock or all locks on these old DX versions?
Well, you need to store the rectangle at Lock time but only draw it at Unlock time. And I have no idea if any game ever does concurrent locks (so I have no idea how concurrent lock work).
If you want to see concurrent locks, grab Command & Conquer Tiberian Sun. It doesn't use those old APIs you're talking about, but if you wanted to know...