Browse Source

Convert a few more shaders to HLSL

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
60fc9edd56

+ 25 - 24
AnKi/Shaders/TonemappingAverageLuminance.ankiprog

@@ -3,34 +3,37 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
+#pragma anki hlsl
 #pragma anki start comp
 
-#include <AnKi/Shaders/TonemappingFunctions.glsl>
+#include <AnKi/Shaders/TonemappingFunctions.hlsl>
 
 #define LOG_AVG 0
 
 ANKI_SPECIALIZATION_CONSTANT_UVEC2(kInputTexSize, 0u);
 
-const UVec2 kWorkgroupSize = UVec2(32u, 16u);
-layout(local_size_x = kWorkgroupSize.x, local_size_y = kWorkgroupSize.y, local_size_z = 1) in;
+#define THREAD_COUNT_X 32u
+#define THREAD_COUNT_Y 16u
+#define THREAD_COUNT UVec2(THREAD_COUNT_X, THREAD_COUNT_Y)
 
 // Align the tex size to workgroup size
-const UVec2 kAlignedInputTexSize = kWorkgroupSize * ((kInputTexSize + kWorkgroupSize - 1u) / kWorkgroupSize);
-const UVec2 kPixelsPerTile = kAlignedInputTexSize / kWorkgroupSize;
+constexpr UVec2 kAlignedInputTexSize = THREAD_COUNT * ((kInputTexSize + THREAD_COUNT - 1u) / THREAD_COUNT);
+constexpr UVec2 kPixelsPerTile = kAlignedInputTexSize / THREAD_COUNT;
 
-layout(set = 0, binding = 0) uniform ANKI_RP texture2D u_tex;
+[[vk::binding(0)]] Texture2D<RVec4> g_tex;
 
 #define TONEMAPPING_RESOURCE_AS_WRITE_IMAGE 1
-const U32 kTonemappingBinding = 1u;
-#include <AnKi/Shaders/TonemappingResources.glsl>
+constexpr U32 kTonemappingBinding = 1u;
+#include <AnKi/Shaders/TonemappingResources.hlsl>
 
-shared F32 s_avgLum[kWorkgroupSize.x * kWorkgroupSize.y];
+groupshared F32 s_avgLum[THREAD_COUNT_X * THREAD_COUNT_Y];
 
-void main()
+[numthreads(THREAD_COUNT_X, THREAD_COUNT_Y, 1)] void main(UVec3 svGroupThreadId : SV_GROUPTHREADID,
+														  U32 svGroupIndex : SV_GROUPINDEX)
 {
 	// Gather the log-average luminance of a tile. It will miss some pixels but not too many
-	const U32 yStart = gl_LocalInvocationID.y * kPixelsPerTile.y;
-	const U32 xStart = gl_LocalInvocationID.x * kPixelsPerTile.x;
+	const U32 yStart = svGroupThreadId.y * kPixelsPerTile.y;
+	const U32 xStart = svGroupThreadId.x * kPixelsPerTile.x;
 
 	F32 avgLum = 0.0;
 	[unroll] for(U32 y = 0u; y < kPixelsPerTile.y; ++y)
@@ -43,7 +46,7 @@ void main()
 				continue;
 			}
 
-			const Vec3 color = texelFetch(u_tex, IVec2(uv), 0).rgb;
+			const Vec3 color = g_tex.Load(IVec3(uv, 0)).rgb;
 			const F32 lum = computeLuminance(color);
 #if LOG_AVG
 			avgLum += log(max(kEpsilonf, lum));
@@ -53,30 +56,28 @@ void main()
 		}
 	}
 
-	s_avgLum[gl_LocalInvocationIndex] = avgLum;
+	s_avgLum[svGroupIndex] = avgLum;
 
-	memoryBarrierShared();
-	barrier();
+	GroupMemoryBarrierWithGroupSync();
 
 	// Gather the results into one
