On Sunday, 13 October 2024 10:16:47 CDT Derek Lesho wrote:
- "Just Use Zink": this idea has been floated for a while, and would be
to use a PE build of Zink, the MESA gallium driver on top of Vulkan, which would then automatically make use of our VK_EXT_map_memory_placed integration in winevulkan and bypass the problem. RĂ©mi has a branch with a draft solution for this [1] The advantage of approach is that it doesn't require any more extensions to any more APIs, but the disadvantage is that Wine would have to worry about keeping a separate version of Mesa up to date and support for building the required c++ components of mesa to its build system, as can be seen in the commits.
I don't think Zink is a viable option.
First and foremost, the range of GPU hardware out there that should be reasonably supported is not all Vulkan-capable at this point. (Even Mesa still supports GPU hardware well below the Vulkan feature requirements).
Also, as Stefan mentioned, its stability and performance are well below what they should be in order to avoid functional regressions. While these may be solvable in the long term (although I'm a bit concerned about stability), I do think it means we can't rely on it. Distributions and corporate consumers alike are chomping at the bit to delete 32-bit support, and that means that we need to provide a smooth transition without any regressions.
- GL extension with placed memory allocation callback: In this case,
Wine provides a map and unmap callback for the GL implementation to use in creating the pages it needs for GPU-mappings. In comparison to the PE Zink solution, we can continue to use system libraries, and maintain fast buffer IO, as long as the glMapBuffer implementation returns the mapped ptr directly. The main downside for this solution is of course the introduction of a new extension to the mostly dormant GL API, but here it would be possible to just use a VK_EXT_map_memory leveraging Zink like in the first solution, only this time on the Unix side.
For this solution I've created a draft: Wine MR [2] Mesa Branch with Zink implementation [3]
If this is going to require explicit use of Zink on the Unix side, I don't think it's feasible either, unfortunately, for the same reasons.
- glMapBuffer extension which we send our placed allocation: The idea
here is that slightly extended glMapBuffer could be sent a flag to use Wine mapping, avoiding callbacks and targeting the problem where it manifests for Wine (when we get an address out of 32-bit space). This was briefly discussed on the LGD discord server, but it won't work well, due to the fact that a GL buffer is usually only a suballocation of a memory mapping, and often has already been assigned to another pool of memory by the time glMapMemory is called. Mesa would have to add a considerable sized implementation setting up custom-allocator pools, and be able to move buffers between them to implement this.
- glBufferStorage extension to ease Mesa implementation: The next
logical conclusion based on the problems of the last solution is that the Mesa implementation should get the information about any custom allocation at buffer creation time. The closest equivalent to this is the glBufferStorage entry, where we could create a new type of memory that we would ask the implementation to put the buffer in. For this solution we'd either have to implement custom memory allocator or introduce more API entries in order to allow the driver to convey to the application what size mappings it prefers. This would be very unwieldy, and wouldn't solve speed up the slow buffer copies for legacy buffers which don't use ARB_buffer_storage.
I don't think the "legacy buffers" part is a problem. We can explicitly call glBufferStorage() if the application doesn't. (IIRC it's legal to call it multiple times, so we can call it once on creation with the relevant flag, and then append the flag if it's called again later.)
As for suballocation, my best proposal is that instead of specifying an exact address, Wine would simply specify that the address needs to be below the 4GB boundary. I don't remember if there was a reason to allow a specific address on the Vulkan side, but we don't need it in Wine, and I don't know that a new GL extension needs to be quite as forward-looking at this point.
- finally, going off the last possibility, if we're willing to create
our own buffer allocator (we probably shouldn't, as the driver probably knows best), we could use the already existing EXT_external_objects extensions to import Vulkan memory objects, from which our allocator would allocate slices for the buffers. In glMapBuffer we would then return the Vulkan placed memory mapping.
This is infeasible due to the Vulkan requirement, and would be quite a lot of work. Moreover, though, there is at least one important case where suballocated buffers are not as versatile as normal ones: you cannot use an index buffer with an offset in an indirect draw. [Incidentally, this is probably the biggest thing hampering D3D10+ performance in the GL renderer.]