Explorar o código

Moving light pass in a compute shader in preparation for tiled deferred rendering
Added light culling
Vulkan/DX11: Render target textures can now also be used as storage textures

BearishSun %!s(int64=9) %!d(string=hai) anos
pai
achega
eec99bff10
Modificáronse 27 ficheiros con 1019 adicións e 1346 borrados
  1. 10 10
      Data/Examples/Example.bsl
  2. BIN=BIN
      Data/Examples/Example.bsl.asset
  3. 205 218
      Data/Raw/Engine/DataList.json
  4. 0 327
      Data/Raw/Engine/Includes/DeferredLightPass.bslinc
  5. 0 257
      Data/Raw/Engine/Includes/DeferredPointLightPass.bslinc
  6. 10 18
      Data/Raw/Engine/Includes/GBuffer.bslinc
  7. 169 0
      Data/Raw/Engine/Includes/LightingCommon.bslinc
  8. 6 0
      Data/Raw/Engine/Includes/PerCameraData.bslinc
  9. 35 0
      Data/Raw/Engine/Includes/SurfaceData.bslinc
  10. 10 10
      Data/Raw/Engine/Shaders/Default.bsl
  11. 0 121
      Data/Raw/Engine/Shaders/DeferredDirectionalLightPass.bsl
  12. 0 2
      Data/Raw/Engine/Shaders/DeferredPointLightPassIn.bsl
  13. 0 1
      Data/Raw/Engine/Shaders/DeferredPointLightPassOut.bsl
  14. 10 10
      Data/Raw/Engine/Shaders/Diffuse.bsl
  15. 239 0
      Data/Raw/Engine/Shaders/TiledDeferredLighting.bsl
  16. 2 12
      Source/BansheeVulkanRenderAPI/Include/BsVulkanTexture.h
  17. 2 2
      Source/BansheeVulkanRenderAPI/Source/BsVulkanSwapChain.cpp
  18. 44 50
      Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp
  19. 9 9
      Source/BansheeVulkanRenderAPI/Source/BsVulkanUtility.cpp
  20. 41 70
      Source/RenderBeast/Include/BsLightRendering.h
  21. 8 10
      Source/RenderBeast/Include/BsRenderBeast.h
  22. 3 0
      Source/RenderBeast/Include/BsRenderTargets.h
  23. 7 0
      Source/RenderBeast/Include/BsRendererCamera.h
  24. 85 129
      Source/RenderBeast/Source/BsLightRendering.cpp
  25. 97 87
      Source/RenderBeast/Source/BsRenderBeast.cpp
  26. 7 2
      Source/RenderBeast/Source/BsRenderTargets.cpp
  27. 20 1
      Source/RenderBeast/Source/BsRendererCamera.cpp

+ 10 - 10
Data/Examples/Example.bsl

@@ -22,14 +22,14 @@ Technique : base("Surface") =
 				out float4 OutGBufferA : SV_Target1,
 				out float4 OutGBufferB : SV_Target2) : SV_Target0
 			{
-				GBufferData gbufferData;
-				gbufferData.albedo = float4(tex.Sample(samp, input.uv0).xyz, 1.0f);
-				gbufferData.worldNormal.xyz = input.tangentToWorldZ;
+				SurfaceData surfaceData;
+				surfaceData.albedo = float4(tex.Sample(samp, input.uv0).xyz, 1.0f);
+				surfaceData.worldNormal.xyz = input.tangentToWorldZ;
 				
-				encodeGBuffer(gbufferData, OutGBufferA, OutGBufferB);
+				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB);
 				
 				// TODO - Just returning a simple ambient term, use better environment lighting later
-				return float4(gbufferData.albedo.rgb, 1.0f) * 0.2f; 
+				return float4(surfaceData.albedo.rgb, 1.0f) * 0.2f; 
 			}	
 		};
 	};
@@ -53,14 +53,14 @@ Technique : base("Surface") =
 			
 			void main()
 			{
-				GBufferData gbufferData;
-				gbufferData.albedo = texture(tex, uv0);
-				gbufferData.worldNormal.xyz = tangentToWorldZ;
+				SurfaceData surfaceData;
+				surfaceData.albedo = texture(tex, uv0);
+				surfaceData.worldNormal.xyz = tangentToWorldZ;
 				
-				encodeGBuffer(gbufferData, fragColor[1], fragColor[2]);
+				encodeGBuffer(surfaceData, fragColor[1], fragColor[2]);
 				
 				// TODO - Just returning a simple ambient term, use better environment lighting later
-				fragColor[0] = vec4(gbufferData.albedo.rgb, 1.0f) * 0.2f; 
+				fragColor[0] = vec4(surfaceData.albedo.rgb, 1.0f) * 0.2f; 
 			}	
 		};
 	};

BIN=BIN
Data/Examples/Example.bsl.asset


+ 205 - 218
Data/Raw/Engine/DataList.json

@@ -1,4 +1,204 @@
 {
+    "Cursors": [
+        {
+            "Path": "Arrow.psd",
+            "UUID": "4c1c6cf4-7d37-46f1-9263-a8f0d498b7e0"
+        },
+        {
+            "Path": "ArrowDrag.psd",
+            "UUID": "2eebb0e7-4d21-43d5-9349-d2b0c71aabbe"
+        },
+        {
+            "Path": "ArrowLeftRight.psd",
+            "UUID": "23830d8f-f81f-4141-9b61-e0414b5e3f58"
+        },
+        {
+            "Path": "Deny.psd",
+            "UUID": "caba0f11-d080-4876-b832-9d664adac056"
+        },
+        {
+            "Path": "IBeam.psd",
+            "UUID": "38e6a064-8225-4126-8198-7892af7fedd0"
+        },
+        {
+            "Path": "SizeNESW.psd",
+            "UUID": "a7ac5600-acc8-4692-b149-a52cd4116af7"
+        },
+        {
+            "Path": "SizeNS.psd",
+            "UUID": "1f8930d0-953c-4575-b453-5a3bd62b4873"
+        },
+        {
+            "Path": "SizeNWSE.psd",
+            "UUID": "7ff92ce5-cba0-4846-a1b2-1249e67c371a"
+        },
+        {
+            "Path": "SizeWE.psd",
+            "UUID": "dfcb4a8a-f213-4697-9b61-4cc4368f530f"
+        },
+        {
+            "Path": "Wait.psd",
+            "UUID": "7ad1fc24-5e08-489c-8cd4-02b4e452a412"
+        }
+    ],
+    "Icons": [
+        {
+            "Path": "BansheeIcon.png",
+            "UUID": "a5f7a27c-e2ec-4a9d-8a13-b35f070f94be"
+        }
+    ],
+    "Includes": [
+        {
+            "Path": "DeferredBasePass.bslinc",
+            "UUID": "d4078f9c-d7e9-4d63-b506-4d270c08b01e"
+        },
+        {
+            "Path": "GBuffer.bslinc",
+            "UUID": "ef1a179a-4bf9-4dbd-b62a-e18524d959b6"
+        },
+        {
+            "Path": "NormalVertexInput.bslinc",
+            "UUID": "967325e7-262b-49bf-8c90-032a8bbc8ce2"
+        },
+        {
+            "Path": "PerCameraData.bslinc",
+            "UUID": "c1e4d309-8c20-4fd4-bf14-eb129af39d4e"
+        },
+        {
+            "Path": "PerObjectData.bslinc",
+            "UUID": "ed07f3ce-3abd-4379-b8f0-4c884af524a7"
+        },
+        {
+            "Path": "PPBase.bslinc",
+            "UUID": "44dc42de-410a-4949-a2e8-cb451a416481"
+        },
+        {
+            "Path": "PPTonemapCommon.bslinc",
+            "UUID": "a5d1c354-a05d-45b4-bccf-2f88db9aecb0"
+        },
+        {
+            "Path": "PPWhiteBalance.bslinc",
+            "UUID": "b46d1cee-75f7-4387-8b32-7eb646f099f4"
+        },
+        {
+            "Path": "ReflectionCubemapCommon.bslinc",
+            "UUID": "eef92578-b8ed-45d6-8eed-d85697ade3c5"
+        },
+        {
+            "Path": "ResolveCommon.bslinc",
+            "UUID": "1cde4f3c-534e-4128-8ee1-63e3bb620734"
+        },
+        {
+            "Path": "SkinnedVertexInput.bslinc",
+            "UUID": "d6a2ea27-5f4c-41ad-88bc-cad7dd7adc8d"
+        },
+        {
+            "Path": "SpriteImage.bslinc",
+            "UUID": "0114b1da-9899-45ca-8486-a9791482d3c5"
+        },
+        {
+            "Path": "Surface.bslinc",
+            "UUID": "468be285-026c-49d8-99ea-5f1709ea605a"
+        },
+        {
+            "Path": "VolumeRenderBase.bslinc",
+            "UUID": "6d0dfe4e-45ef-4fe1-9344-33b8b9e69048"
+        },
+        {
+            "Path": "LightingCommon.bslinc",
+            "UUID": "00fdff24-2c52-40ef-921b-0444286886d6"
+        },
+        {
+            "Path": "SurfaceData.bslinc",
+            "UUID": "3364cb35-9140-4571-8fae-d5648ae7386f"
+        }
+    ],
+    "Shaders": [
+        {
+            "Path": "Blit.bsl",
+            "UUID": "7953ba8a-6fc6-43ad-a472-cce558105cde"
+        },
+        {
+            "Path": "Default.bsl",
+            "UUID": "a8e36d37-d6f7-4117-bbba-31dca716c8a3"
+        },
+        {
+            "Path": "Diffuse.bsl",
+            "UUID": "4e2b2437-0a02-456c-8d98-71df27ccf697"
+        },
+        {
+            "Path": "PPCreateTonemapLUT.bsl",
+            "UUID": "766adb8c-1302-4f2d-a26f-6a0f8ff6b147"
+        },
+        {
+            "Path": "PPDownsample.bsl",
+            "UUID": "c1a11fc5-f7b4-422d-a359-70be6dac05ef"
+        },
+        {
+            "Path": "PPEyeAdaptation.bsl",
+            "UUID": "6baa01c8-fe61-4613-9fa9-a9ae045dfc64"
+        },
+        {
+            "Path": "PPEyeAdaptHistogram.bsl",
+            "UUID": "5414fffc-a96c-4a8a-86e3-c24050d14363"
+        },
+        {
+            "Path": "PPEyeAdaptHistogramReduce.bsl",
+            "UUID": "4c98431b-bd58-4160-8ff0-7d12add946fa"
+        },
+        {
+            "Path": "PPTonemapping.bsl",
+            "UUID": "cbe752ea-301a-47aa-b8ae-2f35d103595c"
+        },
+        {
+            "Path": "PPTonemapping.bsl",
+            "UUID": "36366f4c-3584-4dbf-9c2b-bb2638438b33"
+        },
+        {
+            "Path": "PPTonemapping.bsl",
+            "UUID": "520d9228-c7b5-492e-bd08-1fdc7e033ea8"
+        },
+        {
+            "Path": "PPTonemapping.bsl",
+            "UUID": "a8aa01e7-7e72-4f84-89f8-a0097250b0d3"
+        },
+        {
+            "Path": "ReflectionCubemapFilter.bsl",
+            "UUID": "31b4b9ae-2afa-4cd8-b532-fe82a7f42baa"
+        },
+        {
+            "Path": "Resolve.bsl",
+            "UUID": "9d5f5101-2d7e-432c-b8ad-1998de9ca5c7"
+        },
+        {
+            "Path": "Skybox.bsl",
+            "UUID": "b1c191fa-0c24-4987-8d3b-72b17511621d"
+        },
+        {
+            "Path": "SpriteImageAlpha.bsl",
+            "UUID": "4c00537f-9d3e-4cb7-8a30-b4ee9f278006"
+        },
+        {
+            "Path": "SpriteImageNoAlpha.bsl",
+            "UUID": "2db979ff-386a-492e-8f6d-675ed5133e31"
+        },
+        {
+            "Path": "SpriteLine.bsl",
+            "UUID": "3a9e31a8-cbef-49ac-af2a-2dc200372d36"
+        },
+        {
+            "Path": "SpriteText.bsl",
+            "UUID": "25df2c87-c206-4c2f-ab2b-3aad9e7f90f1"
+        },
+        {
+            "Path": "TestFX.bsl",
+            "UUID": "9e783e45-bf1f-41cc-bb48-eb2e1200cfb6"
+        },
+        {
+            "Path": "TiledDeferredLighting.bsl",
+            "UUID": "787d7293-f335-4eda-a897-c706e6b5c818"
+        }
+    ],
     "Skin": [
         {
             "Path": "ButtonActive.png",
@@ -50,7 +250,7 @@
             "SpriteUUID": "8aad937c-499d-4935-bd7d-d9389aed4f33",
             "TextureUUID": "1070d714-83a2-4d15-860b-c3607ff5a3e0"
         },
-		{
+        {
             "Path": "DropDownBoxEntryToggleHover.png",
             "SpriteUUID": "4f0bfa04-ccfb-11e6-9d9d-cec0c932ce01",
             "TextureUUID": "4f0bfd7e-ccfb-11e6-9d9d-cec0c932ce01"
@@ -69,7 +269,7 @@
             "Path": "DropDownBoxEntryToggleNormalOn.png",
             "SpriteUUID": "4f0c0a12-ccfb-11e6-9d9d-cec0c932ce01",
             "TextureUUID": "4f0c0bca-ccfb-11e6-9d9d-cec0c932ce01"
-        },		
+        },
         {
             "Path": "DropDownBoxExpandBtnHover.png",
             "SpriteUUID": "94748c7b-dc27-44dd-8798-22f76ea69b36",
@@ -219,7 +419,7 @@
             "Path": "ScrollBarHHandleResizeableNormal.png",
             "SpriteUUID": "18282c00-cd06-11e6-9d9d-cec0c932ce01",
             "TextureUUID": "18282cd2-cd06-11e6-9d9d-cec0c932ce01"
-        },		
+        },
         {
             "Path": "ScrollBarVBackground.png",
             "SpriteUUID": "b37d3e5b-891a-4950-a4f9-3f8fa820d40a",
@@ -254,7 +454,7 @@
             "Path": "ScrollBarVHandleResizeableNormal.png",
             "SpriteUUID": "3ae0b230-cd06-11e6-9d9d-cec0c932ce01",
             "TextureUUID": "3ae0b3f2-cd06-11e6-9d9d-cec0c932ce01"
-        },		
+        },
         {
             "Path": "SliderHandleActive.png",
             "SpriteUUID": "1ede5e0e-ccff-11e6-9d9d-cec0c932ce01",
@@ -290,11 +490,6 @@
             "SpriteUUID": "1ede736c-ccff-11e6-9d9d-cec0c932ce01",
             "TextureUUID": "1ede7448-ccff-11e6-9d9d-cec0c932ce01"
         },