-	[[dont_unroll]] for(U32 s = (kWorkgroupSize.x * kWorkgroupSize.y) / 2u; s > 0u; s >>= 1u)
+	[loop] for(U32 s = (THREAD_COUNT_X * THREAD_COUNT_Y) / 2u; s > 0u; s >>= 1u)
 	{
-		if(gl_LocalInvocationIndex < s)
+		if(svGroupIndex < s)
 		{
-			s_avgLum[gl_LocalInvocationIndex] += s_avgLum[gl_LocalInvocationIndex + s];
+			s_avgLum[svGroupIndex] += s_avgLum[svGroupIndex + s];
 		}
 
 #if ANKI_PLATFORM_MOBILE
 		if(s > 16u)
 		{
-			memoryBarrierShared();
-			barrier();
+			GroupMemoryBarrierWithGroupSync();
 		}
 #endif
 	}
 
 	// Write the result
-	[branch] if(gl_LocalInvocationIndex == 0u)
+	[branch] if(svGroupIndex == 0u)
 	{
 #if LOG_AVG
 		const F32 crntLum = exp(s_avgLum[0] * (1.0 / F32(kInputTexSize.x * kInputTexSize.y)));
@@ -89,13 +90,13 @@ void main()
 
 		// Lerp between previous and new L value
 		const F32 interpolationFactor = 0.05;
-		F32 finalAvgLum = mix(prevLum, crntLum, interpolationFactor);
+		F32 finalAvgLum = lerp(prevLum, crntLum, interpolationFactor);
 #else
 		F32 finalAvgLum = crntLum;
 #endif
 
 		// This is a workaround because sometimes the avg lum becomes nan
-		finalAvgLum = clamp(finalAvgLum, kEpsilonf, kMaxF32);
+		finalAvgLum = clamp(finalAvgLum, kEpsilonF32, kMaxF32);
 
 		writeExposureAndAverageLuminance(computeExposure(finalAvgLum, 0.0), finalAvgLum);
 	}

+ 8 - 9
AnKi/Shaders/VisualizeHdrRenderTarget.ankiprog

@@ -3,21 +3,20 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
+#pragma anki hlsl
+
 #pragma anki start vert
-#include <AnKi/Shaders/QuadVert.glsl>
+#include <AnKi/Shaders/QuadVert.hlsl>
 #pragma anki end
 
 #pragma anki start frag
-#include <AnKi/Shaders/TonemappingFunctions.glsl>
-
-layout(set = 0, binding = 0) uniform sampler u_nearestAnyClampSampler;
-layout(set = 0, binding = 1) uniform texture2D u_inTex;
+#include <AnKi/Shaders/TonemappingFunctions.hlsl>
 
-layout(location = 0) in Vec2 in_uv;
-layout(location = 0) out Vec3 out_color;
+[[vk::binding(0)]] SamplerState g_nearestAnyClampSampler;
+[[vk::binding(1)]] Texture2D g_inTex;
 
-void main()
+Vec3 main(Vec2 uv : TEXCOORD) : SV_TARGET0
 {
-	out_color = reinhardTonemap(textureLod(u_inTex, u_nearestAnyClampSampler, in_uv, 0.0).rgb);
+	return reinhardTonemap(g_inTex.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).rgb);
 }
 #pragma anki end

+ 8 - 9
AnKi/Shaders/VisualizeRenderTarget.ankiprog

@@ -3,21 +3,20 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
+#pragma anki hlsl
+
 #pragma anki start vert
-#include <AnKi/Shaders/QuadVert.glsl>
+#include <AnKi/Shaders/QuadVert.hlsl>
 #pragma anki end
 
 #pragma anki start frag
-#include <AnKi/Shaders/Common.glsl>
-
-layout(set = 0, binding = 0) uniform sampler u_nearestAnyClampSampler;
-layout(set = 0, binding = 1) uniform texture2D u_inTex;
+#include <AnKi/Shaders/Common.hlsl>
 
-layout(location = 0) in Vec2 in_uv;
-layout(location = 0) out Vec3 out_color;
+[[vk::binding(0)]] SamplerState g_nearestAnyClampSampler;
+[[vk::binding(1)]] Texture2D g_inTex;
 
-void main()
+Vec3 main(Vec2 uv : TEXCOORD) : SV_TARGET0
 {
-	out_color = textureLod(u_inTex, u_nearestAnyClampSampler, in_uv, 0.0).rgb;
+	return g_inTex.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).rgb;
 }
 #pragma anki end

+ 25 - 31
Docs/CodeStyle.md

@@ -1,19 +1,19 @@
-This document describes the style of code in AnKi 3D Engine. The code is written primarily in C++ with some GLSL and python as well.
+This document describes the style of code in AnKi 3D Engine. The code is written primarily in C++ with some HLSL and python as well.
 
 Table of contents
 =================
 
