On 6/19/25 14:13, zhengxianwei wrote:
Zhiyi Zhang provided an implementation of DComp composition: https://gitlab.winehq.org/zhiyi/wine/-/commit/ef4f90c2ae909f4a732f0ebeae3b7e... 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?