-        {
-            "Path": "StatusBarBackground.png",
-            "SpriteUUID": "09887d53-d880-4576-b87b-50899b8bbf6d",
-            "TextureUUID": "4739c121-fcc5-4a08-b7b4-8c030030243d"
-        },		
         {
             "Path": "ToggleHover.png",
             "SpriteUUID": "daa9fd29-4228-47ca-8b9e-39636f0b566c",
@@ -320,213 +515,5 @@
             "SpriteUUID": "46bc0d6b-5cf0-4edc-bc5f-e0a06b8b04c2",
             "TextureUUID": "723670c8-f634-435f-8887-001a6791226a"
         }
-    ],
-    "Cursors": [
-        {
-            "Path": "Arrow.psd",
-            "UUID": "4c1c6cf4-7d37-46f1-9263-a8f0d498b7e0"
-        },
-        {
-            "Path": "ArrowDrag.psd",
-            "UUID": "2eebb0e7-4d21-43d5-9349-d2b0c71aabbe"
-        },
-        {
-            "Path": "ArrowLeftRight.psd",
-            "UUID": "23830d8f-f81f-4141-9b61-e0414b5e3f58"
-        },
-        {
-            "Path": "Deny.psd",
-            "UUID": "caba0f11-d080-4876-b832-9d664adac056"
-        },
-        {
-            "Path": "IBeam.psd",
-            "UUID": "38e6a064-8225-4126-8198-7892af7fedd0"
-        },
-        {
-            "Path": "SizeNESW.psd",
-            "UUID": "a7ac5600-acc8-4692-b149-a52cd4116af7"
-        },
-        {
-            "Path": "SizeNS.psd",
-            "UUID": "1f8930d0-953c-4575-b453-5a3bd62b4873"
-        },
-        {
-            "Path": "SizeNWSE.psd",
-            "UUID": "7ff92ce5-cba0-4846-a1b2-1249e67c371a"
-        },
-        {
-            "Path": "SizeWE.psd",
-            "UUID": "dfcb4a8a-f213-4697-9b61-4cc4368f530f"
-        },
-        {
-            "Path": "Wait.psd",
-            "UUID": "7ad1fc24-5e08-489c-8cd4-02b4e452a412"
-        }
-    ],
-    "Icons": [
-        {
-            "Path": "BansheeIcon.png",
-            "UUID": "a5f7a27c-e2ec-4a9d-8a13-b35f070f94be"
-        }
-    ],
-	"Includes": [
-        {
-            "Path": "DeferredBasePass.bslinc",
-            "UUID": "d4078f9c-d7e9-4d63-b506-4d270c08b01e"
-        },
-        {
-            "Path": "DeferredLightPass.bslinc",
-            "UUID": "6f58d7c8-11b5-4840-9787-50a7d2255a76"
-        },
-        {
-            "Path": "DeferredPointLightPass.bslinc",
-            "UUID": "f069380d-13e0-4a96-82e1-cffba4c4a631"
-        },
-        {
-            "Path": "GBuffer.bslinc",
-            "UUID": "ef1a179a-4bf9-4dbd-b62a-e18524d959b6"
-        },
-        {
-            "Path": "NormalVertexInput.bslinc",
-            "UUID": "967325e7-262b-49bf-8c90-032a8bbc8ce2"
-        },
-        {
-            "Path": "PerCameraData.bslinc",
-            "UUID": "c1e4d309-8c20-4fd4-bf14-eb129af39d4e"
-        },
-        {
-            "Path": "PerObjectData.bslinc",
-            "UUID": "ed07f3ce-3abd-4379-b8f0-4c884af524a7"
-        },
-        {
-            "Path": "PPBase.bslinc",
-            "UUID": "44dc42de-410a-4949-a2e8-cb451a416481"
-        },
-        {
-            "Path": "PPTonemapCommon.bslinc",
-            "UUID": "a5d1c354-a05d-45b4-bccf-2f88db9aecb0"
-        },
-        {
-            "Path": "PPWhiteBalance.bslinc",
-            "UUID": "b46d1cee-75f7-4387-8b32-7eb646f099f4"
-        },
-        {
-            "Path": "ReflectionCubemapCommon.bslinc",
-            "UUID": "eef92578-b8ed-45d6-8eed-d85697ade3c5"
-        },		
-        {
-            "Path": "ResolveCommon.bslinc",
-            "UUID": "1cde4f3c-534e-4128-8ee1-63e3bb620734"
-        },
-        {
-            "Path": "SkinnedVertexInput.bslinc",
-            "UUID": "d6a2ea27-5f4c-41ad-88bc-cad7dd7adc8d"
-        },
-        {
-            "Path": "SpriteImage.bslinc",
-            "UUID": "0114b1da-9899-45ca-8486-a9791482d3c5"
-        },
-        {
-            "Path": "Surface.bslinc",
-            "UUID": "468be285-026c-49d8-99ea-5f1709ea605a"
-        },
-        {
-            "Path": "VolumeRenderBase.bslinc",
-            "UUID": "6d0dfe4e-45ef-4fe1-9344-33b8b9e69048"
-        }
-    ],
-    "Shaders": [
-        {
-            "Path": "Blit.bsl",
-            "UUID": "7953ba8a-6fc6-43ad-a472-cce558105cde"
-        },
-        {
-            "Path": "Default.bsl",
-            "UUID": "a8e36d37-d6f7-4117-bbba-31dca716c8a3"
-        },
-        {
-            "Path": "DeferredDirectionalLightPass.bsl",
-            "UUID": "57de2ae2-96a1-4067-88c3-8a3967b90657"
-        },
-        {
-            "Path": "DeferredPointLightPassIn.bsl",
-            "UUID": "7757c740-5657-45aa-a2ce-cf86da65c047"
-        },
-        {
-            "Path": "DeferredPointLightPassOut.bsl",
-            "UUID": "a5f2cc18-855e-4d33-a040-0926dc753a2d"
-        },
-        {
-            "Path": "Diffuse.bsl",
-            "UUID": "4e2b2437-0a02-456c-8d98-71df27ccf697"
-        },
-        {
-            "Path": "PPCreateTonemapLUT.bsl",
-            "UUID": "766adb8c-1302-4f2d-a26f-6a0f8ff6b147"
-        },
-        {
-            "Path": "PPDownsample.bsl",
-            "UUID": "c1a11fc5-f7b4-422d-a359-70be6dac05ef"
-        },
-        {
-            "Path": "PPEyeAdaptation.bsl",
-            "UUID": "6baa01c8-fe61-4613-9fa9-a9ae045dfc64"
-        },
-        {
-            "Path": "PPEyeAdaptHistogram.bsl",
-            "UUID": "5414fffc-a96c-4a8a-86e3-c24050d14363"
-        },
-        {
-            "Path": "PPEyeAdaptHistogramReduce.bsl",
-            "UUID": "4c98431b-bd58-4160-8ff0-7d12add946fa"
-        },
-        {
-            "Path": "PPTonemapping.bsl",
-            "UUID": "cbe752ea-301a-47aa-b8ae-2f35d103595c"
-        },
-        {
-            "Path": "PPTonemapping.bsl",
-            "UUID": "36366f4c-3584-4dbf-9c2b-bb2638438b33"
-        },
-        {
-            "Path": "PPTonemapping.bsl",
-            "UUID": "520d9228-c7b5-492e-bd08-1fdc7e033ea8"
-        },
-        {
-            "Path": "PPTonemapping.bsl",
-            "UUID": "a8aa01e7-7e72-4f84-89f8-a0097250b0d3"
-        },
-        {
-            "Path": "ReflectionCubemapFilter.bsl",
-            "UUID": "31b4b9ae-2afa-4cd8-b532-fe82a7f42baa"
-        },		
-        {
-            "Path": "Resolve.bsl",
-            "UUID": "9d5f5101-2d7e-432c-b8ad-1998de9ca5c7"
-        },
-        {
-            "Path": "Skybox.bsl",
-            "UUID": "b1c191fa-0c24-4987-8d3b-72b17511621d"
-        },		
-        {
-            "Path": "SpriteImageAlpha.bsl",
-            "UUID": "4c00537f-9d3e-4cb7-8a30-b4ee9f278006"
-        },
-        {
-            "Path": "SpriteImageNoAlpha.bsl",
-            "UUID": "2db979ff-386a-492e-8f6d-675ed5133e31"
-        },
-        {
-            "Path": "SpriteLine.bsl",
-            "UUID": "3a9e31a8-cbef-49ac-af2a-2dc200372d36"
-        },
-        {
-            "Path": "SpriteText.bsl",
-            "UUID": "25df2c87-c206-4c2f-ab2b-3aad9e7f90f1"
-        },
-        {
-            "Path": "TestFX.bsl",
-            "UUID": "9e783e45-bf1f-41cc-bb48-eb2e1200cfb6"
-        }
-    ]	
+    ]
 }

+ 0 - 327
Data/Raw/Engine/Includes/DeferredLightPass.bslinc

