summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/emit.cpp46
-rw-r--r--tests/compute/half-calc.slang32
-rw-r--r--tests/compute/half-calc.slang.expected.txt4
-rw-r--r--tests/compute/half-structured-buffer.slang30
-rw-r--r--tests/compute/half-structured-buffer.slang.expected.txt16
-rw-r--r--tools/gfx/render-d3d11.cpp3
-rw-r--r--tools/gfx/render-d3d12.cpp21
-rw-r--r--tools/gfx/render-gl.cpp3
-rw-r--r--tools/gfx/render-vk.cpp81
-rw-r--r--tools/gfx/render.h3
-rw-r--r--tools/gfx/vk-api.cpp4
-rw-r--r--tools/gfx/vk-api.h7
-rw-r--r--tools/gfx/vk-module.h3
-rw-r--r--tools/render-test/options.cpp21
-rw-r--r--tools/render-test/options.h2
-rw-r--r--tools/render-test/render-test-main.cpp11
-rw-r--r--tools/slang-test/slang-test-main.cpp4
17 files changed, 276 insertions, 15 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index d2de479b4..84585f248 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -47,6 +47,8 @@ struct ExtensionUsageTracker
StringBuilder glslExtensionRequireLines;
ProfileVersion profileVersion = ProfileVersion::GLSL_110;
+
+ bool hasHalfExtension = false;
};
void requireGLSLExtension(
@@ -76,6 +78,21 @@ void requireGLSLVersionImpl(
}
}
+void requireGLSLHalfExtension(ExtensionUsageTracker* tracker)
+{
+ if (!tracker->hasHalfExtension)
+ {
+ // https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_shader_16bit_storage.txt
+ requireGLSLExtension(tracker, "GL_EXT_shader_16bit_storage");
+
+ // https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_shader_explicit_arithmetic_types.txt
+ // Use GL_KHX_shader_explicit_arithmetic_types because that is what appears defined in glslang
+ requireGLSLExtension(tracker, "GL_KHX_shader_explicit_arithmetic_types");
+
+ tracker->hasHalfExtension = true;
+ }
+}
+
// Shared state for an entire emit session
struct SharedEmitContext
@@ -810,7 +827,12 @@ struct EmitVisitor
case kIROp_BoolType: Emit("b"); break;
- case kIROp_HalfType: Emit("f16"); break;
+ case kIROp_HalfType:
+ {
+ _requireHalf();
+ Emit("f16");
+ break;
+ }
case kIROp_DoubleType: Emit("d"); break;
case kIROp_VectorType:
@@ -1197,6 +1219,14 @@ struct EmitVisitor
}
}
+ void _requireHalf()
+ {
+ if (getTarget(context) == CodeGenTarget::GLSL)
+ {
+ requireGLSLHalfExtension(&context->shared->extensionUsageTracker);
+ }
+ }
+
void emitSimpleTypeImpl(IRType* type)
{
switch (type->op)
@@ -1217,7 +1247,19 @@ struct EmitVisitor
case kIROp_UIntType: Emit("uint"); return;
case kIROp_UInt64Type: Emit("uint64_t"); return;
- case kIROp_HalfType: Emit("half"); return;
+ case kIROp_HalfType:
+ {
+ _requireHalf();
+ if (getTarget(context) == CodeGenTarget::GLSL)
+ {
+ Emit("float16_t");
+ }
+ else
+ {
+ Emit("half");
+ }
+ return;
+ }
case kIROp_FloatType: Emit("float"); return;
case kIROp_DoubleType: Emit("double"); return;
diff --git a/tests/compute/half-calc.slang b/tests/compute/half-calc.slang
new file mode 100644
index 000000000..b47678dae
--- /dev/null
+++ b/tests/compute/half-calc.slang
@@ -0,0 +1,32 @@
+//TEST(compute):COMPARE_COMPUTE:-dx12 -compute -use-dxil -profile cs_6_2 -render-features half
+//TEST(compute):COMPARE_COMPUTE:-vk -compute -use-dxil -profile cs_6_2 -render-features half
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
+
+// Test for doing a calculation using half
+
+RWStructuredBuffer<float> outputBuffer;
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ uint tid = dispatchThreadID.x;
+
+ //half2 v0 = { 1, -2 };
+ //half2 v1 = { -2, 4 };
+
+ //half2 v2 = (v0 * 2.0f + v1);
+
+ // This should work (it compiles on dxc, but slang doesn't seem to have overloads yet)
+ //half offset = length(v2);
+
+ //half offset = v2.x + v2.y;
+
+ half offset = 0.0f;
+
+ half v = tid;
+ v *= half(3.0f);
+ v += half(1.0f);
+ v += offset;
+
+ outputBuffer[tid] = v;
+} \ No newline at end of file
diff --git a/tests/compute/half-calc.slang.expected.txt b/tests/compute/half-calc.slang.expected.txt
new file mode 100644
index 000000000..2915a0dbc
--- /dev/null
+++ b/tests/compute/half-calc.slang.expected.txt
@@ -0,0 +1,4 @@
+3F800000
+40800000
+40E00000
+41200000
diff --git a/tests/compute/half-structured-buffer.slang b/tests/compute/half-structured-buffer.slang
new file mode 100644
index 000000000..e67aba55e
--- /dev/null
+++ b/tests/compute/half-structured-buffer.slang
@@ -0,0 +1,30 @@
+//TEST(compute):COMPARE_COMPUTE:-vk -compute -profile cs_6_2 -render-features half
+//Disable on Dx12 for now - because writing to structured buffer produces unexpected results
+//DISABLE_TEST(compute):COMPARE_COMPUTE:-dx12 -compute -use-dxil -profile cs_6_2 -render-features half
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=16):dxbinding(0),glbinding(0),out
+
+struct Thing
+{
+ uint pos;
+ float radius;
+ half4 color;
+};
+
+RWStructuredBuffer<Thing> outputBuffer;
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ uint tid = dispatchThreadID.x;
+
+ float v = float(tid);
+
+ float base = v* 4.0f;
+
+ Thing thing;
+ thing.pos = tid;
+ thing.color = half4(base, base + 1.0f, base + 2.0f, base + 3.0f);
+ thing.radius = v;
+
+ outputBuffer[tid] = thing;
+} \ No newline at end of file
diff --git a/tests/compute/half-structured-buffer.slang.expected.txt b/tests/compute/half-structured-buffer.slang.expected.txt
new file mode 100644
index 000000000..9170926f3
--- /dev/null
+++ b/tests/compute/half-structured-buffer.slang.expected.txt
@@ -0,0 +1,16 @@
+0
+0
+3C000000
+42004000
+1
+3F800000
+45004400
+47004600
+2
+40000000
+48804800
+49804900
+3
+40400000
+4A804A00
+4B804B00
diff --git a/tools/gfx/render-d3d11.cpp b/tools/gfx/render-d3d11.cpp
index 690b869ca..8b961c8f2 100644
--- a/tools/gfx/render-d3d11.cpp
+++ b/tools/gfx/render-d3d11.cpp
@@ -54,6 +54,7 @@ public:
// Renderer implementation
virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override;
+ virtual const List<String>& getFeatures() override { return m_features; }
virtual void setClearColor(const float color[4]) override;
virtual void clearFrame() override;
virtual void presentFrame() override;
@@ -329,6 +330,8 @@ public:
Desc m_desc;
float m_clearColor[4] = { 0, 0, 0, 0 };
+
+ List<String> m_features;
};
Renderer* createD3D11Renderer()
diff --git a/tools/gfx/render-d3d12.cpp b/tools/gfx/render-d3d12.cpp
index 0b611a219..5483e7e4b 100644
--- a/tools/gfx/render-d3d12.cpp
+++ b/tools/gfx/render-d3d12.cpp
@@ -55,6 +55,7 @@ class D3D12Renderer : public Renderer
public:
// Renderer implementation
virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override;
+ virtual const List<String>& getFeatures() override { return m_features; }
virtual void setClearColor(const float color[4]) override;
virtual void clearFrame() override;
virtual void presentFrame() override;
@@ -571,6 +572,8 @@ protected:
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE m_D3D12SerializeRootSignature = nullptr;
HWND m_hwnd = nullptr;
+
+ List<String> m_features;
};
Renderer* createD3D12Renderer()
@@ -1397,6 +1400,8 @@ Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle)
return SLANG_FAIL;
}
+
+
FlagCombiner combiner;
// TODO: we should probably provide a command-line option
// to override UseDebug of default rather than leave it
@@ -1426,6 +1431,22 @@ Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle)
return SLANG_FAIL;
}
+ // Find what features are supported
+ {
+ // Check this is how this is laid out...
+ SLANG_COMPILE_TIME_ASSERT(D3D_SHADER_MODEL_6_0 == 0x60);
+
+ D3D12_FEATURE_DATA_SHADER_MODEL featureShaderMode;
+ featureShaderMode.HighestShaderModel = D3D_SHADER_MODEL(0x62);
+
+ if (SLANG_SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &featureShaderMode, sizeof(featureShaderMode))) &&
+ featureShaderMode.HighestShaderModel >= 0x62)
+ {
+ // With sm_6_2 we have half
+ m_features.Add("half");
+ }
+ }
+
m_numRenderFrames = 3;
m_numRenderTargets = 2;
diff --git a/tools/gfx/render-gl.cpp b/tools/gfx/render-gl.cpp
index 879ff7a3c..a2d379778 100644
--- a/tools/gfx/render-gl.cpp
+++ b/tools/gfx/render-gl.cpp
@@ -81,6 +81,7 @@ public:
// Renderer implementation
virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override;
+ virtual const List<String>& getFeatures() override { return m_features; }
virtual void setClearColor(const float color[4]) override;
virtual void clearFrame() override;
virtual void presentFrame() override;
@@ -354,6 +355,8 @@ public:
Desc m_desc;
+ List<String> m_features;
+
// Declare a function pointer for each OpenGL
// extension function we need to load
#define DECLARE_GL_EXTENSION_FUNC(NAME, TYPE) TYPE NAME;
diff --git a/tools/gfx/render-vk.cpp b/tools/gfx/render-vk.cpp
index e291c7e9c..defc08355 100644
--- a/tools/gfx/render-vk.cpp
+++ b/tools/gfx/render-vk.cpp
@@ -42,6 +42,7 @@ public:
// Renderer implementation
virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override;
+ virtual const List<String>& getFeatures() override { return m_features; }
virtual void setClearColor(const float color[4]) override;
virtual void clearFrame() override;
virtual void presentFrame() override;
@@ -488,6 +489,7 @@ public:
float m_clearColor[4] = { 0, 0, 0, 0 };
Desc m_desc;
+ List<String> m_features;
};
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VkRenderer::Buffer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
@@ -898,6 +900,8 @@ SlangResult VKRenderer::initialize(const Desc& desc, void* inWindowHandle)
{
VK_KHR_SURFACE_EXTENSION_NAME,
+ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+
#if SLANG_WINDOWS_FAMILY
VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
#else
@@ -949,6 +953,71 @@ SlangResult VKRenderer::initialize(const Desc& desc, void* inWindowHandle)
SLANG_RETURN_ON_FAIL(m_api.initPhysicalDevice(physicalDevices[selectedDeviceIndex]));
+ List<const char*> deviceExtensions;
+ deviceExtensions.Add(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+
+ VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
+ deviceCreateInfo.queueCreateInfoCount = 1;
+
+ deviceCreateInfo.pEnabledFeatures = &m_api.m_deviceFeatures;
+
+ // Get the device features (doesn't use, but useful when debugging)
+ if (m_api.vkGetPhysicalDeviceFeatures2)
+ {
+ VkPhysicalDeviceFeatures2 deviceFeatures2 = {};
+ deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ m_api.vkGetPhysicalDeviceFeatures2(m_api.m_physicalDevice, &deviceFeatures2);
+ }
+
+ VkPhysicalDeviceProperties basicProps = {};
+ m_api.vkGetPhysicalDeviceProperties(m_api.m_physicalDevice, &basicProps);
+
+ // Get the API version
+ const uint32_t majorVersion = VK_VERSION_MAJOR(basicProps.apiVersion);
+ const uint32_t minorVersion = VK_VERSION_MINOR(basicProps.apiVersion);
+
+ // Float16 features
+ // Need in this scope because it will be linked into the device creation (if it is available)
+ VkPhysicalDeviceFloat16Int8FeaturesKHR float16Features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR };
+
+ // API version check, can't use vkGetPhysicalDeviceProperties2 yet since this device might not support it
+ if (VK_MAKE_VERSION(majorVersion, minorVersion, 0) >= VK_API_VERSION_1_1 &&
+ m_api.vkGetPhysicalDeviceProperties2 &&
+ m_api.vkGetPhysicalDeviceFeatures2)
+ {
+ VkPhysicalDeviceProperties2 physicalDeviceProps2;
+
+ physicalDeviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ physicalDeviceProps2.pNext = nullptr;
+ physicalDeviceProps2.properties = {};
+
+ m_api.vkGetPhysicalDeviceProperties2(m_api.m_physicalDevice, &physicalDeviceProps2);
+
+ // Get device features
+ VkPhysicalDeviceFeatures2 deviceFeatures2 = {};
+ deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+
+ // Link together for lookup
+ float16Features.pNext = deviceFeatures2.pNext;
+ deviceFeatures2.pNext = &float16Features;
+
+ m_api.vkGetPhysicalDeviceFeatures2(m_api.m_physicalDevice, &deviceFeatures2);
+
+ // If we have float16 features then enable
+ if (float16Features.shaderFloat16)
+ {
+ // Link into the creation features
+ float16Features.pNext = (void*)deviceCreateInfo.pNext;
+ deviceCreateInfo.pNext = &float16Features;
+
+ // Add the Float16 extension
+ deviceExtensions.Add(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
+
+ // We have half support
+ m_features.Add("half");
+ }
+ }
+
int queueFamilyIndex = m_api.findQueue(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
assert(queueFamilyIndex >= 0);
@@ -958,18 +1027,10 @@ SlangResult VKRenderer::initialize(const Desc& desc, void* inWindowHandle)
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
- char const* const deviceExtensions[] =
- {
- VK_KHR_SWAPCHAIN_EXTENSION_NAME,
- };
-
- VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
- deviceCreateInfo.queueCreateInfoCount = 1;
deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
- deviceCreateInfo.pEnabledFeatures = &m_api.m_deviceFeatures;
- deviceCreateInfo.enabledExtensionCount = SLANG_COUNT_OF(deviceExtensions);
- deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions;
+ deviceCreateInfo.enabledExtensionCount = uint32_t(deviceExtensions.Count());
+ deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.Buffer();
SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateDevice(m_api.m_physicalDevice, &deviceCreateInfo, nullptr, &m_device));
SLANG_RETURN_ON_FAIL(m_api.initDeviceProcs(m_device));
diff --git a/tools/gfx/render.h b/tools/gfx/render.h
index b91fb513f..775e71613 100644
--- a/tools/gfx/render.h
+++ b/tools/gfx/render.h
@@ -785,6 +785,9 @@ public:
virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) = 0;
+ bool hasFeature(const Slang::UnownedStringSlice& feature) { return getFeatures().IndexOf(Slang::String(feature)) != UInt(-1); }
+ virtual const Slang::List<Slang::String>& getFeatures() = 0;
+
virtual void setClearColor(const float color[4]) = 0;
virtual void clearFrame() = 0;
diff --git a/tools/gfx/vk-api.cpp b/tools/gfx/vk-api.cpp
index 4030e43ba..6e250e281 100644
--- a/tools/gfx/vk-api.cpp
+++ b/tools/gfx/vk-api.cpp
@@ -49,11 +49,15 @@ Slang::Result VulkanApi::initInstanceProcs(VkInstance instance)
VK_API_ALL_INSTANCE_PROCS(VK_API_GET_INSTANCE_PROC)
+ // Get optional
+ VK_API_INSTANCE_PROCS_OPT(VK_API_GET_INSTANCE_PROC)
+
if (!areDefined(ProcType::Instance))
{
return SLANG_FAIL;
}
+
m_instance = instance;
return SLANG_OK;
}
diff --git a/tools/gfx/vk-api.h b/tools/gfx/vk-api.h
index 5ec28ef6e..001f44d19 100644
--- a/tools/gfx/vk-api.h
+++ b/tools/gfx/vk-api.h
@@ -10,6 +10,11 @@ namespace gfx {
x(vkCreateInstance) \
/* */
+#define VK_API_INSTANCE_PROCS_OPT(x) \
+ x(vkGetPhysicalDeviceFeatures2) \
+ x(vkGetPhysicalDeviceProperties2) \
+ /* */
+
#define VK_API_INSTANCE_PROCS(x) \
x(vkCreateDevice) \
x(vkCreateDebugReportCallbackEXT) \
@@ -146,6 +151,8 @@ namespace gfx {
VK_API_ALL_GLOBAL_PROCS(x) \
VK_API_ALL_INSTANCE_PROCS(x) \
VK_API_ALL_DEVICE_PROCS(x) \
+ \
+ VK_API_INSTANCE_PROCS_OPT(x) \
/* */
#define VK_API_DECLARE_PROC(NAME) PFN_##NAME NAME = nullptr;
diff --git a/tools/gfx/vk-module.h b/tools/gfx/vk-module.h
index efa166d08..4d18823ca 100644
--- a/tools/gfx/vk-module.h
+++ b/tools/gfx/vk-module.h
@@ -1,4 +1,4 @@
-// vk-module.h
+// vk-module.h
#pragma once
#include "../../slang.h"
@@ -12,6 +12,7 @@
#endif
#define VK_NO_PROTOTYPES
+
#include <vulkan/include/vulkan/vulkan.h>
namespace gfx {
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index b6208c4b3..1171a2a03 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -9,7 +9,11 @@
#include "../../source/core/slang-writer.h"
#include "../../source/core/slang-render-api-util.h"
+#include "../../source/core/list.h"
+#include "../../source/core/slang-string-util.h"
+
namespace renderer_test {
+using namespace Slang;
static const Options gDefaultOptions;
@@ -98,6 +102,23 @@ SlangResult parseOptions(int argc, const char*const* argv, Slang::WriterHelper s
}
gOptions.profileName = *argCursor++;
}
+ else if (strcmp(arg, "-render-features") == 0 || strcmp(arg, "-render-feature") == 0)
+ {
+ if (argCursor == argEnd)
+ {
+ stdError.print("expected argument for '%s' option\n", arg);
+ return SLANG_FAIL;
+ }
+ const char* value = *argCursor++;
+
+ List<UnownedStringSlice> values;
+ StringUtil::split(UnownedStringSlice(value), ',', values);
+
+ for (const auto& value : values)
+ {
+ gOptions.renderFeatures.Add(value);
+ }
+ }
else if( strcmp(arg, "-xslang") == 0 )
{
// This is an option that we want to pass along to Slang
diff --git a/tools/render-test/options.h b/tools/render-test/options.h
index 6c1482ab4..7b55b9ac0 100644
--- a/tools/render-test/options.h
+++ b/tools/render-test/options.h
@@ -55,6 +55,8 @@ struct Options
int slangArgCount = 0;
bool useDXIL = false;
+
+ Slang::List<Slang::String> renderFeatures; /// Required render features for this test to run
};
extern Options gOptions;
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index 0be84f52f..ee408f283 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -574,6 +574,17 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
}
}
+ {
+ for (const auto& feature : gOptions.renderFeatures)
+ {
+ // If doesn't have required feature... we have to give up
+ if (!renderer->hasFeature(feature.getUnownedSlice()))
+ {
+ return SLANG_E_NOT_AVAILABLE;
+ }
+ }
+ }
+
// Use the profile name set on options if set
profileName = gOptions.profileName ? gOptions.profileName : profileName;
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index d385e868d..0b4b83198 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -1694,7 +1694,7 @@ static RenderApiType _findRenderApi(const List<String>& args, bool onlyExplicit)
return targetLanguageRenderer;
}
-static void _addSythesizedTest(RenderApiType rendererType, const List<TestOptions>& renderTests, List<TestOptions>& outSynthesizedTests)
+static void _addSynthesizedTest(RenderApiType rendererType, const List<TestOptions>& renderTests, List<TestOptions>& outSynthesizedTests)
{
for (const auto& test : renderTests)
{
@@ -1784,7 +1784,7 @@ void runTestsOnFile(
const int index = ByteEncodeUtil::calcMsb8(missingApis);
SLANG_ASSERT(index >= 0 && index <= int(RenderApiType::CountOf));
- _addSythesizedTest(RenderApiType(index), renderTests, synthesizedTests);
+ _addSynthesizedTest(RenderApiType(index), renderTests, synthesizedTests);
// Disable the bit
missingApis &= ~(RenderApiFlags(1) << index);