Browse Source

FrameBuffer Read/Write access WIP

Hugo Amnov 6 years ago
parent
commit
58563b0b1b

+ 62 - 0
examples/21-deferred/common.sh

@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#include "../common/common.sh"
+
+vec2 blinn(vec3 _lightDir, vec3 _normal, vec3 _viewDir)
+{
+	float ndotl = dot(_normal, _lightDir);
+	vec3 reflected = _lightDir - 2.0*ndotl*_normal; // reflect(_lightDir, _normal);
+	float rdotv = dot(reflected, _viewDir);
+	return vec2(ndotl, rdotv);
+}
+
+float fresnel(float _ndotl, float _bias, float _pow)
+{
+	float facing = (1.0 - _ndotl);
+	return max(_bias + (1.0 - _bias) * pow(facing, _pow), 0.0);
+}
+
+vec4 lit(float _ndotl, float _rdotv, float _m)
+{
+	float diff = max(0.0, _ndotl);
+	float spec = step(0.0, _ndotl) * max(0.0, _rdotv * _m);
+	return vec4(1.0, diff, spec, 1.0);
+}
+
+vec4 powRgba(vec4 _rgba, float _pow)
+{
+	vec4 result;
+	result.xyz = pow(_rgba.xyz, vec3_splat(_pow) );
+	result.w = _rgba.w;
+	return result;
+}
+
+vec3 calcLight(vec3 _wpos, vec3 _normal, vec3 _view, vec3 _lightPos, float _lightRadius, vec3 _lightRgb, float _lightInner)
+{
+	vec3 lp = _lightPos - _wpos;
+	float attn = 1.0 - smoothstep(_lightInner, 1.0, length(lp) / _lightRadius);
+	vec3 lightDir = normalize(lp);
+	vec2 bln = blinn(lightDir, _normal, _view);
+	vec4 lc = lit(bln.x, bln.y, 1.0);
+	vec3 rgb = _lightRgb * saturate(lc.y) * attn;
+	return rgb;
+}
+
+float toClipSpaceDepth(float _depthTextureZ)
+{
+#if BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_METAL
+	return _depthTextureZ;
+#else
+	return _depthTextureZ * 2.0 - 1.0;
+#endif // BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_METAL
+}
+
+vec3 clipToWorld(mat4 _invViewProj, vec3 _clipPos)
+{
+	vec4 wpos = mul(_invViewProj, vec4(_clipPos, 1.0) );
+	return wpos.xyz / wpos.w;
+}
+

+ 77 - 22
examples/21-deferred/deferred.cpp

@@ -282,6 +282,7 @@ public:
 		m_lineProgram    = loadProgram("vs_deferred_debug_line", "fs_deferred_debug_line");
 		m_lineProgram    = loadProgram("vs_deferred_debug_line", "fs_deferred_debug_line");
 
 
 		m_useTArray = false;
 		m_useTArray = false;
+		m_useUav = false;
 
 
 		if (0 != (BGFX_CAPS_TEXTURE_2D_ARRAY & bgfx::getCaps()->supported) )
 		if (0 != (BGFX_CAPS_TEXTURE_2D_ARRAY & bgfx::getCaps()->supported) )
 		{
 		{
@@ -292,6 +293,17 @@ public:
 			m_lightTaProgram = BGFX_INVALID_HANDLE;
 			m_lightTaProgram = BGFX_INVALID_HANDLE;
 		}
 		}
 
 
+		if(0 != (BGFX_CAPS_READ_WRITE_ATTACH & bgfx::getCaps()->supported))
+		{
+			m_lightUavProgram = loadProgram("vs_deferred_light", "fs_deferred_light_uav");
+			m_clearUavProgram = loadProgram("vs_deferred_light", "fs_deferred_clear_uav");
+		}
+		else
+		{
+			m_lightUavProgram = BGFX_INVALID_HANDLE;
+			m_clearUavProgram = BGFX_INVALID_HANDLE;
+		}
+
 		// Load diffuse texture.
 		// Load diffuse texture.
 		m_textureColor  = loadTexture("textures/fieldstone-rgba.dds");
 		m_textureColor  = loadTexture("textures/fieldstone-rgba.dds");
 
 
@@ -423,6 +435,7 @@ public:
 				||  m_oldHeight    != m_height
 				||  m_oldHeight    != m_height
 				||  m_oldReset     != m_reset
 				||  m_oldReset     != m_reset
 				||  m_oldUseTArray != m_useTArray
 				||  m_oldUseTArray != m_useTArray