@@ -1,327 +0,0 @@
-#include "$ENGINE$\GBuffer.bslinc"
-#include "$ENGINE$\PerCameraData.bslinc"
-
-Parameters =
-{
-	Sampler2D 	gGBufferASamp : alias("gGBufferATex");
-	Sampler2D 	gGBufferBSamp : alias("gGBufferBTex");
-	Sampler2D 	gDepthBufferSamp : alias("gDepthBufferTex");
-	
-	Texture2D 	gGBufferATex : auto("GBufferA");
-	Texture2D	gGBufferBTex : auto("GBufferB");
-	Texture2D 	gDepthBufferTex : auto("GBufferDepth");
-};
-
-Blocks =
-{
-	Block PerCamera : auto("PerCamera");
-	Block PerLight : auto("PerLight");
-};
-
-Technique
- : base("DeferredLightPass")
- : inherits("GBuffer")
- : inherits("PerCameraData") =
-{
-	Language = "HLSL11";
-	
-	Pass =
-	{
-		Target = 
-		{
-			Blend = true;
-			Color = { ONE, ONE, ADD };
-			WriteMask = RGB;
-		};
-		
-		DepthWrite = false;
-
-		Common = 
-		{
-			#define PI 3.1415926
-			#define HALF_PI 1.5707963
-			
-			cbuffer PerLight
-			{
-				// x, y, z - World position of the light
-				// w - Light type - Directional = 0, Point = >0, Spot = >0.5
-				float4 gLightPositionAndType;
-				float4 gLightColorAndIntensity;
-				// x - outerAngle in radians, y - cos(outerAngle), z - 1.0f/(cos(innerAngle) - cos(outerAngle)), w - inverse point light radius
-				float4 gLightSpotAnglesAndSqrdInvRadius;
-				float3 gLightDirection;
-				
-				// x - Num sides (zero for point lights)
-				// y - Num slices (zero for point lights)
-				// z - Sphere radius for point lights
-				// w - Cone radius for spot lights
-				float4 gLightGeometry; 
-				float4x4 gMatConeTransform;
-			}
-			
-			struct LightData
-			{
-				float3 position;
-				float3 direction;
-				float intensity;
-				bool isSpot;
-				bool isPoint;
-				float3 spotAngles; 
-				float3 color;
-				float radiusSqrdInv;
-			};
-			
-			float convertFromDeviceZ(float deviceZ)
-			{
-				return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;
-			}
-			
-			GBufferData decodeGBuffer(float4 GBufferAData, float4 GBufferBData, float deviceZ)
-			{
-				GBufferData output;
-				
-				output.albedo.xyz = GBufferAData.xyz;
-				output.albedo.w = 1.0f;
-				output.worldNormal = GBufferBData * float4(2, 2, 2, 1) - float4(1, 1, 1, 0);
-				output.worldNormal.xyz = normalize(output.worldNormal.xyz);
-				output.depth = convertFromDeviceZ(deviceZ);
-				
-				return output;
-			}
-			
-			LightData getLightData()
-			{
-				LightData output;
-				
-				output.position = gLightPositionAndType.xyz;
-				output.direction = gLightDirection;
-				output.color = gLightColorAndIntensity.rgb;
-				output.intensity = gLightColorAndIntensity.w;
-				output.isPoint = gLightPositionAndType.w > 0.0f;
-				output.isSpot = gLightPositionAndType.w > 0.5f;
-				output.spotAngles = gLightSpotAnglesAndSqrdInvRadius.xyz;
-				output.radiusSqrdInv = gLightSpotAnglesAndSqrdInvRadius.w;
-				
-				return output;
-			}
-			
-			float getSpotAttenuation(float3 worldPosToLight, float3 direction, float3 angles)
-			{
-				float output = saturate((dot(-worldPosToLight, direction) - angles.y) * angles.z);
-				return output * output;
-			}			
-			
-			float4 getLighting(float3 worldPosition, float2 uv, GBufferData gBuffer, LightData lightData)
-			{
-				float3 N = gBuffer.worldNormal.xyz;
-				float NoL = 1.0f;
-				
-				float distanceAttenuation = 1.0f;
-				float spotFalloff = 1.0f;
-				float radiusAttenuation = 1.0f;
-				if (lightData.isPoint)
-				{
-					float3 L = lightData.position - worldPosition;
-					
-					float distanceSqrd = dot(L, L);
-					distanceAttenuation = 1/(distanceSqrd + 1);
-					
-					L = normalize(L);
-					NoL = saturate(dot(N, L)); // TODO - Add bias here?
-
-					radiusAttenuation = distanceSqrd * lightData.radiusSqrdInv;
-					radiusAttenuation *= radiusAttenuation;
-					radiusAttenuation = saturate(1.0f - radiusAttenuation);
-					radiusAttenuation *= radiusAttenuation;
-					
-					if (lightData.isSpot)
-						spotFalloff = getSpotAttenuation(L, lightData.direction, lightData.spotAngles);
-				}
-				else
-				{
-					float3 L = -lightData.direction;
-					NoL = saturate(dot(N, L)); // TODO - Add bias here?
-				}
-
-				float attenuation = distanceAttenuation * spotFalloff * radiusAttenuation;
-
-				float3 diffuse = gBuffer.albedo.xyz / PI; // TODO - Add better lighting model later
-
-				float4 output = float4(lightData.color * lightData.intensity * ((NoL * attenuation) * diffuse), 1);
-				return output;
-			}
-		};
-		
-		Fragment = 
-		{
-			SamplerState 	gGBufferASamp : register(s0);
-			SamplerState 	gGBufferBSamp : register(s1);
-			SamplerState 	gDepthBufferSamp : register(s2);
-	
-			Texture2D 	gGBufferATex : register(t0);
-			Texture2D	gGBufferBTex : register(t1);
-			Texture2D 	gDepthBufferTex : register(t2);
-			
-			GBufferData getGBufferData(float2 uv)
-			{
-				float4 GBufferAData = gGBufferATex.SampleLevel(gGBufferASamp, uv, 0);
-				float4 GBufferBData = gGBufferBTex.SampleLevel(gGBufferBSamp, uv, 0);
-				float deviceZ = gDepthBufferTex.SampleLevel(gDepthBufferSamp, uv, 0).r;
-				
-				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
-			}			
-		};	
-	};
-};
-
-Technique
- : base("DeferredLightPass")
- : inherits("GBuffer")
- : inherits("PerCameraData") =
-{
-	Language = "GLSL";
-	
-	Pass =
-	{
-		Target = 
-		{
-			Blend = true;
-			Color = { ONE, ONE, ADD };
-			WriteMask = RGB;
-		};
-		
-		DepthWrite = false;
-
-		Common = 
-		{
-			#define PI 3.1415926
-			#define HALF_PI 1.5707963
-			
-			layout(binding = 1, std140) uniform PerLight
-			{
-				// x, y, z - World position of the lightData
-				// w - Type type - Directional = 0, Point = >0, Spot = >0.5
-				vec4 gLightPositionAndType;
-				vec4 gLightColorAndIntensity;
-				// x - outerAngle in radians, y - cos(outerAngle), z - 1.0f/(cos(innerAngle) - cos(outerAngle)), w - inverse point light radius
-				vec4 gLightSpotAnglesAndSqrdInvRadius;
-				vec3 gLightDirection;
-				
-				// x - Num sides (zero for point lights)
-				// y - Num slices (zero for point lights)
-				// z - Sphere radius for point lights
-				// w - Cone radius for spot lights
-				vec4 gLightGeometry; 
-				mat4 gMatConeTransform;
-			};
-			
-			struct LightData
-			{
-				vec3 position;
-				vec3 direction;
-				float intensity;
-				bool isSpot;
-				bool isPoint;
-				vec3 spotAngles; 
-				vec3 color;
-				float radiusSqrdInv;
-			};
-			
-			float convertFromDeviceZ(float deviceZ)
-			{
-				return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;	
-			}
-			
-			GBufferData decodeGBuffer(vec4 GBufferAData, vec4 GBufferBData, float deviceZ)
-			{
-				GBufferData gBufferData;
-				
-				gBufferData.albedo.xyz = GBufferAData.xyz;
-				gBufferData.albedo.w = 1.0f;
-				gBufferData.worldNormal = GBufferBData * vec4(2, 2, 2, 1) - vec4(1, 1, 1, 0);
-				gBufferData.worldNormal.xyz = normalize(gBufferData.worldNormal.xyz);
-				gBufferData.depth = convertFromDeviceZ(deviceZ);
-				
-				return gBufferData;
-			}
-			
-			LightData getLightData()
-			{
-				LightData lightData;
-				
-				lightData.position = gLightPositionAndType.xyz;
-				lightData.direction = gLightDirection;
-				lightData.color = gLightColorAndIntensity.rgb;
-				lightData.intensity = gLightColorAndIntensity.w;
-				lightData.isPoint = gLightPositionAndType.w > 0.0f;
-				lightData.isSpot = gLightPositionAndType.w > 0.5f;
-				lightData.spotAngles = gLightSpotAnglesAndSqrdInvRadius.xyz;
-				lightData.radiusSqrdInv = gLightSpotAnglesAndSqrdInvRadius.w;
-				
-				return lightData;
-			}
-			
-			float getSpotAttenuation(vec3 worldPosToLight, vec3 direction, vec3 angles)
-			{
-				float atten = clamp((dot(-worldPosToLight, direction) - angles.y) * angles.z, 0.0, 1.0);
-				return atten * atten;
-			}			
-			
-			vec4 getLighting(vec3 worldPosition, vec2 uv, GBufferData gBuffer, LightData lightData)
-			{
-				vec3 N = gBuffer.worldNormal.xyz;
-				float NoL = 1.0f;
-				
-				float distanceAttenuation = 1.0f;
-				float spotFalloff = 1.0f;
-				float radiusAttenuation = 1.0f;
-				if (lightData.isPoint)
-				{
-					vec3 L = lightData.position - worldPosition;
-					
-					float distanceSqrd = dot(L, L);
-					distanceAttenuation = 1/(distanceSqrd + 1);
-					
-					L = normalize(L);
-					NoL = clamp(dot(N, L), 0.0, 1.0); // TODO - Add bias here?
-
-					radiusAttenuation = distanceSqrd * lightData.radiusSqrdInv;
-					radiusAttenuation *= radiusAttenuation;
-					radiusAttenuation = clamp(1.0f - radiusAttenuation, 0.0, 1.0);
-					radiusAttenuation *= radiusAttenuation;
-					
-					if (lightData.isSpot)
-						spotFalloff = getSpotAttenuation(L, lightData.direction, lightData.spotAngles);
-				}
-				else
-				{
-					vec3 L = -lightData.direction;
-					NoL = clamp(dot(N, L), 0.0, 1.0); // TODO - Add bias here?
-				}
-
-				float attenuation = distanceAttenuation * spotFalloff * radiusAttenuation;
-
-				vec3 diffuse = gBuffer.albedo.xyz / PI; // TODO - Add better lighting model later
-
-				vec4 lighting = vec4(lightData.color * lightData.intensity * ((NoL * attenuation) * diffuse), 1);
-				return lighting;
-			}
-		};
-		
-		Fragment = 
-		{
-			layout(binding = 2) uniform sampler2D gGBufferATex;
-			layout(binding = 3) uniform sampler2D gGBufferBTex;
-			layout(binding = 4) uniform sampler2D gDepthBufferTex;
-			
-			GBufferData getGBufferData(vec2 uv)
-			{
-				vec4 GBufferAData = textureLod(gGBufferATex, uv, 0);
-				vec4 GBufferBData = textureLod(gGBufferBTex, uv, 0);
-				float deviceZ = textureLod(gDepthBufferTex, uv, 0).r;
-				
-				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
-			}			
-		};	
-	};
-};

+ 0 - 257
Data/Raw/Engine/Includes/DeferredPointLightPass.bslinc

@@ -1,257 +0,0 @@
-#include "$ENGINE$\DeferredLightPass.bslinc"
-
-Technique 
- : inherits("DeferredLightPass") =
-{
-	Language = "HLSL11";
-	
-	Pass =
-	{
-		DepthWrite = false;
-	
-		#ifdef INSIDE_GEOMETRY
-		
-		DepthRead = false;
-		Cull = CW;
-		
-		#else
-		
-		DepthRead = true;
-		Cull = CCW;
-		
-		#endif
-	
-		Common = 
-		{
-			struct VStoFS
-			{
-				float4 position : SV_POSITION;
-				float4 screenPos : TEXCOORD0;
-			};
-		};
-	
-		Vertex =
-		{
-			struct VertexInput
-			{
-				float3 position : POSITION;
-				uint vertexIdx : SV_VERTEXID;
-			};
-			
-			VStoFS main(VertexInput input)
-			{
-				VStoFS output;
-				
-				float3 worldPosition;
-				uint numSides = gLightGeometry.x;
-				if(numSides > 0) // Generate spot light geometry
-				{
-					uint numSlices = gLightGeometry.y;
-					float radius = gLightGeometry.w;
-					float angle = gLightSpotAnglesAndSqrdInvRadius.x;
-				
-					// Extra scale to ensure edges lie on the circle, not inside it
-					// TODO - These can be precomputed
-					float extraRadiusScale = 1.0f / cos(PI / (float)numSides);
-					float angleTan = tan(angle);
-					float height = radius / angleTan;
-		
-					uint sphereStartIdx = numSides * numSlices;
-					// Cone vertices
-					if (input.vertexIdx < sphereStartIdx)
-					{
-						uint sliceIdx = input.vertexIdx / numSides;
-						uint sideIdx = input.vertexIdx % numSides;
-
-						float curAngle = sideIdx * 2 * PI / (float)numSides;
-						float sliceOffset = height * sliceIdx / (float)(numSlices - 1);
-						float sliceRadius = sliceOffset * angleTan * extraRadiusScale;
-
-						float4 localPos = float4(sliceRadius * cos(curAngle), 
-							sliceRadius * sin(curAngle), -sliceOffset, 1.0f);
-						worldPosition = (mul(gMatConeTransform, localPos)).xyz;
-					}
-					else // Sphere cap vertices
-					{
-						uint sphereVertexIdx = input.vertexIdx - sphereStartIdx;
-						uint sliceIdx = sphereVertexIdx / numSides;
-						uint sideIdx = sphereVertexIdx % numSides;
-
-						float curAngle = sideIdx * 2 * PI / (float)numSides;
-						float sliceOffset = radius * sliceIdx / (float)(numSlices - 1);
-						float sliceRadius = sqrt(max(0.0f, radius * radius - sliceOffset * sliceOffset)) * extraRadiusScale;
-
-						float4 localPos = float4(sliceRadius * cos(curAngle), 
-							sliceRadius * sin(curAngle), -height - sliceOffset, 1.0f);
-						worldPosition = (mul(gMatConeTransform, localPos)).xyz;
-					}
-				}
-				else // Scale and position pre-generated sphere geometry
-				{
-					worldPosition = input.position * gLightGeometry.z + gLightPositionAndType.xyz;
-				}
-				
-				output.screenPos = mul(gMatViewProj, float4(worldPosition, 1));
-				output.position = output.screenPos;
-				
-				return output;
-			}			
-		};
-		
-		Fragment = 
-		{
-			float4 main(VStoFS input) : SV_Target0
-			{
-				float2 correctedPos = input.screenPos.xy / input.screenPos.w;
-				float2 screenUV = correctedPos * gClipToUVScaleOffset.xy + gClipToUVScaleOffset.zw;
-
-				GBufferData gBufferData = getGBufferData(screenUV);
-				
-				if(gBufferData.worldNormal.w > 0.0f)
-				{
-					// x, y are now in clip space, z, w are in view space
-					// We multiply them by a special inverse view-projection matrix, that had the projection entries that effect
-					// z, w eliminated (since they are already in view space)
-					float4 mixedSpacePos = float4(correctedPos.xy * -gBufferData.depth, gBufferData.depth, 1);
-					float4 worldPosition4D = mul(gMatScreenToWorld, mixedSpacePos);
-					float3 worldPosition = worldPosition4D.xyz / worldPosition4D.w;
-
-					LightData lightData = getLightData();
-					return getLighting(worldPosition, screenUV, gBufferData, lightData);
-				}
-				else
-					return float4(0.0f, 0.0f, 0.0f, 0.0f);
-			}
-		};
-	};
-};
-
-Technique
- : inherits("DeferredLightPass") =
-{
-	Language = "GLSL";
-	
-	Pass =
-	{
-		DepthWrite = false;
-	
-		#ifdef INSIDE_GEOMETRY
-		
-		DepthRead = false;
-		Cull = CW;
-		
-		#else
-		
-		DepthRead = true;
-		Cull = CCW;
-		
-		#endif
-	
-		Vertex =
-		{
-			layout(location = 0) in vec3 bs_position;
-		
-			layout(location = 0) out vec4 position;
-			layout(location = 1) out vec4 screenPos;
-			
-			out gl_PerVertex
-			{
-				vec4 gl_Position;
-			};				
-			
-			void main()
-			{
-				vec3 worldPosition;
-				uint numSides = uint(gLightGeometry.x);
-				if(numSides > 0) // Generate spot light geometry
-				{
-					uint numSlices = uint(gLightGeometry.y);
-					float radius = gLightGeometry.w;
-					float angle = gLightSpotAnglesAndSqrdInvRadius.x;
-				
-					// Extra scale to ensure edges lie on the circle, not inside it
-					// TODO - These can be precomputed
-					float extraRadiusScale = 1.0f / cos(PI / float(numSides));
-					float angleTan = tan(angle);
-					float height = radius / angleTan;
-		
-					#ifdef VULKAN
-						uint vertexIdx = gl_VertexIndex;
-					#else
-						uint vertexIdx = gl_VertexID;
-					#endif
-		
-					uint sphereStartIdx = numSides * numSlices;
-					// Cone vertices
-					if (vertexIdx < sphereStartIdx)
-					{
-						uint sliceIdx = vertexIdx / numSides;
-						uint sideIdx = vertexIdx % numSides;
-
-						float curAngle = float(sideIdx) * 2 * PI / float(numSides);
-						float sliceOffset = height * sliceIdx / float(numSlices - 1);
-						float sliceRadius = sliceOffset * angleTan * extraRadiusScale;
-
-						vec4 localPos = vec4(sliceRadius * cos(curAngle), 
-							sliceRadius * sin(curAngle), -sliceOffset, 1.0f);
-						worldPosition = (gMatConeTransform * localPos).xyz;
-					}
-					else // Sphere cap vertices
-					{
-						uint sphereVertexIdx = vertexIdx - sphereStartIdx;
-						uint sliceIdx = sphereVertexIdx / numSides;
-						uint sideIdx = sphereVertexIdx % numSides;
-
-						float curAngle = float(sideIdx) * 2 * PI / float(numSides);
-						float sliceOffset = radius * sliceIdx / float(numSlices - 1);
-						float sliceRadius = sqrt(max(0.0f, radius * radius - sliceOffset * sliceOffset)) * extraRadiusScale;
-
-						vec4 localPos = vec4(sliceRadius * cos(curAngle), 
-							sliceRadius * sin(curAngle), -height - sliceOffset, 1.0f);
-						worldPosition = (gMatConeTransform * localPos).xyz;
-					}
-				}
-				else // Scale and position pre-generated sphere geometry
-				{
-					worldPosition = bs_position * gLightGeometry.z + gLightPositionAndType.xyz;
-				}
-				
-				screenPos = gMatViewProj * vec4(worldPosition, 1);
-				position = screenPos;
-				
-				gl_Position = position;
-			}			
-		};
-		
-		Fragment = 
-		{
-			layout(location = 0) in vec4 position;
-			layout(location = 1) in vec4 screenPos;
-		
-			layout(location = 0) out vec4 fragColor;
-		
-			void main()
-			{
-				vec2 correctedPos = screenPos.xy / screenPos.w;
-				vec2 screenUV = correctedPos * gClipToUVScaleOffset.xy + gClipToUVScaleOffset.zw;
-
-				GBufferData gBufferData = getGBufferData(screenUV);
-				
-				if(gBufferData.worldNormal.w > 0.0f)
-				{
-					// x, y are now in clip space, z, w are in view space
-					// We multiply them by a special inverse view-projection matrix, that had the projection entries that effect
-					// z, w eliminated (since they are already in view space)
-					vec4 mixedSpacePos = vec4(correctedPos.xy * -gBufferData.depth, gBufferData.depth, 1);
-					vec4 worldPosition4D = gMatScreenToWorld * mixedSpacePos;
-					vec3 worldPosition = worldPosition4D.xyz / worldPosition4D.w;
-
-					LightData lightData = getLightData();
-					fragColor = getLighting(worldPosition, screenUV, gBufferData, lightData);
-				}
-				else
-					fragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f);
-			}
-		};
-	};
-};

