Adding support for floating point atomic operations in Vulkan - glsl

Recently the extension VK_EXT_shader_atomic_float has been added. I'm trying to figure out how to use it.
I've added the appropriate flag to my shader
#version 450
#extension GL_EXT_shader_atomic_float : enable
and I also added VK_EXT_shader_atomic_float to the device extensions
const char* extension_names[] = {"VK_EXT_shader_atomic_float", ... other extensions ...};
struct VkDeviceCreateInfo createInfo;
createInfo.enabledExtensionCount = 4;
createInfo.ppEnabledExtensionNames = extension_names;
Unfortunately I still get
[Debug][Error][Validation]"Validation Error: [ VUID-VkShaderModuleCreateInfo-pCode-01091 ] Object 0: handle = 0x55967fac1038, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xa7bb8db6 | vkCreateShaderModule(): The SPIR-V Capability (AtomicFloat32AddEXT) was declared, but none of the requirements were met to use it. The Vulkan spec states: If pCode declares any of the capabilities listed in the SPIR-V Environment appendix, one of the corresponding requirements must be satisfied (https://vulkan.lunarg.com/doc/view/1.2.182.0/linux/1.2-extensions/vkspec.html#VUID-VkShaderModuleCreateInfo-pCode-01091)"
I suppose I should add something to vkShaderModuleCreateInfo.pNext, but I'm not sure what exactly.

If you go here
https://vulkan.lunarg.com/doc/view/1.2.182.0/linux/1.2-extensions/vkspec.html#spirvenv-capabilities
you can scroll down to the desired extension. In this case it's
AtomicFloat32AddEXT
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT::shaderBufferFloat32AtomicAdd
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT::shaderSharedFloat32AtomicAdd
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT::shaderImageFloat32AtomicAdd
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT::sparseImageFloat32AtomicAdd
This tells you that you need to use VkPhysicalDeviceShaderAtomicFloatFeaturesEXT structure and set it's corresponding flag. The structure is defined as
typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT {
VkStructureType sType;
void* pNext;
VkBool32 shaderBufferFloat32Atomics;
VkBool32 shaderBufferFloat32AtomicAdd;
VkBool32 shaderBufferFloat64Atomics;
VkBool32 shaderBufferFloat64AtomicAdd;
VkBool32 shaderSharedFloat32Atomics;
VkBool32 shaderSharedFloat32AtomicAdd;
VkBool32 shaderSharedFloat64Atomics;
VkBool32 shaderSharedFloat64AtomicAdd;
VkBool32 shaderImageFloat32Atomics;
VkBool32 shaderImageFloat32AtomicAdd;
VkBool32 sparseImageFloat32Atomics;
VkBool32 sparseImageFloat32AtomicAdd;
} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT;
So the complete code would looks more or less like this
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT floatFeatures;
floatFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT;
floatFeatures.shaderBufferFloat32AtomicAdd = true; // this allows to perform atomic operations on storage buffers
const char* extension_names[] = {"VK_EXT_shader_atomic_float", ... other extensions ...};
VkDeviceCreateInfo createInfo;
createInfo.enabledExtensionCount = 4;
createInfo.ppEnabledExtensionNames = extension_names;
createInfo.pNext = &floatFeatures;

Related

verify structure layout at build time

How can I verify the layout of a (repr(C)) structure without running the code? E.g. when I have
#[repr(C)]
struct Registers {
urxd: u32, // 0x00
_rsrvd0: [u32;15],
utxd: u32, // 0x40
_rsrvd1: [u32;15],
ucr1: u32, // 0x80
}
how can I make the build process fail when ucr1 is not at positition 0x80 (e.g. due to miscalculated _rsrvd members or target depending padding)?
In C I would write something like
struct foo {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
};
static void _test() {
_Static_assert(offsetof(struct foo, d) == 12);
}
For _Static_assert there seem to exist crates like static_assertions which implement hacks like these from the good old C times (negative array sizes and so).
But for offsetof() I have found only non-const implementations.
Code is for embedded platforms without #[test] support so I can not test it at runtime. Running #[test] on a std-platform might give wrong results because padding/alignment is different there.
You can use the const_field_offset crate to get the offset and the static_assertions to assert during the build.
use const_field_offset;
use static_assertions as sa;
#[repr(C)]
#[derive(const_field_offset::FieldOffsets)]
struct Registers {
urxd: u32, // 0x00
_rsrvd0: [u32;15],
utxd: u32, // 0x40
_rsrvd1: [u32;15],
ucr1: u32, // 0x80
}
sa::const_assert!(0x80 == Registers::FIELD_OFFSETS.ucr1.get_byte_offset());
When the assert fails, the error message isn't super helpful, but it does at least fail the build:
sa::const_assert!(0x79 == Registers::FIELD_OFFSETS.ucr1.get_byte_offset());
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow

