On May 9, 2014, at 5:34 AM, Alexandre Julliard wrote:
Ken Thomases ken@codeweavers.com writes:
On May 8, 2014, at 3:18 AM, Alexandre Julliard wrote:
It can't be using an old surface unless you introduced the concept of multiple surfaces in the first place...
You don't even acknowledge the need for multiple surfaces _serially_? That wined3d might create a surface on a virgin window and then destroy it, and then later create another one?
It's probably a question of terminology. To my mind, there is one place in the window where you can render stuff, using a specific pixel format.
If multiple users try to set a different format on the window at the same time, there's a need to arbitrate that. Your solution is to create multiple surfaces, but then this moves the problem to arbitrating which surface is the "real" one, i.e. the one that actually puts something on the screen. Because in the end there's only one visible window surface.
Obviously under X11 we need to create a new drawable because the format is set at creation time, but that doesn't necessarily have to be something that wined3d knows about. Conceptually it's still the same window surface.
Actually, I believe it is something that wined3d needs to know about. Commit 4c4552c5a1910a9d5adf8eccff0ac62d89ffe376 introduced a number of regressions. One of them was a performance drop. This drop happens even in the case where nothing else sets a pixel format on the window. The performance problem comes just from wined3d having to check if there _might_ have been contention over the pixel format – if the app might have changed it since the last time wined3d was entered. To avoid that check, each swapchain must know that the OpenGL context it uses is attached to a private drawable that is not shared either with WGL nor with other swapchains. It has to know that once it sets the pixel format on its private drawable, nothing else can change it. (This is the purpose of the hdc_is_private and hdc_has_format flags introduced with commits 27287382 and f3aa4812.)
Also, it is my understanding – and I hope that Henri, Stefan, or Matteo will correct me if I'm wrong – that swapchains are independent sets of backbuffers. An app can have more than one. Each swapchain has a separate pixel format. The app can issue a bunch of drawing commands to each and they should be independent. It can draw a circle in one and a square in the other. It can then "present" either swapchain and only that swapchain's rendering will make it to screen. It will show either a circle or a square but not a circle overlapping a square or the like. It can then, of course, present the other or not or do it in the other order.
The point is, multiple surfaces is a natural fit with D3D's model. The swapchain which was most recently presented is the visible one. Which means that the X11 driver would have to order a drawable front during wglSwapBuffers() (not when the context is made current, which is what I said in a previous email).
I don't know how wined3d currently deals with the case of multiple swapchains targeting the same window. That is, how it keeps the drawing commands and backbuffers of one independent from those of another. Using separate contexts works to some extent, but only until the OpenGL command buffer fills, at which point the drawing from one would be flushed to the backbuffer the contexts share. Wined3d may ignore this or maybe it uses FBOs or something for the backbuffers of secondary swapchains. In either case, multiple surfaces offers an opportunity to improve the status quo.
I also want to say that I already tried to solve the issues entirely within the X11 driver. For example, I tried an approach where the X11 driver puts off realizing a change of the window pixel format until it's absolutely necessary http://bugs.winehq.org/show_bug.cgi?id=35718#c32. It didn't really solve the problem because wined3d needs to restore the thread's current WGL context each time it returns from a call, and that requires that the window pixel format be restored for real.
I think the fundamental nature of the problem is unavoidable so long as wined3d uses WGL/OpenGL, which relies on implicit thread state. When wined3d issues OpenGL commands, that state needs to be wined3d's but when the app issues its commands, it needs to be the app's. There's no getting around "thrashing" the current context because of that, but the pixel format thrashing can be avoided by using separate surfaces. And because this thread state model extends all the way from the driver through WGL to wined3d, there's no avoiding exposing the existence of those surfaces to wined3d.
-Ken