Or pass a user-level callback into win32u, and have it invoked inside win32u:composite? This might require adding a new syscall — not sure if that would make things simpler?

On Thu, Jun 19, 2025 at 3:48 PM Zhiyi Zhang <zzhang@codeweavers.com> wrote:


On 6/19/25 14:13, zhengxianwei wrote:
> Zhiyi Zhang provided an implementation of DComp composition:
> https://gitlab.winehq.org/zhiyi/wine/-/commit/ef4f90c2ae909f4a732f0ebeae3b7e98479cd63d <https://gitlab.winehq.org/zhiyi/wine/-/commit/ef4f90c2ae909f4a732f0ebeae3b7e98479cd63d>
>
> I created a simple sample that renders three equally sized red circles with varying alpha values on a plain white background window.
>
> On Windows, it displays as follows.
>
> dcomp_test_window.png
>
> But on Linux, it display as follows.
> dcomp_test_wine.png
>
> One of the main issues here is that the background turns black. This is because the foreground (swapchain) is not alpha-blended with the background (GDI); instead, it is simply overlaid using BitBlt.
>
> ```
> *    BitBlt(dst_dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, src_dc, 0, 0, SRCCOPY);
> *
> ```
>
> So I added an alpha_blend step here instead of simply using the original BitBlt.
>
> ```
>     s1 = src_data;
>     d1 = dst_data;
>     for (int i = 0; i < height; i++)
>     {
>         for (int j = 0; j < width; j++)
>         {
>             // src is alpha pre multiple
>             float bg_alpha = ((255.f - s1[3])) / 255;
>             d1[0] = (d1[0] * bg_alpha) + s1[0];
>             d1[1] = (d1[1] * bg_alpha) + s1[1];
>             d1[2] = (d1[2] * bg_alpha) + s1[2];
>
>             s1 += 4;
>             d1 += 4;
>         }
>     }
>
>     //iret = SetDIBits(dst_hdc, dst_bitmap, 0, height, dst_data, &bmi, DIB_RGB_COLORS);
>     iret = SetDIBitsToDevice(dst_hdc, 0, 0, width, height,
>         0, 0, 0, height, dst_data, &bmi, DIB_RGB_COLORS);
> ```
> The new display effect is as follows.
> dcomp_test_wine_alpha_blend.png
> It looks like basic blending is working, but the alpha values of the circles are lost. After analyzing the issue, I found the following cause.
>
>
> I'll draw a diagram to briefly illustrate the cause of this issue.
>
> My original expectation of the image generation process
>
> flush1.png
>
> But the actual process is as follows
>
> image.png
>
> After the bitmap is alpha-blended and displayed on the screen, it is retrieved again in the next frame and repeatedly involved in alpha blending — resulting in redundant computations.
>
>
>
> I personally think that a more reasonable solution would be to insert |window_surface_composition| within |window_surface_flush| to more thoroughly resolve these kinds of issues
>
> image.png
>
>
> During |window_surface_flush|, composite the current surface with the swapchain's surface into an offscreen surface, then flush that to the screen. This way, the original window surface won't be affected.


Sounds reasonable.


>
> I'm trying to fix this issue now — do you have any suggestions?
>

>