Problems Translating C++ 'extern "C" __declspec(dllexport)' struct to Rust

I am currently attempting to rebuild and update a Project written in Rust (more specifically it's an SKSE64 plugin for Skyrim: https://github.com/lukasaldersley/sse-mod-skyrim-search-se forked from qbx2)
The last problem I'm facing is the library now requires a struct to be exported from our library for version checking.
I have attempted many probably stupid ways to implement this, but I can't get it to work.
The c++ code is as follows:
struct SKSEPluginVersionData
{
enum
{
kVersion = 1,
};
enum
{
// set this if you are using a (potential at this time of writing) post-AE version of the Address Library
kVersionIndependent_AddressLibraryPostAE = 1 << 0,
// set this if you exclusively use signature matching to find your addresses and have NO HARDCODED ADDRESSES
kVersionIndependent_Signatures = 1 << 1,
};
UInt32 dataVersion; // set to kVersion
UInt32 pluginVersion; // version number of your plugin
char name[256]; // null-terminated ASCII plugin name
char author[256]; // null-terminated ASCII plugin author name (can be empty)
char supportEmail[256]; // null-terminated ASCII support email address (can be empty)
// version compatibility
UInt32 versionIndependence; // set to one of the kVersionIndependent_ enums or zero
UInt32 compatibleVersions[16]; // zero-terminated list of RUNTIME_VERSION_ defines your plugin is compatible with
UInt32 seVersionRequired; // minimum version of the script extender required, compared against PACKED_SKSE_VERSION
// you probably should just set this to 0 unless you know what you are doing
};
#define RUNTIME_VERSION_1_6_318 0x010613E0
extern "C" {
__declspec(dllexport) SKSEPluginVersionData SKSEPlugin_Version =
{
SKSEPluginVersionData::kVersion,
1,
"Skyrim Search",
"qbx2",
"",
0, // not version independent
{ RUNTIME_VERSION_1_6_318, 0 }, // RUNTIME_VERSION_1_6_318 is
0, // works with any version of the script extender. you probably do not need to put anything here
};
};
What I've come up with so far in Rust is:
enum KVersionenum {
KVersion=1,
}
#[repr(C)]
pub struct SKSEPluginVersionData {
dataVersion: u32,
pluginVersion: u32,
name: [char;256],
author: [char;256],
supportEmail: [char;256],
versionIndependence: u32,
compatibleVersions: [u32;16],
seVersionRequired: u32,
}
//0x010613E0 is RUNTIME_VERSION_1_6_318
//how can I do this OUTSIDE of a method and how can I make it public to the dll? is that even possible?
let SKSEPlugin_Version = SKSEPluginVersionData {
dataVersion: KVersionenum::KVersion as u32,
pluginVersion: 1,
name: "Skyrim Search\0", //this doesn't work, how can I fill this char array?
author: "qbx2 / lukasaldersley\0", //same here
supportEmail: "something#something.something\0", //and here
versionIndependence: 0,
compatibleVersions: [0x010613E0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //I'm sure this is a horrible way of doing this
seVersionRequired: 0,
};
When I tried to use the let thingy outside of a function the compiler complained about expecting 'item' but my google-fu isn't good enough to find any useful information there because I just kept finding information about items in the videogame Rust.
For the car array/string problem I have come across that std:ffi stuff and am completely lost in it's documentation but as far as I can tell it will only ever deal with pointers, which is not what I need.
The two questions now are how to I fill these char arrays (I cannot just pass a pointer) and how do I create an instance of this struct as a global variable (or however Rust calls it) that I can export since the let name = something {...} doesn't work.
As far as I can tell exporting to the dll for a function would look like this, but I assume it wouldn't work the same way for that struct.
#[no_mangle]
pub extern "C" fn SKSEPlugin_Query(skse: *const SKSEInterface, info: *mut PluginInfo) -> bool {...}
Is it even possible to do this?
Could someone help me here or at least point me in the right direction?
Please note I am an absolute beginner to Rust and apparently falsely assumed just adding a struct wouldn't be so complicated.
First, a char in Rust is a 32-bit value while its 8-bit in C++ (that's not strictly true but Rust doesn't support architectures where it isn't). So the
name, author, and supportEmail fields should be u8 arrays.
You can export a global value by using #[no_mangle] on a public static variable:
#[no_mangle]
pub static SKSEPlugin_Version: SKSEPluginVersionData = SKSEPluginVersionData {
...
};
See: Can a Rust constant/static be exposed to C?
You can initialize a u8 array from a literal using a byte string and dereferencing it: *b"...". Unfortunately, there's no shorthand like in C++ for zero-padding the undetermined part of the array, so you'd be left with:
name: *b"Skyrim Search\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
author: *b"qbx2 / lukasaldersley\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
supportEmail: *b"something#something.something\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
compatibleVersions: [0x010613E0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
Which honestly, is not nice at all. You can clean this up with some functions that pad the array for you, however, initializing static variables requires const functions, which are still relatively immature in Rust so we can't use things like for loops or traits to help us out:
const fn zero_pad_u8<const N: usize, const M: usize>(arr: &[u8; N]) -> [u8; M] {
let mut m = [0; M];
let mut i = 0;
while i < N {
m[i] = arr[i];
i += 1;
}
m
}
const fn zero_pad_u32<const N: usize, const M: usize>(arr: &[u32; N]) -> [u32; M] {
let mut m = [0; M];
let mut i = 0;
while i < N {
m[i] = arr[i];
i += 1;
}
m
}
...
name: zero_pad_u8(b"Skyrim Search"),
author: zero_pad_u8(b"qbx2 / lukasaldersley"),
supportEmail: zero_pad_u8(b"something#something.something"),
compatibleVersions: zero_pad_u32(&[0x010613E0]),
Still not that nice, but at least its manageable. There may be a crate available that can do this for you.
Lastly, you don't have to use the same field naming convention as used in C++ since its just the order and type that matters, so I'd recommend using snake_case, but if you do want to keep the same names for consistency, you can put the #[allow(non_snake_case)] attribute on SKSEPluginVersionData to suppress the compiler warnings.
I would also recommend making a constant for that magic value instead of just a comment:
const RUNTIME_VERSION_1_6_318: u32 = 0x010613E0;
See the full thing on the playground.

Why does managing OpenGl in Rust require Unsafe Code?

I've been writing an app in Rust that uses some OpenGL, and I've observed a trend in how OpenGl is accessed/managed in rust code. Frequently it seems that managing or creating an OpenGl context requires unsafe.
Why do these examples require unsafe code? I haven't been running into any problems because of this unsafe designator, but I'm just curious as to why its there. What kind of problems or constraints do these unsafe requirements impose on developers?
from glutins Multi-Window example
//...
let mut windows = std::collections::HashMap::new();
for index in 0..3 {
let title = format!("Charming Window #{}", index + 1);
let wb = WindowBuilder::new().with_title(title);
let windowed_context = ContextBuilder::new().build_windowed(wb, &el).unwrap();
//uses unsafe code
let windowed_context = unsafe { windowed_context.make_current().unwrap() };
let gl = support::load(&windowed_context.context());
let window_id = windowed_context.window().id();
let context_id = ct.insert(ContextCurrentWrapper::PossiblyCurrent(
ContextWrapper::Windowed(windowed_context),
));
windows.insert(window_id, (context_id, gl, index));
}
//...
from fltk-rs glow demo
//...
unsafe {
let gl = glow::Context::from_loader_function(|s| {
win.get_proc_address(s) as *const _
});
let vertex_array = gl
.create_vertex_array()
.expect("Cannot create vertex array");
gl.bind_vertex_array(Some(vertex_array));
let program = gl.create_program().expect("Cannot create program");
//...
win.draw(move |w| {
gl.clear(glow::COLOR_BUFFER_BIT);
gl.draw_arrays(glow::TRIANGLES, 0, 3);
w.swap_buffers();
});
}
//...
OpenGL is implemented as a library with a C ABI. If you want to call a C function from rust, it always means you have to use unsafe because the C implementation knows nothing about the safety features of rust and naturally doesn't support them. Furthermore, OpenGL uses raw pointers in its API to pass data from or to the GL, which also requires unsafe code in rust.

What does ComPtr.As() do?

I am working on learning DirectX 12 from some examples but I am having trouble understanding what does the ComPtr.As() method does.
ComPtr<ID3D12Device> device;
ComPtr<ID3D12Device> device2;
// Do Stuff with Device
device.As(&device2); // What does this do?
Where did you find this example code? It looks fishy. This is kind of a nonsense use of As. It's equally silly if you expand it to the underlying QueryInterface:
hr = device->QueryInterface( IID_PPV_ARGS(device2) );
In fact, your code would be better written as:
device2 = device;
Typically you'd use As to obtain a new interface from an existing interface. For example with Direct3D 11, you create the device as a Direct3D 11.0 interface and then have to QueryInterface the 11.1, 11.2, 11.3, and/or 11.4 versions to use them:
ComPtr<ID3D11Device> device;
DX::ThrowIfFailed(D3D11CreateDevice(..., device.ReleaseAndGetAddressOf());
ComPtr<ID3D11Device2> device2;
hr = device.As(&device2);
if (FAILED(hr))
// Do whatever handling you do if the system doesn't support 11.2
Another common use with Direct3D 11 is dealing with the debug interfaces which may not be present:
#ifndef NDEBUG
ComPtr<ID3D11Debug> d3dDebug;
if (SUCCEEDED(device.As(&d3dDebug)))
{
ComPtr<ID3D11InfoQueue> d3dInfoQueue;
if (SUCCEEDED(d3dDebug.As(&d3dInfoQueue)))
{
#ifdef _DEBUG
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
#endif
D3D11_MESSAGE_ID hide [] =
{
D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,
// TODO: Add more message IDs here as needed.
};
D3D11_INFO_QUEUE_FILTER filter = {};
filter.DenyList.NumIDs = _countof(hide);
filter.DenyList.pIDList = hide;
d3dInfoQueue->AddStorageFilterEntries(&filter);
}
}
#endif
It's also important to not ignore the HRESULT return value that comes back from As. You should use SUCCEEDED or FAILED macro, or a fast-fail like ThrowIfFailed.
See ComPtr.

Marshalling VARIANT across ABI boundaries in a WinRT component

I am porting our component which is written in C++ at its core and has both an ActiveX and a .Net shell. The component internally uses the VARIANT type in many places. Some public properties (get/set) and methods of this component's arguments are of the VARIANT type in the ActiveX implementation and System::Object in the .Net implementation. Internally in our code we use the VARIANT directly.
When implementing the ActiveX component, I did not need to do any marshaling since VARIANT is an OLE/COM type.
When implementing .Net component, I used similar to this:
VARIANT var;
//...
//Initialize the VARIANT value
//...
System::IntPtr p( &var );
System::Object ^o = System::Runtime::InteropServices::Marshal::GetObjectForNativeVariant(p );
return o;
In WinRT, there does not seem to be any similar Marshal class that will do the job. According to MSDN "The WinRT Platform::Runtime::InteropServices namespace is intended for internal use only, and is not intended to be used for development."
What are my options? Surely there must be an existing class to do the work of marshalling a VARIANT across ABI boundaries. I don't want to write such a marshaller and then find out that it already exists !
Any help would be much appreciated.
Thanks for your reply. I ended up writing a utility class using Windows::Foundation::IPropertyValue.
I posted the code here together with a link back to this thread:
Marshalling a VARIANT in a WinRT component
Example:
// in a C# we can write:
string [] sarray = new string[2];
sarray[0] = "abc";
sarray[1] = "def";
SetValue(sarray);
//in C++/CX we write:
void SetValue( Object ^value )
{
VARIANT var;
VariantInit( &var );
var = acMarshall::MarshalObjectToVariant( value );
//
// We will have a SAFEARRAY of BSTRs in the VARIANT...
//
VariantClear( &var );
}
// and the reverse, in C++/CX
Object ^ GetValue()
{
VARIANT var;
VariantInit(&var);
v.vt = VT_BSTR | VT_ARRAY;
SAFEARRAYBOUND sab;
sab.cElements = 2;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( VT_BSTR, 1, &sab );
LPVOID p = NULL;
SafeArrayAccessData( psa, &p );
((BSTR *) p)[0] = SysAllocString(L"string one");
((BSTR *) p)[1] = SysAllocString(L"string two");
SafeArrayUnaccessData( psa );
var.parray = psa;
Object ^ obj = acMarshall::MarshalVariantToObject( var );
VariantClear( &var );
return obj;
}
//and in C#:
object obj = GetValue() //obj will contain a string array...
Regards,
Roger
There is no "VARIANT" equivalent in the Windows Runtime. At the ABI level, System::Object is represented as an object implementing IInspectable, that may be a mechanism that you can use to replace your variant.
It is possible to use IReference to create an IInspectable based interface which represents your higher level objects but it won't have the weakly typed semantics that VARIANT does.