uninformed musings on ddraw + bugs 2082 and 1347 + dib engine

Vincent Povirk madewokherd+d41d at gmail.com
Wed May 28 21:46:24 CDT 2008


I apologize if what I'm about to say is wrong and useless. I feel the
need to say it just in case it is not as wrong and useless as I fear.

Background:

We have two very difficult (possibly unfixable) ddraw bugs:

http://bugs.winehq.org/show_bug.cgi?id=2082 - DirectDraw games only
showing black screen

http://bugs.winehq.org/show_bug.cgi?id=1347 - Screen is wiped/blanked
on usage of DirectDraw

Both of these bugs are the result of the fact that Windows (probably
even Windows Vista when Aero is disabled, which I believe happens
temporarily when an exclusive move ddraw app is active) ddraw can give
apps direct access to the screen and X cannot.

Instead of drawing to the screen, Wine draws to the application's
window, which it determines based on an argument the application
passed to SetCooperativeLevel. In the case of 2082, this window is
obscured and no drawing happens even though it would on windows. There
is a hack for ddraw that uses hwnd 0 instead (so drawing operations do
go to the screen), but it can also break things in situations where an
application uses both ddraw and gdi.

1347 is the result of non-fullscreen applications passing hwnd 0 to
SetCooperativeLevel and (so I'm told) going through this series of
steps:
1. Lock the primary surface, thus mapping the image on the screen to memory.
2. Write to your window.
3. Unlock the primary surface.

On Windows, as long as Aero isn't running, this works out fine. But on
Wine, mapping the image on the screen to memory is impossible.
Instead, Wine simply gives the app an empty buffer, which the app
writes to (but only its own window). It is impossible to determine
afterwards which parts of the that buffer were written. When the
primary surface is unlocked, Wine draws the image in the buffer to the
application's SCL window, which is often (but not always) what the
application happened to be drawing.

Stefan mentions the idea of grabbing a screenshot when the surface is
locked and writing it back when the surface is unlocked (which he says
in one case would cause framerate to drop to less than 1 fps, which I
believe).

He thinks 1347 is unfixable. I think that if so, 2082 is also
unfixable because even in fullscreen mode we can have problems caused
by interactions with ddraw and gdi (using hwnd 0 is not always the
right thing even for a fullscreen app).

Now, here's where we get to the crazy uninformed ideas:

What if, instead of picking one hwnd to draw to, ddraw drew to every
window owned by an application?

I'm making some assumptions here: it has to be possible to find the
space occupied by "every window owned by an application" and draw to
it at a reasonable speed. I'm also assuming that no app we want to
support will want to draw to windows owned by other programs,
especially X programs, even though there's nothing in ddraw that would
prevent it.

Well, we'd still theoretically have some problems. What if a program
locked/unlocked the primary surface multiple times, once for each of
various widgets that it wants to draw? The widgets would flicker. And
what if a program has its own window that it wants to draw to with
gdi? Its gdi parts would be painted black.

Alright then, what if we had a single clientside buffer per app, the
size and depth (as far as the app is concerned) of the screen, that
was not synced with the actual contents of the screen but was
preserved between locks/unlocks? Any operation in ddraw or gdi that
resulted in a draw to the screen would have to first go through this
buffer. The lock/unlock sequence would overdraw all the application's
windows with the last thing the application drew there.

Ignoring opengl (opengl and ddraw working simultaneously in one
process should be extremely rare; maybe some swing apps do it), that
should work pretty much perfectly. Sadly I can't even pretend to know
enough to say how this affects opengl.

It would require clientside buffers, and it would probably be
difficult for current gdi to support. It seems like the sort of thing
that would be more reasonable if we had a dib engine. (!)

Also, giving every process a clientside buffer the size of the screen
would be wasteful of memory (and optimizing for a rare case; most
programs won't even have a primary surface, let along be
locking/unlocking it). It may be more reasonable to have one per
visible window or even one per X window, which would be manipulated as
needed for lock/unlock (not sure about the X window thing because
they'd have to be shared between processes.. but perhaps we need that
capability anyway? it would also effectively mean we CAN give apps
direct access to the screen for virtual desktops and CAN allow ddraw
drawing to other Wine processes' windows).

-- 
Vincent Povirk



More information about the wine-devel mailing list