+				||  m_oldUseUav    != m_useUav
 				||  !bgfx::isValid(m_gbuffer) )
 				||  !bgfx::isValid(m_gbuffer) )
 				{
 				{
 					// Recreate variable size render targets when resolution changes.
 					// Recreate variable size render targets when resolution changes.
@@ -430,6 +443,7 @@ public:
 					m_oldHeight    = m_height;
 					m_oldHeight    = m_height;
 					m_oldReset     = m_reset;
 					m_oldReset     = m_reset;
 					m_oldUseTArray = m_useTArray;
 					m_oldUseTArray = m_useTArray;
+					m_oldUseUav    = m_useUav;
 
 
 					if (bgfx::isValid(m_gbuffer) )
 					if (bgfx::isValid(m_gbuffer) )
 					{
 					{
@@ -440,7 +454,6 @@ public:
 					}
 					}
 
 
 					const uint64_t tsFlags = 0
 					const uint64_t tsFlags = 0
-						| BGFX_TEXTURE_RT
 						| BGFX_SAMPLER_MIN_POINT
 						| BGFX_SAMPLER_MIN_POINT
 						| BGFX_SAMPLER_MAG_POINT
 						| BGFX_SAMPLER_MAG_POINT
 						| BGFX_SAMPLER_MIP_POINT
 						| BGFX_SAMPLER_MIP_POINT
@@ -448,33 +461,48 @@ public:
 						| BGFX_SAMPLER_V_CLAMP
 						| BGFX_SAMPLER_V_CLAMP
 						;
 						;
 
 
-					bgfx::Attachment at[3];
+					bgfx::Attachment gbufferAt[3];
 
 
-					if (m_useTArray)
+					if(m_useTArray)
 					{
 					{
-						m_gbufferTex[0] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 2, bgfx::TextureFormat::BGRA8, tsFlags);
-						at[0].init(m_gbufferTex[0], bgfx::Access::Write, 0);
-						at[1].init(m_gbufferTex[0], bgfx::Access::Write, 1);
+						m_gbufferTex[0] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 2, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT | tsFlags);
+						gbufferAt[0].init(m_gbufferTex[0], bgfx::Access::Write, 0);
+						gbufferAt[1].init(m_gbufferTex[0], bgfx::Access::Write, 1);
 					}
 					}
 					else
 					else
 					{
 					{
-						m_gbufferTex[0] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::BGRA8, tsFlags);
-						m_gbufferTex[1] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::BGRA8, tsFlags);
-						at[0].init(m_gbufferTex[0]);
-						at[1].init(m_gbufferTex[1]);
+						m_gbufferTex[0] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT | tsFlags);
+						m_gbufferTex[1] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT | tsFlags);
+						gbufferAt[0].init(m_gbufferTex[0]);
+						gbufferAt[1].init(m_gbufferTex[1]);
 					}
 					}
 
 
-					m_gbufferTex[2] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::D24S8, tsFlags);
-					at[2].init(m_gbufferTex[2]);
+					m_gbufferTex[2] = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::D24S8, BGFX_TEXTURE_RT | tsFlags);
+					gbufferAt[2].init(m_gbufferTex[2]);
 
 
-					m_gbuffer = bgfx::createFrameBuffer(BX_COUNTOF(at), at, true);
+					m_gbuffer = bgfx::createFrameBuffer(BX_COUNTOF(gbufferAt), gbufferAt, true);
 
 
-					if (bgfx::isValid(m_lightBuffer) )
+					if(bgfx::isValid(m_lightBuffer))
 					{
 					{
 						bgfx::destroy(m_lightBuffer);
 						bgfx::destroy(m_lightBuffer);
 					}
 					}
 
 
-					m_lightBuffer = bgfx::createFrameBuffer(uint16_t(m_width), uint16_t(m_height), bgfx::TextureFormat::BGRA8, tsFlags);
+					if(m_useUav)
+					{
+						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);
+
+						m_lightBuffer = bgfx::createFrameBuffer(BX_COUNTOF(lightAt), lightAt, true);
+					}
+					else
+					{
+						m_lightBufferTex = bgfx::createTexture2D(uint16_t(m_width), uint16_t(m_height), false, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_RT | tsFlags);
+						m_lightBuffer = bgfx::createFrameBuffer(1, &m_lightBufferTex, true);
+					}
 				}
 				}
 
 
 				ImGui::SetNextWindowPos(
 				ImGui::SetNextWindowPos(
@@ -503,6 +531,15 @@ public:
 					ImGui::Text("Texture array frame buffer is not supported.");
 					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::Checkbox("Animate mesh.", &m_animateMesh);
 				ImGui::SliderFloat("Anim.speed", &m_lightAnimationSpeed, 0.0f, 0.4f);
 				ImGui::SliderFloat("Anim.speed", &m_lightAnimationSpeed, 0.0f, 0.4f);
 
 
@@ -596,6 +633,17 @@ public:
 					}
 					}
 				}
 				}
 
 