+ 10 - 18
Data/Raw/Engine/Includes/GBuffer.bslinc

@@ -1,4 +1,8 @@
-Technique : base("GBuffer") =
+#include "$ENGINE$\SurfaceData.bslinc"
+
+Technique 
+ : inherits("SurfaceData")
+ : base("GBuffer") =
 {
 	Language = "HLSL11";
 
@@ -6,14 +10,7 @@ Technique : base("GBuffer") =
 	{
 		Common = 
 		{
-			struct GBufferData
-			{
-				float4 albedo;
-				float4 worldNormal;
-				float depth;
-			};
-			
-			void encodeGBuffer(GBufferData data, out float4 GBufferAData, out float4 GBufferBData)
+			void encodeGBuffer(SurfaceData data, out float4 GBufferAData, out float4 GBufferBData)
 			{
 				GBufferAData = data.albedo;
 				GBufferBData.xyz = float3(data.worldNormal.xyz * 0.5f + 0.5f);
@@ -23,7 +20,9 @@ Technique : base("GBuffer") =
 	};
 };
 
-Technique : base("GBuffer") =
+Technique 
+ : inherits("SurfaceData")
+ : base("GBuffer") =
 {
 	Language = "GLSL";
 
@@ -31,14 +30,7 @@ Technique : base("GBuffer") =
 	{
 		Common = 
 		{
-			struct GBufferData
-			{
-				vec4 albedo;
-				vec4 worldNormal;
-				float depth;
-			};
-			
-			void encodeGBuffer(GBufferData data, out vec4 GBufferAData, out vec4 GBufferBData)
+			void encodeGBuffer(SurfaceData data, out vec4 GBufferAData, out vec4 GBufferBData)
 			{
 				GBufferAData = data.albedo;
 				GBufferBData.xyz = vec3(data.worldNormal.xyz * 0.5f + 0.5f);

+ 169 - 0
Data/Raw/Engine/Includes/LightingCommon.bslinc

@@ -0,0 +1,169 @@
+#include "$ENGINE$\PerCameraData.bslinc"
+
+Blocks =
+{
+	Block PerCamera : auto("PerCamera");
+};
+
+Technique
+ : base("LightingCommon")
+ : inherits("PerCameraData") =
+{
+	Language = "HLSL11";
+	
+	Pass =
+	{
+		Compute = 
+		{
+			#define PI 3.1415926
+			#define HALF_PI 1.5707963
+			
+			struct LightData
+			{
+				float3 position;
+				float radius;
+				float3 direction;
+				float intensity;
+				float3 spotAngles;
+				float radiusSqrdInv;
+				float3 color;
+			};
+			
+			float convertFromDeviceZ(float deviceZ)
+			{
+				return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;
+			}
+			
+			float getSpotAttenuation(float3 worldPosToLight, float3 direction, float3 angles)
+			{
+				float output = saturate((dot(-worldPosToLight, direction) - angles.y) * angles.z);
+				return output * output;
+			}			
+			
+			float3 getDirLightContibution(SurfaceData surfaceData, LightData lightData)
+			{
+				float3 N = surfaceData.worldNormal.xyz;
+				float3 L = -lightData.direction;
+				
+				float NoL = saturate(dot(N, L)); // TODO - Add bias here?
+				return lightData.color * lightData.intensity * NoL;
+			}
+			
+			float3 getPointLightContribution(float3 L, float3 worldPosition, SurfaceData surfaceData, LightData lightData)
+			{
+				float3 N = surfaceData.worldNormal.xyz;
+				
+				float distanceSqrd = dot(L, L);
+				float distanceAttenuation = 1/(distanceSqrd + 1);
+				
+				L = normalize(L);
+				float NoL = saturate(dot(N, L)); // TODO - Add bias here?
+
+				float radiusAttenuation = distanceSqrd * lightData.radiusSqrdInv;
+				radiusAttenuation *= radiusAttenuation;
+				radiusAttenuation = saturate(1.0f - radiusAttenuation);
+				radiusAttenuation *= radiusAttenuation;
+
+				float attenuation = distanceAttenuation * radiusAttenuation;
+				return lightData.color * lightData.intensity * (NoL * attenuation);
+			}
+			
+			float3 getPointLightContribution(float3 worldPosition, SurfaceData surfaceData, LightData lightData)
+			{
+				float3 L = lightData.position - worldPosition;
+				
+				return getPointLightContribution(L, worldPosition, surfaceData, lightData);
+			}
+			
+			float3 getSpotLightContribution(float3 worldPosition, SurfaceData surfaceData, LightData lightData)
+			{
+				float3 L = lightData.position - worldPosition;
+				float3 pointLightContribution = getPointLightContribution(L, worldPosition, surfaceData, lightData);
+				float spotFalloff = getSpotAttenuation(L, lightData.direction, lightData.spotAngles);
+				
+				return pointLightContribution * spotFalloff;
+			}
+		};
+	};
+};
+
+Technique
+ : base("LightingCommon")
+ : inherits("PerCameraData") =
+{
+	Language = "GLSL";
+	
+	Pass =
+	{
+		Compute = 
+		{
+			#define PI 3.1415926
+			#define HALF_PI 1.5707963
+			
+			struct LightData
+			{
+				vec3 position;
+				float radius;
+				vec3 direction;
+				float intensity;
+				vec3 spotAngles;
+				float radiusSqrdInv;
+				vec3 color;
+			};
+			
+			float convertFromDeviceZ(float deviceZ)
+			{
+				return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;	
+			}
+						
+			float getSpotAttenuation(vec3 worldPosToLight, vec3 direction, vec3 angles)
+			{
+				float atten = clamp((dot(-worldPosToLight, direction) - angles.y) * angles.z, 0.0, 1.0);
+				return atten * atten;
+			}
+			
+			vec3 getDirLightContibution(SurfaceData surfaceData, LightData lightData)
+			{
+				vec3 N = surfaceData.worldNormal.xyz;
+				vec3 L = -lightData.direction;
+				
+				float NoL = clamp(dot(N, L), 0.0, 1.0); // TODO - Add bias here?
+				return lightData.color * lightData.intensity * NoL;
+			}
+			
+			vec3 getPointLightContribution(vec3 L, vec3 worldPosition, SurfaceData surfaceData, LightData lightData)
+			{
+				vec3 N = surfaceData.worldNormal.xyz;
+
+				float distanceSqrd = dot(L, L);
+				float distanceAttenuation = 1/(distanceSqrd + 1);
+				
+				L = normalize(L);
+				float NoL = clamp(dot(N, L), 0.0, 1.0); // TODO - Add bias here?
+
+				float radiusAttenuation = distanceSqrd * lightData.radiusSqrdInv;
+				radiusAttenuation *= radiusAttenuation;
+				radiusAttenuation = clamp(1.0f - radiusAttenuation, 0.0, 1.0);
+				radiusAttenuation *= radiusAttenuation;
+				
+				float attenuation = distanceAttenuation * radiusAttenuation;
+				return lightData.color * lightData.intensity * ((NoL * attenuation));
+			}
+			
+			vec3 getPointLightContribution(vec3 worldPosition, SurfaceData surfaceData, LightData lightData)
+			{
+				vec3 L = lightData.position - worldPosition;
+				return getPointLightContribution(L, worldPosition, surfaceData, lightData);
+			}
+			
+			vec3 getSpotLightContribution(vec3 worldPosition, SurfaceData surfaceData, LightData lightData)
+			{
+				vec3 L = lightData.position - worldPosition;
+				vec3 pointLightContribution = getPointLightContribution(L, worldPosition, surfaceData, lightData);
+				float spotFalloff = getSpotAttenuation(L, lightData.direction, lightData.spotAngles);
+				
+				return pointLightContribution * spotFalloff;
+			}
+		};
+	};
+};

+ 6 - 0
Data/Raw/Engine/Includes/PerCameraData.bslinc

@@ -16,6 +16,10 @@ Parameters =
 	// Converts device Z to world Z using this formula: worldZ = (1 / (deviceZ + y)) * x
 	float2		gDeviceZToWorldZ : auto("DeviceToWorldZ");
 	
+	// xy - Viewport offset in pixels
+	// zw - Viewport width & height in pixels
+	int4 		gViewportRectangle : auto("ViewportRect");
+	
 	// xy - (Viewport size in pixels / 2) / Target size in pixels
 	// zw - (Viewport offset in pixels + (Viewport size in pixels / 2) + Optional pixel center offset) / Target size in pixels	
 	float4 		gClipToUVScaleOffset : auto("ClipToUVScaleOffset");		
@@ -45,6 +49,7 @@ Technique : base("PerCameraData") =
 				float4x4 gMatInvViewProj;
 				float4x4 gMatScreenToWorld;
 				float2 	 gDeviceZToWorldZ;
+				int4 	 gViewportRectangle;
 				float4 	 gClipToUVScaleOffset;				
 			}
 		};
@@ -70,6 +75,7 @@ Technique : base("PerCameraData") =
 				mat4 gMatInvViewProj;
 				mat4 gMatScreenToWorld;
 				vec2 gDeviceZToWorldZ;
+				ivec4 gViewportRectangle;
 				vec4 gClipToUVScaleOffset;				
 			};
 		};

+ 35 - 0
Data/Raw/Engine/Includes/SurfaceData.bslinc

@@ -0,0 +1,35 @@
+Technique : base("SurfaceData") =
+{
+	Language = "HLSL11";
+
+	Pass =
+	{
+		Common = 
+		{
+			struct SurfaceData
+			{
+				float4 albedo;
+				float4 worldNormal;
+				float depth;
+			};
+		};
+	};
+};
+
+Technique : base("SurfaceData") =
+{
+	Language = "GLSL";
+
+	Pass =
+	{
+		Common = 
+		{
+			struct SurfaceData
+			{
+				vec4 albedo;
+				vec4 worldNormal;
+				float depth;
+			};
+		};
+	};
+};

+ 10 - 10
Data/Raw/Engine/Shaders/Default.bsl

@@ -13,14 +13,14 @@ Technique : base("Surface") =
 				out float4 OutGBufferA : SV_Target1,
 				out float4 OutGBufferB : SV_Target2) : SV_Target0
 			{
-				GBufferData gbufferData;
-				gbufferData.albedo = float4(0.05f, 0.05f, 0.05f, 1.0f);
-				gbufferData.worldNormal.xyz = input.tangentToWorldZ;
+				SurfaceData surfaceData;
+				surfaceData.albedo = float4(0.05f, 0.05f, 0.05f, 1.0f);
+				surfaceData.worldNormal.xyz = input.tangentToWorldZ;
 				
-				encodeGBuffer(gbufferData, OutGBufferA, OutGBufferB);
+				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB);
 				
 				// TODO - Just returning a simple ambient term, use better environment lighting later
-				return float4(gbufferData.albedo.rgb, 1.0f); 
+				return float4(surfaceData.albedo.rgb, 1.0f); 
 			}	
 		};
 	};
@@ -42,14 +42,14 @@ Technique : base("Surface") =
 		
 			void main()
 			{
-				GBufferData gbufferData;
-				gbufferData.albedo = vec4(0.05f, 0.05f, 0.05f, 1.0f);
-				gbufferData.worldNormal.xyz = tangentToWorldZ;
+				SurfaceData surfaceData;
+				surfaceData.albedo = vec4(0.05f, 0.05f, 0.05f, 1.0f);
+				surfaceData.worldNormal.xyz = tangentToWorldZ;
 				
-				encodeGBuffer(gbufferData, fragColor[1], fragColor[2]);
+				encodeGBuffer(surfaceData, fragColor[1], fragColor[2]);
 				
 				// TODO - Just returning a simple ambient term, use better environment lighting later
-				fragColor[0] = vec4(gbufferData.albedo.rgb, 1.0f); 
+				fragColor[0] = vec4(surfaceData.albedo.rgb, 1.0f); 
 			}	
 		};
 	};

+ 0 - 121
Data/Raw/Engine/Shaders/DeferredDirectionalLightPass.bsl

@@ -1,121 +0,0 @@
-#include "$ENGINE$\DeferredLightPass.bslinc"
-
-Technique 
-  : inherits("DeferredLightPass") =
-{
-	Language = "HLSL11";
-	
-	Pass =
-	{
-		DepthRead = false;
-	
-		Common = 
-		{
-			struct VStoFS
-			{
-				float4 position : SV_POSITION;
-				float2 uv0 : TEXCOORD0;
-				float3 screenDir : TEXCOORD1;
-			};
-		};
-	
-		Vertex =
-		{
-			struct VertexInput
-			{
-				float2 screenPos : POSITION;
-				float2 uv0 : TEXCOORD0;
-			};
-			
-			VStoFS main(VertexInput input)
-			{
-				VStoFS output;
-			
-				output.position = float4(input.screenPos, 0, 1);
-				output.uv0 = input.uv0;
-				output.screenDir = mul(gMatInvProj, float4(input.screenPos, 1, 0)).xyz - gViewOrigin.xyz;
-			
-				return output;
-			}			
-		};
-		
-		Fragment = 
-		{
-			float4 main(VStoFS input) : SV_Target0
-			{
-				GBufferData gBufferData = getGBufferData(input.uv0);
-
-				if(gBufferData.worldNormal.w > 0.0f)
-				{
-					float3 cameraDir = normalize(input.screenDir);
-					float3 worldPosition = input.screenDir * gBufferData.depth + gViewOrigin;
-					
-					LightData lightData = getLightData();
-					return getLighting(worldPosition, input.uv0, gBufferData, lightData);
-				}
-				else
-					return float4(0.0f, 0.0f, 0.0f, 0.0f);
-			}
-		};
-	};
-};
-
-Technique 
-	: inherits("DeferredLightPass") =
-{
-	Language = "GLSL";
-	
-	Pass =
-	{
-		DepthRead = false;
-	
-		Vertex =
-		{
-			layout(location = 0) in vec2 bs_position;
-			layout(location = 1) in vec2 bs_texcoord0;
-		
-			layout(location = 0) out vec4 position;
-			layout(location = 1) out vec2 uv0;
-			layout(location = 2) out vec3 screenDir;
-		
-			out gl_PerVertex
-			{
-				vec4 gl_Position;
-			};	
-			
-			void main()
-			{
-				position = vec4(bs_position.x, bs_position.y, 0, 1);
-				uv0 = bs_texcoord0;
-				screenDir = (gMatInvProj * position).xyz - gViewOrigin.xyz;
-			
-				gl_Position = position;
-			}			
-		};
-		
-		Fragment = 
-		{
-			layout(location = 0) in vec4 position;
-			layout(location = 1) in vec2 uv0;
-			layout(location = 2) in vec3 screenDir;
-		
-			layout(location = 0) out vec4 fragColor;
-		
-			void main()
-			{
-				GBufferData gBufferData = getGBufferData(uv0);
-
-				if(gBufferData.worldNormal.w > 0.0f)
-				{
-					vec3 cameraDir = normalize(screenDir);
-					vec3 worldPosition = screenDir * gBufferData.depth + gViewOrigin;
-					
-					LightData lightData = getLightData();
-					fragColor = getLighting(worldPosition, uv0, gBufferData, lightData);
-				}
-				else
-					fragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f);
-			}
-		};
-	};
-};

