KhronosGroup / Vulkan-Docs

The Vulkan API Specification and related tools
Other
2.8k stars 467 forks source link

No Vulkan equivalent to DXGI_FORMAT_A8_UNORM #1944

Open wiesoweshalbwarum opened 2 years ago

wiesoweshalbwarum commented 2 years ago

Vulkan has no equivalent to DXGI_FORMAT_A8_UNORM. The closest format is VK_FORMAT_R8_UNORM but it can't be used to fully emulate DXGI_FORMAT_A8_UNORM because swizzled image views can't be used for storage image descriptors.

krOoze commented 2 years ago

Don't swizzle it. Problem solved?

HansKristian-Work commented 2 years ago

Don't swizzle it. Problem solved?

Unfortunately that won't fly in D3D emulation. For normal applications, sure. For sampled images and render targets, it's possible to fix it up by using R8 with swizzles in the case of VkImageView and render targets can change the shader output to redirect alpha to red channel (and fix up blend state accordingly). Storage images cannot be fixed up like that without extreme heroics (have to assume it has work with full bindless).

krOoze commented 2 years ago

Storage images can also write to the first component (which is probably always better, since there are no G8 or B8 formats neither).

Do we expect drivers to do any better than implement it the same way as the emulator? Would deprecated features like alpha formats even ever be used with modern features like bindless?

wiesoweshalbwarum commented 2 years ago

Storage images can also write to the first component

That would require shader changes and it's not possible to know which format is going to be used at shader compile time.

Would deprecated features like alpha formats even ever be used with modern features like bindless?

It's not deprecated, D3D12 has it and even requires support for A8 UAV stores. https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/hardware-support-for-direct3d-12-1-formats#dxgi_format_a8_unormfns-65

Do we expect drivers to do any better than implement it the same way as the emulator?

Any vendor that wants to supports modern d3d12 presumably has some solution for it. AMD can quite freely swizzle storage images, Intel has a hardware format for A8_UNORM: https://gitlab.freedesktop.org/mesa/mesa/-/blob/ba9c73f9d4d49a875c2a7cd0bbae46294892a013/src/intel/isl/isl_format.c#L247

nanokatze commented 2 years ago

Would deprecated features like alpha formats even ever be used with modern features like bindless?

Yes, there was a recently released AAA D3D12 game that used A8 for a while and couldn't work correctly on vkd3d-p on nvidia hardware for that very reason. No idea whether it used bindless or not but that's beside the point.

krOoze commented 2 years ago

It is deprecated in modern OpenGL, therefore the feature is fundamentally suspect.

It is not quite besides the point, because as discussed the non-bindless case is trivial to implement without polluting drivers and further convoluting the spec.

wiesoweshalbwarum commented 2 years ago

It is deprecated in modern OpenGL, therefore the feature is fundamentally suspect.

(modern) OpenGL is barely relevant compared to D3D12, so why does is matter what OpenGL deprecated or not?

It is not quite besides the point, because as discussed the non-bindless case is trivial to implement without polluting drivers and further convoluting the spec.

Almost everything is update after bind in D3D12, there really isn't a trivial solution.

jrfonseca commented 1 year ago

We also stumbled across further difficulties translating from Direct3D to Vulkan due to lack of a VK_FORMAT_A8_UNORM.

Emulating DXGI_FORMAT_A8_UNORM with VK_FORMAT_R8_UNORM fails even for mere texture sampling, when border color is used, and the Vulkan implementation advertises VkPhysicalDeviceBorderColorSwizzleFeaturesEXT::borderColorSwizzleFromImage as true, as the implementation will end up returning the red component of the border color, instead of the alpha component.

Microsoft Windows HCK wgf11filter test explicitly tests this.

Statically determining which sampler object is used with which resource shader view is not generally possible with Direct3D 12 onwards (SM 5.1 or 6), as both sampler and SRV objects can be dynamically indexed in the shader.

Getting this right would imply creating multiple sampler object variants, with different swizzled colors, pass all to the shader, and emit logic in the shader to dynamically choose the right variant based on the SRV format.

This would make HLSL -> SPIRV transpiled shaders unnecessary complex, and all due to the lack of one single format, which I'd expect most hardware (at least that Direct3D 11/12 capable) would natively support.

krOoze commented 1 year ago

Why would you expect border for component 0 to come from anything else than component 0? That's not broken; rather the opposite. And why would you expect single component format to have multiple components. That's conceptual nonsense.

How would any hardware support it natively, if the format itself is a complete conceptual nonsense that was there in service to the higher level fixed-function legacy API (so antithesis to Vulkan). I imagine it would always have to be emulated in some way. Either in the driver, or in the microcode, or worse in unnecessary silicon.

We need to move away from this mentality. Just because MS has nonconceptual defect in its API, it does not mean Vulkan has to copy-paste it and also frankenstein it onto modern stuff, while polluting the drivers and making a mess in the Vulkan and GLSL specifications to allow for weird nonconceptual format that does not even start with component index 0 like normal ones. And it will get only worse in time when everything will want to move to full pointer arithmetic. I mean is the driver supposed to magically enter strides in the pointers based on format or do we make awkward exception that the format is actually tightly packed for purpose of pointers but not tightly packed for vector\texel semantics...

Only way I can think of to implement something like this somewhat conceptually is introduce a two-plane RGB_A_2PLANE format and make it optional to allocate\bind memory for the RGB plane. But I think the emulator implementors would run into similar problems. It is fundamentally hard to translate something non-conceptual into something more conceptual.

jrfonseca commented 1 year ago

Why would you expect border for component 0 to come from anything else than component 0? That's not broken; rather the opposite.

