I am using ash and gpu_allocator to try to port some C++ code to rust.
I am running into a validation error that the C++ code never runs into:
"Validation Error: [ VUID-VkMemoryAllocateInfo-flags-03331 ] Object 0: handle = 0x56443b02d140, name = Logical device from NVIDIA GeForce GTX 1070, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xf972dfbf | If VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT is set, bufferDeviceAddress must be enabled. The Vulkan spec states: If VkMemoryAllocateFlagsInfo::flags includes VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, the bufferDeviceAddress feature must be enabled (https://vulkan.lunarg.com/doc/view/1.3.211.0/linux/1.3-extensions/vkspec.html#VUID-VkMemoryAllocateInfo-flags-03331)"', src/vulkan/hardware_interface.rs:709:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
It seems, from the message I need to enable an extension.
Confusion n1, it seems this should always be enabbled, according to the docs:
https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_buffer_device_address.html
Because it was moved to be a core extension? Bbut maybe I miss understand what core means, so I tried enabling it manually.
I Have a list of extension names that I pass to the device upon creation:
const DEVICE_EXTENSIONS : &'static [&str] =
&[
"VK_KHR_swapchain",
"VK_KHR_dynamic_rendering",
"VK_EXT_buffer_device_address",
"VK_EXT_extended_dynamic_state",
"VK_EXT_conservative_rasterization",
];
let extensions : Vec<CString> = DEVICE_EXTENSIONS.iter().map(
|extension_name| CString::new(extension_name.to_string()).unwrap()
).collect();
let raw_extensions : Vec<*const i8> = extensions.iter().map(
|extension| extension.as_ptr()
).collect();
let mut dynamic_rendering =
vk::PhysicalDeviceDynamicRenderingFeaturesKHR {
dynamic_rendering : true as u32,
..Default::default()
};
type PDDRF = vk::PhysicalDeviceDynamicRenderingFeaturesKHR;
let indexing_features =
vk::PhysicalDeviceDescriptorIndexingFeatures
{
p_next : (&mut dynamic_rendering) as *mut PDDRF as *mut c_void,
shader_sampled_image_array_non_uniform_indexing : true as u32,
..Default::default()
};
// The enabledLayerCount and ppEnabledLayerNames parameters are deprecated,
// they should always be 0 and nullptr.
// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkDeviceCreateInfo.html
let create_info =
vk::DeviceCreateInfo {
p_next : &indexing_features as *const _ as *const c_void,
queue_create_info_count : 1,
p_queue_create_infos : &queue_create_info,
enabled_extension_count : requested_device_extensions.len() as u32,
pp_enabled_extension_names : raw_extensions.as_ptr(),
p_enabled_features : &device_features,
..Default::default()
};
A little convoluted, I know, but so far the swapchain extension seems to load just fine, so I don't understand why the device address extension is never enabled.
Someone mentioned I should enable the feature alongside the extension:
let buffer_address =
vk::PhysicalDeviceBufferAddressFeaturesEXT
{
buffer_device_address : vk::TRUE,
..Default::default()
};
let dynamic_rendering =
vk::PhysicalDeviceDynamicRenderingFeaturesKHR {
p_next : (&buffer_address) as *const _ as *mut c_void,
dynamic_rendering : true as u32,
..Default::default()
};
type PDDRF = vk::PhysicalDeviceDynamicRenderingFeaturesKHR;
let indexing_features =
vk::PhysicalDeviceDescriptorIndexingFeatures
{
p_next : (&dynamic_rendering) as *const PDDRF as *mut c_void,
shader_sampled_image_array_non_uniform_indexing : true as u32,
..Default::default()
};
// The enabledLayerCount and ppEnabledLayerNames parameters are deprecated,
// they should always be 0 and nullptr.
// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkDeviceCreateInfo.html
let create_info =
vk::DeviceCreateInfo
{
p_next : &indexing_features as *const _ as *const c_void,
queue_create_info_count : 1,
p_queue_create_infos : &queue_create_info,
enabled_extension_count : requested_device_extensions.len() as u32,
pp_enabled_extension_names : raw_extensions.as_ptr(),
p_enabled_features : &device_features,
..Default::default()
};
But I still get the same error even with this.
You already mentioned on the Khronos Vulkan Discord that you got it working with the piece of code I posted using ash's builder pattern and push_next features, but I think I see why your original code triggers the validation layer.
Enabling the feature
You're enabling VK_EXT_buffer_device_address and using its structure VkPhysicalDeviceBufferDeviceAddressFeaturesEXT,
but VK_EXT_buffer_device_address was deprecated by VK_KHR_buffer_device_address; it was promoted to a KHR extension.
Worth nothing here is, that VkPhysicalDeviceBufferDeviceAddressFeaturesKHR is not an alias for VkPhysicalDeviceBufferDeviceAddressFeaturesEXT, it's a different structure (... with identical layout).
They therefore have different sType values:
// Provided by VK_EXT_buffer_device_address
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000,
// Provided by VK_VERSION_1_2
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000,
// Provided by VK_KHR_buffer_device_address
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES,
Now let's check the relevant piece of code for the validation layer, where it checks for the VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT flag for vkAllocateMemory:
VkBool32 buffer_device_address = false;
// --snip--
const auto *bda_features = LvlFindInChain<VkPhysicalDeviceBufferDeviceAddressFeatures>(device_createinfo_pnext);
if (bda_features) {
capture_replay = bda_features->bufferDeviceAddressCaptureReplay;
buffer_device_address = bda_features->bufferDeviceAddress;
}
It tries to find a VkPhysicalDeviceBufferDeviceAddressFeatures in the pNext chain, which is an alias for VkPhysicalDeviceBufferDeviceAddressFeaturesKHR, not the EXT one, as can be seen from the source code for LvlFindInChain:
// Find an entry of the given type in the const pNext chain
template <typename T> const T *LvlFindInChain(const void *next) {
// --snip--
if (LvlTypeMap<T>::kSType == current->sType) {
// Map type VkPhysicalDeviceBufferDeviceAddressFeatures to id VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES
template <> struct LvlTypeMap<VkPhysicalDeviceBufferDeviceAddressFeatures> {
static const VkStructureType kSType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
};
That is, the validation layer looks for a structure with
sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES == 1000257000,
not one with VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT == 1000244000,
therefore it concludes that bufferDeviceAddress feature is not enabled.
You needed to use the promoted KHR one to satisfy the validation layer, even though your Vulkan driver probably supported the deprecated EXT one as well.
gpu-allocator
As for why using the gpu-allocator crate seemingly necessitated enabling buffer device address,
I'd suggest checking if you accidentally set gpu_allocator::vulkan::AllocatorCreatorDesc::buffer_device_address to true.
This is what prompts the library to use VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT when calling vkAllocateMemory:
let allocation_flags = vk::MemoryAllocateFlags::DEVICE_ADDRESS;
let mut flags_info = vk::MemoryAllocateFlagsInfo::builder().flags(allocation_flags);
// TODO(manon): Test this based on if the device has this feature enabled or not
let alloc_info = if buffer_device_address {
alloc_info.push_next(&mut flags_info)
Related
Here is the repo im using as a reference for adding a image:
https://github.com/emilk/egui/blob/master/examples/retained_image/src/main.rs
Im getting this error when trying to draw a image to the screen on this line of code:
date_backdrop.show(ui);
"mismatched types
expected mutable reference &mut egui::ui::Ui
found mutable reference &mut Ui
perhaps two different versions of crate egui are being used?"
dont understand how to fix this issue. still new to rust
here is my code:
use eframe::egui;
use egui_extras::RetainedImage;
struct InitView;
impl eframe::epi::App for InitView {
fn name(&self) -> &str {
"CheckIt"
}
fn update(&mut self,ctx: &eframe::egui::CtxRef,frame: &mut eframe::epi::Frame<'_>) {
let date_backdrop = RetainedImage::from_image_bytes(
"date_backdrop.png",
include_bytes!("date_backdrop.png"),
)
.unwrap();
//background color
let frame = egui::containers::Frame {
fill: egui::Color32::from_rgb(241, 233, 218),
..Default::default()
};
//main window
egui::CentralPanel::default().frame(frame).show(ctx, |ui| {
ui.heading("This is an image:");
date_backdrop.show(ui);
});
}
}
fn main(){
let app: InitView = InitView;
let win_options = eframe::NativeOptions{
initial_window_size: Some(egui::Vec2::new(386.0, 636.0)),
always_on_top: true,
resizable: false,
..Default::default()
};
eframe::run_native(Box::new(app), win_options);
}
Here is my Cargo.toml:
[package]
name = "checkit"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
eframe = "0.14.0"
image = { version = "0.24", default-features = false, features = ["png"] }
egui_extras = { version = "0.20.0", features = ["image"] }
As the error tells, you have two incompatible version of egui in the dependency tree: eframe 0.14 pulls in egui 0.14, while egui_extras 0.20 pulls in egui 0.20. When major version is 0, different minor versions are treated as incompatible, therefore the types from them are not interchangable.
As far as I can see, both eframe and egui_extras depend on the same minor version of egui as their own version, so you have to synchronize these two dependencies to use the same minor version. The easiest way is probably to bump eframe to 0.20.
I'm kinda stuck. I have a program abstraction to locate uniforms for me. I have a fragment shader with a float uniform elapsed, and a vertex shader with a mat4 uniform projection.
The helper function is defined as followed:
pub fn find_uniform(&mut self, name: &str) -> Result<(), UniformError> {
if let Some(_) = self.uniforms.get(name) {
return Ok(());
}
let target_location = unsafe {
let location = gl::GetUniformLocation(self.program_id, name.as_bytes().as_ptr() as *const i8);
let error = gl::GetError();
if error != gl::NO_ERROR {
return Err(UniformError::new(true, error));
}
location
};
if target_location < 0 {
return Err(UniformError::new(false, UNIFORM_NOT_FOUND));
}
self.uniforms.insert(name.to_string(), target_location);
return Ok(());
}
If I use the helper function to look for only elapsed or if i look for both with native gl calls it works:
// No error
if let Err(e) = program.find_uniform("elapsed") {
eprint!("Failed to find elapsed, probably loading wrong shader. err: {}", e);
return;
};
// OR
unsafe {
let location1 = gl::GetUniformLocation(program.program_id, b"elapsed".as_ptr() as *const i8);
println!("{}", location1); // 0
let location2 = gl::GetUniformLocation(program.program_id, b"projection".as_ptr() as *const i8);
println!("{}", location2); // 1
}
But if I use my helper function for both it fails to find whatever i look for first:
if let Err(e) = program.find_uniform("elapsed") {
// Enters error branch here
eprint!("Failed to find elapsed, probably loading wrong shader. err: {}", e);
return;
};
if let Err(e) = program.find_uniform("projection") {
eprint!("Failed to find projection, probably loading wrong shader. err: {}", e);
return;
};
Does anyone have an idea of what I'm doing wrong?
Looking at your code, the conversion to name.as_bytes().as_ptr() as *const i8 is unsafe and depends on memory layout. Rust strings are not C-strings and are not null terminated by default. Use std::ffi::CString::new(); to ensure the string null-terminated. So your current program depends purely if you get lucky in having a null byte after your byte strings.
The following code should work:
let target_location = unsafe {
use std::ffi::CString;
let c_name = CString::new(name).expect("Convert to c-string");
let location = gl::GetUniformLocation(self.program_id, c_name.as_ptr());
let error = gl::GetError();
if error != gl::NO_ERROR {
return Err(UniformError::new(true, error));
}
location
};
See also:
How to pass data to openGL functions correctly in Rust
Im trying to implement the pallet_evm to my substrate runtime
i've seen this handy instruction but the types have changed
How to implement the EVM Trait for a Substrate Runtime?
impl FeeCalculator for FixedGasPrice {
fn min_gas_price() -> U256 {
// Gas price is always one token per gas.
1.into()
}
}
parameter_types! {
pub const ChainId: u64 = 43;
}
impl pallet_evm::Trait for Runtime {
type FeeCalculator = FixedGasPrice;
type CallOrigin = EnsureAddressOrigin<AccountId, Success = AccountId>;
type WithdrawOrigin = EnsureAddressOrigin<AccountId, Success = AccountId>;
type AddressMapping = AddressMapping<AccountId>;
type Currency = balances::Module<Runtime>;
type Event = Event;
type ChainId = ChainId;
}
how do we implement this pallet now with rc-5?
I want to make an HTTP request using the hyper crate. If the user has provided the proxy settings, the request must go through the proxy, otherwise the request will be sent without the proxy.
Here is my approach: -
use hyper::Client;
use hyper::client::HttpConnector;
use hyper_proxy::Intercept;
use hyper_proxy::Proxy;
use hyper_proxy::ProxyConnector;
fn main(){
let proxy_url_opt:Option<String> = Some(String::from("http://ip-address:port"))
let client = match proxy_url_opt { // Line 68
Some(proxy_url)=>{
let uri_str = &proxy_url;
let proxy_uri = uri_str.parse().unwrap();
let mut proxy = Proxy::new(Intercept::All, proxy_uri);
let connector = HttpConnector::new();
let proxy_connector = ProxyConnector::from_proxy(connector, proxy).unwrap();
let client = Client::builder().build(proxy_connector);
client // Line 80
}
None=>{
Client::new() // Line 83
}
};
// while condition {
let response = client.request(request).await?;
// }
}
But this code giving me and error.
match arms have incompatible types
expected struct `hyper_proxy::ProxyConnector`, found struct `hyper::client::connect::http::HttpConnector`
note: expected type `hyper::client::Client<hyper_proxy::ProxyConnector<hyper::client::connect::http::HttpConnector>, _>`
found struct `hyper::client::Client<hyper::client::connect::http::HttpConnector, hyper::body::body::Body>`rustc(E0308)
main.rs(68, 18): `match` arms have incompatible types
main.rs(80, 13): this is found to be of type `hyper::client::Client<hyper_proxy::ProxyConnector<hyper::client::connect::http::HttpConnector>, _>`
main.rs(83, 13): expected struct `hyper_proxy::ProxyConnector`, found struct `hyper::client::connect::http::HttpConnector`
What is the rust way to solve this?
With the support of yorodm I have solved it using an enum. This is how I solved it:-
enum Client {
Proxy(HyperClient<ProxyConnector<HttpConnector>>),
Http(HyperClient<HttpConnector>)
}
impl Client {
pub fn request(&self, mut req: Request<Body>) -> ResponseFuture{
match self {
Client::Proxy(client)=>{
client.request(req)
}
Client::Http(client)=>{
client.request(req)
}
}
}
}
I'm trying to read the Windows event log using EvtQuery and the winapi crate.
I'm getting system error 87 - ERROR_INVALID_PARAMETER
fn to_vec(str: &str) -> Vec<u16> {
return std::ffi::OsStr::new(str)
.encode_wide()
.chain(Some(0).into_iter())
.collect();
}
fn read_log() {
let v = to_vec("System");
let provider = v.as_ptr();
let vv = to_vec("*");
let my_query = vv.as_ptr();
unsafe {
let query_read = winapi::um::winevt::EvtQuery(std::ptr::null_mut(), provider, my_query, 0);
let status = winapi::um::errhandlingapi::GetLastError();
println!("{}", status);
}
}
What am I doing wrong?
The flags parameter of EvtQuery must be one or more values from the EVT_QUERY_FLAGS enumeration.
You are using the literal 0, which is no existing flag:
typedef enum _EVT_QUERY_FLAGS {
EvtQueryChannelPath = 0x1,
EvtQueryFilePath = 0x2,
EvtQueryForwardDirection = 0x100,
EvtQueryReverseDirection = 0x200,
EvtQueryTolerateQueryErrors = 0x1000
} EVT_QUERY_FLAGS;
In your case, you can use EvtQueryChannelPath with the numerical value of 1. This is exposed as EvtQueryChannelPath in winapi.