+				// Clear UAV texture
+				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(RENDER_PASS_LIGHT_ID, m_clearUavProgram);
+				}
+
 				// Draw lights into light buffer.
 				// Draw lights into light buffer.
 				for (int32_t light = 0; light < m_numLights; ++light)
 				for (int32_t light = 0; light < m_numLights; ++light)
 				{
 				{
@@ -717,17 +765,18 @@ public:
 							| BGFX_STATE_BLEND_ADD
 							| BGFX_STATE_BLEND_ADD
 							);
 							);
 						screenSpaceQuad( (float)m_width, (float)m_height, s_texelHalf, m_caps->originBottomLeft);
 						screenSpaceQuad( (float)m_width, (float)m_height, s_texelHalf, m_caps->originBottomLeft);
-						bgfx::submit(RENDER_PASS_LIGHT_ID
-							, bgfx::isValid(m_lightTaProgram) && m_useTArray
-							? m_lightTaProgram
-							: m_lightProgram
-							);
+						if(bgfx::isValid(m_lightTaProgram) && m_useTArray)
+							bgfx::submit(RENDER_PASS_LIGHT_ID, m_lightTaProgram);
+						else if(bgfx::isValid(m_lightUavProgram) && m_useUav)
+							bgfx::submit(RENDER_PASS_LIGHT_ID, m_lightUavProgram);
+						else
+							bgfx::submit(RENDER_PASS_LIGHT_ID, m_lightProgram);
 					}
 					}
 				}
 				}
 
 
 				// Combine color and light buffers.
 				// Combine color and light buffers.