If you refer to https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_border_color_swizzle.html then you'll see in fact some hardware does the exact opposite of this. (This stems from the fact there are two ways of applying image swizzles: after or before texture wrapping, leading to the border color to be swizzled or unswizzled, respectively.)

But in general you're, right. One normally would expect border for component 0 to come for component 0.

The issue is that when emulating A8_UNORM with R8_UNORM on hardware which advertises borderColorSwizzleFromImage = TRUE that's not possible to attain.

In short, I'm not arguing for weird border color semantics, I'm just stating the point that emulating A8_UNORM with R8_UNORM plus texture swizzles is not generally practical.

Concerning, the enablement of Direct3D to Vulkan API translation, you might consider that an frakenstenien abomination. But that's has not been the impression I get from the direction Vulkan API has taken. Rather the contrary: this sort of API translation has been quite top of mind as far as I can tell.

In this particular case, I'm arguing for an optional extension. I don't believe there's a need for making A8_NORM part of core or even required format. HW that can trivially support the format can advertise the extension. HW that does not, can simply not expose it.

krOoze commented 1 year ago

Right, I don't mean to be insensitive to pragmatic concerns. But we are low-level. If there is any place to be insensitive to contemporary pragmatic concerns that are at the cost of long term sustainability, this is the place.

I mean, look at us. We are discussing swizzling of a thing that has only one component. Let that sink it. There is not (or rather should not) be anything to swizzel at all, ideally. There's nothing to swizzel with, if you only have one thing. There should only be identity. Our discussion steers this way only because some other API is wrong, and some apps use the wrong part of the API for wrong reasons.

And I am not sure why what I am saying is even controversial. Where are the people demanding G8_UNORM and B8_UNORM formats?

As I understand it, the ask here is not just to add a format. It is to add a class of formats that behaves fundamentally different from all the other sane formats. And for what? I feel there should be some barrier. Some muster that has to be passed of what we try to cram into the specification (and indirectly into the drivers and silicon).

One criticism of OpenGL was there was way too many nonsense extensions. If you only want an extension, then what even is the point. You will have to assume it is not supported, and emulate it anyway. (Or you are sneakily assuming everyone will support it for eternity anyway, because they are forced to, which undermines your point)

I am all for API translation (rather everything leading to Vulkan). But preferrably by way of making the API more expressible, rather than making cutouts for bad parts of other APIs by the way of copy-pasting the functionality verbatim with no regard for compatibility with rest of the modern functionality, or any functionality to come that will have to be made compatible with this feature in some sensible way.

nanokatze commented 1 year ago

Where are the people demanding G8_UNORM and B8_UNORM formats?

Vulkan doesn't exist in a vacuum, it exists to address needs of its users. If there were some programs with non-zero users and those programs were using some API with those formats that's being translated into Vulkan, and there was a reason to ask for an extension: implementations could easily support it by virtue of the hardware just having those formats, or supporting swizzles on storage images and attachments, like the hardware in today's landscape is doing it with A8, you can be certain that there would be people demanding these formats.

And given that it's very easy for at least 12-capable hardware to support this format, in fact much easier than it would be for any kind of a translation layer, what's not "low-level" about this functionality?

Implementations that can't support this format easily will just not support this extension, and apps that target them will simply have to transition away from using the format, while translation layers might resort to e.g. adding some extra code to shaders. In other cases there's little reason to apply such effort and tricks when the underlying implementation can support this format with much less effort.

jrfonseca commented 1 year ago

Where are the people demanding G8_UNORM and B8_UNORM formats? [...] As I understand it, the ask here is not just to add a format. It is to add a class of formats that behaves fundamentally different from all the other sane formats. And for what?

This is a strawman argument. You're arguing against things are not being asked.

It's also a poor strawman. Vulkan has VK_FORMAT_R8G8B8A8_UNORM and VK_FORMAT_B8G8R8A8_UNORM and VK_FORMAT_A8B8G8R8_UNORM_PACK32 which are all swizzles of one another. Where are the people asking for all the remaining factorial(4) permutations?

Once again, these formats exist because they can't be faithfully replaced with image swizzles, and because hardware supports them.

But preferably by way of making the API more expressible, rather than making cutouts for bad parts of other APIs by the way of copy-pasting the functionality verbatim with no regard for compatibility with rest of the modern functionality, or any functionality to come that will have to be made compatible with this feature in some sensible way.

I haven't seen another sensible way proposed so far, besides adding an A8_UNORM format. Just because it mimics another API it doesn't make it inherently wrong nor bad, or that folks haven't put thought into it.

I don't see in what way a A8_UNORM format creates challenges that don't already exist with formats as R8G8B8A8_UNORM/B8G8R8A8_UNORM. On the flip side, making Vulkan API more expressible seems far more dangerous in terms of compatibility/interactions with future features.

krOoze commented 1 year ago

We are quickly getting into the repetitive "Na-ah, opposite of everything you said is true!" part of the discussion. I said what needed to be said and not sure what more to say to break the loop. Rather than take the space to reitarate my talking points slightly rephrazed, I would be eager to hear from the vendors which know much more about the feature and how and why they implement it.

The part I should like to reiterate though is that I find following things philosophically wrongheaded for the long term shaping of the API (whether they apply here or not I leave to the reader):

jrfonseca commented 1 year ago

FWIW, we plan to prototype and submit a PR for a _VK_MESA_a8_unormformat extension, which exposes such a format for Mesa. I'll refer this issue and discussion when I do. An eventual _VK_EXT_a8_unormformat can be considered depending on the support/push-back. (I personally don't feel strongly either way.)