On 5/3/21 4:08 PM, Derek Lesho wrote:
On 5/3/21 4:14 PM, Zebediah Figura (she/her) wrote:
Hello Derek, it looks like you've put a lot of thought into this problem. I assume you've already discussed this privately in detail with our Direct3D maintainers, but for the benefit of the rest of us, I have a few questions:
- How do you plan to accomodate the following (whether in the near or
distant future):
CL_KHR_d3d11_sharing
CL_KHR_gl_sharing
Shared resources in d3d9-11, when using the OpenGL backend
Shared resources in d3d12
My plan is to add an optional map inside the resource objects in which graphics API implementations (DXVK, vkd3d-proton, wined3d ...) and wine layers (openGL, openCL) can store extra data as needed. There would be an interface in the driver which takes a key (probably a GUID) and either accept or return an arbitrary blob of data. The benefit to this approach, in my view, is that it would allow some flexibility as requirements are understood and evolve for sharing between all these APIs. For example, at first, DXVK might roll its own data structure / interface for sharing between its D3D9 and D3D11 implementations, and maybe later on as the problem is better understood, an interface could come into being for sharing between DXVK's d3d11 and wined3d's d3d9.
I was kind of hoping for some more specific answers, i.e. rough descriptions of what the code does. Nevertheless, according to my understanding, this really doesn't account for all of the specifics of each API I've listed. Put simply, I'm worried that this patch set fits Vulkan and nothing else.
- Shared resources between d3d9-12 devices, when using wined3d or
libvkd3d on Windows
- Shared resources between d3d9-12 devices and OpenGL or Vulkan, when
using wined3d or libvkd3d on Windows
I decided not to worry about the situation on windows, as it seems much more complex to me. There seems to be a number of sparsely documented D3DKMT APIs for tracking information about shared resources, and it seemed to me that it would be improper to try to implement these interfaces given how different the stack is on wine. As for a custom interface unrelated to the native one working on Windows, I'm really not sure how feasible that would be, and what benefits it would provide. We need to be able to associate metadata to the objects underlying the HANDLEs, as well as provide a global lookup for these objects, all in usermode. You could try implementing a global memory section that stores this metadata associated to KMT (global) handles, but you would have trouble doing the same for regular NT handles, since as far as I can see it is impossible to fetch a KMT handle from a regular NT handle on the windows implementation. If a solution does come about for this problem, I doubt it would be a good fit for wine.
I would strongly advise not throwing these possibilities out the window immediately.
- What is the reason for the "weak" reference counting introduced in
this patch?
In wine's ntoskrnl's object manager code, object structure data isn't freed until there are no more references to the object in the server. This is because a driver could reasonably expect that even though they don't hold any references to an object, they can expect for their pointer to valid if they or anyone else holds a handle to the object. The weak references allow a driver to safely store their own data alongside a weakly-referenced object, as with a weak reference, the destruction of the object structure will be deferred until there are no more weak references. The reason why the driver can't just hold a full reference is that it has no indication on when to free it, an application can request a HANDLE for a graphics resource, then completely de-initialize the graphics API, keeping the HANDLE. That is to say, there's no single point in the winevulkan code where we can make a call to the driver to free that object. On the other hand, if the driver were to keep no reference to the object, but just the pointer, it would have no way of knowing whether the object pointers are still valid when the client asks for information about an object.
The code, as it stands, looks all sorts of wrong. The right approach would be to let the server notify ntoskrnl of destruction, the way it already does.
That's easier said than done, of course, and it takes some thought. One possible approach that comes to mind is to have shared resource handles be (NT) handles to device file objects. These files expose a pair of ioctls IOCTL_RESOURCE_SET_INFO and IOCTL_RESOURCE_GET_INFO, which store and retrieve a structure like:
struct resource_info { obj_handle_t fd_handle; struct wined3d_resource_desc desc; unsigned int layer_count; unsigned int level_count; };
"file" is itself a handle, which was created through wine_server_fd_to_handle(), and will be duplicated anew into the calling process through each IOCTL_RESOURCE_GET_INFO call. The remaining parameters are stored and returned transparently.
When winevulkan needs to create a shared resource handle, it does something like this:
vkGetMemoryFdKHR(..., &fd); file = CreateFile(...); resource_info.fd_handle = wine_server_fd_to_handle(fd); /* fill resource_info.desc &c. */ DeviceIoControl(file, ..., &resource_info, ...); CloseHandle(fd_handle);
and eventually returns "file" from vkGetMemoryWin32HandleKHR().
When wined3d, Vulkan, or OpenGL needs to open a shared resource handle, it uses IOCTL_RESOURCE_GET_INFO on that handle, followed by wine_server_handle_to_fd(). wined3d will subsequently use the other fields of struct resource_info; other APIs will ignore them.
Extending this to objects which aren't resources (e.g. semaphores, fences) is left as an exercise to the reader; it could be done with a separate pair of ioctls or by extending the above structure.
I will of course disclaim that I have thought this approach through completely, or that it is the best approach (in particular, I still am inclined to think that server-side management probably isn't that bad), but it seems like a reasonable way to use the existing ntoskrnl infrastructure and avoid any awful hacks.
Note that this still doesn't handle OpenGL, and that's something that should really be resolved before anything is implemented.
- Why is winevideo.sys necessary at all, if
wine_server_fd_to_handle() and wine_server_handle_to_fd() provide the necessary wrapping of an external FD object?
Because we need more information to be stored in the object behind the HANDLE, and we need a way to lookup these objects globally. For example, with D3D11 shared resources, we must be able to lookup and object by its KMT handle and name, and we must be able to store extra information about the object such as width, height, and layers, as Vulkan doesn't do this for us. Of course, we could figure add a way to put these objects into the server's object namespace, but that still leaves the KMT handles to worry about.
- What kind of objects are Vulkan or Direct3D shared handles on
Windows? E.g. what does NtQueryObject(ObjectTypeInformation) return? Are named Vulkan objects implemented using the NT namespace? How is this different between e.g. D3D11_RESOURCE_MISC_SHARED and D3D11_RESOURCE_MISC_SHARED_NTHANDLE, or between VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT and VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT?
KMT handles are in their own namespace, completely separated from the NT object system. None of the usual object APIs work with them. The objects behind the NT handles do have a custom type, and named Vulkan objects are implemented using the NT namespace. This is not reflected in the implementation I sent. I previously sent a patchset to implement these resources in 2019, and back then, the concern was that implementing these custom object types complicated wineserver code unnecessarily since the fd<->HANDLE APIs were already present. This is the reason why I had to come up with the new approach.
That is an answer to one of the questions I asked, though not really the others.
In particular, I suspect (especially given [1]) that the name parameter is really an NT name, or maps to one, which means that name assignment and lookup should be done in a way consistent with other NT objects.
- Are D3D11_RESOURCE_MISC_SHARED / KMT handles cross-process? If not,
should they be implemented using a process-local handle table somewhere instead of using NT handles? (Could/should we use D3DKMT* APIs from gdi32?)
I'd always assumed that they were, and I must admit I wrote the rest of this email under that assumption. I'll write tests tomorrow to find out. If they aren't, that would indeed make things a lot simpler...
On the flip side of this, is there any reason that we can't just pretend NT handles are KMT handles?
- Would it make more sense to use wineserver to manage shared
resources instead of a separate driver, and thereby avoid introducing hacks into ntoskrnl?
I think I addressed this in my response to question 4.
[1] https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12devi...