On 6/3/25 17:02, zhengxianwei wrote:
Hello,
I would like to implement part of the logic within |dcomp.dll| in order to properly support applications that depend on it.
I found that Zhiyi Zhang has implemented some data structures and interface stubs:
https://gitlab.winehq.org/zhiyi/wine/-/commits/directcomposition?ref_type=he... https://gitlab.winehq.org/zhiyi/wine/-/commits/directcomposition?ref_type=heads
Among these, the only method with actual logic appears to be |IDCompositionDevice::Commit|.
However, after reviewing the implementation, I suspect there may be an issue with the current approach.
It seems that Zhiyi Zhang starts a separate thread for each |IDCompositionDevice|, and this thread runs at a fixed refresh rate.
But this approach appears to introduce a problem: from the window's (|HWND|) perspective, there are now *two threads* concurrently updating its device context.
This results in a frame sequence similar to the following (note: the frame intervals are illustrative only):
gdi_frame | dcomp_frame | gdi_frame | gdi_frame | dcomp_frame
In this model, GDI-generated frames and DComp-generated frames are interleaved.
Is my understanding correct?
Hi,
This is indeed possible. However, this only happens when the window is using both GDI and d2d/dcomp to render the window. Normally, it's either GDI or d2d and then composited by dcomp so usually this doesn't happen.
If so, I believe this method may lead to *inaccurate rendering results*, although I am not entirely certain about the exact consequences (as I am not an expert in this area).
Therefore, I have decided to pursue an approach that produces a *standardized frame stream* like the following:
gdi_mix_dcomp_frame | gdi_mix_dcomp_frame | gdi_mix_dcomp_frame
In other words, I plan to merge GDI and DComp content before presenting each frame, ensuring consistency in the final output.
I’ve reviewed the normal GDI frame refresh process, and it seems to follow this path:
--> flush_window_surfaces --> window_surface_flush --> x11drv_surface_flush
I’m planning to insert the following logic inside |x11drv_surface_flush|:
if (is_hwnd_bind_to_dcomp(hwnd)) { struct Surface *final = get_comp_surface(hwnd);
blend_dcomp_surface_over_gdi(dest_surface, final);
}
However, there’s still a question regarding *how to access the DComp data* inside |x11drv_surface_flush|.
One option is to do the composition inside |IDCompositionDevice::Commit()| like this:
void IDCompositionDevice_Commit() { composite_proc(); ... ... push_frame_to_x11drv();
}
Another option is to *directly call into DComp APIs from within |x11drv|* to retrieve the surface data on demand.
However, *both approaches feel somewhat unnatural*, and from what I can tell, Windows seems to establish some kind of *internal channel* to pass the composed content to the compositor.
Is there a better or more canonical way to do this?
My dcomp branch is from two years ago and very experimental. The original goal was to just get rendering with dcomp API working. On Windows, dcomp probably has access to all window content and presents composited window content during vblank. Due to Wine doesn't have a compositor at the moment and doesn't support vblank. I used a way that sort of works but by no means correct. For your problem, I guess just do whatever works for you because the current dcomp architecture is not the same as Windows.
Thanks, Zhiyi
Any suggestions or guidance would be greatly appreciated.