[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