Browse Source

Adds UAV support for D3D12, Vulkan and reworked for OpenGL, D3D11 (#2119)

* Adds UAV support for D3D12, Vulkan and reworked support for OpenGL, D3D11

UAV support is now uniform across compute and draw.
To set a UAV you just use bgfx::setImage() and IMAGE2D in the shader, just like in compute.
Due to these changes shaders will have to be recompiled.

The changes include:
	- D3D11 requires patching of the UAV slot number (which is now done by modifying the DXBC instead of using a macro)
	- If the DXBC binary includes a debug chunk, that is also patched to match the new slot number
	- All the other renderers don't need any kind of patching
	- There are some shader annotations to better convert the UAV format used in hlsl to spirv

Possibility of further enhancements:
	- bgfx::setViewFrameBuffer() only supports binding to a framebuffer or, using BGFX_INVALID_HANDLE, to bind the default backbuffer. This doesn't allow for the case where there is no need to bind to either one of them, for example when using a fragment shader only to read and write to an UAV.

* Bump shader version, because they need to be recompiled.
kingscallop 5 years ago
parent
commit
436b7fab9e

+ 25 - 20
bindings/cs/bgfx.cs

@@ -1041,9 +1041,9 @@ public static partial class bgfx
 		FragmentOrdering       = 0x0000000000000040,
 	
 		/// <summary>
-		/// Read/Write frame buffer attachments are supported.
+		/// Image Read/Write is supported.
 		/// </summary>
-		FramebufferRw          = 0x0000000000000080,
+		ImageRw                = 0x0000000000000080,
 	
 		/// <summary>
 		/// Graphics debugger is present.
@@ -1148,87 +1148,92 @@ public static partial class bgfx
 	}
 	
 	[Flags]
-	public enum CapsFormatFlags : ushort
+	public enum CapsFormatFlags : uint
 	{
 		/// <summary>
 		/// Texture format is not supported.
 		/// </summary>
-		TextureNone            = 0x0000,
+		TextureNone            = 0x00000000,
 	
 		/// <summary>
 		/// Texture format is supported.
 		/// </summary>
-		Texture2d              = 0x0001,
+		Texture2d              = 0x00000001,
 	
 		/// <summary>
 		/// Texture as sRGB format is supported.
 		/// </summary>
-		Texture2dSrgb          = 0x0002,
+		Texture2dSrgb          = 0x00000002,
 	
 		/// <summary>
 		/// Texture format is emulated.
 		/// </summary>
-		Texture2dEmulated      = 0x0004,
+		Texture2dEmulated      = 0x00000004,
 	
 		/// <summary>
 		/// Texture format is supported.
 		/// </summary>
-		Texture3d              = 0x0008,
+		Texture3d              = 0x00000008,
 	
 		/// <summary>
 		/// Texture as sRGB format is supported.
 		/// </summary>
-		Texture3dSrgb          = 0x0010,
+		Texture3dSrgb          = 0x00000010,
 	
 		/// <summary>
 		/// Texture format is emulated.
 		/// </summary>
-		Texture3dEmulated      = 0x0020,
+		Texture3dEmulated      = 0x00000020,
 	
 		/// <summary>
 		/// Texture format is supported.
 		/// </summary>
-		TextureCube            = 0x0040,
+		TextureCube            = 0x00000040,
 	
 		/// <summary>
 		/// Texture as sRGB format is supported.
 		/// </summary>
-		TextureCubeSrgb        = 0x0080,
+		TextureCubeSrgb        = 0x00000080,
 	
 		/// <summary>
 		/// Texture format is emulated.
 		/// </summary>
-		TextureCubeEmulated    = 0x0100,
+		TextureCubeEmulated    = 0x00000100,
 	
 		/// <summary>
 		/// Texture format can be used from vertex shader.
 		/// </summary>
-		TextureVertex          = 0x0200,
+		TextureVertex          = 0x00000200,
 	
 		/// <summary>
-		/// Texture format can be used as image from compute shader.
+		/// Texture format can be used as image and read from.
 		/// </summary>
-		TextureImage           = 0x0400,
+		TextureImageRead       = 0x00000400,
+	
+		/// <summary>
+		/// Texture format can be used as image and written to.
+		/// </summary>
+		TextureImageWrite      = 0x00000800,
 	
 		/// <summary>
 		/// Texture format can be used as frame buffer.
 		/// </summary>
-		TextureFramebuffer     = 0x0800,
+		TextureFramebuffer     = 0x00001000,
 	
 		/// <summary>
 		/// Texture format can be used as MSAA frame buffer.
 		/// </summary>
-		TextureFramebufferMsaa = 0x1000,
+		TextureFramebufferMsaa = 0x00002000,
 	
 		/// <summary>
 		/// Texture can be sampled as MSAA.
 		/// </summary>
-		TextureMsaa            = 0x2000,
+		TextureMsaa            = 0x00004000,
 	
 		/// <summary>
 		/// Texture format supports auto-generated mips.
 		/// </summary>
-		TextureMipAutogen      = 0x4000,
+		TextureMipAutogen      = 0x00008000,
 	}
 	
 	[Flags]

+ 22 - 19
bindings/d/types.d

@@ -354,7 +354,7 @@ enum ulong BGFX_CAPS_CONSERVATIVE_RASTER = 0x0000000000000008; /// Conservative
 enum ulong BGFX_CAPS_DRAW_INDIRECT = 0x0000000000000010; /// Draw indirect is supported.
 enum ulong BGFX_CAPS_FRAGMENT_DEPTH = 0x0000000000000020; /// Fragment depth is accessible in fragment shader.
 enum ulong BGFX_CAPS_FRAGMENT_ORDERING = 0x0000000000000040; /// Fragment ordering is available in fragment shader.
-enum ulong BGFX_CAPS_FRAMEBUFFER_RW = 0x0000000000000080; /// Read/Write frame buffer attachments are supported.
+enum ulong BGFX_CAPS_IMAGE_RW = 0x0000000000000080; /// Image Read/Write is supported.
 enum ulong BGFX_CAPS_GRAPHICS_DEBUGGER = 0x0000000000000100; /// Graphics debugger is present.
 enum ulong BGFX_CAPS_RESERVED = 0x0000000000000200;
 enum ulong BGFX_CAPS_HDR10 = 0x0000000000000400; /// HDR10 rendering is supported.
@@ -377,22 +377,23 @@ enum ulong BGFX_CAPS_VERTEX_ATTRIB_UINT10 = 0x0000000004000000; /// Vertex attri
 enum ulong BGFX_CAPS_VERTEX_ID = 0x0000000008000000; /// Rendering with VertexID only is supported.
 enum ulong BGFX_CAPS_TEXTURE_COMPARE_ALL = 0x0000000000300000; /// All texture compare modes are supported.
 
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_NONE = 0x0000; /// Texture format is not supported.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_2D = 0x0001; /// Texture format is supported.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_2D_SRGB = 0x0002; /// Texture as sRGB format is supported.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_2D_EMULATED = 0x0004; /// Texture format is emulated.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_3D = 0x0008; /// Texture format is supported.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_3D_SRGB = 0x0010; /// Texture as sRGB format is supported.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_3D_EMULATED = 0x0020; /// Texture format is emulated.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_CUBE = 0x0040; /// Texture format is supported.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB = 0x0080; /// Texture as sRGB format is supported.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED = 0x0100; /// Texture format is emulated.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_VERTEX = 0x0200; /// Texture format can be used from vertex shader.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_IMAGE = 0x0400; /// Texture format can be used as image from compute shader.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER = 0x0800; /// Texture format can be used as frame buffer.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA = 0x1000; /// Texture format can be used as MSAA frame buffer.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_MSAA = 0x2000; /// Texture can be sampled as MSAA.
-enum ushort BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN = 0x4000; /// Texture format supports auto-generated mips.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_NONE = 0x00000000; /// Texture format is not supported.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_2D = 0x00000001; /// Texture format is supported.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_2D_SRGB = 0x00000002; /// Texture as sRGB format is supported.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_2D_EMULATED = 0x00000004; /// Texture format is emulated.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_3D = 0x00000008; /// Texture format is supported.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_3D_SRGB = 0x00000010; /// Texture as sRGB format is supported.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_3D_EMULATED = 0x00000020; /// Texture format is emulated.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_CUBE = 0x00000040; /// Texture format is supported.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB = 0x00000080; /// Texture as sRGB format is supported.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED = 0x00000100; /// Texture format is emulated.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_VERTEX = 0x00000200; /// Texture format can be used from vertex shader.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ = 0x00000400; /// Texture format can be used as image and read from.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE = 0x00000800; /// Texture format can be used as image and written to.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER = 0x00001000; /// Texture format can be used as frame buffer.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA = 0x00002000; /// Texture format can be used as MSAA frame buffer.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_MSAA = 0x00004000; /// Texture can be sampled as MSAA.
+enum uint BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN = 0x00008000; /// Texture format supports auto-generated mips.
 
 enum ubyte BGFX_RESOLVE_NONE = 0x00; /// No resolve flags.
 enum ubyte BGFX_RESOLVE_AUTO_GEN_MIPS = 0x01; /// Auto-generate mip maps on resolve.
@@ -759,8 +760,10 @@ struct bgfx_caps_t
 	 *   - `BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB` - Texture as sRGB format is supported.
 	 *   - `BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED` - Texture format is emulated.
 	 *   - `BGFX_CAPS_FORMAT_TEXTURE_VERTEX` - Texture format can be used from vertex shader.