-* [Comments in C++ & GLSL](#Comments%20in%20C++%20&%20GLSL)
+* [Comments in C++ & HLSL](#Comments%20in%20C++%20&%20HLSL)
 * [Comments in python](#Comments%20in%20python)
-* [Naming conventions in C++ & GLSL](#Naming%20conventions%20in%20C++%20&%20GLSL)
+* [Naming conventions in C++ & HLSL](#Naming%20conventions%20in%20C++%20&%20HLSL)
 * [Naming conventions in python](#Naming%20conventions%20in%20python)
 * [Naming conventions for files and directories](#Naming%20conventions%20for%20files%20and%20directories)
 * [C++ rules](#C++%20rules)
-* [GLSL rules](#GLSL%20rules)
-* [Code formatting in C++ & GLSL](#Code%20formatting%20in%20C++%20&%20GLSL)
+* [HLSL rules](#HLSL%20rules)
+* [Code formatting in C++ & HLSL](#Code%20formatting%20in%20C++%20&%20HLSL)
 * [Code formatting in python](#Code%20formatting%20in%20python)
 
-Comments in C++ & GLSL
+Comments in C++ & HLSL
 ======================
 
 All comments are C++ like (double slash):
@@ -30,7 +30,7 @@ Comments in python
 
 Whatever the PEP 8 guide proposes.
 
-Naming conventions in C++ & GLSL
+Naming conventions in C++ & HLSL
 ================================
 
 **Variables, functions and methods** are lower camelCase.
@@ -54,11 +54,11 @@ All **constexpr expressions** start with a `k` and that includes enumerants.
 
 All **macros and defines** should be SCREAMING_SNAKE_CASE and they should have an `ANKI_` prefix.
 
-	ANKI_ASSERT(...);
+	#define ANKI_ASSERT(expr)
 
 	#define ANKI_MAX_SOMETHING ...
 
-All **template typedefs** should start with `T`. No need for constant template arguments.
+All **template typedefs** should start with `T`. The rule doesn't apply in constant template arguments.
 
 	template<typename TSomething, typename TOther, U32 kSomeConst>
 
@@ -74,13 +74,9 @@ All **function and method names** should form a sentence with at least one verb.
 - All member variables have the `m_` prefix. That applies to classes and structs.
 - All global variables have the `g_` prefix.
 
-In GLSL there are more exceptions:
+In HLSL there are more exceptions:
 
-- All uniforms (buffers, textures, images, push constants) and storage buffers have the `u_` prefix.
-- All input globals the `in_` prefix.
-- All output globals the `out_` prefix.
-- All shared storage the `s_` prefix.
-- All storage or uniform block names have the  `b_` prefix.
+- All groupshared variables use the `s_` prefix.
 
 **Variables that act as a measure for quantity** should have the `count` suffix. Not `num` or `numberOf` or similar.
 
@@ -130,9 +126,9 @@ C++ rules
 **Always use `constexpr`** when applicable. Never use defines for constants.
 
 	constexpr uint kSomeConst = ...; // YES!!
-	#define SOME_CONST (...)         // NO
+	#define SOME_CONST ...           // NO
 
-**Never use `struct`** and always use `class` instead. Since it's difficult to come up with rules on when to use struct over class always use class and be done with it.
+**Always use `class`** and never use `struct`. Since it's difficult to come up with rules on when to use struct over class, always use class and be done with it.
 
 	class MyTrivialType
 	{
@@ -146,14 +142,14 @@ C++ rules
 	auto i = 10;               // NO
 	auto it = list.getBegin(); // ... FINE
 
-**Includes should always have the full file path**. This avoids issues with files of similar name. Non-AnKi includes follow AnKi includes.
+**Includes should always have the full file path**. This avoids issues with files of similar name. Also, non-AnKi includes follow AnKi includes.
 
 	#include <AnKi/Util/Thread.h>
 	#include <AnKi/Util/WeakArray.h>
 	#include <AnKi/Util/Allocator.h>
 	#include <cstdio>
 
-**Never use public nested classes**. Only private nested classes are allowed. Nested classes cannot be forward declared. Nexted typedefs are fine.
+**Never use public nested classes**. Only private nested classes are allowed. Nested classes cannot be forward declared. Nested typedefs are fine.
 
 	class MyClass
 	{
@@ -165,10 +161,10 @@ C++ rules
 		using SomeTypedef = U32;
 
 	private:
-		// OK
+		// OK, it's private
 		class Nested {...};
 
-		// Also OK
+		// Also OK, it's private
 		class
 		{
 			...
@@ -208,8 +204,8 @@ If you have to overload the operator Bool always use **`explicit operator Bool`
 
 The use of **references and pointers** is govern by some rules. Always use references except when you transfer or share ownership. Pointers are also allowed for optional data that can be nullptr.
 
-	// ptr is a pointer so you CAN NOT destroy it after a call to doSomething is done
-	// ref is a reference so you CAN destroy it after a call to doSomething is done
+	// ptr is a pointer so you CAN NOT destroy after a call to doSomething is done
+	// ref is a reference so you CAN destroy after a call to doSomething is done
 	void Foo::doSomething(TypeA* ptr, TypeB& ref)
 	{
 		// Store the ptr somewhere
@@ -266,23 +262,21 @@ Always **use `override` or `final`** on virtual methods and try to use `final` o
 
 Always place the **condition of a conditional ternary operator** inside parenthesis.
 
-	a = b ? 1 : 0;   // NO
+	a =  b  ? 1 : 0;   // NO
 	a = (b) ? 1 : 0; // YES
 
-GLSL rules
+HLSL rules
 ==========
 
-Same rules as in C++ (when applicable) with one exception: You **can use `structs`** in GLSL because there is no other way.
+Same rules as in C++ (when applicable) with one exception: You should **use `struct` instead of `class`** for user defined types.
 
-Code formatting in C++ & GLSL
+Code formatting in C++ & HLSL
 =============================
 
-clang-format deals with code formatting. To format all the C++ and GLSL files in the source tree type the following in a terminal:
+clang-format deals with code formatting. To format all the C++ and HLSL files in the source tree type the following in a terminal:
 
 	$ cd /path/to/anki
-	$ ./Tools/FormatSource.sh
-
-If you need to format on Windows do the same from a WSL terminal.
+	$ python ./Tools/FormatSource.py
 
 Code formatting in python
 =========================

+ 8 - 5
Tools/FormatSource.py

@@ -11,16 +11,18 @@ import threading
 import multiprocessing
 import os
 import tempfile
-import shutil
 import platform
 
 file_extensions = ["h", "hpp", "c", "cpp", "glsl", "hlsl", "ankiprog"]
 directories = ["AnKi", "Tests", "Sandbox", "Tools", "Samples"]
-hlsl_semantics = ["TEXCOORD", "SV_POSITION", "SV_TARGET0", "SV_TARGET", "SV_DISPATCHTHREADID", "SV_GROUPINDEX",
-                  "SV_GROUPID"]
+hlsl_semantics = ["TEXCOORD", "SV_POSITION", "SV_TARGET0", "SV_TARGET1", "SV_TARGET2", "SV_TARGET3", "SV_TARGET4",
+                  "SV_TARGET5", "SV_TARGET6", "SV_TARGET7", "SV_DISPATCHTHREADID", "SV_GROUPINDEX", "SV_GROUPID",
+                  "SV_GROUPTHREADID"]
 hlsl_attribs = ["[shader(\"closesthit\")]", "[shader(\"anyhit\")]", "[shader(\"raygeneration\")]", "[shader(\"miss\")]",
                 "[raypayload]"]
-hlsl_attribs_fake = ["__ak_chit__", "__ak_ahit__", "__ak_rgen__", "__ak_miss__", "[[raypayload]]"]
+hlsl_attribs_fake = ["______shaderclosesthit", "______shaderanyhit", "______shaderraygeneration", "______shadermiss",
+                     "[[raypaylo]]"]
+
 
 def thread_callback(tid):
     """ Call clang-format """
@@ -47,7 +49,7 @@ def thread_callback(tid):
             file_txt = file.read()
             file.close()
 
-            original_file_hash = hash(file_txt) 
+            original_file_hash = hash(file_txt)
 
             # Replace all semantics
             for semantic in hlsl_semantics:
@@ -100,6 +102,7 @@ def thread_callback(tid):
             # Cleanup
             os.remove(tmp_filename)
 
+
 # Gather the filenames
 file_names = []
 for directory in directories: