[PATCH] winex11.drv: Fix drawing of layered windows with a client window.

Rémi Bernon rbernon at codeweavers.com
Tue Apr 27 04:45:23 CDT 2021


On 4/27/21 11:35 AM, Joshua Ashton wrote:
> 
> 
> On 4/27/21 10:33 AM, Rémi Bernon wrote:
>> On 4/27/21 10:51 AM, Giovanni Mascellani wrote:
>>> Testing on Windows 10, it seems that when a window has both a surface
>>> (because it is layered) and a client window (because a d3d9 or analogous
>>> device was created for it), the surface takes the priority, i.e., gdi
>>> and d3d9 are ignored, and just the layered bitmap is painted.
>>>
>>> Before this change, expose events lead to redrawing the surface only
>>> on the whole window, but not on the client window. This implies that
>>> if a d3d9 device is created for a layered window, it takes the priority
>>> in the client window region, contradicting the behavior observed on
>>> Windows.
>>>
>>> Signed-off-by: Giovanni Mascellani <gmascellani at codeweavers.com>
>>> ---
>>>   dlls/winex11.drv/event.c | 24 ++++++++++++------------
>>>   1 file changed, 12 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
>>> index 99943478729..38c8bd825bb 100644
>>> --- a/dlls/winex11.drv/event.c
>>> +++ b/dlls/winex11.drv/event.c
>>> @@ -938,21 +938,21 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent 
>>> *xev )
>>>       rect.right  = pos.x + event->width;
>>>       rect.bottom = pos.y + event->height;
>>> -    if (event->window != data->client_window)
>>> +    if (event->window == data->client_window)
>>> +        OffsetRect( &rect, data->client_rect.left - 
>>> data->whole_rect.left,
>>> +                    data->client_rect.top - data->whole_rect.top );
>>> +    if (data->surface)
>>>       {
>>> -        if (data->surface)
>>> -        {
>>> -            surface_region = expose_surface( data->surface, &rect );
>>> -            if (!surface_region) flags = 0;
>>> -            else OffsetRgn( surface_region, data->whole_rect.left - 
>>> data->client_rect.left,
>>> -                            data->whole_rect.top - 
>>> data->client_rect.top );
>>> +        surface_region = expose_surface( data->surface, &rect );
>>> +        if (!surface_region) flags = 0;
>>> +        else OffsetRgn( surface_region, data->whole_rect.left - 
>>> data->client_rect.left,
>>> +                        data->whole_rect.top - data->client_rect.top );
>>> -            if (data->vis.visualid != default_visual.visualid)
>>> -                data->surface->funcs->flush( data->surface );
>>> -        }
>>> -        OffsetRect( &rect, data->whole_rect.left - 
>>> data->client_rect.left,
>>> -                    data->whole_rect.top - data->client_rect.top );
>>> +        if (data->vis.visualid != default_visual.visualid)
>>> +            data->surface->funcs->flush( data->surface );
>>>       }
>>> +    OffsetRect( &rect, data->whole_rect.left - data->client_rect.left,
>>> +                data->whole_rect.top - data->client_rect.top );
>>>       if (event->window != root_window)
>>>       {
>>>
>>
>> As far as I can tell from a quick test with OpenGL rendering, there is 
>> two different behavior on Windows:
>>
>> I'm only considering the layered attribute and calls on top-level 
>> windows, as I couldn't make it work on child windows, to the contrary 
>> to what MSDN says is supported on Windows > 8.
>>
>>
>> 1) When UpdateLayeredWindow is called, the displayed image is the one 
>> that has been provided in the call, regardless of any later drawing 
>> call indeed, be it GDI or OpenGL. If the window has child windows, 
>> they aren't displayed either, regardless of the API they use too.
>>
>>
>> 2) When SetLayeredWindowAttributes has been called, the window is 
>> displayed, with the transparency computed according to the attributes. 
>> If the window has child windows, they are displayed normally, but with 
>> the same transparency transformation. Drawing with GDI or OpenGL on 
>> the top-level or the child windows works as for a normal window, 
>> except for the transparency.
>>
>>
>> Here I would expect the surface flush to only work once until a later 
>> GL swap buffer / VK present override it (although I'm not completely 
>> sure when the Expose events are generated).
>>
>> It may also work differently depending on if the client windows are 
>> off-screen or not (depending on whether it's a client window of a 
>> child or if the top-level has child windows).
>>
>> Although this patch possibly fixes some bad cases I think the layered 
>> window implementation is actually incorrect in a more general way.
>>
>>
>> To make things simpler I think we should maybe make the off-screen 
>> GL/VK rendering the default and do the present ourselves on the 
>> top-level windows, and put the GL/VK on-screen /only/ when we're sure 
>> we can (which is hopefully still going to be quite often).
> 
> What would be the performance implications of this?
> 

Hopefully it would have no overhead in the critical cases, assuming we 
can reliably detect non-layered / no-child windows where we can safely 
put the client windows on screen and not do the blit ourselves.

Also I think it could maybe be linked to some full-screen exclusive 
state, where the client windows would be put on-screen and top-most, or 
something like that, solving cases where we incorrectly have top-level 
windows on top of GL/VK rendering.

I also have some local patches that use X Present extension to blit 
(including for cases where we need to clip child windows), but whether 
that helps is unclear.
-- 
Rémi Bernon <rbernon at codeweavers.com>



More information about the wine-devel mailing list