-				bgfx::setTexture(0, s_albedo, bgfx::getTexture(m_gbuffer,     0) );
-				bgfx::setTexture(1, s_light,  bgfx::getTexture(m_lightBuffer, 0) );
+				bgfx::setTexture(0, s_albedo, m_gbufferTex[0]);
+				bgfx::setTexture(1, s_light,  m_lightBufferTex);
 				bgfx::setState(0
 				bgfx::setState(0
 					| BGFX_STATE_WRITE_RGB
 					| BGFX_STATE_WRITE_RGB
 					| BGFX_STATE_WRITE_A
 					| BGFX_STATE_WRITE_A
@@ -788,6 +837,8 @@ public:
 	bgfx::ProgramHandle m_geomProgram;
 	bgfx::ProgramHandle m_geomProgram;
 	bgfx::ProgramHandle m_lightProgram;
 	bgfx::ProgramHandle m_lightProgram;
 	bgfx::ProgramHandle m_lightTaProgram;
 	bgfx::ProgramHandle m_lightTaProgram;
+	bgfx::ProgramHandle m_lightUavProgram;
+	bgfx::ProgramHandle m_clearUavProgram;
 	bgfx::ProgramHandle m_combineProgram;
 	bgfx::ProgramHandle m_combineProgram;
 	bgfx::ProgramHandle m_debugProgram;
 	bgfx::ProgramHandle m_debugProgram;
 	bgfx::ProgramHandle m_lineProgram;
 	bgfx::ProgramHandle m_lineProgram;
@@ -795,6 +846,7 @@ public:
 	bgfx::TextureHandle m_textureNormal;
 	bgfx::TextureHandle m_textureNormal;
 
 
 	bgfx::TextureHandle m_gbufferTex[3];
 	bgfx::TextureHandle m_gbufferTex[3];
+	bgfx::TextureHandle m_lightBufferTex;
 	bgfx::FrameBufferHandle m_gbuffer;
 	bgfx::FrameBufferHandle m_gbuffer;
 	bgfx::FrameBufferHandle m_lightBuffer;
 	bgfx::FrameBufferHandle m_lightBuffer;
 
 
@@ -810,6 +862,9 @@ public:
 	bool m_useTArray;
 	bool m_useTArray;
 	bool m_oldUseTArray;
 	bool m_oldUseTArray;
 
 
+	bool m_useUav;
+	bool m_oldUseUav;
+
 	int32_t m_scrollArea;
 	int32_t m_scrollArea;
 	int32_t m_numLights;
 	int32_t m_numLights;
 	float m_lightAnimationSpeed;
 	float m_lightAnimationSpeed;

+ 17 - 0
examples/21-deferred/fs_deferred_clear_uav.sc

@@ -0,0 +1,17 @@
+$input v_texcoord0
+
+/*
+ * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#include "common.sh"
+#include <bgfx_compute.sh>
+
+IMAGE2D_RW(s_lights, rgba8, 1);
+
+void main()
+{
+    ivec2 coord = ivec2(gl_FragCoord.xy);
+    imageStore(s_lights, coord, vec4(0.0, 0.0, 0.0, 0.0));
+}

+ 2 - 58
examples/21-deferred/fs_deferred_light.sc

@@ -5,7 +5,7 @@ $input v_texcoord0
  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  */
  */
 
 
-#include "../common/common.sh"
+#include "common.sh"
 
 
 SAMPLER2D(s_normal, 0);
 SAMPLER2D(s_normal, 0);
 SAMPLER2D(s_depth,  1);
 SAMPLER2D(s_depth,  1);
@@ -14,61 +14,6 @@ uniform vec4 u_lightPosRadius[1];
 uniform vec4 u_lightRgbInnerR[1];
 uniform vec4 u_lightRgbInnerR[1];
 uniform mat4 u_mtx;
 uniform mat4 u_mtx;
 
 
-vec2 blinn(vec3 _lightDir, vec3 _normal, vec3 _viewDir)
-{
-	float ndotl = dot(_normal, _lightDir);
-	vec3 reflected = _lightDir - 2.0*ndotl*_normal; // reflect(_lightDir, _normal);
-	float rdotv = dot(reflected, _viewDir);
-	return vec2(ndotl, rdotv);
-}
-
-float fresnel(float _ndotl, float _bias, float _pow)
-{
-	float facing = (1.0 - _ndotl);
-	return max(_bias + (1.0 - _bias) * pow(facing, _pow), 0.0);
-}
-
-vec4 lit(float _ndotl, float _rdotv, float _m)
-{
-	float diff = max(0.0, _ndotl);
-	float spec = step(0.0, _ndotl) * max(0.0, _rdotv * _m);
-	return vec4(1.0, diff, spec, 1.0);
-}
-
-vec4 powRgba(vec4 _rgba, float _pow)
-{
-	vec4 result;
-	result.xyz = pow(_rgba.xyz, vec3_splat(_pow) );
-	result.w = _rgba.w;
-	return result;
-}
-
-vec3 calcLight(int _idx, vec3 _wpos, vec3 _normal, vec3 _view)
-{
-	vec3 lp = u_lightPosRadius[_idx].xyz - _wpos;
-	float attn = 1.0 - smoothstep(u_lightRgbInnerR[_idx].w, 1.0, length(lp) / u_lightPosRadius[_idx].w);
-	vec3 lightDir = normalize(lp);
-	vec2 bln = blinn(lightDir, _normal, _view);
-	vec4 lc = lit(bln.x, bln.y, 1.0);
-	vec3 rgb = u_lightRgbInnerR[_idx].xyz * saturate(lc.y) * attn;
-	return rgb;
-}
-
-float toClipSpaceDepth(float _depthTextureZ)
-{
-#if BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_METAL
-	return _depthTextureZ;
-#else
-	return _depthTextureZ * 2.0 - 1.0;
-#endif // BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_METAL
-}
-
-vec3 clipToWorld(mat4 _invViewProj, vec3 _clipPos)
-{
-	vec4 wpos = mul(_invViewProj, vec4(_clipPos, 1.0) );
-	return wpos.xyz / wpos.w;
-}
-
 void main()
 void main()
 {
 {
 	vec3  normal      = decodeNormalUint(texture2D(s_normal, v_texcoord0).xyz);
 	vec3  normal      = decodeNormalUint(texture2D(s_normal, v_texcoord0).xyz);
@@ -84,8 +29,7 @@ void main()
 	vec3 view = mul(u_view, vec4(wpos, 0.0) ).xyz;
 	vec3 view = mul(u_view, vec4(wpos, 0.0) ).xyz;
 	view = -normalize(view);
 	view = -normalize(view);
 
 
-	vec3 lightColor;
-	lightColor = calcLight(0, wpos, normal, view);
+	vec3 lightColor = calcLight(wpos, normal, view, u_lightPosRadius[0].xyz, u_lightPosRadius[0].w, u_lightRgbInnerR[0].xyz, u_lightRgbInnerR[0].w);
 	gl_FragColor.xyz = toGamma(lightColor.xyz);
 	gl_FragColor.xyz = toGamma(lightColor.xyz);
 	gl_FragColor.w = 1.0;
 	gl_FragColor.w = 1.0;
 }
 }

+ 2 - 58
examples/21-deferred/fs_deferred_light_ta.sc

@@ -5,7 +5,7 @@ $input v_texcoord0
  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  */
  */
 
 
-#include "../common/common.sh"
+#include "common.sh"
 
 
 SAMPLER2DARRAY(s_normal, 0);
 SAMPLER2DARRAY(s_normal, 0);
 SAMPLER2D(s_depth,  1);
 SAMPLER2D(s_depth,  1);
@@ -14,61 +14,6 @@ uniform vec4 u_lightPosRadius[1];
 uniform vec4 u_lightRgbInnerR[1];
 uniform vec4 u_lightRgbInnerR[1];
 uniform mat4 u_mtx;
 uniform mat4 u_mtx;
 
 
-vec2 blinn(vec3 _lightDir, vec3 _normal, vec3 _viewDir)
-{
-	float ndotl = dot(_normal, _lightDir);
-	vec3 reflected = _lightDir - 2.0*ndotl*_normal; // reflect(_lightDir, _normal);
-	float rdotv = dot(reflected, _viewDir);
-	return vec2(ndotl, rdotv);
-}
-
-float fresnel(float _ndotl, float _bias, float _pow)
-{
-	float facing = (1.0 - _ndotl);
-	return max(_bias + (1.0 - _bias) * pow(facing, _pow), 0.0);
-}
-
-vec4 lit(float _ndotl, float _rdotv, float _m)
-{
-	float diff = max(0.0, _ndotl);
-	float spec = step(0.0, _ndotl) * max(0.0, _rdotv * _m);
-	return vec4(1.0, diff, spec, 1.0);
-}
-
-vec4 powRgba(vec4 _rgba, float _pow)
-{
-	vec4 result;
-	result.xyz = pow(_rgba.xyz, vec3_splat(_pow) );
-	result.w = _rgba.w;
-	return result;
-}
-
-vec3 calcLight(int _idx, vec3 _wpos, vec3 _normal, vec3 _view)
-{
-	vec3 lp = u_lightPosRadius[_idx].xyz - _wpos;
-	float attn = 1.0 - smoothstep(u_lightRgbInnerR[_idx].w, 1.0, length(lp) / u_lightPosRadius[_idx].w);
-	vec3 lightDir = normalize(lp);
-	vec2 bln = blinn(lightDir, _normal, _view);
-	vec4 lc = lit(bln.x, bln.y, 1.0);
-	vec3 rgb = u_lightRgbInnerR[_idx].xyz * saturate(lc.y) * attn;
-	return rgb;
-}
-
-float toClipSpaceDepth(float _depthTextureZ)
-{
-#if BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_METAL
-	return _depthTextureZ;
-#else
-	return _depthTextureZ * 2.0 - 1.0;
-#endif // BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_METAL
-}
-
-vec3 clipToWorld(mat4 _invViewProj, vec3 _clipPos)
-{
-	vec4 wpos = mul(_invViewProj, vec4(_clipPos, 1.0) );
-	return wpos.xyz / wpos.w;
-}
-
 void main()
 void main()
 {
 {
 	vec3  normal      = decodeNormalUint(texture2DArray(s_normal, vec3(v_texcoord0, 1.0) ).xyz);
 	vec3  normal      = decodeNormalUint(texture2DArray(s_normal, vec3(v_texcoord0, 1.0) ).xyz);
@@ -84,8 +29,7 @@ void main()
 	vec3 view = mul(u_view, vec4(wpos, 0.0) ).xyz;
 	vec3 view = mul(u_view, vec4(wpos, 0.0) ).xyz;
 	view = -normalize(view);
 	view = -normalize(view);
 
 
-	vec3 lightColor;
-	lightColor = calcLight(0, wpos, normal, view);
+	vec3 lightColor = calcLight(wpos, normal, view, u_lightPosRadius[0].xyz, u_lightPosRadius[0].w, u_lightRgbInnerR[0].xyz, u_lightRgbInnerR[0].w);
 	gl_FragColor.xyz = toGamma(lightColor.xyz);
 	gl_FragColor.xyz = toGamma(lightColor.xyz);
 	gl_FragColor.w = 1.0;
 	gl_FragColor.w = 1.0;
 }
 }

+ 40 - 0
examples/21-deferred/fs_deferred_light_uav.sc

@@ -0,0 +1,40 @@
+$input v_texcoord0
+
+/*
+ * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#include "common.sh"
+#include <bgfx_compute.sh>
+
+SAMPLER2D(s_normal, 0);
+SAMPLER2D(s_depth,  1);
+
+IMAGE2D_RW(s_lights, rgba8, 1);
+
+uniform vec4 u_lightPosRadius[1];
+uniform vec4 u_lightRgbInnerR[1];
+uniform mat4 u_mtx;
+
+void main()
+{
+	vec3  normal      = decodeNormalUint(texture2D(s_normal, v_texcoord0).xyz);
+	float deviceDepth = texture2D(s_depth, v_texcoord0).x;
+	float depth       = toClipSpaceDepth(deviceDepth);
+
+	vec3 clip = vec3(v_texcoord0 * 2.0 - 1.0, depth);
+#if BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_METAL
+	clip.y = -clip.y;
+#endif // BGFX_SHADER_LANGUAGE_HLSL || BGFX_SHADER_LANGUAGE_PSSL || BGFX_SHADER_LANGUAGE_METAL
+	vec3 wpos = clipToWorld(u_mtx, clip);
+
+	vec3 view = mul(u_view, vec4(wpos, 0.0) ).xyz;
+	view = -normalize(view);
+
+    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_lights, coord);
+    imageStore(s_lights, coord, color + vec4(toGamma(lightColor.xyz), 1.0));
+}

BIN
examples/runtime/shaders/dx11/fs_deferred_clear_uav.bin


BIN
examples/runtime/shaders/dx11/fs_deferred_light_uav.bin


BIN
examples/runtime/shaders/glsl/fs_deferred_clear_uav.bin


BIN
examples/runtime/shaders/glsl/fs_deferred_light_uav.bin


+ 1 - 0
include/bgfx/defines.h

@@ -502,6 +502,7 @@
 #define BGFX_CAPS_VERTEX_ATTRIB_HALF     UINT64_C(0x0000000001000000) //!< Vertex attribute half-float is supported.
 #define BGFX_CAPS_VERTEX_ATTRIB_HALF     UINT64_C(0x0000000001000000) //!< Vertex attribute half-float is supported.
 #define BGFX_CAPS_VERTEX_ATTRIB_UINT10   UINT64_C(0x0000000002000000) //!< Vertex attribute 10_10_10_2 is supported.
 #define BGFX_CAPS_VERTEX_ATTRIB_UINT10   UINT64_C(0x0000000002000000) //!< Vertex attribute 10_10_10_2 is supported.
 #define BGFX_CAPS_VERTEX_ID              UINT64_C(0x0000000004000000) //!< Rendering with VertexID only is supported.
 #define BGFX_CAPS_VERTEX_ID              UINT64_C(0x0000000004000000) //!< Rendering with VertexID only is supported.
+#define BGFX_CAPS_READ_WRITE_ATTACH      UINT64_C(0x0000000008000000) //!< Read/Write frame buffer attachments are supported.
 
 
 ///
 ///
 #define BGFX_CAPS_FORMAT_TEXTURE_NONE             UINT16_C(0x0000) //!< Texture format is not supported.
 #define BGFX_CAPS_FORMAT_TEXTURE_NONE             UINT16_C(0x0000) //!< Texture format is not supported.

+ 15 - 3
src/renderer_d3d11.cpp

@@ -391,10 +391,12 @@ namespace bgfx { namespace d3d11
 
 
 		void clear()
 		void clear()
 		{
 		{
+			bx::memSet(m_uav, 0, sizeof(m_uav));
 			bx::memSet(m_srv, 0, sizeof(m_srv) );
 			bx::memSet(m_srv, 0, sizeof(m_srv) );
 			bx::memSet(m_sampler, 0, sizeof(m_sampler) );
 			bx::memSet(m_sampler, 0, sizeof(m_sampler) );
 		}
 		}
 
 
+		ID3D11UnorderedAccessView* m_uav[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
 		ID3D11ShaderResourceView* m_srv[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
 		ID3D11ShaderResourceView* m_srv[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
 		ID3D11SamplerState* m_sampler[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
 		ID3D11SamplerState* m_sampler[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS];
 	};
 	};
@@ -1178,6 +1180,9 @@ namespace bgfx { namespace d3d11
 						: 0)
 						: 0)
 					| BGFX_CAPS_TEXTURE_2D_ARRAY
 					| BGFX_CAPS_TEXTURE_2D_ARRAY
 					| BGFX_CAPS_TEXTURE_CUBE_ARRAY
 					| BGFX_CAPS_TEXTURE_CUBE_ARRAY
+					| ((m_featureLevel >= D3D_FEATURE_LEVEL_11_1)
+						? BGFX_CAPS_READ_WRITE_ATTACH
+						: 0)
 					);
 					);
 
 
 				m_timerQuerySupport   = m_featureLevel >= D3D_FEATURE_LEVEL_10_0;
 				m_timerQuerySupport   = m_featureLevel >= D3D_FEATURE_LEVEL_10_0;
@@ -2503,7 +2508,7 @@ namespace bgfx { namespace d3d11
 				m_currentColor        = m_backBufferColor;
 				m_currentColor        = m_backBufferColor;
 				m_currentDepthStencil = m_backBufferDepthStencil;
 				m_currentDepthStencil = m_backBufferDepthStencil;
 
 
-				m_deviceCtx->OMSetRenderTargets(1, &m_currentColor, m_currentDepthStencil);
+				m_deviceCtx->OMSetRenderTargetsAndUnorderedAccessViews(1, &m_currentColor, m_currentDepthStencil, 1, 0, NULL, NULL);
 				m_needPresent |= _needPresent;
 				m_needPresent |= _needPresent;
 			}
 			}
 			else
 			else
@@ -4579,6 +4584,10 @@ namespace bgfx { namespace d3d11
 		{
 		{
 			m_rtv[ii] = NULL;
 			m_rtv[ii] = NULL;
 		}
 		}
+		for(uint32_t ii = 0; ii < BX_COUNTOF(m_uav); ++ii)
+		{
+			m_uav[ii] = NULL;
+		}
 		m_dsv       = NULL;
 		m_dsv       = NULL;
 		m_swapChain = NULL;
 		m_swapChain = NULL;
 
 
@@ -4690,6 +4699,8 @@ namespace bgfx { namespace d3d11
 		if (0 < m_numTh)
 		if (0 < m_numTh)
 		{
 		{
 			m_num = 0;
 			m_num = 0;
+			m_numUav = 0;
+
 			for (uint32_t ii = 0; ii < m_numTh; ++ii)
 			for (uint32_t ii = 0; ii < m_numTh; ++ii)
 			{
 			{
 				const Attachment& at = m_attachment[ii];
 				const Attachment& at = m_attachment[ii];
@@ -4851,7 +4862,8 @@ namespace bgfx { namespace d3d11
 					}
 					}
 					else
 					else
 					{
 					{
-						BX_CHECK(false, "");
+						m_uav[m_num + m_numUav] = texture.m_uav;
+						m_numUav++;
 					}
 					}
 				}
 				}
 			}
 			}
@@ -4924,7 +4936,7 @@ namespace bgfx { namespace d3d11
 
 
 	void FrameBufferD3D11::set()
 	void FrameBufferD3D11::set()
 	{
 	{
-		s_renderD3D11->m_deviceCtx->OMSetRenderTargets(m_num, m_rtv, m_dsv);
+		s_renderD3D11->m_deviceCtx->OMSetRenderTargetsAndUnorderedAccessViews(m_num, m_rtv, m_dsv, m_num, m_numUav, m_uav + m_num, NULL);
 		m_needPresent = UINT16_MAX != m_denseIdx;
 		m_needPresent = UINT16_MAX != m_denseIdx;
 		s_renderD3D11->m_currentColor        = m_rtv[0];
 		s_renderD3D11->m_currentColor        = m_rtv[0];
 		s_renderD3D11->m_currentDepthStencil = m_dsv;
 		s_renderD3D11->m_currentDepthStencil = m_dsv;

+ 3 - 0
src/renderer_d3d11.h

@@ -330,6 +330,7 @@ namespace bgfx { namespace d3d11
 			, m_denseIdx(UINT16_MAX)
 			, m_denseIdx(UINT16_MAX)
 			, m_num(0)
 			, m_num(0)
 			, m_numTh(0)
 			, m_numTh(0)
+			, m_numUav(0)
 			, m_needPresent(false)
 			, m_needPresent(false)
 		{
 		{
 		}
 		}
@@ -345,6 +346,7 @@ namespace bgfx { namespace d3d11
 		HRESULT present(uint32_t _syncInterval);
 		HRESULT present(uint32_t _syncInterval);
 
 
 		ID3D11RenderTargetView* m_rtv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
 		ID3D11RenderTargetView* m_rtv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
+		ID3D11UnorderedAccessView* m_uav[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
 		ID3D11ShaderResourceView* m_srv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
 		ID3D11ShaderResourceView* m_srv[BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS-1];
 		ID3D11DepthStencilView* m_dsv;
 		ID3D11DepthStencilView* m_dsv;
 		Dxgi::SwapChainI* m_swapChain;
 		Dxgi::SwapChainI* m_swapChain;
@@ -356,6 +358,7 @@ namespace bgfx { namespace d3d11
 		uint16_t m_denseIdx;
 		uint16_t m_denseIdx;
 		uint8_t m_num;
 		uint8_t m_num;
 		uint8_t m_numTh;
 		uint8_t m_numTh;
+		uint8_t m_numUav;
 		bool m_needPresent;
 		bool m_needPresent;
 	};
 	};
 
 

+ 38 - 6
src/renderer_gl.cpp

@@ -2434,12 +2434,18 @@ BX_TRACE("%d, %d, %d, %s", _array, _srgb, _mipAutogen, getName(_format) );
 				m_atocSupport = s_extension[Extension::ARB_multisample].m_supported;
 				m_atocSupport = s_extension[Extension::ARB_multisample].m_supported;
 				m_conservativeRasterSupport = s_extension[Extension::NV_conservative_raster].m_supported;
 				m_conservativeRasterSupport = s_extension[Extension::NV_conservative_raster].m_supported;
 
 
+				m_imageLoadStoreSupport = false
+					|| s_extension[Extension::ARB_shader_image_load_store].m_supported
+					|| s_extension[Extension::EXT_shader_image_load_store].m_supported
+					;
+
 				g_caps.supported |= 0
 				g_caps.supported |= 0
 					| (m_atocSupport               ? BGFX_CAPS_ALPHA_TO_COVERAGE      : 0)
 					| (m_atocSupport               ? BGFX_CAPS_ALPHA_TO_COVERAGE      : 0)
 					| (m_conservativeRasterSupport ? BGFX_CAPS_CONSERVATIVE_RASTER    : 0)
 					| (m_conservativeRasterSupport ? BGFX_CAPS_CONSERVATIVE_RASTER    : 0)
 					| (m_occlusionQuerySupport     ? BGFX_CAPS_OCCLUSION_QUERY        : 0)
 					| (m_occlusionQuerySupport     ? BGFX_CAPS_OCCLUSION_QUERY        : 0)
 					| (m_depthTextureSupport       ? BGFX_CAPS_TEXTURE_COMPARE_LEQUAL : 0)
 					| (m_depthTextureSupport       ? BGFX_CAPS_TEXTURE_COMPARE_LEQUAL : 0)
 					| (computeSupport              ? BGFX_CAPS_COMPUTE                : 0)
 					| (computeSupport              ? BGFX_CAPS_COMPUTE                : 0)
+					| (m_imageLoadStoreSupport     ? BGFX_CAPS_READ_WRITE_ATTACH                    : 0)
 					;
 					;
 
 
 				g_caps.supported |= m_glctx.getCaps();
 				g_caps.supported |= m_glctx.getCaps();
@@ -3244,6 +3250,8 @@ BX_TRACE("%d, %d, %d, %s", _array, _srgb, _mipAutogen, getName(_format) );
 					m_glctx.makeCurrent(NULL);
 					m_glctx.makeCurrent(NULL);
 					m_currentFbo = frameBuffer.m_fbo[0];
 					m_currentFbo = frameBuffer.m_fbo[0];
 				}
 				}
+
+				frameBuffer.set();
 			}
 			}
 
 
 			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_currentFbo) );
 			GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_currentFbo) );
@@ -3888,6 +3896,7 @@ BX_TRACE("%d, %d, %d, %s", _array, _srgb, _mipAutogen, getName(_format) );
 		bool m_occlusionQuerySupport;
 		bool m_occlusionQuerySupport;
 		bool m_atocSupport;
 		bool m_atocSupport;
 		bool m_conservativeRasterSupport;
 		bool m_conservativeRasterSupport;
+		bool m_imageLoadStoreSupport;
 		bool m_flip;
 		bool m_flip;
 
 
 		uint64_t m_hash;
 		uint64_t m_hash;
@@ -5936,7 +5945,7 @@ BX_TRACE("%d, %d, %d, %s", _array, _srgb, _mipAutogen, getName(_format) );
 							attachment = GL_DEPTH_ATTACHMENT;
 							attachment = GL_DEPTH_ATTACHMENT;
 						}
 						}
 					}
 					}
-					else
+					else if (Access::Write == at.access)
 					{
 					{
 						buffers[colorIdx] = attachment;
 						buffers[colorIdx] = attachment;
 						++colorIdx;
 						++colorIdx;
@@ -5968,7 +5977,7 @@ BX_TRACE("%d, %d, %d, %s", _array, _srgb, _mipAutogen, getName(_format) );
 								) );
 								) );
 						}
 						}
 					}
 					}
-					else if (Access::Write == at.access)
+					else
 					{
 					{
 						if (1 < texture.m_numLayers
 						if (1 < texture.m_numLayers
 						&&  !texture.isCubeMap())
 						&&  !texture.isCubeMap())
@@ -5995,10 +6004,6 @@ BX_TRACE("%d, %d, %d, %s", _array, _srgb, _mipAutogen, getName(_format) );
 								) );
 								) );
 						}
 						}
 					}
 					}
-					else
-					{
-						BX_CHECK(false, "");
-					}
 
 
 					needResolve |= (0 != texture.m_rbo) && (0 != texture.m_id);
 					needResolve |= (0 != texture.m_rbo) && (0 != texture.m_id);
 				}
 				}
@@ -6196,6 +6201,33 @@ BX_TRACE("%d, %d, %d, %s", _array, _srgb, _mipAutogen, getName(_format) );
 		GL_CHECK(glInvalidateFramebuffer(GL_FRAMEBUFFER, idx, buffers) );
 		GL_CHECK(glInvalidateFramebuffer(GL_FRAMEBUFFER, idx, buffers) );
 	}
 	}
 
 
+	void FrameBufferGL::set()
+	{
+		for(uint32_t ii = 0; ii < m_numTh; ++ii)
+		{
+			if(m_attachment[ii].access == Access::Write)
+				continue;
+
+			TextureHandle handle = m_attachment[ii].handle;
+			if(isValid(handle))
+			{
+				const TextureGL& texture = s_renderGL->m_textures[handle.idx];
+
+				if(0 != (texture.m_flags&BGFX_TEXTURE_COMPUTE_WRITE))
+				{
+					GL_CHECK(glBindImageTexture(ii
+						, texture.m_id
+						, m_attachment[ii].mip
+						, GL_FALSE //texture.isLayered() ? GL_TRUE : GL_FALSE
+						, m_attachment[ii].layer
+						, s_access[Access::ReadWrite]
+						, s_imageFormat[texture.m_textureFormat])
+					);
+				}
+			}
+		}
+	}
+
 	void OcclusionQueryGL::create()
 	void OcclusionQueryGL::create()
 	{
 	{
 		for (uint32_t ii = 0; ii < BX_COUNTOF(m_query); ++ii)
 		for (uint32_t ii = 0; ii < BX_COUNTOF(m_query); ++ii)

+ 1 - 0
src/renderer_gl.h

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