Hi, I'm just getting started with Wine and am working on getting a few .NET Core WPF apps running on Linux with Wine. Surprisingly enough I was able to get a basic application working without too much difficulty. Here is an animated gif of a test app if you are interested: https://ccifra.github.io/WPFOnLinux/WPFOnLinux.html. It is running on a very slow VM so don't pay much attention to the performance.
To get this far I just needed to fix up some stubbed out methods in api-ms-win-crt-private-l1-1-0. I want to submit a patch with my changes and I was not sure what your testing requirements are when stubs are updated to point to existing methods? Are there examples of tests that I should follow?
I have run into one bug so far when the applications bring up multiple windows. Basically the contents of additional windows will render back into the first window. Input events like cursor interactions work correctly in the second window (if you know where to click). It does not seem to always happen, combo box dropdowns work for example, but it usually does. I have not been able to narrow the issue any further so I thought I would check to see if this is a known issue or if anyone had any pointers on where I can start looking. I don't know much about the graphics stack. I can also share a sample app which shows off the issue if anyone is interested in taking a look.
Please let me know if I should post this kinds of questions somewhere else.
Thanks for your help, --Chris
I figured out the issues with multiple windows and WPF. WPF passes in an override window to SwapChain Present when it wants to draw into a specific window. In Wine when swapchain_gl_present calls context_acquire the context returned is for the wrong window because it does not look at the override window of the swap chain. I can fix the issue but it requires modifying context_acquire to take the swap chain as a parameter. In the failure case there is no texture passed to context_acquire because the swap chain does not have a back buffer so I do not have a way to get the correct swap chain. Because there is no texture wined3d_context_gl_acquire uses the first swap chain of the device which is not the correct swap chain and has a different window.
I wanted to check and make sure that changing context_acquire to take a swap chain is a reasonable fix?
The signature would change from:
static inline struct wined3d_context *context_acquire(struct wined3d_device *device, struct wined3d_texture *texture, unsigned int sub_resource_idx)
to:
static inline struct wined3d_context *context_acquire(struct wined3d_device *device, struct wined3d_swapchain *swapchain, struct wined3d_texture *texture, unsigned int sub_resource_idx)
I would also need to change adapter_acquire_context on wined3d_adapter_ops to also take the swap chain. This will enable wined3d_context_gl_acquire to get the correct context by looking at the correct swapchain.
--Chris
-----Original Message----- From: wine-devel wine-devel-bounces@winehq.org On Behalf Of Christopher Cifra Sent: Friday, August 9, 2019 12:16 PM To: wine-devel@winehq.org Subject: [EXTERNAL] Wine for NET Core WPF Apps
Hi, I'm just getting started with Wine and am working on getting a few .NET Core WPF apps running on Linux with Wine. Surprisingly enough I was able to get a basic application working without too much difficulty. Here is an animated gif of a test app if you are interested: https://urldefense.com/v3/__https://ccifra.github.io/WPFOnLinux/WPFOnLinux.h... . It is running on a very slow VM so don't pay much attention to the performance.
To get this far I just needed to fix up some stubbed out methods in api-ms-win-crt-private-l1-1-0. I want to submit a patch with my changes and I was not sure what your testing requirements are when stubs are updated to point to existing methods? Are there examples of tests that I should follow?
I have run into one bug so far when the applications bring up multiple windows. Basically the contents of additional windows will render back into the first window. Input events like cursor interactions work correctly in the second window (if you know where to click). It does not seem to always happen, combo box dropdowns work for example, but it usually does. I have not been able to narrow the issue any further so I thought I would check to see if this is a known issue or if anyone had any pointers on where I can start looking. I don't know much about the graphics stack. I can also share a sample app which shows off the issue if anyone is interested in taking a look.
Please let me know if I should post this kinds of questions somewhere else.
Thanks for your help, --Chris
On Thu, 15 Aug 2019 at 06:25, Christopher Cifra christopher.cifra@ni.com wrote:
I figured out the issues with multiple windows and WPF. WPF passes in an override window to SwapChain Present when it wants to draw into a specific window. In Wine when swapchain_gl_present calls context_acquire the context returned is for the wrong window because it does not look at the override window of the swap chain. I can fix the issue but it requires modifying context_acquire to take the swap chain as a parameter. In the failure case there is no texture passed to context_acquire because the swap chain does not have a back buffer so I do not have a way to get the correct swap chain. Because there is no texture wined3d_context_gl_acquire uses the first swap chain of the device which is not the correct swap chain and has a different window.
That doesn't sound quite right. The override window is handled by the wined3d_swapchain_set_window() call in wined3d_cs_exec_present(), and then applied to the context by the wined3d_context_gl_update_window() call in wined3d_context_gl_activate().
The context_acquire() call in swapchain_gl_present() passes in the frontbuffer, but if the swapchain didn't have any backbuffers you wouldn't get there in the first place; wined3d_swapchain_present() would return an error.
Henri
That makes sense and matches what I am seeing. The swapchain does have the correct window set on it by way of wined3d_swapchain_set_window. But in wined3d_context_gl_acquire we get into the rendering offscreen case:
if (current_context && current_context->current_rt.texture == texture) { ... } else if (texture && !wined3d_resource_is_offscreen(&texture->resource)) { ... } else { TRACE("Rendering offscreen.\n");
/* Stay with the current context if possible. Otherwise use the * context for the primary swapchain. */ if (current_context && current_context->device == device) context = current_context; else if (!(context = swapchain_get_context(device->swapchains[0]))) return NULL; }
Which then uses device->swapchains[0] to get the context. device->swapchains[0] is not the correct swapchain and it does not have the same window. Then wined3d_context_gl_activate is called with a context for the wrong window.
My first hack fix was to change what device->swapchains[0] was pointing to and that worked just fine. It does not seem like that is a good idea though. Passing in the swapchain allows the rendering offscreen case to use the specified swapchain instead of the first swapchain of the device.
I also tried always getting the swapchain from the texture but that caused other issues that I don't fully understand yet.
I can create a patch with my change if you think it may be easier for you to recommend a better alternative. Here is a portion of the trace log of when things go wrong: 0034:trace:d3d:wined3d_device_end_scene device 0x1a4a3200. 0034:trace:d3d:wined3d_swapchain_present swapchain 0x1a3c5290, src_rect (864,562)-(996,623), dst_rect (864,562)-(996,623), dst_window_override 0x20056, swap_interval 0, flags 0. 0036:warn:d3d:wined3d_context_gl_bind_shader_resources No resource view bound at index 0, 0. 0034:trace:d3d:wined3d_device_begin_scene device 0x1a4a3200. 0036:trace:d3d:wined3d_context_gl_check_fbo_status FBO complete. 0034:trace:d3d:wined3d_query_create device 0x1a4a3200, type 0x8, parent 0x1a633f90, parent_ops 0x7f4518c8a750, query 0x1a633fa0. 0034:trace:d3d:wined3d_event_query_create device 0x1a4a3200, type 0x8, parent 0x1a633f90, parent_ops 0x7f4518c8a750, query 0x1a633fa0. 0034:trace:d3d:wined3d_event_query_create Created query 0x1a632360. 0034:trace:d3d:wined3d_query_get_data_size query 0x1a632360. 0034:trace:d3d:wined3d_query_issue query 0x1a632360, flags 0x1. 0034:trace:d3d:wined3d_device_end_scene device 0x1a4a3200.
0034:trace:d3d:wined3d_swapchain_present swapchain 0x1a639fb0, src_rect (0,0)-(1190,637), dst_rect (0,0)-(1190,637), dst_window_override 0x1005e, swap_interval 0, flags 0. ^ here we are presenting the swap chain that should render into the second window
0036:trace:d3d:wined3d_context_gl_release Releasing context 0x1a419180, level 1. 0036:trace:d3d:wined3d_cs_run WINED3D_CS_OP_DRAW executed. 0036:trace:d3d:wined3d_cs_run Executing WINED3D_CS_OP_PRESENT. 0036:trace:d3d:wined3d_context_gl_acquire device 0x1a4a3200, texture 0x1a56b530, sub_resource_idx 0. 0036:trace:d3d:wined3d_context_gl_acquire Rendering offscreen. 0036:trace:d3d:wined3d_context_gl_enter Entering context 0x1a419180, level 1.
0036:trace:d3d:swapchain_gl_present Presenting DC 0x27003f. ^ This is the same DC as when we render into the first window
0036:trace:d3d:wined3d_texture_load_location texture 0x1a56b530, sub_resource_idx 0, context 0x1a419180, location WINED3D_LOCATION_TEXTURE_RGB. 0036:trace:d3d:wined3d_texture_load_location Current resource location WINED3D_LOCATION_TEXTURE_RGB. 0036:trace:d3d:wined3d_texture_load_location Location WINED3D_LOCATION_TEXTURE_RGB is already up to date. 0036:trace:d3d:swapchain_blit swapchain 0x1a3c5290, context 0x1a419180, src_rect (864,562)-(996,623), dst_rect (864,562)-(996,623).
dst_window_override 0x1005e is the second window. When we present with that override we will enter the Renering offscreen case and use device->swapchaings[0]. You can then see that we are presenting to DC 0x27003f which is the same one as when we present to the first window.
Thanks for all of your help! --Chris
-----Original Message----- From: Henri Verbeet hverbeet@gmail.com Sent: Thursday, August 15, 2019 5:16 AM To: Christopher Cifra christopher.cifra@ni.com Cc: wine-devel@winehq.org Subject: [EXTERNAL] Re: Wine for NET Core WPF Apps
On Thu, 15 Aug 2019 at 06:25, Christopher Cifra christopher.cifra@ni.com wrote:
I figured out the issues with multiple windows and WPF. WPF passes in an override window to SwapChain Present when it wants to draw into a specific window. In Wine when swapchain_gl_present calls context_acquire the context returned is for the wrong window because it does not look at the override window of the swap chain. I can fix the issue but it requires modifying context_acquire to take the swap chain as a parameter. In the failure case there is no texture passed to context_acquire because the swap chain does not have a back buffer so I do not have a way to get the correct swap chain. Because there is no texture wined3d_context_gl_acquire uses the first swap chain of the device which is not the correct swap chain and has a different window.
That doesn't sound quite right. The override window is handled by the wined3d_swapchain_set_window() call in wined3d_cs_exec_present(), and then applied to the context by the wined3d_context_gl_update_window() call in wined3d_context_gl_activate().
The context_acquire() call in swapchain_gl_present() passes in the frontbuffer, but if the swapchain didn't have any backbuffers you wouldn't get there in the first place; wined3d_swapchain_present() would return an error.
Henri
On Fri, 16 Aug 2019 at 04:42, Christopher Cifra christopher.cifra@ni.com wrote:
That makes sense and matches what I am seeing. The swapchain does have the correct window set on it by way of wined3d_swapchain_set_window. But in wined3d_context_gl_acquire we get into the rendering offscreen case:
if (current_context && current_context->current_rt.texture == texture) { ... } else if (texture && !wined3d_resource_is_offscreen(&texture->resource)) { ... } else { TRACE("Rendering offscreen.\n"); /* Stay with the current context if possible. Otherwise use the * context for the primary swapchain. */ if (current_context && current_context->device == device) context = current_context; else if (!(context = swapchain_get_context(device->swapchains[0]))) return NULL; }
Just to make sure, are you using wine-4.13 or later? What you should be seeing is that swapchain_gl_present()[1] calls context_acquire() with swapchain->frontbuffer, which is always considered onscreen by wined3d_resource_is_offscreen()[2].
Henri
[1] https://source.winehq.org/git/wine.git/blob/wine-4.13:/dlls/wined3d/swapchai... [2] https://source.winehq.org/git/wine.git/blob/wine-4.13:/dlls/wined3d/resource...
Ugh, it looks like last time I pulled the latest source was just before your change went in. With the latest source everything seems to work great! At least I learned a lot debugging this issue. And most importantly .NET Core WPF on Linux seems to be working quite well. I need to do more testing but my initial testing is very encouraging.
Thanks for your help. --Chris
-----Original Message----- From: Henri Verbeet hverbeet@gmail.com Sent: Friday, August 16, 2019 7:09 AM To: Christopher Cifra christopher.cifra@ni.com Cc: wine-devel@winehq.org Subject: [EXTERNAL] Re: Re: Wine for NET Core WPF Apps
On Fri, 16 Aug 2019 at 04:42, Christopher Cifra christopher.cifra@ni.com wrote:
That makes sense and matches what I am seeing. The swapchain does have the correct window set on it by way of wined3d_swapchain_set_window. But in wined3d_context_gl_acquire we get into the rendering offscreen case:
if (current_context && current_context->current_rt.texture == texture) { ... } else if (texture && !wined3d_resource_is_offscreen(&texture->resource)) { ... } else { TRACE("Rendering offscreen.\n"); /* Stay with the current context if possible. Otherwise use the * context for the primary swapchain. */ if (current_context && current_context->device == device) context = current_context; else if (!(context = swapchain_get_context(device->swapchains[0]))) return NULL; }
Just to make sure, are you using wine-4.13 or later? What you should be seeing is that swapchain_gl_present()[1] calls context_acquire() with swapchain->frontbuffer, which is always considered onscreen by wined3d_resource_is_offscreen()[2].
Henri
[1] https://urldefense.com/v3/__https://source.winehq.org/git/wine.git/blob/wine... [2] https://urldefense.com/v3/__https://source.winehq.org/git/wine.git/blob/wine...
On Sun, 18 Aug 2019 at 00:45, Christopher Cifra christopher.cifra@ni.com wrote:
Ugh, it looks like last time I pulled the latest source was just before your change went in. With the latest source everything seems to work great! At least I learned a lot debugging this issue. And most importantly .NET Core WPF on Linux seems to be working quite well. I need to do more testing but my initial testing is very encouraging.
Glad you got it to work. :)
Henri
On Sat, Aug 17, 2019 at 10:15 PM Christopher Cifra christopher.cifra@ni.com wrote:
Ugh, it looks like last time I pulled the latest source was just before your change went in. With the latest source everything seems to work great! At least I learned a lot debugging this issue. And most importantly .NET Core WPF on Linux seems to be working quite well. I need to do more testing but my initial testing is very encouraging.
That's excellent news! Well done!