+ 0 - 2
Data/Raw/Engine/Shaders/DeferredPointLightPassIn.bsl

@@ -1,2 +0,0 @@
-#define INSIDE_GEOMETRY
-#include "$ENGINE$\DeferredPointLightPass.bslinc"

+ 0 - 1
Data/Raw/Engine/Shaders/DeferredPointLightPassOut.bsl

@@ -1 +0,0 @@
-#include "$ENGINE$\DeferredPointLightPass.bslinc"

+ 10 - 10
Data/Raw/Engine/Shaders/Diffuse.bsl

@@ -31,14 +31,14 @@ Technique : base("Surface") =
 				float3 normal = normalize(gNormalTex.Sample(gNormalSamp, input.uv0) * 2.0f - float3(1, 1, 1));
 				float3 worldNormal = calcWorldNormal(input, normal);
 			
-				GBufferData gbufferData;
-				gbufferData.albedo = gAlbedoTex.Sample(gAlbedoSamp, input.uv0);
-				gbufferData.worldNormal.xyz = worldNormal;
+				SurfaceData surfaceData;
+				surfaceData.albedo = gAlbedoTex.Sample(gAlbedoSamp, input.uv0);
+				surfaceData.worldNormal.xyz = worldNormal;
 				
-				encodeGBuffer(gbufferData, OutGBufferA, OutGBufferB);
+				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB);
 				
 				// TODO - Just returning a simple ambient term, use better environment lighting later
-				return float4(gbufferData.albedo.rgb, 1.0f) * 0.01f; 
+				return float4(surfaceData.albedo.rgb, 1.0f) * 0.01f; 
 			}	
 		};
 	};
@@ -66,14 +66,14 @@ Technique : base("Surface") =
 				vec3 normal = normalize(texture(gNormalTex, uv0).xyz * 2.0f - vec3(1, 1, 1));
 				vec3 worldNormal = calcWorldNormal(tangentToWorldZ, tangentToWorldX, normal);
 			
-				GBufferData gbufferData;
-				gbufferData.albedo = texture(gAlbedoTex, uv0);
-				gbufferData.worldNormal.xyz = worldNormal;
+				SurfaceData surfaceData;
+				surfaceData.albedo = texture(gAlbedoTex, uv0);
+				surfaceData.worldNormal.xyz = worldNormal;
 				
-				encodeGBuffer(gbufferData, fragColor[1], fragColor[2]);
+				encodeGBuffer(surfaceData, fragColor[1], fragColor[2]);
 				
 				// TODO - Just returning a simple ambient term, use better environment lighting later
-				fragColor[0] = vec4(gbufferData.albedo.rgb, 1.0f) * 0.01f; 
+				fragColor[0] = vec4(surfaceData.albedo.rgb, 1.0f) * 0.01f; 
 			}	
 		};
 	};

+ 239 - 0
Data/Raw/Engine/Shaders/TiledDeferredLighting.bsl

@@ -0,0 +1,239 @@
+#include "$ENGINE$\GBuffer.bslinc"
+#include "$ENGINE$\LightingCommon.bslinc"
+
+Parameters =
+{
+	Sampler2D 	gGBufferASamp : alias("gGBufferATex");
+	Sampler2D 	gGBufferBSamp : alias("gGBufferBTex");
+	Sampler2D 	gDepthBufferSamp : alias("gDepthBufferTex");
+	
+	Texture2D 	gGBufferATex : auto("GBufferA");
+	Texture2D	gGBufferBTex : auto("GBufferB");
+	Texture2D 	gDepthBufferTex : auto("GBufferDepth");
+};
+
+Technique 
+  : inherits("GBuffer")
+  : inherits("LightingCommon") =
+{
+	Language = "HLSL11";
+	
+	Pass =
+	{
+		Compute = 
+		{
+			SamplerState 	gGBufferASamp : register(s0);
+			SamplerState 	gGBufferBSamp : register(s1);
+			SamplerState 	gDepthBufferSamp : register(s2);
+	
+			Texture2D 		gGBufferATex : register(t0);
+			Texture2D		gGBufferBTex : register(t1);
+			Texture2D 		gDepthBufferTex : register(t2);
+			
+			SurfaceData decodeGBuffer(float4 GBufferAData, float4 GBufferBData, float deviceZ)
+			{
+				SurfaceData output;
+				
+				output.albedo.xyz = GBufferAData.xyz;
+				output.albedo.w = 1.0f;
+				output.worldNormal = GBufferBData * float4(2, 2, 2, 1) - float4(1, 1, 1, 0);
+				output.worldNormal.xyz = normalize(output.worldNormal.xyz);
+				output.depth = convertFromDeviceZ(deviceZ);
+				
+				return output;
+			}			
+			
+			SurfaceData getGBufferData(float2 uv)
+			{
+				float4 GBufferAData = gGBufferATex.SampleLevel(gGBufferASamp, uv, 0);
+				float4 GBufferBData = gGBufferBTex.SampleLevel(gGBufferBSamp, uv, 0);
+				float deviceZ = gDepthBufferTex.SampleLevel(gDepthBufferSamp, uv, 0).r;
+				
+				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
+			}
+			
+			SurfaceData getGBufferData(uint2 pixelPos)
+			{
+				float4 GBufferAData = gGBufferATex.Load(int3(pixelPos, 0));
+				float4 GBufferBData = gGBufferBTex.Load(int3(pixelPos, 0));
+				float deviceZ = gDepthBufferTex.Load(int3(pixelPos, 0)).r;
+				
+				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
+			}	
+			
+			StructuredBuffer<LightData> gDirLights : register(t3);
+			StructuredBuffer<LightData> gPointLights : register(t4);
+			StructuredBuffer<LightData> gSpotLights  : register(t5);				
+		
+			RWTexture2D<float4>			gOutput : register(u0);
+		
+			cbuffer Params : register(b0)
+			{
+				// x - directional, y - point, z - spot
+				uint3 gNumLightsPerType;
+			}
+		
+			[numthreads(TILE_SIZE, TILE_SIZE, 1)]
+			void main(
+				uint3 groupId : SV_GroupID,
+				uint3 groupThreadId : SV_GroupThreadID,
+				uint3 dispatchThreadId : SV_DispatchThreadID,
+				uint threadIndex : SV_GroupIndex)
+			{
+				uint2 pixelPos = dispatchThreadId.xy + gViewportRectangle.xy;
+				SurfaceData surfaceData = getGBufferData(pixelPos);
+
+				float3 lightAccumulator = 0;
+				float alpha = 0.0f;
+				if(surfaceData.worldNormal.w > 0.0f)
+				{
+					float2 screenUv = ((float2)(gViewportRectangle.xy + pixelPos) + 0.5f) / (float2)gViewportRectangle.zw;
+					float2 clipSpacePos = (screenUv - gClipToUVScaleOffset.zw) / gClipToUVScaleOffset.xy;
+				
+					// x, y are now in clip space, z, w are in view space
+					// We multiply them by a special inverse view-projection matrix, that had the projection entries that effect
+					// z, w eliminated (since they are already in view space)
+					// Note: Multiply by depth should be avoided if using ortographic projection
+					float4 mixedSpacePos = float4(clipSpacePos.xy * -surfaceData.depth, surfaceData.depth, 1);
+					float4 worldPosition4D = mul(gMatScreenToWorld, mixedSpacePos);
+					float3 worldPosition = worldPosition4D.xyz / worldPosition4D.w;
+					
+					for(uint i = 0; i < gNumLightsPerType.x; i++)
+						lightAccumulator += getDirLightContibution(surfaceData, gDirLights[i]);
+					
+					for(uint i = 0; i < gNumLightsPerType.y; i++)
+						lightAccumulator += getPointLightContribution(worldPosition, surfaceData, gPointLights[i]);
+					
+					for(uint i = 0; i < gNumLightsPerType.z; i++)
+						lightAccumulator += getSpotLightContribution(worldPosition, surfaceData, gSpotLights[i]);
+						
+					alpha = 1.0f;
+				}
+				
+				float3 diffuse = surfaceData.albedo.xyz / PI; // TODO - Add better lighting model later
+				uint2 viewportMax = gViewportRectangle.xy + gViewportRectangle.zw;
+
+				// Ignore pixels out of valid range
+				if (all(dispatchThreadId.xy < viewportMax)) 
+					gOutput[pixelPos] = float4(gOutput[pixelPos].xyz + diffuse * lightAccumulator, alpha);
+			}
+		};
+	};
+};
+
+Technique 
+  : inherits("GBuffer")
+  : inherits("LightingCommon") =
+{
+	Language = "GLSL";
+	
+	Pass =
+	{
+		Compute = 
+		{
+			layout (local_size_x = TILE_SIZE, local_size_y = TILE_SIZE) in;
+		
+			layout(binding = 0) uniform sampler2D gGBufferATex;
+			layout(binding = 1) uniform sampler2D gGBufferBTex;
+			layout(binding = 2) uniform sampler2D gDepthBufferTex;
+			
+			SurfaceData decodeGBuffer(vec4 GBufferAData, vec4 GBufferBData, float deviceZ)
+			{
+				SurfaceData surfaceData;
+				
+				surfaceData.albedo.xyz = GBufferAData.xyz;
+				surfaceData.albedo.w = 1.0f;
+				surfaceData.worldNormal = GBufferBData * vec4(2, 2, 2, 1) - vec4(1, 1, 1, 0);
+				surfaceData.worldNormal.xyz = normalize(surfaceData.worldNormal.xyz);
+				surfaceData.depth = convertFromDeviceZ(deviceZ);
+				
+				return surfaceData;
+			}			
+			
+			SurfaceData getGBufferData(vec2 uv)
+			{
+				vec4 GBufferAData = textureLod(gGBufferATex, uv, 0);
+				vec4 GBufferBData = textureLod(gGBufferBTex, uv, 0);
+				float deviceZ = textureLod(gDepthBufferTex, uv, 0).r;
+				
+				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
+			}	
+			
+			SurfaceData getGBufferData(ivec2 pixelPos)
+			{
+				vec4 GBufferAData = texelFetch(gGBufferATex, pixelPos, 0);
+				vec4 GBufferBData = texelFetch(gGBufferBTex, pixelPos, 0);
+				float deviceZ = texelFetch(gDepthBufferTex, pixelPos, 0).r;
+				
+				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
+			}	
+			
+			layout(std430, binding = 3) buffer gDirLights
+			{
+				LightData[] gDirLightsData;
+			};
+			
+			layout(std430, binding = 4) buffer gPointLights
+			{
+				LightData[] gPointLightsData;
+			};
+			
+			layout(std430, binding = 5) buffer gSpotLights
+			{
+				LightData[] gSpotLightsData;
+			};	
+			
+			layout(binding = 6, rgba16f) uniform image2D gOutput;
+			
+			layout(binding = 7, std140) uniform Params
+			{
+				// x - directional, y - point, z - spot
+				uvec3 gNumLightsPerType;
+			};
+			
+			void main()
+			{
+				ivec2 pixelPos = ivec2(gl_GlobalInvocationID.xy) + gViewportRectangle.xy;
+				SurfaceData surfaceData = getGBufferData(pixelPos);
+
+				float alpha = 0.0f;
+				vec3 lightAccumulator = vec3(0, 0, 0);
+				if(surfaceData.worldNormal.w > 0.0f)
+				{
+					vec2 screenUv = (vec2(gViewportRectangle.xy + pixelPos) + 0.5f) / vec2(gViewportRectangle.zw);
+					vec2 clipSpacePos = (screenUv - gClipToUVScaleOffset.zw) / gClipToUVScaleOffset.xy;
+				
+					// x, y are now in clip space, z, w are in view space
+					// We multiply them by a special inverse view-projection matrix, that had the projection entries that effect
+					// z, w eliminated (since they are already in view space)
+					// Note: Multiply by depth should be avoided if using ortographic projection
+					vec4 mixedSpacePos = vec4(clipSpacePos.xy * -surfaceData.depth, surfaceData.depth, 1);
+					vec4 worldPosition4D = gMatScreenToWorld * mixedSpacePos;
+					vec3 worldPosition = worldPosition4D.xyz / worldPosition4D.w;
+					
+					for(uint i = 0; i < gNumLightsPerType.x; i++)
+						lightAccumulator += getDirLightContibution(surfaceData, gDirLightsData[i]);
+					
+					for(uint i = 0; i < gNumLightsPerType.y; i++)
+						lightAccumulator += getPointLightContribution(worldPosition, surfaceData, gPointLightsData[i]);
+					
+					for(uint i = 0; i < gNumLightsPerType.z; i++)
+						lightAccumulator += getSpotLightContribution(worldPosition, surfaceData, gSpotLightsData[i]);
+						
+					alpha = 1.0f;
+				}
+				
+				vec3 diffuse = surfaceData.albedo.xyz / PI; // TODO - Add better lighting model later
+				
+				uvec2 viewportMax = gViewportRectangle.xy + gViewportRectangle.zw;
+
+				// Ignore pixels out of valid range
+				if (all(lessThan(gl_GlobalInvocationID.xy, viewportMax))) 
+				{
+					vec4 existingValue = imageLoad(gOutput, pixelPos);
+					imageStore(gOutput, pixelPos, vec4(diffuse * lightAccumulator + existingValue.xyz, alpha));
+				}
+			}
+		};
+	};
+};

+ 2 - 12
Source/BansheeVulkanRenderAPI/Include/BsVulkanTexture.h