-	 *   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE` - Texture format can be used as image from compute
-	 *     shader.
+	 *   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ` - Texture format can be used as image
+	 *     and read from.
+	 *   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE` - Texture format can be used as image
+	 *     and written to.
 	 *   - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER` - Texture format can be used as frame
 	 *     buffer.
 	 *   - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA` - Texture format can be used as MSAA

+ 92 - 66
examples/21-deferred/deferred.cpp

@@ -13,10 +13,11 @@ namespace
 {
 
 constexpr bgfx::ViewId kRenderPassGeometry     = 0;
-constexpr bgfx::ViewId kRenderPassLight        = 1;
-constexpr bgfx::ViewId kRenderPassCombine      = 2;
-constexpr bgfx::ViewId kRenderPassDebugLights  = 3;
-constexpr bgfx::ViewId kRenderPassDebugGBuffer = 4;
+constexpr bgfx::ViewId kRenderPassClearUav     = 1;
+constexpr bgfx::ViewId kRenderPassLight        = 2;
+constexpr bgfx::ViewId kRenderPassCombine      = 3;
+constexpr bgfx::ViewId kRenderPassDebugLights  = 4;
+constexpr bgfx::ViewId kRenderPassDebugGBuffer = 5;
 
 static float s_texelHalf = 0.0f;
 
@@ -230,6 +231,7 @@ public:
 				, 1.0f
 				, 0
 				, 1
+				, 0
 				);
 
 		// Set light pass view clear state.
@@ -293,10 +295,12 @@ public:
 			m_lightTaProgram = BGFX_INVALID_HANDLE;
 		}
 
-		if (0 != (BGFX_CAPS_FRAMEBUFFER_RW & bgfx::getCaps()->supported) )
+		if (0 != (BGFX_CAPS_IMAGE_RW & bgfx::getCaps()->supported)
+		&&  0 != (BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ & bgfx::getCaps()->formats[bgfx::TextureFormat::RGBA8])
+		&&  0 != (BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE & bgfx::getCaps()->formats[bgfx::TextureFormat::RGBA8]) )
 		{
-			m_lightUavProgram = loadProgram("vs_deferred_light", "fs_deferred_light_uav");
 			m_clearUavProgram = loadProgram("vs_deferred_light", "fs_deferred_clear_uav");
+			m_lightUavProgram = loadProgram("vs_deferred_light", "fs_deferred_light_uav");
 		}
 		else
 		{
@@ -310,6 +314,8 @@ public:
 		// Load normal texture.
 		m_textureNormal = loadTexture("textures/fieldstone-n.dds");
 
+		m_lightBufferTex.idx = bgfx::kInvalidHandle;
+
 		m_gbufferTex[0].idx = bgfx::kInvalidHandle;
 		m_gbufferTex[1].idx = bgfx::kInvalidHandle;
 		m_gbufferTex[2].idx = bgfx::kInvalidHandle;
@@ -352,9 +358,18 @@ public:
 		if (bgfx::isValid(m_gbuffer) )
 		{
 			bgfx::destroy(m_gbuffer);
+		}
+
+		if (bgfx::isValid(m_lightBuffer) )
+		{
 			bgfx::destroy(m_lightBuffer);
 		}
 
+		if (bgfx::isValid(m_lightBufferTex) )
+		{
+			bgfx::destroy(m_lightBufferTex);
+		}
+
 		bgfx::destroy(m_ibh);
 		bgfx::destroy(m_vbh);
 
@@ -421,6 +436,46 @@ public:
 
 			float time = (float)( (now-m_timeOffset)/freq);
 
+			ImGui::SetNextWindowPos(
+				ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
+				, ImGuiCond_FirstUseEver
+			);
+			ImGui::SetNextWindowSize(
+				ImVec2(m_width / 5.0f, m_height / 3.0f)
+				, ImGuiCond_FirstUseEver
+			);
+			ImGui::Begin("Settings"
+				, NULL
+				, 0
+			);
+
+			ImGui::SliderInt("Num lights", &m_numLights, 1, 2048);
+			ImGui::Checkbox("Show G-Buffer.", &m_showGBuffer);
+			ImGui::Checkbox("Show light scissor.", &m_showScissorRects);
+
+			if (bgfx::isValid(m_lightTaProgram))
+			{
+				ImGui::Checkbox("Use texture array frame buffer.", &m_useTArray);
+			}
+			else
+			{
+				ImGui::Text("Texture array frame buffer is not supported.");
+			}
+
+			if (bgfx::isValid(m_lightUavProgram))
+			{
+				ImGui::Checkbox("Use UAV.", &m_useUav);
+			}
+			else
+			{
+				ImGui::Text("UAV is not supported.");
+			}
+
+			ImGui::Checkbox("Animate mesh.", &m_animateMesh);
+			ImGui::SliderFloat("Anim.speed", &m_lightAnimationSpeed, 0.0f, 0.4f);
+
+			ImGui::End();
+
 			if (2 > m_caps->limits.maxFBAttachments)
 			{
 				// When multiple render targets (MRT) is not supported by GPU,
@@ -486,7 +541,7 @@ public:
 					bgfx::TextureFormat::Enum depthFormat =
 						  bgfx::isTextureValid(0, false, 1, bgfx::TextureFormat::D32F, BGFX_TEXTURE_RT | tsFlags)
 						? bgfx::TextureFormat::D32F
-						: bgfx::TextureFormat::D24S8
+						: bgfx::TextureFormat::D24
 						;
 
 					m_gbufferTex[2] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, depthFormat, BGFX_TEXTURE_RT | tsFlags);
@@ -497,18 +552,18 @@ public:
 					if (bgfx::isValid(m_lightBuffer) )
 					{
 						bgfx::destroy(m_lightBuffer);
+						m_lightBuffer.idx = bgfx::kInvalidHandle;
 					}
 
-					if (m_useUav)
+					if (bgfx::isValid(m_lightBufferTex))
 					{
-						bgfx::Attachment lightAt[2];
-
-						bgfx::TextureHandle target = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT | tsFlags);
-						m_lightBufferTex = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_COMPUTE_WRITE | tsFlags);
-						lightAt[0].init(target);
-						lightAt[1].init(m_lightBufferTex, bgfx::Access::ReadWrite);
+						bgfx::destroy(m_lightBufferTex);
+						m_lightBufferTex.idx = bgfx::kInvalidHandle;
+					}
 
-						m_lightBuffer = bgfx::createFrameBuffer(BX_COUNTOF(lightAt), lightAt, true);
+					if (m_useUav)
+					{
+						m_lightBufferTex = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_COMPUTE_WRITE | tsFlags);
 					}
 					else
 					{
@@ -517,46 +572,6 @@ public:
 					}
 				}
 
-				ImGui::SetNextWindowPos(
-					  ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
-					, ImGuiCond_FirstUseEver
-					);
-				ImGui::SetNextWindowSize(
-					  ImVec2(m_width / 5.0f, m_height / 3.0f)
-					, ImGuiCond_FirstUseEver
-					);
-				ImGui::Begin("Settings"
-					, NULL
-					, 0
-					);
-
-				ImGui::SliderInt("Num lights", &m_numLights, 1, 2048);
-				ImGui::Checkbox("Show G-Buffer.", &m_showGBuffer);
-				ImGui::Checkbox("Show light scissor.", &m_showScissorRects);
-
-				if (bgfx::isValid(m_lightTaProgram) )
-				{
-					ImGui::Checkbox("Use texture array frame buffer.", &m_useTArray);
-				}
-				else
-				{
-					ImGui::Text("Texture array frame buffer is not supported.");
-				}
-
-				if (bgfx::isValid(m_lightUavProgram) )
-				{
-					ImGui::Checkbox("Use UAV frame buffer attachment.", &m_useUav);
-				}
-				else
-				{
-					ImGui::Text("UAV frame buffer attachment is not supported.");
-				}
-
-				ImGui::Checkbox("Animate mesh.", &m_animateMesh);
-				ImGui::SliderFloat("Anim.speed", &m_lightAnimationSpeed, 0.0f, 0.4f);
-
-				ImGui::End();
-
 				// Update camera.
 				cameraUpdate(deltaTime, m_mouseState);
 
@@ -567,13 +582,21 @@ public:
 				float vp[16];
 				float invMvp[16];
 				{
-					bgfx::setViewRect(kRenderPassGeometry,      0, 0, uint16_t(m_width), uint16_t(m_height) );
-					bgfx::setViewRect(kRenderPassLight,         0, 0, uint16_t(m_width), uint16_t(m_height) );
-					bgfx::setViewRect(kRenderPassCombine,       0, 0, uint16_t(m_width), uint16_t(m_height) );
+					bgfx::setViewRect(kRenderPassGeometry,     0, 0, uint16_t(m_width), uint16_t(m_height) );
+					bgfx::setViewRect(kRenderPassClearUav,     0, 0, uint16_t(m_width), uint16_t(m_height) );
+					bgfx::setViewRect(kRenderPassLight,        0, 0, uint16_t(m_width), uint16_t(m_height) );
+					bgfx::setViewRect(kRenderPassCombine,      0, 0, uint16_t(m_width), uint16_t(m_height) );
 					bgfx::setViewRect(kRenderPassDebugLights,  0, 0, uint16_t(m_width), uint16_t(m_height) );
 					bgfx::setViewRect(kRenderPassDebugGBuffer, 0, 0, uint16_t(m_width), uint16_t(m_height) );
 
-					bgfx::setViewFrameBuffer(kRenderPassLight, m_lightBuffer);
+					if (!m_useUav)
+					{
+						bgfx::setViewFrameBuffer(kRenderPassLight, m_lightBuffer);
+					}
+					else
+					{
+						bgfx::setViewFrameBuffer(kRenderPassLight, BGFX_INVALID_HANDLE);
+					}
 
 					float proj[16];
 					bx::mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f, m_caps->homogeneousDepth);
@@ -587,8 +610,9 @@ public:
 					const bgfx::Caps* caps = bgfx::getCaps();
 
 					bx::mtxOrtho(proj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f, 0.0f, caps->homogeneousDepth);
-					bgfx::setViewTransform(kRenderPassLight,   NULL, proj);
-					bgfx::setViewTransform(kRenderPassCombine, NULL, proj);
+					bgfx::setViewTransform(kRenderPassClearUav, NULL, proj);
+					bgfx::setViewTransform(kRenderPassLight,    NULL, proj);
+					bgfx::setViewTransform(kRenderPassCombine,  NULL, proj);
 
 					const float aspectRatio = float(m_height)/float(m_width);
 					const float size = 10.0f;
@@ -649,11 +673,10 @@ public:
 				if (m_useUav)
 				{
 					screenSpaceQuad( (float)m_width, (float)m_height, s_texelHalf, m_caps->originBottomLeft);
-					bgfx::setState(0
-						| BGFX_STATE_WRITE_RGB
-						| BGFX_STATE_WRITE_A
-						);
-					bgfx::submit(kRenderPassLight, m_clearUavProgram);
+					bgfx::setViewFrameBuffer(kRenderPassClearUav, BGFX_INVALID_HANDLE);
+					bgfx::setState(0);
+					bgfx::setImage(2, m_lightBufferTex, 0, bgfx::Access::ReadWrite, bgfx::TextureFormat::RGBA8);
+					bgfx::submit(kRenderPassClearUav, m_clearUavProgram);
 				}
 
 				// Draw lights into light buffer.
@@ -786,6 +809,9 @@ public:
 						else if (bgfx::isValid(m_lightUavProgram)
 							 &&  m_useUav)
 						{
+							bgfx::setViewFrameBuffer(kRenderPassLight, BGFX_INVALID_HANDLE);
+							bgfx::setState(0);
+							bgfx::setImage(3, m_lightBufferTex, 0, bgfx::Access::ReadWrite, bgfx::TextureFormat::RGBA8);
 							bgfx::submit(kRenderPassLight, m_lightUavProgram);
 						}
 						else

+ 2 - 3
examples/21-deferred/fs_deferred_clear_uav.sc

@@ -5,13 +5,12 @@ $input v_texcoord0
  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  */
 
-#include "common.sh"
 #include <bgfx_compute.sh>
 
-FRAMEBUFFER_IMAGE2D_RW(s_light, rgba8, 0);
+IMAGE2D_RW(i_light, rgba8, 2);
 
 void main()
 {
     ivec2 coord = ivec2(gl_FragCoord.xy);
-    imageStore(s_light, coord, vec4(0.0, 0.0, 0.0, 0.0));
+    imageStore(i_light, coord, vec4(0.0, 0.0, 0.0, 0.0));
 }

+ 3 - 3
examples/21-deferred/fs_deferred_light_uav.sc

@@ -11,7 +11,7 @@ $input v_texcoord0
 SAMPLER2D(s_normal, 0);
 SAMPLER2D(s_depth,  1);
 
-FRAMEBUFFER_IMAGE2D_RW(s_light, rgba8, 0);
+IMAGE2D_RW(i_light, rgba8, 3);
 
 uniform vec4 u_lightPosRadius[1];
 uniform vec4 u_lightRgbInnerR[1];
@@ -35,6 +35,6 @@ void main()
     ivec2 coord = ivec2(gl_FragCoord.xy);
 
 	vec3 lightColor = calcLight(wpos, normal, view, u_lightPosRadius[0].xyz, u_lightPosRadius[0].w, u_lightRgbInnerR[0].xyz, u_lightRgbInnerR[0].w);
-    vec4 color = imageLoad(s_light, coord);
-    imageStore(s_light, coord, color + vec4(toGamma(lightColor.xyz), 1.0));
+	vec4 color = imageLoad(i_light, coord);
+	imageStore(i_light, coord, color + vec4(toGamma(lightColor.xyz), 1.0));
 }

+ 4 - 2
include/bgfx/bgfx.h

@@ -799,8 +799,10 @@ namespace bgfx
 		///   - `BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB` - Texture as sRGB format is supported.
 		///   - `BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED` - Texture format is emulated.
 		///   - `BGFX_CAPS_FORMAT_TEXTURE_VERTEX` - Texture format can be used from vertex shader.
-		///   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE` - Texture format can be used as image from compute
-		///     shader.
+		///   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ` - Texture format can be used as image
+		///     and read from.
+		///   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE` - Texture format can be used as image
+		///     and written to.
 		///   - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER` - Texture format can be used as frame
 		///     buffer.
 		///   - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA` - Texture format can be used as MSAA

