Why?

D3D9 (Floating Point Depth Bias)

D3D9 requires us to use floating point depth bias values -- this is an issue as Vulkan uses lowest representable value for the value (which is format based), however, we can't just multiply our way out of this problem, as this wouldn't work as depth bias has completely different behaviour for floating point depth stencil formats.

Having regular floating point values is natively supported on both AMD and Intel with minimal effort.

This extension proposes the ability to set the depth bias mode, so we can take advantage of this.

D3D11 (Vendor Scale)

There is a detail I did not mention in the previous section, and that is in Vulkan (and D3D11 for some vendors), the depth bias may be scaled (eg. to get a separation between line and tri) and we have no knowledge of this scale for a given format, etc. This produces inaccurate rendering as in RADV the scales don't match that (or the lack thereof) in D3D11.

This extension propses that we have the ability to control this if we wish -- hence alleviating the problem.

Test Implementation

I've bodged together a test of this for a proof of concept that something like this could work. It's not meant to be future-proof, but hopefully it shows my point and what I mean.

I have done an implementation of what I believe the extension should look like in RADV, and hooked it up to D9VK, DXVK and WineVulkan. The appropriate patches are below:

Mesa Branch/Patches

Ext Vulkan Header Patch: https://github.com/Joshua-Ashton/mesa/commit/5b531cc3f44b0cf516c0d32e1a92c4a4f014d3d8.patch
RADV Impl. Patch: https://github.com/Joshua-Ashton/mesa/commit/4684da9df3fea497b0ea8808ff0c9a413a1c21c9.patch

WineVulkan Branch/Patches

Pre-requisite Update Patch (1.1.113): https://github.com/Joshua-Ashton/wine/commit/0cb2cdff035d5b52734da249b4f23ce5d7be33ec.patch
Add Extension Support Patch: https://github.com/Joshua-Ashton/wine/commit/a6700dd9f857543f0ebd7d27b9b0504e5b2b108b.patch

D9VK Branch

Branch: https://github.com/Joshua-Ashton/d9vk/tree/d3d9-depth-bias

What it looks like


#define VK_JOSH_depth_bias_info 1
#define VK_JOSH_DEPTH_BIAS_INFO_SPEC_VERSION 1
#define VK_JOSH_DEPTH_BIAS_INFO_EXTENSION_NAME "VK_JOSH_depth_bias_info"

///////////////////////
//VkDepthBiasModeJOSH//
///////////////////////
// VK_DEPTH_BIAS_MODE_LEAST_REPRESENTABLE_JOSH (default w/o struct)
// -> The given depth bias value in VkPipelineRasterizationStateCreateInfo is
//    treat like a least representable value of the given depth format, r = format dependent
////
// VK_DEPTH_BIAS_MODE_FLOAT_JOSH
// -> The given depth bias value in VkPipelineRasterizationStateCreateInfo is
//    treat like a floating point number. r = 1
//
typedef enum VkDepthBiasModeJOSH {
    VK_DEPTH_BIAS_MODE_LEAST_REPRESENTABLE_JOSH = 0,
    VK_DEPTH_BIAS_MODE_FLOAT_JOSH = 1,
    VK_DEPTH_BIAS_MODE_MAX_ENUM_JOSH = 0x7FFFFFFF
} VkDepthBiasModeJOSH;

//////////////////
//depthBiasScale//
//////////////////
// depthBiasScale allows complete control of the vendor's scale for the depth bias
// only enabled if the useDepthBiasScale is VK_TRUE

// pNext of VkPipelineRasterizationStateCreateInfo
typedef struct VkPipelineRasterizationDepthBiasCreateInfoJOSH {
    VkStructureType                                        sType;
    const void*                                            pNext;
    VkBool32                                               useDepthBiasScale;
    float                                                  depthBiasScale;
    VkDepthBiasModeJOSH                                    depthBiasMode;
} VkPipelineRasterizationDepthBiasCreateInfoJOSH;

typedef struct VkPhysicalDeviceDepthBiasFeaturesJOSH {
    VkStructureType    sType;
    void*              pNext;
    VkBool32           modeFloat;
    VkBool32           userScale;
} VkPhysicalDeviceDepthBiasFeaturesJOSH;