@@ -14,16 +14,6 @@ namespace bs { namespace ct
 
 	class VulkanImageSubresource;
 
-	/** Type of a Vulkan image, determining its usage. */
-	enum class VulkanImageUsage
-	{
-		Sampled,
-		SampledDynamic,
-		Storage,
-		ColorAttachment,
-		DepthAttachment
-	};
-
 	/** Descriptor used for initializing a VulkanImage. */
 	struct VULKAN_IMAGE_DESC
 	{
@@ -34,7 +24,7 @@ namespace bs { namespace ct
 		VkFormat format; /**< Pixel format of the image. */
 		UINT32 numFaces; /**< Number of faces (array slices, or cube-map faces). */
 		UINT32 numMipLevels; /**< Number of mipmap levels per face. */
-		VulkanImageUsage usage; /** Determines how will the image be used. */
+		UINT32 usage; /** Determines how will the image be used. */
 	};
 
 	/** Wrapper around a Vulkan image object that manages its usage and lifetime. */
@@ -161,7 +151,7 @@ namespace bs { namespace ct
 		VkDeviceMemory mMemory;
 		VkImageView mMainView;
 		VkImageView mFramebufferMainView;
-		VulkanImageUsage mUsage;
+		INT32 mUsage;
 		bool mOwnsImage;
 
 		UINT32 mNumFaces;

+ 2 - 2
Source/BansheeVulkanRenderAPI/Source/BsVulkanSwapChain.cpp

@@ -131,7 +131,7 @@ namespace bs { namespace ct
 		VULKAN_IMAGE_DESC imageDesc;
 		imageDesc.format = colorFormat;
 		imageDesc.type = TEX_TYPE_2D;
-		imageDesc.usage = VulkanImageUsage::ColorAttachment;
+		imageDesc.usage = TU_RENDERTARGET;
 		imageDesc.layout = VK_IMAGE_LAYOUT_UNDEFINED;
 		imageDesc.numFaces = 1;
 		imageDesc.numMipLevels = 1;
@@ -175,7 +175,7 @@ namespace bs { namespace ct
 			assert(result == VK_SUCCESS);
 
 			imageDesc.image = depthStencilImage;
-			imageDesc.usage = VulkanImageUsage::DepthAttachment;
+			imageDesc.usage = TU_DEPTHSTENCIL;
 			imageDesc.format = depthFormat;
 			imageDesc.memory = mDevice->allocateMemory(depthStencilImage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 

+ 44 - 50
Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

@@ -22,18 +22,7 @@ namespace bs { namespace ct
 		desc.numFaces = props.getNumFaces();
 		desc.numMipLevels = props.getNumMipmaps() + 1;
 		desc.layout = layout;
-
-		int usage = props.getUsage();
-		if ((usage & TU_RENDERTARGET) != 0)
-			desc.usage = VulkanImageUsage::ColorAttachment;
-		else if ((usage & TU_DEPTHSTENCIL) != 0)
-			desc.usage = VulkanImageUsage::DepthAttachment;
-		else if ((usage & TU_LOADSTORE) != 0)
-			desc.usage = VulkanImageUsage::Storage;
-		else if ((usage & TU_DYNAMIC) != 0)
-			desc.usage = VulkanImageUsage::SampledDynamic;
-		else
-			desc.usage = VulkanImageUsage::Sampled;
+		desc.usage = (UINT32)props.getUsage();
 
 		return desc;
 	}
@@ -77,7 +66,7 @@ namespace bs { namespace ct
 		}
 
 		TextureSurface completeSurface(0, desc.numMipLevels, 0, desc.numFaces);
-		if (mUsage == VulkanImageUsage::DepthAttachment)
+		if ((mUsage & TU_DEPTHSTENCIL) != 0)
 		{
 			mFramebufferMainView = createView(completeSurface, getAspectFlags());
 			mMainView = createView(completeSurface, VK_IMAGE_ASPECT_DEPTH_BIT);
@@ -133,7 +122,7 @@ namespace bs { namespace ct
 
 	VkImageView VulkanImage::getView(bool framebuffer) const
 	{
-		if(framebuffer && mUsage == VulkanImageUsage::DepthAttachment)
+		if(framebuffer && (mUsage & TU_DEPTHSTENCIL) != 0)
 			return mFramebufferMainView;
 
 		return mMainView;
@@ -148,7 +137,7 @@ namespace bs { namespace ct
 				surface.arraySlice == entry.surface.arraySlice &&
 				surface.numArraySlices == entry.surface.numArraySlices)
 			{
-				if(mUsage != VulkanImageUsage::DepthAttachment)
+				if((mUsage & TU_DEPTHSTENCIL) == 0)
 					return entry.view;
 				else
 				{
@@ -162,7 +151,7 @@ namespace bs { namespace ct
 		info.surface = surface;
 		info.framebuffer = framebuffer;
 
-		if (mUsage == VulkanImageUsage::DepthAttachment)
+		if ((mUsage & TU_DEPTHSTENCIL) != 0)
 		{
 			if(framebuffer)
 				info.view = createView(surface, getAspectFlags());
@@ -223,23 +212,26 @@ namespace bs { namespace ct
 
 	VkImageLayout VulkanImage::getOptimalLayout() const
 	{
-		switch (mUsage)
-		{
-		case VulkanImageUsage::ColorAttachment:
+		// If it's load-store, no other flags matter, it must be in general layout
+		if ((mUsage & TU_LOADSTORE) != 0)
+			return VK_IMAGE_LAYOUT_GENERAL;
+		
+		if ((mUsage & TU_RENDERTARGET) != 0)
 			return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-		case VulkanImageUsage::DepthAttachment:
+		else if ((mUsage & TU_DEPTHSTENCIL) != 0)
 			return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-		case VulkanImageUsage::Storage:
-		case VulkanImageUsage::SampledDynamic:
-			return VK_IMAGE_LAYOUT_GENERAL;
-		default:
+		else
+		{
+			if ((mUsage & TU_DYNAMIC) != 0)
+				return VK_IMAGE_LAYOUT_GENERAL;
+
 			return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 		}
 	}
 
 	VkImageAspectFlags VulkanImage::getAspectFlags() const
 	{
-		if (mUsage == VulkanImageUsage::DepthAttachment)
+		if ((mUsage & TU_DEPTHSTENCIL) != 0)
 		{
 			bool hasStencil = mImageViewCI.format == VK_FORMAT_D16_UNORM_S8_UINT ||
 				mImageViewCI.format == VK_FORMAT_D24_UNORM_S8_UINT ||
@@ -352,23 +344,26 @@ namespace bs { namespace ct
 		{
 		case VK_IMAGE_LAYOUT_GENERAL:
 			{
-				switch(mUsage)
+				accessFlags = VK_ACCESS_SHADER_READ_BIT;
+				if ((mUsage & TU_LOADSTORE) != 0)
 				{
-				case VulkanImageUsage::Storage:
-					accessFlags = VK_ACCESS_SHADER_READ_BIT;
-					
-					if(!readOnly)
+					if (!readOnly)
 						accessFlags |= VK_ACCESS_SHADER_WRITE_BIT;
-					break;
-				case VulkanImageUsage::ColorAttachment:
-					accessFlags = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
-					break;
-				case VulkanImageUsage::DepthAttachment:
-					accessFlags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
-					break;
-				default:
-					accessFlags = VK_ACCESS_SHADER_READ_BIT;
-					break;
+				}
+
+				if ((mUsage & TU_RENDERTARGET) != 0)
+				{
+					accessFlags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+
+					if(!readOnly)
+						accessFlags |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+				}
+				else if ((mUsage & TU_DEPTHSTENCIL) != 0)
+				{
+					accessFlags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+
+					if (!readOnly)
+						accessFlags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
 				}
 			}
 
@@ -613,29 +608,28 @@ namespace bs { namespace ct
 		// Note: I force rendertarget and depthstencil types to be readable in shader. Depending on performance impact
 		// it might be beneficial to allow the user to enable this explicitly only when needed.
 		
+		mImageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+
 		int usage = props.getUsage();
 		if ((usage & TU_RENDERTARGET) != 0)
 		{
-			mImageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+			mImageCI.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 			mSupportsGPUWrites = true;
 		}
 		else if ((usage & TU_DEPTHSTENCIL) != 0)
 		{
-			mImageCI.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
-			mSupportsGPUWrites = true;
-		}
-		else if ((usage & TU_LOADSTORE) != 0)
-		{
-			mImageCI.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+			mImageCI.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
 			mSupportsGPUWrites = true;
 		}
 		else
+			mImageCI.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+		
+		if ((usage & TU_LOADSTORE) != 0)
 		{
-			mImageCI.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+			mImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+			mSupportsGPUWrites = true;
 		}
 
-		mImageCI.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
-
 		VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
 		VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
 		if ((usage & TU_DYNAMIC) != 0) // Attempt to use linear tiling for dynamic textures, so we can directly map and modify them

+ 9 - 9
Source/BansheeVulkanRenderAPI/Source/BsVulkanUtility.cpp

@@ -14,15 +14,15 @@ namespace bs { namespace ct
 		PixelUtil::checkFormat(format, texType, usage);
 
 		// Check actual device for format support
-		VkFormatFeatureFlagBits featureFlagBit;
+		VkFormatFeatureFlags wantedFeatureFlags = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
 		if ((usage & TU_RENDERTARGET) != 0)
-			featureFlagBit = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
-		else if ((usage & TU_DEPTHSTENCIL) != 0)
-			featureFlagBit = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
-		else if ((usage & TU_LOADSTORE) != 0)
-			featureFlagBit = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
-		else
-			featureFlagBit = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
+			wantedFeatureFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
+
+		if ((usage & TU_DEPTHSTENCIL) != 0)
+			wantedFeatureFlags |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+		if ((usage & TU_LOADSTORE) != 0)
+			wantedFeatureFlags |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
 
 		VkFormatProperties props;
 		auto isSupported = [&](VkFormat vkFmt)
@@ -30,7 +30,7 @@ namespace bs { namespace ct
 			vkGetPhysicalDeviceFormatProperties(device.getPhysical(), vkFmt, &props);
 			VkFormatFeatureFlags featureFlags = optimalTiling ? props.optimalTilingFeatures : props.linearTilingFeatures;
 
-			return (featureFlags & featureFlagBit) != 0;
+			return (featureFlags & wantedFeatureFlags) != 0;
 		};
 
 		VkFormat vkFormat = getPixelFormat(format, hwGamma);

+ 41 - 70
Source/RenderBeast/Include/BsLightRendering.h

@@ -12,97 +12,68 @@ namespace bs { namespace ct
 	 *  @{
 	 */
 
-	BS_PARAM_BLOCK_BEGIN(PerLightParamDef)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightPositionAndType)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightColorAndIntensity)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightSpotAnglesAndSqrdInvRadius)
-		BS_PARAM_BLOCK_ENTRY(Vector3, gLightDirection)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightGeometry)
-		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatConeTransform)
-	BS_PARAM_BLOCK_END
-
-	extern PerLightParamDef gPerLightParamDef;
+	/** Information about a single light, as seen by the lighting shader. */
+	struct LightData
+	{
+		Vector3 position;
+		float radius;
+		Vector3 direction;
+		float intensity;
+		Vector3 spotAngles;
+		float radiusSqrdInv;
+		Vector3 color;
+	};
 
-	/** Manipulates parameters used in various light rendering shaders. */
-	class LightRenderingParams
+	/**	Renderer information specific to a single light. */
+	class RendererLight
 	{
 	public:
-		LightRenderingParams(const SPtr<Material>& lightMaterial, const SPtr<GpuParamsSet>& paramsSet);
+		RendererLight(Light* light);
 
-		/** Updates parameters that are common for all lights. */
-		void setStaticParameters(const SPtr<RenderTargets>& gbuffer,
-			const SPtr<GpuParamBlockBuffer>& perCamera);
+		/** Populates the structure with light parameters. */
+		void getParameters(LightData& output) const;
 
-		/** Updates data in the parameter buffer from the data in the provided light. */
-		void setParameters(const Light* light);
+		/** Gets the internal light representation. */
+		Light* getInternal() const { return mInternal; }
 
-		/** Returns the internal parameter buffer that can be bound to the pipeline. */
-		const SPtr<GpuParamBlockBuffer>& getBuffer() const;
 	private:
-		SPtr<Material> mMaterial;
-		SPtr<GpuParamsSet> mParamsSet;
-
-		GpuParamTexture mGBufferA;
-		GpuParamTexture mGBufferB;
-		GpuParamTexture mGBufferDepth;
-		SPtr<GpuParamBlockBuffer> mParamBuffer;
+		Light* mInternal;
 	};
 
-	/** Shader that renders directional light sources during deferred rendering light pass. */
-	class DirectionalLightMat : public RendererMaterial<DirectionalLightMat>
-	{
-		RMAT_DEF("DeferredDirectionalLightPass.bsl");
-
-	public:
-		DirectionalLightMat();
-
-		/** Binds the material for rendering and sets up any global parameters. */
-		void bind(const SPtr<RenderTargets>& gbuffer, const SPtr<GpuParamBlockBuffer>& perCamera);
+	BS_PARAM_BLOCK_BEGIN(TiledLightingParamDef)
+		BS_PARAM_BLOCK_ENTRY(Vector3I, gNumLightsPerType)
+	BS_PARAM_BLOCK_END
 
-		/** Updates the per-light buffers used by the material. */
-		void setPerLightParams(const Light* light);
-	private:
-		LightRenderingParams mParams;
-	};
+	extern TiledLightingParamDef gTiledLightingParamDef;
 
-	/** 
-	 * Shader that renders point (radial & spot) light sources during deferred rendering light pass. Used when the camera
-	 * is inside the point light geometry.
-	 */
-	class PointLightInMat : public RendererMaterial<PointLightInMat>
+	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
+	class TiledDeferredLightingMat : public RendererMaterial<TiledDeferredLightingMat>
 	{
-		RMAT_DEF("DeferredPointLightPassIn.bsl");
+		RMAT_DEF("TiledDeferredLighting.bsl");
 
 	public:
-		PointLightInMat();
+		TiledDeferredLightingMat();
 
-		/** Binds the material for rendering and sets up any global parameters. */
-		void bind(const SPtr<RenderTargets>& gbuffer, const SPtr<GpuParamBlockBuffer>& perCamera);
+		/** Binds the material for rendering, sets up parameters and executes it. */
+		void execute(const SPtr<RenderTargets>& gbuffer, const SPtr<GpuParamBlockBuffer>& perCamera);
 
-		/** Updates the per-light buffers used by the material. */
-		void setPerLightParams(const Light* light);
+		/** Binds all the active lights. */
+		void setLights(const Vector<LightData> (&lightData)[3]);
 	private:
-		LightRenderingParams mParams;
-	};
+		GpuParamTexture mGBufferA;
+		GpuParamTexture mGBufferB;
+		GpuParamTexture mGBufferDepth;
 
-	/** 
-	 * Shader that renders point (radial & spot) light sources during deferred rendering light pass. Used when the camera
-	 * is outside the point light geometry.
-	 */
-	class PointLightOutMat : public RendererMaterial<PointLightOutMat>
-	{
-		RMAT_DEF("DeferredPointLightPassOut.bsl");
+		GpuParamBuffer mDirLightBufferParam;
+		GpuParamBuffer mPointLightBufferParam;
+		GpuParamBuffer mSpotLightBufferParam;
 
-	public:
-		PointLightOutMat();
+		GpuParamLoadStoreTexture mOutputParam;
 
-		/** Binds the material for rendering and sets up any global parameters. */
-		void bind(const SPtr<RenderTargets>& gbuffer, const SPtr<GpuParamBlockBuffer>& perCamera);
+		SPtr<GpuParamBlockBuffer> mParamBuffer;
+		SPtr<GpuBuffer> mLightBuffers[3];
 
-		/** Updates the per-light buffers used by the material. */
-		void setPerLightParams(const Light* light);
-	private:
-		LightRenderingParams mParams;
+		static const UINT32 TILE_SIZE;
 	};
 
 	/** @} */

+ 8 - 10
Source/RenderBeast/Include/BsRenderBeast.h

@@ -44,12 +44,6 @@ namespace bs
 			Vector<const Camera*> cameras;
 		};
 
-		/**	Renderer information specific to a single light. */
-		struct RendererLight
-		{
-			Light* internal;
-		};
-
 		/** Renderer information for a single material. */
 		struct RendererMaterial
 		{
@@ -215,14 +209,14 @@ namespace bs
 
 		Vector<RendererLight> mDirectionalLights;
 		Vector<RendererLight> mPointLights;
-		Vector<Sphere> mLightWorldBounds;
+		Vector<RendererLight> mSpotLights;
+		Vector<Sphere> mPointLightWorldBounds;
+		Vector<Sphere> mSpotLightWorldBounds;
 
 		SPtr<RenderBeastOptions> mCoreOptions;
 
 		DefaultMaterial* mDefaultMaterial;
-		PointLightInMat* mPointLightInMat;
-		PointLightOutMat* mPointLightOutMat;
-		DirectionalLightMat* mDirLightMat;
+		TiledDeferredLightingMat* mTiledDeferredLightingMat;
 		SkyboxMat* mSkyboxMat;
 
 		ObjectRenderer* mObjectRenderer;
@@ -230,6 +224,10 @@ namespace bs
 		// Sim thread only fields
 		SPtr<RenderBeastOptions> mOptions;
 		bool mOptionsDirty;
+
+		// Helpers to avoid memory allocations
+		Vector<LightData> mLightDataTemp[3];
+		Vector<bool> mLightVisibilityTemp;
 	};
 
 	/** @} */

+ 3 - 0
Source/RenderBeast/Include/BsRenderTargets.h

@@ -52,6 +52,9 @@ namespace bs { namespace ct
 		/** Returns the scene color render target. */
 		SPtr<RenderTexture> getSceneColorRT() const { return mSceneColorRT; }
 
+		/** Returns the gbuffer texture that scene color is stored in. */
+		SPtr<Texture> getSceneColor() const;
+
 		/**	Returns the first color texture of the gbuffer as a bindable texture. */
 		SPtr<Texture> getTextureA() const;
 

+ 7 - 0
Source/RenderBeast/Include/BsRendererCamera.h

@@ -26,6 +26,7 @@ namespace bs { namespace ct
 		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatInvViewProj)
 		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatScreenToWorld)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gDeviceZToWorldZ)
+		BS_PARAM_BLOCK_ENTRY(Vector4I, gViewportRectangle)
 		BS_PARAM_BLOCK_ENTRY(Vector4, gClipToUVScaleOffset)
 	BS_PARAM_BLOCK_END
 
@@ -213,6 +214,12 @@ namespace bs { namespace ct
 		 */
 		void calculateVisibility(const Vector<CullInfo>& cullInfos, Vector<bool>& visibility) const;
 
+		/**
+		* Culls the provided set of bounds against the current frustum and outputs a set of visibility flags determining
+		* which entry is or ins't visible by this view. Both inputs must be arrays of the same size.
+		*/
+		void calculateVisibility(const Vector<Sphere>& bounds, Vector<bool>& visibility) const;
+
 		/** Returns the visibility mask calculated with the last call to determineVisible(). */
 		const VisibilityInfo& getVisibilityMasks() const { return mVisibility; }
 

+ 85 - 129
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -7,35 +7,70 @@
 #include "BsRenderTargets.h"
 #include "BsGpuParams.h"
 #include "BsGpuParamsSet.h"
+#include "BsGpuBuffer.h"
 #include "BsLight.h"
 #include "BsRendererUtility.h"
 
 namespace bs { namespace ct
 {
-	PerLightParamDef gPerLightParamDef;
+	static const UINT32 BUFFER_INCREMENT = 16 * sizeof(LightData);
 
-	LightRenderingParams::LightRenderingParams(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet)
-		:mMaterial(material), mParamsSet(paramsSet)
+	TiledLightingParamDef gTiledLightingParamDef;
+
+	RendererLight::RendererLight(Light* light)
+		:mInternal(light)
+	{ }
+
+	void RendererLight::getParameters(LightData& output) const
+	{
+		Radian spotAngle = Math::clamp(mInternal->getSpotAngle() * 0.5f, Degree(0), Degree(89));
+		Radian spotFalloffAngle = Math::clamp(mInternal->getSpotFalloffAngle() * 0.5f, Degree(0), (Degree)spotAngle);
+		Color color = mInternal->getColor();
+
+		output.position = mInternal->getPosition();
+		output.radius = mInternal->getBounds().getRadius();
+		output.direction = mInternal->getRotation().zAxis();
+		output.intensity = mInternal->getIntensity();
+		output.spotAngles.x = spotAngle.valueRadians();
+		output.spotAngles.y = Math::cos(output.spotAngles.x);
+		output.spotAngles.z = 1.0f / (Math::cos(spotFalloffAngle) - output.spotAngles.y);
+		output.radiusSqrdInv = 1.0f / (output.radius * output.radius);
+		output.color = Vector3(color.r, color.g, color.b);
+	}
+
+	const UINT32 TiledDeferredLightingMat::TILE_SIZE = 16;
+
+	TiledDeferredLightingMat::TiledDeferredLightingMat()
 	{
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 
-		auto& texParams = material->getShader()->getTextureParams();
+		auto& texParams = mMaterial->getShader()->getTextureParams();
 		for (auto& entry : texParams)
 		{
 			if (entry.second.rendererSemantic == RPS_GBufferA)
-				params->getTextureParam(GPT_FRAGMENT_PROGRAM, entry.second.name, mGBufferA);
+				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferA);
 			else if (entry.second.rendererSemantic == RPS_GBufferB)
-				params->getTextureParam(GPT_FRAGMENT_PROGRAM, entry.second.name, mGBufferB);
+				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferB);
 			else if (entry.second.rendererSemantic == RPS_GBufferDepth)
-				params->getTextureParam(GPT_FRAGMENT_PROGRAM, entry.second.name, mGBufferDepth);
+				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferDepth);
 		}
 
-		mParamBuffer = gPerLightParamDef.createBuffer();
-		mParamsSet->setParamBlockBuffer("PerLight", mParamBuffer, true);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gDirLights", mDirLightBufferParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gPointLights", mPointLightBufferParam);
+		params->getBufferParam(GPT_COMPUTE_PROGRAM, "gSpotLights", mSpotLightBufferParam);
+
+		params->getLoadStoreTextureParam(GPT_COMPUTE_PROGRAM, "gOutput", mOutputParam);
+
+		mParamBuffer = gTiledLightingParamDef.createBuffer();
+		mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
+	}
+
+	void TiledDeferredLightingMat::_initDefines(ShaderDefines& defines)
+	{
+		defines.set("TILE_SIZE", TILE_SIZE);
 	}
 
-	void LightRenderingParams::setStaticParameters(const SPtr<RenderTargets>& gbuffer, 
-		const SPtr<GpuParamBlockBuffer>& perCamera)
+	void TiledDeferredLightingMat::execute(const SPtr<RenderTargets>& gbuffer, const SPtr<GpuParamBlockBuffer>& perCamera)
 	{
 		mGBufferA.set(gbuffer->getTextureA());
 		mGBufferB.set(gbuffer->getTextureB());
@@ -43,139 +78,60 @@ namespace bs { namespace ct
 
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);
 
-		gRendererUtility().setPassParams(mParamsSet);
-	}
-
-	void LightRenderingParams::setParameters(const Light* light)
-	{
-		// Note: I could just copy the data directly to the parameter buffer if I ensured the parameter
-		// layout matches
-
-		Vector4 positionAndType = (Vector4)light->getPosition();
-
-		switch (light->getType())
-		{
-		case LightType::Directional:
-			positionAndType.w = 0;
-			break;
-		case LightType::Point:
-			positionAndType.w = 0.3f;
-			break;
-		case LightType::Spot:
-			positionAndType.w = 0.8f;
-			break;
-		}
-
-		gPerLightParamDef.gLightPositionAndType.set(mParamBuffer, positionAndType);
-			
-		Vector4 colorAndIntensity;
-		colorAndIntensity.x = light->getColor().r;
-		colorAndIntensity.y = light->getColor().g;
-		colorAndIntensity.z = light->getColor().b;
-		colorAndIntensity.w = light->getIntensity();
-
-		gPerLightParamDef.gLightColorAndIntensity.set(mParamBuffer, colorAndIntensity);
-
-		Radian spotAngle = Math::clamp(light->getSpotAngle() * 0.5f, Degree(1), Degree(90));
-		Radian spotFalloffAngle = Math::clamp(light->getSpotFalloffAngle() * 0.5f, Degree(1), (Degree)spotAngle);
+		SPtr<Texture> sceneColorTex = gbuffer->getSceneColor();
+		mOutputParam.set(sceneColorTex);
 
-		Vector4 spotAnglesAndInvSqrdRadius;
-		spotAnglesAndInvSqrdRadius.x = spotAngle.valueRadians();
-		spotAnglesAndInvSqrdRadius.y = Math::cos(spotAnglesAndInvSqrdRadius.x);
-		spotAnglesAndInvSqrdRadius.z = 1.0f / (Math::cos(spotFalloffAngle) - spotAnglesAndInvSqrdRadius.y);
-		spotAnglesAndInvSqrdRadius.w = 1.0f / (light->getBounds().getRadius() * light->getBounds().getRadius());
+		UINT32 width = sceneColorTex->getProperties().getWidth();
+		UINT32 height = sceneColorTex->getProperties().getHeight();
 
-		gPerLightParamDef.gLightSpotAnglesAndSqrdInvRadius.set(mParamBuffer, spotAnglesAndInvSqrdRadius);
+		UINT32 numTilesX = (UINT32)Math::ceilToInt(width / (float)TILE_SIZE);
+		UINT32 numTilesY = (UINT32)Math::ceilToInt(height / (float)TILE_SIZE);
 
-		gPerLightParamDef.gLightDirection.set(mParamBuffer, -light->getRotation().zAxis());
-
-		Vector4 lightGeometry;
-		lightGeometry.x = light->getType() == LightType::Spot ? (float)Light::LIGHT_CONE_NUM_SIDES : 0;
-		lightGeometry.y = (float)Light::LIGHT_CONE_NUM_SLICES;
-		lightGeometry.z = light->getBounds().getRadius();
-
-		float coneRadius = Math::sin(spotAngle) * light->getRange();
-		lightGeometry.w = coneRadius;
-
-		gPerLightParamDef.gLightGeometry.set(mParamBuffer, lightGeometry);
-
-		Matrix4 transform = Matrix4::TRS(light->getPosition(), light->getRotation(), Vector3::ONE);
-		gPerLightParamDef.gMatConeTransform.set(mParamBuffer, transform);
-
-		mParamBuffer->flushToGPU();
-	}
+		gRendererUtility().setComputePass(mMaterial, 0);
+		gRendererUtility().setPassParams(mParamsSet);
 
-	const SPtr<GpuParamBlockBuffer>& LightRenderingParams::getBuffer() const
-	{
-		return mParamBuffer;
-	}
-	
-	DirectionalLightMat::DirectionalLightMat()
-		:mParams(mMaterial, mParamsSet)
-	{
-		
+		RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
 	}
 
-	void DirectionalLightMat::_initDefines(ShaderDefines& defines)
+	void TiledDeferredLightingMat::setLights(const Vector<LightData>(&lightData)[3])
 	{
-		// Do nothing
-	}
+		Vector3I numLightsPerType;
+		for (UINT32 i = 0; i < 3; i++)
+		{
+			UINT32 numLights = (UINT32)lightData[i].size();
+			numLightsPerType[i] = numLights;
 
-	void DirectionalLightMat::bind(const SPtr<RenderTargets>& gbuffer,
-		const SPtr<GpuParamBlockBuffer>& perCamera)
-	{
-		RendererUtility::instance().setPass(mMaterial, 0);
-		mParams.setStaticParameters(gbuffer, perCamera);
-	}
+			UINT32 size = numLights * sizeof(LightData);
+			UINT32 curBufferSize;
 
-	void DirectionalLightMat::setPerLightParams(const Light* light)
-	{
-		mParams.setParameters(light);
-	}
+			if (mLightBuffers[i] != nullptr)
+				curBufferSize = mLightBuffers[i]->getSize();
+			else
+				curBufferSize = 0;
 
-	PointLightInMat::PointLightInMat()
-		:mParams(mMaterial, mParamsSet)
-	{
+			if(size > curBufferSize || curBufferSize == 0)
+			{
+				// Allocate at least one block even if no lights, to avoid issues with null buffers
+				UINT32 bufferSize = std::max(1, Math::ceilToInt(size / (float)BUFFER_INCREMENT)) * BUFFER_INCREMENT;
 
-	}
+				GPU_BUFFER_DESC bufferDesc;
+				bufferDesc.type = GBT_STRUCTURED;
+				bufferDesc.elementCount = bufferSize / sizeof(LightData);
+				bufferDesc.elementSize = sizeof(LightData);
+				bufferDesc.format = BF_UNKNOWN;
 
-	void PointLightInMat::_initDefines(ShaderDefines& defines)
-	{
-		// Do nothing
-	}
+				mLightBuffers[i] = GpuBuffer::create(bufferDesc);
+			}
 
-	void PointLightInMat::bind(const SPtr<RenderTargets>& gbuffer, 
-		const SPtr<GpuParamBlockBuffer>& perCamera)
-	{
-		RendererUtility::instance().setPass(mMaterial, 0);
-		mParams.setStaticParameters(gbuffer, perCamera);
-	}
-
-	void PointLightInMat::setPerLightParams(const Light* light)
-	{
-		mParams.setParameters(light);
-	}
-
-	PointLightOutMat::PointLightOutMat()
-		:mParams(mMaterial, mParamsSet)
-	{
-		
-	}
+			mLightBuffers[i]->writeData(0, size, lightData[i].data(), BWT_DISCARD);
+		}
 
-	void PointLightOutMat::_initDefines(ShaderDefines& defines)
-	{
-		// Do nothing
-	}
+		mDirLightBufferParam.set(mLightBuffers[0]);
+		mPointLightBufferParam.set(mLightBuffers[1]);
+		mSpotLightBufferParam.set(mLightBuffers[2]);
 
-	void PointLightOutMat::bind(const SPtr<RenderTargets>& gbuffer,
-		const SPtr<GpuParamBlockBuffer>& perCamera)
-	{
-		RendererUtility::instance().setPass(mMaterial, 0);
-		mParams.setStaticParameters(gbuffer, perCamera);
-	}
+		gTiledLightingParamDef.gNumLightsPerType.set(mParamBuffer, numLightsPerType);
 
-	void PointLightOutMat::setPerLightParams(const Light* light)
-	{
-		mParams.setParameters(light);
+		mParamBuffer->flushToGPU();
 	}
 }}

+ 97 - 87
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -39,7 +39,7 @@ using namespace std::placeholders;
 namespace bs { namespace ct
 {
 	RenderBeast::RenderBeast()
-		: mDefaultMaterial(nullptr), mPointLightInMat(nullptr), mPointLightOutMat(nullptr), mDirLightMat(nullptr)
+		: mDefaultMaterial(nullptr), mTiledDeferredLightingMat(nullptr)
 		, mSkyboxMat(nullptr), mObjectRenderer(nullptr), mOptions(bs_shared_ptr_new<RenderBeastOptions>())
 		, mOptionsDirty(true)
 	{ }
@@ -73,9 +73,7 @@ namespace bs { namespace ct
 		mObjectRenderer = bs_new<ObjectRenderer>();
 
 		mDefaultMaterial = bs_new<DefaultMaterial>();
-		mPointLightInMat = bs_new<PointLightInMat>();
-		mPointLightOutMat = bs_new<PointLightOutMat>();
-		mDirLightMat = bs_new<DirectionalLightMat>();
+		mTiledDeferredLightingMat = bs_new<TiledDeferredLightingMat>();
 		mSkyboxMat = bs_new<SkyboxMat>();
 
 		RenderTexturePool::startUp();
@@ -102,9 +100,7 @@ namespace bs { namespace ct
 		RenderTexturePool::shutDown();
 
 		bs_delete(mDefaultMaterial);
-		bs_delete(mPointLightInMat);
-		bs_delete(mPointLightOutMat);
-		bs_delete(mDirLightMat);
+		bs_delete(mTiledDeferredLightingMat);
 		bs_delete(mSkyboxMat);
 
 		RendererUtility::shutDown();
@@ -302,22 +298,26 @@ namespace bs { namespace ct
 			UINT32 lightId = (UINT32)mDirectionalLights.size();
 			light->setRendererId(lightId);
 
-			mDirectionalLights.push_back(RendererLight());
-
-			RendererLight& lightData = mDirectionalLights.back();
-			lightData.internal = light;
+			mDirectionalLights.push_back(RendererLight(light));
 		}
 		else
 		{
-			UINT32 lightId = (UINT32)mPointLights.size();
-
-			light->setRendererId(lightId);
+			if (light->getType() == LightType::Point)
+			{
+				UINT32 lightId = (UINT32)mPointLights.size();
+				light->setRendererId(lightId);
 
-			mPointLights.push_back(RendererLight());
-			mLightWorldBounds.push_back(light->getBounds());
+				mPointLights.push_back(RendererLight(light));
+				mPointLightWorldBounds.push_back(light->getBounds());
+			}
+			else // Spot
+			{
+				UINT32 lightId = (UINT32)mSpotLights.size();
+				light->setRendererId(lightId);
 
-			RendererLight& lightData = mPointLights.back();
-			lightData.internal = light;
+				mSpotLights.push_back(RendererLight(light));
+				mSpotLightWorldBounds.push_back(light->getBounds());
+			}
 		}
 	}
 
@@ -325,8 +325,10 @@ namespace bs { namespace ct
 	{
 		UINT32 lightId = light->getRendererId();
 
-		if (light->getType() != LightType::Directional)
-			mLightWorldBounds[lightId] = light->getBounds();
+		if (light->getType() == LightType::Point)
+			mPointLightWorldBounds[lightId] = light->getBounds();
+		else if(light->getType() == LightType::Spot)
+			mSpotLightWorldBounds[lightId] = light->getBounds();
 	}
 
 	void RenderBeast::notifyLightRemoved(Light* light)
@@ -334,7 +336,7 @@ namespace bs { namespace ct
 		UINT32 lightId = light->getRendererId();
 		if (light->getType() == LightType::Directional)
 		{
-			Light* lastLight = mDirectionalLights.back().internal;
+			Light* lastLight = mDirectionalLights.back().getInternal();
 			UINT32 lastLightId = lastLight->getRendererId();
 
 			if (lightId != lastLightId)
@@ -349,21 +351,42 @@ namespace bs { namespace ct
 		}
 		else
 		{
-			Light* lastLight = mPointLights.back().internal;
-			UINT32 lastLightId = lastLight->getRendererId();
-
-			if (lightId != lastLightId)
+			if (light->getType() == LightType::Point)
 			{
-				// Swap current last element with the one we want to erase
-				std::swap(mPointLights[lightId], mPointLights[lastLightId]);
-				std::swap(mLightWorldBounds[lightId], mLightWorldBounds[lastLightId]);
+				Light* lastLight = mPointLights.back().getInternal();
+				UINT32 lastLightId = lastLight->getRendererId();
 
-				lastLight->setRendererId(lightId);
+				if (lightId != lastLightId)
+				{
+					// Swap current last element with the one we want to erase
+					std::swap(mPointLights[lightId], mPointLights[lastLightId]);
+					std::swap(mPointLightWorldBounds[lightId], mPointLightWorldBounds[lastLightId]);
+
+					lastLight->setRendererId(lightId);
+				}
+
+				// Last element is the one we want to erase
+				mPointLights.erase(mPointLights.end() - 1);
+				mPointLightWorldBounds.erase(mPointLightWorldBounds.end() - 1);
 			}
+			else // Spot
+			{
+				Light* lastLight = mSpotLights.back().getInternal();
+				UINT32 lastLightId = lastLight->getRendererId();
 
-			// Last element is the one we want to erase
-			mPointLights.erase(mPointLights.end() - 1);
-			mLightWorldBounds.erase(mLightWorldBounds.end() - 1);
+				if (lightId != lastLightId)
+				{
+					// Swap current last element with the one we want to erase
+					std::swap(mSpotLights[lightId], mSpotLights[lastLightId]);
+					std::swap(mSpotLightWorldBounds[lightId], mSpotLightWorldBounds[lastLightId]);
+
+					lastLight->setRendererId(lightId);
+				}
+
+				// Last element is the one we want to erase
+				mSpotLights.erase(mSpotLights.end() - 1);
+				mSpotLightWorldBounds.erase(mSpotLightWorldBounds.end() - 1);
+			}
 		}
 	}
 
@@ -692,6 +715,47 @@ namespace bs { namespace ct
 			mRenderables[i]->perObjectParamBuffer->flushToGPU();
 		}
 
+		// Generate a list of lights and their GPU buffers
+		UINT32 numDirLights = (UINT32)mDirectionalLights.size();
+		mLightDataTemp[0].resize(numDirLights);
+		for(UINT32 i = 0; i < numDirLights; i++)
+			mDirectionalLights[i].getParameters(mLightDataTemp[0][i]);
+
+		UINT32 numPointLights = (UINT32)mPointLights.size();
+		mLightVisibilityTemp.resize(numPointLights, false);
+		for (UINT32 i = 0; i < numViews; i++)
+			views[i]->calculateVisibility(mPointLightWorldBounds, mLightVisibilityTemp);
+
+		for(UINT32 i = 0; i < numPointLights; i++)
+		{
+			if (!mLightVisibilityTemp[i])
+				continue;
+
+			mLightDataTemp[1].push_back(LightData());
+			mPointLights[i].getParameters(mLightDataTemp[1].back());
+		}
+
+		UINT32 numSpotLights = (UINT32)mSpotLights.size();
+		mLightVisibilityTemp.resize(numSpotLights, false);
+		for (UINT32 i = 0; i < numViews; i++)
+			views[i]->calculateVisibility(mSpotLightWorldBounds, mLightVisibilityTemp);
+
+		for (UINT32 i = 0; i < numSpotLights; i++)
+		{
+			if (!mLightVisibilityTemp[i])
+				continue;
+
+			mLightDataTemp[2].push_back(LightData());
+			mSpotLights[i].getParameters(mLightDataTemp[2].back());
+		}
+
+		mTiledDeferredLightingMat->setLights(mLightDataTemp);
+
+		mLightDataTemp[0].clear();
+		mLightDataTemp[1].clear();
+		mLightDataTemp[2].clear();
+		mLightVisibilityTemp.clear();
+
 		for (UINT32 i = 0; i < numViews; i++)
 		{
 			if (views[i]->isOverlay())
@@ -780,61 +844,7 @@ namespace bs { namespace ct
 		renderTargets->bindSceneColor(true);
 
 		// Render light pass
-		{
-			mDirLightMat->bind(renderTargets, perCameraBuffer);
-			for (auto& light : mDirectionalLights)
-			{
-				if (!light.internal->getIsActive())
-					continue;
-
-				mDirLightMat->setPerLightParams(light.internal);
-				gRendererUtility().drawScreenQuad();
-			}
-
-			// Draw point lights which our camera is within
-			// TODO - Possibly use instanced drawing here as only two meshes are drawn with various properties
-			mPointLightInMat->bind(renderTargets, perCameraBuffer);
-
-			// TODO - Cull lights based on visibility, right now I just iterate over all of them. 
-			for (auto& light : mPointLights)
-			{
-				if (!light.internal->getIsActive())
-					continue;
-
-				float distToLight = (light.internal->getBounds().getCenter() - viewInfo->getViewOrigin()).squaredLength();
-				float boundRadius = light.internal->getBounds().getRadius() * 1.05f + viewInfo->getNearPlane() * 2.0f;
-
-				bool cameraInLightGeometry = distToLight < boundRadius * boundRadius;
-				if (!cameraInLightGeometry)
-					continue;
-
-				mPointLightInMat->setPerLightParams(light.internal);
-
-				SPtr<Mesh> mesh = light.internal->getMesh();
-				gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
-			}
-
-			// Draw other point lights
-			mPointLightOutMat->bind(renderTargets, perCameraBuffer);
-
-			for (auto& light : mPointLights)
-			{
-				if (!light.internal->getIsActive())
-					continue;
-
-				float distToLight = (light.internal->getBounds().getCenter() - viewInfo->getViewOrigin()).squaredLength();
-				float boundRadius = light.internal->getBounds().getRadius() * 1.05f + viewInfo->getNearPlane() * 2.0f;
-
-				bool cameraInLightGeometry = distToLight < boundRadius * boundRadius;
-				if (cameraInLightGeometry)
-					continue;
-
-				mPointLightOutMat->setPerLightParams(light.internal);
-
-				SPtr<Mesh> mesh = light.internal->getMesh();
-				gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
-			}
-		}
+		mTiledDeferredLightingMat->execute(renderTargets, perCameraBuffer);
 
 		// Render skybox (if any)
 		SPtr<Texture> skyTexture = viewInfo->getSkybox();

+ 7 - 2
Source/RenderBeast/Source/BsRenderTargets.cpp

@@ -34,8 +34,8 @@ namespace bs { namespace ct
 		// then back into sRGB when writing to albedo, and back to linear when reading from albedo during light pass. This /might/ have
 		// a performance impact. In which case we could just use a higher precision albedo buffer, which can then store linear color
 		// directly (storing linear in 8bit buffer causes too much detail to be lost in the blacks).
-		SPtr<PooledRenderTexture> newColorRT = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width, height, TU_RENDERTARGET,
-			mViewTarget.numSamples, false));
+		SPtr<PooledRenderTexture> newColorRT = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width, 
+			height, TU_RENDERTARGET | TU_LOADSTORE, mViewTarget.numSamples, false));
 		SPtr<PooledRenderTexture> newAlbedoRT = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mAlbedoFormat, width, 
 			height, TU_RENDERTARGET, mViewTarget.numSamples, true));
 		SPtr<PooledRenderTexture> newNormalRT = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mNormalFormat, width, 
@@ -131,6 +131,11 @@ namespace bs { namespace ct
 		rapi.setViewport(area);
 	}
 
+	SPtr<Texture> RenderTargets::getSceneColor() const
+	{
+		return mSceneColorTex->texture;
+	}
+
 	SPtr<Texture> RenderTargets::getTextureA() const
 	{
 		return mAlbedoTex->texture;

+ 20 - 1
Source/RenderBeast/Source/BsRendererCamera.cpp

@@ -195,6 +195,17 @@ namespace bs { namespace ct
 		}
 	}
 
+	void RendererCamera::calculateVisibility(const Vector<Sphere>& bounds, Vector<bool>& visibility) const
+	{
+		const ConvexVolume& worldFrustum = mViewDesc.cullFrustum;
+
+		for (UINT32 i = 0; i < (UINT32)bounds.size(); i++)
+		{
+			if (worldFrustum.intersects(bounds[i]))
+				visibility[i] = true;
+		}
+	}
+
 	Vector2 RendererCamera::getDeviceZTransform(const Matrix4& projMatrix) const
 	{
 		// Returns a set of values that will transform depth buffer values (e.g. [0, 1] in DX, [-1, 1] in GL) to a distance
@@ -254,7 +265,7 @@ namespace bs { namespace ct
 		projZ[2][3] = mViewDesc.projTransform[2][3];
 		projZ[3][2] = mViewDesc.projTransform[3][2];
 		projZ[3][3] = 0.0f;
-
+		
 		gPerCameraParamDef.gMatScreenToWorld.set(mParamBuffer, invViewProj * projZ);
 		gPerCameraParamDef.gViewDir.set(mParamBuffer, mViewDesc.viewDirection);
 		gPerCameraParamDef.gViewOrigin.set(mParamBuffer, mViewDesc.viewOrigin);
@@ -262,6 +273,14 @@ namespace bs { namespace ct
 
 		const Rect2I& viewRect = mViewDesc.target.viewRect;
 
+		Vector4I viewportRect;
+		viewportRect[0] = viewRect.x;
+		viewportRect[1] = viewRect.y;
+		viewportRect[2] = viewRect.width;
+		viewportRect[3] = viewRect.height;
+
+		gPerCameraParamDef.gViewportRectangle.set(mParamBuffer, viewportRect);
+
 		float halfWidth = viewRect.width * 0.5f;
 		float halfHeight = viewRect.height * 0.5f;