+ 4 - 2
include/bgfx/c99/bgfx.h

@@ -554,8 +554,10 @@ typedef struct bgfx_caps_s
      *   - `BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB` - Texture as sRGB format is supported.
      *   - `BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED` - Texture format is emulated.
      *   - `BGFX_CAPS_FORMAT_TEXTURE_VERTEX` - Texture format can be used from vertex shader.
-     *   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE` - Texture format can be used as image from compute
-     *     shader.
+     *   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ` - Texture format can be used as image
+     *     and read from.
+     *   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE` - Texture format can be used as image
+     *     and written to.
      *   - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER` - Texture format can be used as frame
      *     buffer.
      *   - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA` - Texture format can be used as MSAA

+ 18 - 17
include/bgfx/defines.h

@@ -468,7 +468,7 @@
 #define BGFX_CAPS_DRAW_INDIRECT             UINT64_C(0x0000000000000010) //!< Draw indirect is supported.
 #define BGFX_CAPS_FRAGMENT_DEPTH            UINT64_C(0x0000000000000020) //!< Fragment depth is accessible in fragment shader.
 #define BGFX_CAPS_FRAGMENT_ORDERING         UINT64_C(0x0000000000000040) //!< Fragment ordering is available in fragment shader.
-#define BGFX_CAPS_FRAMEBUFFER_RW            UINT64_C(0x0000000000000080) //!< Read/Write frame buffer attachments are supported.
+#define BGFX_CAPS_IMAGE_RW                  UINT64_C(0x0000000000000080) //!< Image Read/Write is supported.
 #define BGFX_CAPS_GRAPHICS_DEBUGGER         UINT64_C(0x0000000000000100) //!< Graphics debugger is present.
 #define BGFX_CAPS_RESERVED                  UINT64_C(0x0000000000000200)
 #define BGFX_CAPS_HDR10                     UINT64_C(0x0000000000000400) //!< HDR10 rendering is supported.
@@ -496,22 +496,23 @@
 	)
 
 
-#define BGFX_CAPS_FORMAT_TEXTURE_NONE       UINT16_C(0x0000) //!< Texture format is not supported.
-#define BGFX_CAPS_FORMAT_TEXTURE_2D         UINT16_C(0x0001) //!< Texture format is supported.
-#define BGFX_CAPS_FORMAT_TEXTURE_2D_SRGB    UINT16_C(0x0002) //!< Texture as sRGB format is supported.
-#define BGFX_CAPS_FORMAT_TEXTURE_2D_EMULATED UINT16_C(0x0004) //!< Texture format is emulated.
-#define BGFX_CAPS_FORMAT_TEXTURE_3D         UINT16_C(0x0008) //!< Texture format is supported.
-#define BGFX_CAPS_FORMAT_TEXTURE_3D_SRGB    UINT16_C(0x0010) //!< Texture as sRGB format is supported.
-#define BGFX_CAPS_FORMAT_TEXTURE_3D_EMULATED UINT16_C(0x0020) //!< Texture format is emulated.
-#define BGFX_CAPS_FORMAT_TEXTURE_CUBE       UINT16_C(0x0040) //!< Texture format is supported.
-#define BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB  UINT16_C(0x0080) //!< Texture as sRGB format is supported.
-#define BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED UINT16_C(0x0100) //!< Texture format is emulated.
-#define BGFX_CAPS_FORMAT_TEXTURE_VERTEX     UINT16_C(0x0200) //!< Texture format can be used from vertex shader.
-#define BGFX_CAPS_FORMAT_TEXTURE_IMAGE      UINT16_C(0x0400) //!< Texture format can be used as image from compute shader.
-#define BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER UINT16_C(0x0800) //!< Texture format can be used as frame buffer.
-#define BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA UINT16_C(0x1000) //!< Texture format can be used as MSAA frame buffer.
-#define BGFX_CAPS_FORMAT_TEXTURE_MSAA       UINT16_C(0x2000) //!< Texture can be sampled as MSAA.
-#define BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN UINT16_C(0x4000) //!< Texture format supports auto-generated mips.
+#define BGFX_CAPS_FORMAT_TEXTURE_NONE       UINT32_C(0x00000000) //!< Texture format is not supported.
+#define BGFX_CAPS_FORMAT_TEXTURE_2D         UINT32_C(0x00000001) //!< Texture format is supported.
+#define BGFX_CAPS_FORMAT_TEXTURE_2D_SRGB    UINT32_C(0x00000002) //!< Texture as sRGB format is supported.
+#define BGFX_CAPS_FORMAT_TEXTURE_2D_EMULATED UINT32_C(0x00000004) //!< Texture format is emulated.
+#define BGFX_CAPS_FORMAT_TEXTURE_3D         UINT32_C(0x00000008) //!< Texture format is supported.
+#define BGFX_CAPS_FORMAT_TEXTURE_3D_SRGB    UINT32_C(0x00000010) //!< Texture as sRGB format is supported.
+#define BGFX_CAPS_FORMAT_TEXTURE_3D_EMULATED UINT32_C(0x00000020) //!< Texture format is emulated.
+#define BGFX_CAPS_FORMAT_TEXTURE_CUBE       UINT32_C(0x00000040) //!< Texture format is supported.
+#define BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB  UINT32_C(0x00000080) //!< Texture as sRGB format is supported.
+#define BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED UINT32_C(0x00000100) //!< Texture format is emulated.
+#define BGFX_CAPS_FORMAT_TEXTURE_VERTEX     UINT32_C(0x00000200) //!< Texture format can be used from vertex shader.
+#define BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ UINT32_C(0x00000400) //!< Texture format can be used as image and read from.
+#define BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE UINT32_C(0x00000800) //!< Texture format can be used as image and written to.
+#define BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER UINT32_C(0x00001000) //!< Texture format can be used as frame buffer.
+#define BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA UINT32_C(0x00002000) //!< Texture format can be used as MSAA frame buffer.
+#define BGFX_CAPS_FORMAT_TEXTURE_MSAA       UINT32_C(0x00004000) //!< Texture can be sampled as MSAA.
+#define BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN UINT32_C(0x00008000) //!< Texture format supports auto-generated mips.
 
 #define BGFX_RESOLVE_NONE                   UINT8_C(0x00) //!< No resolve flags.
 #define BGFX_RESOLVE_AUTO_GEN_MIPS          UINT8_C(0x01) //!< Auto-generate mip maps on resolve.

+ 8 - 5
scripts/bgfx.idl

@@ -371,7 +371,7 @@ flag.Caps { bits = 64, base = 1, name = "Caps" }
 	.DrawIndirect           --- Draw indirect is supported.
 	.FragmentDepth          --- Fragment depth is accessible in fragment shader.
 	.FragmentOrdering       --- Fragment ordering is available in fragment shader.
-	.FramebufferRw          --- Read/Write frame buffer attachments are supported.
+	.ImageRw                --- Image Read/Write is supported.
 	.GraphicsDebugger       --- Graphics debugger is present.
 	.Reserved
 	.Hdr10                  --- HDR10 rendering is supported.
@@ -395,7 +395,7 @@ flag.Caps { bits = 64, base = 1, name = "Caps" }
 	.TextureCompareAll { "TextureCompareReserved", "TextureCompareLequal" } --- All texture compare modes are supported.
 	()
 
-flag.CapsFormat { bits = 16 }
+flag.CapsFormat { bits = 32 }
 	.TextureNone             --- Texture format is not supported.
 	.Texture_2d              --- Texture format is supported.
 	.Texture_2dSrgb          --- Texture as sRGB format is supported.
@@ -407,7 +407,8 @@ flag.CapsFormat { bits = 16 }
 	.TextureCubeSrgb         --- Texture as sRGB format is supported.
 	.TextureCubeEmulated     --- Texture format is emulated.
 	.TextureVertex           --- Texture format can be used from vertex shader.
-	.TextureImage            --- Texture format can be used as image from compute shader.
+	.TextureImageRead        --- Texture format can be used as image and read from.
+	.TextureImageWrite       --- Texture format can be used as image and written to.
 	.TextureFramebuffer      --- Texture format can be used as frame buffer.
 	.TextureFramebufferMsaa  --- Texture format can be used as MSAA frame buffer.
 	.TextureMsaa             --- Texture can be sampled as MSAA.
@@ -728,8 +729,10 @@ struct.Caps
 		---   - `BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB` - Texture as sRGB format is supported.
 		---   - `BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED` - Texture format is emulated.
 		---   - `BGFX_CAPS_FORMAT_TEXTURE_VERTEX` - Texture format can be used from vertex shader.
-		---   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE` - Texture format can be used as image from compute
-		---     shader.
+		---   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ` - Texture format can be used as image
+		---     and read from.
+		---   - `BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE` - Texture format can be used as image
+		---     and written to.
 		---   - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER` - Texture format can be used as frame
 		---     buffer.
 		---   - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA` - Texture format can be used as MSAA

+ 4 - 3
src/bgfx.cpp

@@ -1637,7 +1637,7 @@ namespace bgfx
 		BX_TRACE("\t ||||+------------ Cube: x = supported / * = emulated");
 		BX_TRACE("\t |||||+----------- Cube: sRGB format");
 		BX_TRACE("\t ||||||+---------- vertex format");
-		BX_TRACE("\t |||||||+--------- image");
+		BX_TRACE("\t |||||||+--------- image: i = read-write / r = read / w = write");
 		BX_TRACE("\t ||||||||+-------- framebuffer");
 		BX_TRACE("\t |||||||||+------- MSAA framebuffer");
 		BX_TRACE("\t ||||||||||+------ MSAA texture");
@@ -1648,7 +1648,7 @@ namespace bgfx
 			if (TextureFormat::Unknown != ii
 			&&  TextureFormat::UnknownDepth != ii)
 			{
-				uint16_t flags = g_caps.formats[ii];
+				uint32_t flags = g_caps.formats[ii];
 				BX_TRACE("\t[%c%c%c%c%c%c%c%c%c%c%c%c] %s"
 					, flags&BGFX_CAPS_FORMAT_TEXTURE_2D               ? 'x' : flags&BGFX_CAPS_FORMAT_TEXTURE_2D_EMULATED ? '*' : ' '
 					, flags&BGFX_CAPS_FORMAT_TEXTURE_2D_SRGB          ? 'l' : ' '
@@ -1657,7 +1657,8 @@ namespace bgfx
 					, flags&BGFX_CAPS_FORMAT_TEXTURE_CUBE             ? 'x' : flags&BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED ? '*' : ' '
 					, flags&BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB        ? 'l' : ' '
 					, flags&BGFX_CAPS_FORMAT_TEXTURE_VERTEX           ? 'v' : ' '
-					, flags&BGFX_CAPS_FORMAT_TEXTURE_IMAGE            ? 'i' : ' '
+					, (flags&BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ) &&
+					  (flags&BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE)    ? 'i' : flags&BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ ? 'r' : flags&BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE ? 'w' : ' '
 					, flags&BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER      ? 'f' : ' '
 					, flags&BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA ? '+' : ' '
 					, flags&BGFX_CAPS_FORMAT_TEXTURE_MSAA             ? 'm' : ' '

+ 10 - 18
src/bgfx_compute.sh

@@ -10,19 +10,11 @@
 
 #ifndef __cplusplus
 
-#if BGFX_SHADER_LANGUAGE_GLSL
-#	define FRAMEBUFFER_IMAGE2D_RW_0(_name, _format) IMAGE2D_RW(_name, _format, 4)
-#	define FRAMEBUFFER_IMAGE2D_RW_1(_name, _format) IMAGE2D_RW(_name, _format, 5)
-#	define FRAMEBUFFER_IMAGE2D_RW_2(_name, _format) IMAGE2D_RW(_name, _format, 6)
-#	define FRAMEBUFFER_IMAGE2D_RW_3(_name, _format) IMAGE2D_RW(_name, _format, 7)
+#if BGFX_SHADER_LANGUAGE_METAL || BGFX_SHADER_LANGUAGE_SPIRV
+#	define ANNOTATION(_format) [[spv::format_ ## _format]]
 #else
-#	define FRAMEBUFFER_IMAGE2D_RW_0(_name, _format) IMAGE2D_RW(_name, _format, 16)
-#	define FRAMEBUFFER_IMAGE2D_RW_1(_name, _format) IMAGE2D_RW(_name, _format, 17)
-#	define FRAMEBUFFER_IMAGE2D_RW_2(_name, _format) IMAGE2D_RW(_name, _format, 18)
-#	define FRAMEBUFFER_IMAGE2D_RW_3(_name, _format) IMAGE2D_RW(_name, _format, 19)
-#endif // BGFX_SHADER_LANGUAGE_GLSL
-
-#define FRAMEBUFFER_IMAGE2D_RW(_name, _format, _reg) FRAMEBUFFER_IMAGE2D_RW_ ## _reg(_name, _format)
+#	define ANNOTATION(_format)
+#endif
 
 #if BGFX_SHADER_LANGUAGE_GLSL
 
@@ -103,7 +95,7 @@
 #define UIMAGE2D_RO(_name, _format, _reg) IMAGE2D_RO(_name, _format, _reg)
 
 #define IMAGE2D_RW( _name, _format, _reg)                       \
-	RWTexture2D<_format> _name ## Texture : REGISTER(u, _reg);  \
+	ANNOTATION(_format) RWTexture2D<_format> _name ## Texture : REGISTER(u, _reg);  \
 	static BgfxRWImage2D_ ## _format _name = { _name ## Texture }
 
 #define IMAGE2D_WR( _name, _format, _reg) IMAGE2D_RW(_name, _format, _reg)
@@ -117,7 +109,7 @@
 #define UIMAGE2D_ARRAY_RO(_name, _format, _reg) IMAGE2D_ARRAY_RO(_name, _format, _reg)
 
 #define IMAGE2D_ARRAY_RW(_name, _format, _reg)                         \
-	RWTexture2DArray<_format> _name ## Texture : REGISTER(u, _reg);    \
+	ANNOTATION(_format) RWTexture2DArray<_format> _name ## Texture : REGISTER(u, _reg);    \
 	static BgfxRWImage2DArray_ ## _format _name = { _name ## Texture }
 
 #define UIMAGE2D_ARRAY_RW(_name, _format, _reg) IMAGE2D_ARRAY_RW(_name, _format, _reg)
@@ -131,7 +123,7 @@
 #define UIMAGE3D_RO(_name, _format, _reg) IMAGE3D_RO(_name, _format, _reg)
 
 #define IMAGE3D_RW( _name, _format, _reg)                       \
-	RWTexture3D<_format> _name ## Texture : REGISTER(u, _reg);  \
+	ANNOTATION(_format) RWTexture3D<_format> _name ## Texture : REGISTER(u, _reg);  \
 	static BgfxRWImage3D_ ## _format _name = { _name ## Texture }
 
 #define UIMAGE3D_RW(_name, _format, _reg) IMAGE3D_RW(_name, _format, _reg)
@@ -159,7 +151,7 @@
 	\
 	struct BgfxRWImage2D_ ## _format                                      \
 	{                                                                     \
-		RWTexture2D<_format> m_texture;                                   \
+		ANNOTATION(_format) RWTexture2D<_format> m_texture;               \
 	};                                                                    \
 	\
 	struct BgfxROImage2DArray_ ## _format                                 \
@@ -169,7 +161,7 @@
 	\
 	struct BgfxRWImage2DArray_ ## _format                                 \
 	{                                                                     \
-		RWTexture2DArray<_format> m_texture;                              \
+		ANNOTATION(_format) RWTexture2DArray<_format> m_texture;          \
 	};                                                                    \
 	\
 	struct BgfxROImage3D_ ## _format                                      \
@@ -179,7 +171,7 @@
 	\
 	struct BgfxRWImage3D_ ## _format                                      \
 	{                                                                     \
-		RWTexture3D<_format> m_texture;                                   \
+		ANNOTATION(_format) RWTexture3D<_format> m_texture;               \
 	};                                                                    \
 
 #define __IMAGE_IMPL_A(_format, _storeComponents, _type, _loadComponents)            \

+ 3 - 2
src/bgfx_shader.sh

@@ -50,9 +50,10 @@
 #	define bvec3 bool3
 #	define bvec4 bool4
 
-
+// To be able to patch the uav registers on the DXBC SPDB Chunk (D3D11 renderer) the whitespaces around
+// '_type[_reg]' are necessary. This only affects shaders with debug info (i.e., those that have the SPDB Chunk).
 #	if BGFX_SHADER_LANGUAGE_HLSL > 4
-#		define REGISTER(_type, _reg) register(_type[_reg])
+#		define REGISTER(_type, _reg) register( _type[_reg] )
 #	else
 #		define REGISTER(_type, _reg) register(_type ## _reg)
 #	endif // BGFX_SHADER_LANGUAGE_HLSL

+ 195 - 24
src/renderer_d3d11.cpp

@@ -1204,7 +1204,7 @@ namespace bgfx { namespace d3d11
 					| BGFX_CAPS_TEXTURE_2D_ARRAY
 					| BGFX_CAPS_TEXTURE_CUBE_ARRAY
 					| ((m_featureLevel >= D3D_FEATURE_LEVEL_11_1)
-						? BGFX_CAPS_FRAMEBUFFER_RW
+						? BGFX_CAPS_IMAGE_RW
 						: 0)
 					);
 
@@ -1388,7 +1388,7 @@ namespace bgfx { namespace d3d11
 								support |= 0 != (data.OutFormatSupport & (0
 										| D3D11_FORMAT_SUPPORT_SHADER_LOAD
 										) )
-										? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+										? BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ
 										: BGFX_CAPS_FORMAT_TEXTURE_NONE
 										;
 
@@ -1430,10 +1430,10 @@ namespace bgfx { namespace d3d11
 									);
 							}
 
-							if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_IMAGE) )
+							if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ) )
 							{
 								// clear image flag for additional testing
-								support &= ~BGFX_CAPS_FORMAT_TEXTURE_IMAGE;
+								support &= ~BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ;
 
 								data.InFormat = s_textureFormat[ii].m_fmt;
 								hr = m_device->CheckFeatureSupport(D3D11_FEATURE_FORMAT_SUPPORT2, &data, sizeof(data) );
@@ -1441,9 +1441,15 @@ namespace bgfx { namespace d3d11
 								{
 									support |= 0 != (data.OutFormatSupport & (0
 											| D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD
+											) )
+											? BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ
+											: BGFX_CAPS_FORMAT_TEXTURE_NONE
+											;
+
+									support |= 0 != (data.OutFormatSupport & (0
 											| D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE
 											) )
-											? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+											? BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE
 											: BGFX_CAPS_FORMAT_TEXTURE_NONE
 											;
 								}
@@ -1455,12 +1461,12 @@ namespace bgfx { namespace d3d11
 								| BGFX_CAPS_FORMAT_TEXTURE_2D
 								| BGFX_CAPS_FORMAT_TEXTURE_3D
 								| BGFX_CAPS_FORMAT_TEXTURE_CUBE
-								| BGFX_CAPS_FORMAT_TEXTURE_IMAGE
 								| BGFX_CAPS_FORMAT_TEXTURE_VERTEX
-								| BGFX_CAPS_FORMAT_TEXTURE_IMAGE
 								| BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER
 								| BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA
 								| BGFX_CAPS_FORMAT_TEXTURE_MSAA
+								| BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ
+								| BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE
 								;
 						}
 					}
@@ -3022,8 +3028,41 @@ namespace bgfx { namespace d3d11
 			return _visible == (0 != _render->m_occlusion[_handle.idx]);
 		}
 
+		void quietValidation()
+		{
+			const uint32_t maxTextureSamplers = g_caps.limits.maxTextureSamplers;
+
+			// vertex texture fetch not supported on 9_1 through 9_3
+			if (m_featureLevel > D3D_FEATURE_LEVEL_9_3)
+			{
+					m_deviceCtx->VSSetShaderResources(0, maxTextureSamplers, s_zero.m_srv);
+					m_deviceCtx->VSSetSamplers(0, maxTextureSamplers, s_zero.m_sampler);
+			}
+
+			if (m_featureLevel > D3D_FEATURE_LEVEL_11_0)
+			{
+					m_deviceCtx->OMSetRenderTargetsAndUnorderedAccessViews(
+						D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL
+						, NULL
+						, NULL
+						, 16
+						, maxTextureSamplers
+						, s_zero.m_uav
+						, NULL
+					);
+			}
+
+			m_deviceCtx->PSSetShaderResources(0, maxTextureSamplers, s_zero.m_srv);
+			m_deviceCtx->PSSetSamplers(0, maxTextureSamplers, s_zero.m_sampler);
+		}
+
 		void commitTextureStage()
 		{
+			if (BX_ENABLED(BGFX_CONFIG_DEBUG))
+			{
+				quietValidation();
+			}
+
 			const uint32_t maxTextureSamplers = g_caps.limits.maxTextureSamplers;
 
 			// vertex texture fetch not supported on 9_1 through 9_3
@@ -3033,6 +3072,19 @@ namespace bgfx { namespace d3d11
 				m_deviceCtx->VSSetSamplers(0, maxTextureSamplers, m_textureStage.m_sampler);
 			}
 
+			if (m_featureLevel > D3D_FEATURE_LEVEL_11_0)
+			{
+				m_deviceCtx->OMSetRenderTargetsAndUnorderedAccessViews(
+					D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL
+					, NULL
+					, NULL
+					, 16
+					, maxTextureSamplers
+					, m_textureStage.m_uav
+					, NULL
+					);
+			}
+
 			m_deviceCtx->PSSetShaderResources(0, maxTextureSamplers, m_textureStage.m_srv);
 			m_deviceCtx->PSSetSamplers(0, maxTextureSamplers, m_textureStage.m_sampler);
 		}
@@ -3909,6 +3961,88 @@ namespace bgfx { namespace d3d11
 		return find.m_found;
 	}
 
+	static void patchUAVRegisterByteCode(DxbcInstruction& _instruction, void* _userData)
+	{
+		union { void* ptr; uint32_t offset; } cast = { _userData };
+
+		switch (_instruction.opcode)
+		{
+		case DxbcOpcode::DCL_UNORDERED_ACCESS_VIEW_TYPED:
+			{
+				DxbcOperand& operand = _instruction.operand[0];
+				operand.regIndex[0] += 16;
+
+				BX_ASSERT(operand.regIndex[1] == 0 && operand.regIndex[2] == 0
+					, "Unexpected values");
+			}
+			break;
+		case DxbcOpcode::DCL_UNORDERED_ACCESS_VIEW_RAW:
+			{
+				BX_ASSERT(false, "Unsupported UAV access");
+			}
+			break;
+		case DxbcOpcode::DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
+			{
+				BX_ASSERT(false, "Unsupported UAV access");
+			}
+			break;
+		case DxbcOpcode::LD_UAV_TYPED:
+			{
+				DxbcOperand& operand = _instruction.operand[2];
+				operand.regIndex[0] += 16;
+
+				BX_ASSERT(operand.regIndex[1] == 0 && operand.regIndex[2] == 0
+					, "Unexpected values");
+			}
+			break;
+		case DxbcOpcode::STORE_UAV_TYPED:
+			{
+				DxbcOperand& operand = _instruction.operand[0];
+				operand.regIndex[0] += 16;
+
+				BX_ASSERT(operand.regIndex[1] == 0 && operand.regIndex[2] == 0
+					, "Unexpected values");
+			}
+			break;
+		}
+	}
+
+	static void patchUAVRegisterDebugInfo(DxbcSPDB& _spdb)
+	{
+		if (!_spdb.debugCode.empty())
+		{
+			// 'register( u[xx] )'
+			char* ptr = (char*)_spdb.debugCode.data();
+			while (ptr < (char*)_spdb.debugCode.data() + _spdb.debugCode.size() - 3)
+			{
+				if (*(ptr+1) == ' '
+				&&	*(ptr+2) == 'u'
+				&&	*(ptr+3) == '[')
+				{
+					char* startPtr = ptr+4;
+					char* endPtr = ptr+4;
+
+					while (*endPtr != ']')
+					{
+						endPtr++;
+					}
+
+					uint32_t regNum = 0;
+					uint32_t regLen = endPtr - startPtr;
+					bx::fromString(&regNum, bx::StringView(startPtr, regLen));
+
+					regNum += 16;
+					uint32_t len = bx::toString(startPtr, regLen+2, regNum);
+					*(startPtr + len) = ']';
+
+					break;
+				}
+
+				++ptr;
+			}
+		}
+	}
+
 	void ShaderD3D11::create(const Memory* _mem)
 	{
 		bx::MemoryReader reader(_mem->data, _mem->size);
@@ -4029,6 +4163,33 @@ namespace bgfx { namespace d3d11
 		const void* code = reader.getDataPtr();
 		bx::skip(&reader, shaderSize+1);
 
+		const Memory* temp = NULL;
+
+		if (!isShaderType(magic, 'C'))
+		{
+			bx::MemoryReader rd(code, shaderSize);
+
+			DxbcContext dxbc;
+			bx::Error err;
+			read(&rd, dxbc, &err);
+
+			bool patchShader = !dxbc.shader.aon9;
+			if (patchShader)
+			{
+				union { uint32_t offset; void* ptr; } cast = { 0 };
+				filter(dxbc.shader, dxbc.shader, patchUAVRegisterByteCode, cast.ptr);
+				patchUAVRegisterDebugInfo(dxbc.spdb);
+
+				temp = alloc(shaderSize);
+				bx::StaticMemoryBlockWriter wr(temp->data, temp->size);
+
+				int32_t size = write(&wr, dxbc, &err);
+				dxbcHash(temp->data + 20, size - 20, temp->data + 4);
+
+				code = temp->data;
+			}
+		}
+
 		if (isShaderType(magic, 'F') )
 		{
 			m_hasDepthOp = hasDepthOp(code, shaderSize);
@@ -4083,6 +4244,11 @@ namespace bgfx { namespace d3d11
 
 			BX_TRACE("\tCB size: %d", desc.ByteWidth);
 		}
+
+		if (NULL != temp)
+		{
+			release(temp);
+		}
 	}
 
 	void* DirectAccessResourceD3D11::createTexture2D(const D3D11_TEXTURE2D_DESC* _gpuDesc, const D3D11_SUBRESOURCE_DATA* _srd, ID3D11Texture2D** _gpuTexture2d)
@@ -5024,23 +5190,7 @@ namespace bgfx { namespace d3d11
 
 	void FrameBufferD3D11::set()
 	{
-		if (0 < m_numUav)
-		{
-			s_renderD3D11->m_deviceCtx->OMSetRenderTargetsAndUnorderedAccessViews(
-				  m_num
-				, m_rtv
-				, m_dsv
-				, 16
-				, m_numUav
-				, m_uav
-				, NULL
-				);
-		}
-		else
-		{
-			s_renderD3D11->m_deviceCtx->OMSetRenderTargets(m_num, m_rtv, m_dsv);
-		}
-
+		s_renderD3D11->m_deviceCtx->OMSetRenderTargets(m_num, m_rtv, m_dsv);
 		m_needPresent = UINT16_MAX != m_denseIdx;
 		s_renderD3D11->m_currentColor        = m_rtv[0];
 		s_renderD3D11->m_currentDepthStencil = m_dsv;
@@ -5622,6 +5772,7 @@ namespace bgfx { namespace d3d11
 						{
 							m_textureStage.m_srv[stage]     = NULL;
 							m_textureStage.m_sampler[stage] = NULL;
+							m_textureStage.m_uav[stage]     = NULL;
 						}
 					}
 
@@ -5902,6 +6053,24 @@ namespace bgfx { namespace d3d11
 							{
 								switch (bind.m_type)
 								{
+								case Binding::Image:
+									{
+										TextureD3D11& texture = m_textures[bind.m_idx];
+										if (Access::Read != bind.m_access)
+										{
+											m_textureStage.m_uav[stage] = 0 == bind.m_mip
+												? texture.m_uav
+												: s_renderD3D11->getCachedUav(texture.getHandle(), bind.m_mip)
+												;
+										}
+										else
+										{
+											m_textureStage.m_srv[stage]     = s_renderD3D11->getCachedSrv(texture.getHandle(), bind.m_mip, true);
+											m_textureStage.m_sampler[stage] = s_renderD3D11->getSamplerState(uint32_t(texture.m_flags), NULL);
+										}
+									}
+									break;
+
 								case Binding::Texture:
 									{
 										TextureD3D11& texture = m_textures[bind.m_idx];
@@ -5918,6 +6087,7 @@ namespace bgfx { namespace d3d11
 											;
 										m_textureStage.m_srv[stage] = buffer.m_srv;
 										m_textureStage.m_sampler[stage] = NULL;
+										m_textureStage.m_uav[stage]     = NULL;
 									}
 									break;
 								}
@@ -5926,6 +6096,7 @@ namespace bgfx { namespace d3d11
 							{
 								m_textureStage.m_srv[stage]     = NULL;
 								m_textureStage.m_sampler[stage] = NULL;
+								m_textureStage.m_uav[stage]     = NULL;
 							}
 
 							++changes;

+ 42 - 10
src/renderer_d3d12.cpp

@@ -503,7 +503,7 @@ namespace bgfx { namespace d3d12
 
 	ID3D12Resource* createCommittedResource(ID3D12Device* _device, HeapProperty::Enum _heapProperty, uint64_t _size, D3D12_RESOURCE_FLAGS _flags = D3D12_RESOURCE_FLAG_NONE)
 	{
-		D3D12_RESOURCE_DESC resourceDesc;
+		D3D12_RESOURCE_DESC resourceDesc = {};
 		resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
 		resourceDesc.Alignment = 0;
 		resourceDesc.Width     = _size;
@@ -795,7 +795,12 @@ namespace bgfx { namespace d3d12
 								if (SUCCEEDED(hr))
 								{
 //									debug1->SetEnableGPUBasedValidation(true);
-//									debug1->SetEnableSynchronizedCommandQueueValidation(true);
+
+									// https://discordapp.com/channels/590611987420020747/593519198995742733/703642988345032804
+									// D3D12 Bug Number: 26131261
+									// There is a bug in the D3D12 validation that causes example-21 to fail when using UAV
+									// Setting this function below to false avoids the bug
+									debug1->SetEnableSynchronizedCommandQueueValidation(false);
 								}
 
 								DX_RELEASE(debug1, 1);
@@ -1157,6 +1162,7 @@ namespace bgfx { namespace d3d12
 					| BGFX_CAPS_ALPHA_TO_COVERAGE
 					| BGFX_CAPS_TEXTURE_2D_ARRAY
 					| BGFX_CAPS_TEXTURE_CUBE_ARRAY
+					| BGFX_CAPS_IMAGE_RW
 					);
 				g_caps.limits.maxTextureSize     = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
 				g_caps.limits.maxTextureLayers   = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
@@ -1214,7 +1220,7 @@ namespace bgfx { namespace d3d12
 							support |= 0 != (data.Support1 & (0
 									| D3D12_FORMAT_SUPPORT1_SHADER_LOAD
 									) )
-									? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+									? BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ
 									: BGFX_CAPS_FORMAT_TEXTURE_NONE
 									;
 
@@ -1245,10 +1251,10 @@ namespace bgfx { namespace d3d12
 							BX_TRACE("CheckFeatureSupport failed with %x for format %s.", hr, getName(TextureFormat::Enum(ii) ) );
 						}
 
-						if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_IMAGE) )
+						if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ) )
 						{
 							// clear image flag for additional testing
-							support &= ~BGFX_CAPS_FORMAT_TEXTURE_IMAGE;
+							support &= ~BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ;
 
 							data.Format = s_textureFormat[ii].m_fmt;
 							hr = m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &data, sizeof(data) );
@@ -1256,9 +1262,15 @@ namespace bgfx { namespace d3d12
 							{
 								support |= 0 != (data.Support2 & (0
 										| D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD
+										) )
+										? BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ
+										: BGFX_CAPS_FORMAT_TEXTURE_NONE
+										;
+
+								support |= 0 != (data.Support2 & (0
 										| D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE
 										) )
-										? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+										? BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE
 										: BGFX_CAPS_FORMAT_TEXTURE_NONE
 										;
 							}
@@ -2913,7 +2925,7 @@ namespace bgfx { namespace d3d12
 					union { uint32_t offset; void* ptr; } cast = { 0 };
 					filter(dxbc.shader, dxbc.shader, patchCb0, cast.ptr);
 
-					temp = alloc(uint32_t(dxbc.shader.byteCode.size() )+1024);
+					temp = alloc(uint32_t(dxbc.header.size));
 					bx::StaticMemoryBlockWriter wr(temp->data, temp->size);
 
 					int32_t size = write(&wr, dxbc, &err);
@@ -2950,7 +2962,7 @@ namespace bgfx { namespace d3d12
 					};
 					filter(dxbc.shader, dxbc.shader, patchCb0, cast.ptr);
 
-					temp = alloc(uint32_t(dxbc.shader.byteCode.size() )+1024);
+					temp = alloc(uint32_t(dxbc.header.size));
 					bx::StaticMemoryBlockWriter wr(temp->data, temp->size);
 
 					int32_t size = write(&wr, dxbc, &err);
@@ -6491,8 +6503,8 @@ namespace bgfx { namespace d3d12
 						if (NULL == bindCached)
 						{
 							uint32_t numSet = 0;
-							D3D12_GPU_DESCRIPTOR_HANDLE srvHandle[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
-							uint32_t samplerFlags[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
+							D3D12_GPU_DESCRIPTOR_HANDLE srvHandle[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS] = {};
+							uint32_t samplerFlags[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS] = {};
 							{
 								for (uint32_t stage = 0; stage < BGFX_CONFIG_MAX_TEXTURE_SAMPLERS; ++stage)
 								{
@@ -6501,6 +6513,26 @@ namespace bgfx { namespace d3d12
 									{
 										switch (bind.m_type)
 										{
+										case Binding::Image:
+											{
+												TextureD3D12& texture = m_textures[bind.m_idx];
+
+												if (Access::Read != bind.m_access)
+												{
+													texture.setState(m_commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+													scratchBuffer.allocUav(srvHandle[stage], texture, bind.m_mip);
+												}
+												else
+												{
+													texture.setState(m_commandList, D3D12_RESOURCE_STATE_GENERIC_READ);
+													scratchBuffer.allocSrv(srvHandle[stage], texture, bind.m_mip);
+													samplerFlags[stage] = uint32_t(texture.m_flags);
+												}
+
+												++numSet;
+											}
+											break;
+
 										case Binding::Texture:
 											{
 												TextureD3D12& texture = m_textures[bind.m_idx];

+ 23 - 34
src/renderer_gl.cpp

@@ -2629,7 +2629,7 @@ namespace bgfx { namespace gl
 
 					supported |= computeSupport
 						&& isImageFormatValid(fmt)
-						? BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+						? (BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ | BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE)
 						: BGFX_CAPS_FORMAT_TEXTURE_NONE
 						;
 
@@ -2893,7 +2893,7 @@ namespace bgfx { namespace gl
 					| (m_occlusionQuerySupport     ? BGFX_CAPS_OCCLUSION_QUERY        : 0)
 					| (m_depthTextureSupport       ? BGFX_CAPS_TEXTURE_COMPARE_LEQUAL : 0)
 					| (computeSupport              ? BGFX_CAPS_COMPUTE                : 0)
-					| (m_imageLoadStoreSupport     ? BGFX_CAPS_FRAMEBUFFER_RW         : 0)
+					| (m_imageLoadStoreSupport     ? BGFX_CAPS_IMAGE_RW               : 0)
 					;
 
 				g_caps.supported |= m_glctx.getCaps();
@@ -3696,8 +3696,6 @@ namespace bgfx { namespace gl
 					m_glctx.makeCurrent(NULL);
 					m_currentFbo = frameBuffer.m_fbo[0];
 				}
-
-				frameBuffer.set();
 			}
 
 			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_currentFbo) );
@@ -6847,36 +6845,6 @@ namespace bgfx { namespace gl
 		GL_CHECK(glInvalidateFramebuffer(GL_FRAMEBUFFER, idx, buffers) );
 	}
 
-	void FrameBufferGL::set()
-	{
-		for(uint32_t ii = 0; ii < m_numTh; ++ii)
-		{
-			const Attachment& at = m_attachment[ii];
-
-			if (at.access == Access::Write)
-			{
-				continue;
-			}
-
-			if (isValid(at.handle) )
-			{
-				const TextureGL& texture = s_renderGL->m_textures[at.handle.idx];
-
-				if (0 != (texture.m_flags&BGFX_TEXTURE_COMPUTE_WRITE) )
-				{
-					GL_CHECK(glBindImageTexture(ii
-						, texture.m_id
-						, at.mip
-						, GL_FALSE //texture.isLayered() ? GL_TRUE : GL_FALSE
-						, at.layer
-						, s_access[Access::ReadWrite]
-						, s_imageFormat[texture.m_textureFormat])
-						);
-				}
-			}
-		}
-	}
-
 	void OcclusionQueryGL::create()
 	{
 		for (uint32_t ii = 0; ii < BX_COUNTOF(m_query); ++ii)
@@ -7782,6 +7750,7 @@ namespace bgfx { namespace gl
 					viewState.setPredefined<1>(this, view, program, _render, draw);
 
 					{
+						GLbitfield barrier = 0;
 						for (uint32_t stage = 0; stage < BGFX_CONFIG_MAX_TEXTURE_SAMPLERS; ++stage)
 						{
 							const Binding& bind = renderBind.m_bind[stage];
@@ -7795,6 +7764,21 @@ namespace bgfx { namespace gl
 								{
 									switch (bind.m_type)
 									{
+									case Binding::Image:
+										{
+											const TextureGL& texture = m_textures[bind.m_idx];
+											GL_CHECK(glBindImageTexture(stage
+																		, texture.m_id
+																		, bind.m_mip
+																		, texture.isCubeMap() || texture.m_target == GL_TEXTURE_2D_ARRAY ? GL_TRUE : GL_FALSE
+																		, 0
+																		, s_access[bind.m_access]
+																		, s_imageFormat[bind.m_format])
+													);
+											barrier |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
+										}
+										break;
+
 									case Binding::Texture:
 										{
 											TextureGL& texture = m_textures[bind.m_idx];
@@ -7821,6 +7805,11 @@ namespace bgfx { namespace gl
 
 							current = bind;
 						}
+
+						if (0 != barrier)
+						{
+							GL_CHECK(glMemoryBarrier(barrier) );
+						}
 					}
 
 					{

+ 0 - 1
src/renderer_gl.h

@@ -1447,7 +1447,6 @@ namespace bgfx { namespace gl
 		uint16_t destroy();
 		void resolve();
 		void discard(uint16_t _flags);
-		void set();
 
 		SwapChainGL* m_swapChain;
 		GLuint m_fbo[2];

+ 2 - 1
src/renderer_noop.cpp

@@ -53,7 +53,8 @@ namespace bgfx { namespace noop
 					| BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB
 					| BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED
 					| BGFX_CAPS_FORMAT_TEXTURE_VERTEX
-					| BGFX_CAPS_FORMAT_TEXTURE_IMAGE
+					| BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ
+					| BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE
 					| BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER
 					| BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA
 					| BGFX_CAPS_FORMAT_TEXTURE_MSAA

+ 3 - 0
src/renderer_vk.cpp

@@ -1570,6 +1570,7 @@ VK_IMPORT_INSTANCE
 					| BGFX_CAPS_VERTEX_ATTRIB_HALF
 					| BGFX_CAPS_VERTEX_ATTRIB_UINT10
 					| BGFX_CAPS_VERTEX_ID
+					| BGFX_CAPS_IMAGE_RW
 					);
 
 				g_caps.limits.maxTextureSize     = m_deviceProperties.limits.maxImageDimension2D;
@@ -1607,6 +1608,8 @@ VK_IMPORT_INSTANCE
 						{ VK_IMAGE_TYPE_2D, VK_IMAGE_USAGE_SAMPLED_BIT,          VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, { BGFX_CAPS_FORMAT_TEXTURE_CUBE,        BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB   } },
 						{ VK_IMAGE_TYPE_2D, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0,                                   { BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER, BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER } },
 						{ VK_IMAGE_TYPE_2D, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0,                           { BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER, BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER } },
+						{ VK_IMAGE_TYPE_2D, VK_IMAGE_USAGE_STORAGE_BIT, 	     0,									  { BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ,  BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ  } },
+						{ VK_IMAGE_TYPE_2D, VK_IMAGE_USAGE_STORAGE_BIT, 	     0,									  { BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE, BGFX_CAPS_FORMAT_TEXTURE_IMAGE_WRITE } },
 					};
 
 					for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii)

+ 114 - 31
src/shader_dxbc.cpp

@@ -1851,6 +1851,9 @@ namespace bgfx
 #define DXBC_CHUNK_INPUT_SIGNATURE  BX_MAKEFOURCC('I', 'S', 'G', 'N')
 #define DXBC_CHUNK_OUTPUT_SIGNATURE BX_MAKEFOURCC('O', 'S', 'G', 'N')
 
+#define DXBC_CHUNK_SFI0             BX_MAKEFOURCC('S', 'F', 'I', '0')
+#define DXBC_CHUNK_SPDB             BX_MAKEFOURCC('S', 'P', 'D', 'B')
+
 	int32_t read(bx::ReaderSeekerI* _reader, DxbcContext& _dxbc, bx::Error* _err)
 	{
 		int32_t size = 0;
@@ -1869,6 +1872,7 @@ namespace bgfx
 
 			uint32_t fourcc;
 			size += bx::read(_reader, fourcc, _err);
+			_dxbc.chunksFourcc[ii] = fourcc;
 
 			uint32_t chunkSize;
 			size += bx::read(_reader, chunkSize, _err);
@@ -1898,11 +1902,21 @@ namespace bgfx
 				_dxbc.shader.aon9 = true;
 				break;
 
+			case DXBC_CHUNK_SFI0: // ?
+				BX_ASSERT(chunkSize == sizeof(_dxbc.sfi0.data),
+					"Unexpected size of SFI0 chunk");
+
+				size += bx::read(_reader, _dxbc.sfi0.data, _err);
+				break;
+
+			case DXBC_CHUNK_SPDB: // Shader debugging info (new).
+				_dxbc.spdb.debugCode.resize(chunkSize);
+				size += bx::read(_reader, _dxbc.spdb.debugCode.data(), chunkSize, _err);
+				break;
+
 			case BX_MAKEFOURCC('I', 'F', 'C', 'E'): // Interface.
 			case BX_MAKEFOURCC('R', 'D', 'E', 'F'): // Resource definition.
 			case BX_MAKEFOURCC('S', 'D', 'G', 'B'): // Shader debugging info (old).
-			case BX_MAKEFOURCC('S', 'P', 'D', 'B'): // Shader debugging info (new).
-			case BX_MAKEFOURCC('S', 'F', 'I', '0'): // ?
 			case BX_MAKEFOURCC('S', 'T', 'A', 'T'): // Statistics.
 			case BX_MAKEFOURCC('P', 'C', 'S', 'G'): // Patch constant signature.
 			case BX_MAKEFOURCC('P', 'S', 'O', '1'): // Pipeline State Object 1
@@ -1932,6 +1946,28 @@ namespace bgfx
 	{
 		int32_t size = 0;
 
+		uint32_t numSupportedChunks = 0;
+		for (uint32_t ii = 0; ii < _dxbc.header.numChunks; ++ii)
+		{
+			switch(_dxbc.chunksFourcc[ii])
+			{
+			case DXBC_CHUNK_SHADER_EX:
+			case DXBC_CHUNK_SHADER:
+			case BX_MAKEFOURCC('I', 'S', 'G', '1'):
+			case DXBC_CHUNK_INPUT_SIGNATURE:
+			case BX_MAKEFOURCC('O', 'S', 'G', '1'):
+			case BX_MAKEFOURCC('O', 'S', 'G', '5'):
+			case DXBC_CHUNK_OUTPUT_SIGNATURE:
+			case DXBC_CHUNK_SFI0:
+			case DXBC_CHUNK_SPDB:
+				++numSupportedChunks;
+				break;
+
+			default:
+				break;
+			}
+		}
+
 		int64_t dxbcOffset = bx::seek(_writer);
 		size += bx::write(_writer, DXBC_CHUNK_HEADER);
 
@@ -1942,35 +1978,82 @@ namespace bgfx
 		int64_t sizeOffset = bx::seek(_writer);
 		size += bx::writeRep(_writer, 0, 4, _err);
 
-		uint32_t numChunks = 3;
-		size += bx::write(_writer, numChunks, _err);
+		size += bx::write(_writer, numSupportedChunks, _err);
 
 		int64_t chunksOffsets = bx::seek(_writer);
-		size += bx::writeRep(_writer, 0, numChunks*sizeof(uint32_t), _err);
-
-		uint32_t chunkOffset[3];
-		uint32_t chunkSize[3];
-
-		chunkOffset[0] = uint32_t(bx::seek(_writer) - dxbcOffset);
-		size += write(_writer, DXBC_CHUNK_INPUT_SIGNATURE, _err);
-		size += write(_writer, UINT32_C(0), _err);
-		chunkSize[0] = write(_writer, _dxbc.inputSignature, _err);
-
-		chunkOffset[1] = uint32_t(bx::seek(_writer) - dxbcOffset);
-		size += write(_writer, DXBC_CHUNK_OUTPUT_SIGNATURE, _err);
-		size += write(_writer, UINT32_C(0), _err);
-		chunkSize[1] = write(_writer, _dxbc.outputSignature, _err);
-
-		chunkOffset[2] = uint32_t(bx::seek(_writer) - dxbcOffset);
-		size += write(_writer, _dxbc.shader.shex ? DXBC_CHUNK_SHADER_EX : DXBC_CHUNK_SHADER, _err);
-		size += write(_writer, UINT32_C(0), _err);
-		chunkSize[2] = write(_writer, _dxbc.shader, _err);
-
-		size += 0
-			+ chunkSize[0]
-			+ chunkSize[1]
-			+ chunkSize[2]
-			;
+		size += bx::writeRep(_writer, 0, numSupportedChunks*sizeof(uint32_t), _err);
+
+		uint32_t chunkOffset[DXBC_MAX_CHUNKS] = {};
+		uint32_t chunkSize[DXBC_MAX_CHUNKS] = {};
+
+		for (uint32_t ii = 0, idx = 0; ii < _dxbc.header.numChunks; ++ii)
+		{
+			switch (_dxbc.chunksFourcc[ii])
+			{
+			case DXBC_CHUNK_SHADER_EX:
+			case DXBC_CHUNK_SHADER:
+				chunkOffset[idx] = uint32_t(bx::seek(_writer) - dxbcOffset);
+				size += bx::write(_writer, _dxbc.shader.shex ? DXBC_CHUNK_SHADER_EX : DXBC_CHUNK_SHADER, _err);
+				size += bx::write(_writer, UINT32_C(0), _err);
+				chunkSize[idx] = write(_writer, _dxbc.shader, _err);
+				size += chunkSize[idx++];
+				break;
+
+			case BX_MAKEFOURCC('I', 'S', 'G', '1'):
+			case DXBC_CHUNK_INPUT_SIGNATURE:
+				chunkOffset[idx] = uint32_t(bx::seek(_writer) - dxbcOffset);
+				size += bx::write(_writer, DXBC_CHUNK_INPUT_SIGNATURE, _err);
+				size += bx::write(_writer, UINT32_C(0), _err);
+				chunkSize[idx] = write(_writer, _dxbc.inputSignature, _err);
+				size += chunkSize[idx++];
+				break;
+
+			case BX_MAKEFOURCC('O', 'S', 'G', '1'):
+			case BX_MAKEFOURCC('O', 'S', 'G', '5'):
+			case DXBC_CHUNK_OUTPUT_SIGNATURE:
+				chunkOffset[idx] = uint32_t(bx::seek(_writer) - dxbcOffset);
+				size += bx::write(_writer, DXBC_CHUNK_OUTPUT_SIGNATURE, _err);
+				size += bx::write(_writer, UINT32_C(0), _err);
+				chunkSize[idx] = write(_writer, _dxbc.outputSignature, _err);
+				size += chunkSize[idx++];
+				break;
+
+			case DXBC_CHUNK_SFI0:
+				chunkOffset[idx] = uint32_t(bx::seek(_writer) - dxbcOffset);
+				size += bx::write(_writer, DXBC_CHUNK_SFI0, _err);
+				size += bx::write(_writer, UINT32_C(0), _err);
+				chunkSize[idx] = bx::write(_writer, _dxbc.sfi0.data, _err);
+				size += chunkSize[idx++];
+				break;
+
+			case DXBC_CHUNK_SPDB: // Shader debugging info (new).
+				chunkOffset[idx] = uint32_t(bx::seek(_writer) - dxbcOffset);
+				size += bx::write(_writer, DXBC_CHUNK_SPDB, _err);
+				size += bx::write(_writer, UINT32_C(0), _err);
+				chunkSize[idx] = bx::write(_writer, _dxbc.spdb.debugCode.data(), _dxbc.spdb.debugCode.size(), _err);
+				size += chunkSize[idx++];
+				break;
+
+			case BX_MAKEFOURCC('A', 'o', 'n', '9'): // Contains DX9BC for feature level 9.x (*s_4_0_level_9_*) shaders.
+			case BX_MAKEFOURCC('I', 'F', 'C', 'E'): // Interface.
+			case BX_MAKEFOURCC('R', 'D', 'E', 'F'): // Resource definition.
+			case BX_MAKEFOURCC('S', 'D', 'G', 'B'): // Shader debugging info (old).
+			case BX_MAKEFOURCC('S', 'T', 'A', 'T'): // Statistics.
+			case BX_MAKEFOURCC('P', 'C', 'S', 'G'): // Patch constant signature.
+			case BX_MAKEFOURCC('P', 'S', 'O', '1'): // Pipeline State Object 1
+			case BX_MAKEFOURCC('P', 'S', 'O', '2'): // Pipeline State Object 2
+			case BX_MAKEFOURCC('X', 'N', 'A', 'P'): // ?
+			case BX_MAKEFOURCC('X', 'N', 'A', 'S'): // ?
+			default:
+				BX_ASSERT(false, "Writing of DXBC %c%c%c%c chunk unsupported"
+					, ( (char*)&_dxbc.chunksFourcc[ii])[0]
+					, ( (char*)&_dxbc.chunksFourcc[ii])[1]
+					, ( (char*)&_dxbc.chunksFourcc[ii])[2]
+					, ( (char*)&_dxbc.chunksFourcc[ii])[3]
+					);
+				break;
+			}
+		}
 
 		int64_t eof = bx::seek(_writer);
 
@@ -1978,9 +2061,9 @@ namespace bgfx
 		bx::write(_writer, size, _err);
 
 		bx::seek(_writer, chunksOffsets, bx::Whence::Begin);
-		bx::write(_writer, chunkOffset, sizeof(chunkOffset), _err);
+		bx::write(_writer, chunkOffset, numSupportedChunks*sizeof(chunkOffset[0]), _err);
 
-		for (uint32_t ii = 0; ii < BX_COUNTOF(chunkOffset); ++ii)
+		for (uint32_t ii = 0; ii < numSupportedChunks; ++ii)
 		{
 			bx::seek(_writer, chunkOffset[ii]+4, bx::Whence::Begin);
 			bx::write(_writer, chunkSize[ii], _err);

+ 15 - 0
src/shader_dxbc.h

@@ -633,6 +633,16 @@ namespace bgfx
 		bool aon9;
 	};
 
+	struct DxbcSFI0
+	{
+		uint64_t data;
+	};
+
+	struct DxbcSPDB
+	{
+		stl::vector<uint8_t> debugCode;
+	};
+
 	int32_t read(bx::ReaderSeekerI* _reader, DxbcShader& _shader, bx::Error* _err);
 	int32_t write(bx::WriterI* _writer, const DxbcShader& _shader, bx::Error* _err);
 
@@ -642,6 +652,8 @@ namespace bgfx
 	typedef void (*DxbcFilterFn)(DxbcInstruction& _instruction, void* _userData);
 	void filter(DxbcShader& _dst, const DxbcShader& _src, DxbcFilterFn _fn, void* _userData, bx::Error* _err = NULL);
 
+#define DXBC_MAX_CHUNKS 32
+
 	struct DxbcContext
 	{
 		struct Header
@@ -657,6 +669,9 @@ namespace bgfx
 		DxbcSignature inputSignature;
 		DxbcSignature outputSignature;
 		DxbcShader shader;
+		DxbcSFI0 sfi0;
+		DxbcSPDB spdb;
+		uint32_t chunksFourcc[DXBC_MAX_CHUNKS];
 	};
 
 	int32_t read(bx::ReaderSeekerI* _reader, DxbcContext& _dxbc, bx::Error* _err);

+ 2 - 2
tools/shaderc/shaderc.cpp

@@ -13,13 +13,13 @@ extern "C"
 #include <fpp.h>
 } // extern "C"
 
-#define BGFX_SHADER_BIN_VERSION 8
+#define BGFX_SHADER_BIN_VERSION 9
 #define BGFX_CHUNK_MAGIC_CSH BX_MAKEFOURCC('C', 'S', 'H', BGFX_SHADER_BIN_VERSION)
 #define BGFX_CHUNK_MAGIC_FSH BX_MAKEFOURCC('F', 'S', 'H', BGFX_SHADER_BIN_VERSION)
 #define BGFX_CHUNK_MAGIC_VSH BX_MAKEFOURCC('V', 'S', 'H', BGFX_SHADER_BIN_VERSION)
 
 #define BGFX_SHADERC_VERSION_MAJOR 1
-#define BGFX_SHADERC_VERSION_MINOR 16
+#define BGFX_SHADERC_VERSION_MINOR 17
 
 namespace bgfx
 {

+ 1 - 1
tools/shaderc/shaderc_spirv.cpp

@@ -1023,7 +1023,7 @@ namespace bgfx { namespace spirv
 						}
 					}
 
-					// Loop through the separate_images, and extract the uniform names:
+					// Loop through the storage_images, and extract the uniform names:
 					for (auto &resource : resourcesrefl.storage_images)
 					{
 						std::string name = refl.get_name(resource.id);