I am trying to understand how Metal compute shaders work, so I have wrote this code :
class AppDelegate: NSObject, NSApplicationDelegate {
var number:Float!
var buffer:MTLBuffer!
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
let metalDevice = MTLCreateSystemDefaultDevice()!
let library = metalDevice.newDefaultLibrary()!
let commandQueue = metalDevice.newCommandQueue()
let commandBuffer = commandQueue.commandBuffer()
let commandEncoder = commandBuffer.computeCommandEncoder()
let pointlessFunction = library.newFunctionWithName("pointless")!
let pipelineState = try! metalDevice.newComputePipelineStateWithFunction(pointlessFunction)
commandEncoder.setComputePipelineState(pipelineState)
number = 12
buffer = metalDevice.newBufferWithBytes(&number, length: sizeof(Float), options: MTLResourceOptions.StorageModeShared)
commandEncoder.setBuffer(buffer, offset: 0, atIndex: 0)
commandEncoder.endEncoding()
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
let data = NSData(bytesNoCopy: buffer.contents(), length: sizeof(Float), freeWhenDone: false)
var newResult:Float = 0
data.getBytes(&newResult, length: sizeof(Float))
print(newResult)
}
By making a buffer with StorageModeShared, I want changes made to the Metal buffer reflected in my Swift code, but when I populate my newResult variable, it looks like the buffer is still the same value than at the beginning (12) while it should be 125 :
#include <metal_stdlib>
using namespace metal;
kernel void pointless (device float* outData [[ buffer(0) ]]) {
*outData = 125.0;
}
What am I doing wrong ?
A kernel function doesn't run unless you dispatch it. I think you're assuming if you have a function, then Metal should run it one time, until you say otherwise, but that won't happen. It will instead not run at all. Add this before endEncoding and you're good to go!
let size = MTLSize(width: 1, height: 1, depth: 1)
commandEncoder.dispatchThreadgroups(size, threadsPerThreadgroup: size)
Related
I'm trying to fetch information regarding the network interfaces available on the system via GetInterfaceInfo using Microsoft's windows crate. This requires me to do some unsafe operations, and I get it to work for one interface, but not two:
#[cfg(test)]
mod tests {
use super::*;
use windows::{
core::*, Data::Xml::Dom::*, Win32::Foundation::*, Win32::NetworkManagement::IpHelper::*,
Win32::System::Threading::*, Win32::UI::WindowsAndMessaging::*,
};
#[test]
fn main() {
unsafe {
let mut dw_out_buf_len: u32 = 0;
let mut dw_ret_val =
GetInterfaceInfo(std::ptr::null_mut(), &mut dw_out_buf_len as *mut u32);
if dw_ret_val != ERROR_INSUFFICIENT_BUFFER.0 {
panic!();
}
println!("Size: {}", dw_out_buf_len);
// allocate that amount of memory, which will be used as a buffer
let mut ip_interface_info = Vec::with_capacity(dw_out_buf_len as usize);
let mut ptr = ip_interface_info.as_mut_ptr() as *mut IP_INTERFACE_INFO;
dw_ret_val = GetInterfaceInfo(ptr, &mut dw_out_buf_len as *mut u32);
println!("Num adapters: {}", (*ptr).NumAdapters);
for i in 0..(*ptr).NumAdapters as usize {
println!(
"\tAdapter index: {}\n\tAdapter name: {}",
(*ptr).Adapter[i].Index,
String::from_utf16(&(*ptr).Adapter[i].Name).unwrap()
);
}
}
}
}
It crashes when I'm trying to access the second entry (even though there should be two available):
panicked at 'index out of bounds: the len is 1 but the index is 1'
The struct IP_INTERFACE_INFO containing all data has a field called Adapter which seems to be limited to only be array size of 1. Am I reading this correctly? How is it then supposed to hold multiple adapters?
#[repr(C)]
#[doc = "*Required features: `\"Win32_NetworkManagement_IpHelper\"`*"]
pub struct IP_INTERFACE_INFO {
pub NumAdapters: i32,
pub Adapter: [IP_ADAPTER_INDEX_MAP; 1],
}
It appears that IP_INTERFACE_INFO uses a C flexible array member, which often uses the [1] syntax. The C++ example in Managing Interfaces Using GetInterfaceInfo corroborates this usage:
for (i = 0; i < (unsigned int) pInterfaceInfo->NumAdapters; i++) {
printf(" Adapter Index[%d]: %ld\n", i,
pInterfaceInfo->Adapter[i].Index);
printf(" Adapter Name[%d]: %ws\n\n", i,
pInterfaceInfo->Adapter[i].Name);
}
The equivalent in Rust would be to take the single-element array, get the raw pointer to it, then iterate over that. There are lots of details to be aware of, such as allocation alignment and pointer provenance. Here's an annotated example:
use std::{
alloc::{GlobalAlloc, Layout, System},
mem,
ptr::{self, addr_of},
slice,
};
use windows::{
Win32::Foundation::*,
Win32::NetworkManagement::IpHelper::{
GetInterfaceInfo, IP_ADAPTER_INDEX_MAP, IP_INTERFACE_INFO,
},
};
fn main() {
unsafe {
// Perform the first call to know how many bytes to allocate
let mut raw_buf_len = 0;
let ret_val = GetInterfaceInfo(ptr::null_mut(), &mut raw_buf_len);
assert_eq!(
ret_val, ERROR_INSUFFICIENT_BUFFER.0,
"Expected to get the required buffer size, was {ret_val:?}",
);
// Allocate an appropriately sized *and aligned* buffer to store the result
let buf_len = raw_buf_len.try_into().expect("Invalid buffer length");
let layout = Layout::from_size_align(buf_len, mem::align_of::<IP_INTERFACE_INFO>())
.expect("Could not calculate the appropriate memory layout");
let base_ptr = System.alloc(layout);
let ip_interface_info = base_ptr.cast();
// Perform the second call to get the data
let ret_val = GetInterfaceInfo(ip_interface_info, &mut raw_buf_len);
assert_eq!(
ret_val, NO_ERROR.0,
"Could not get the data on the second call: {ret_val:?}",
);
// Construct a pointer to the adapter array that preserves the provenance of the original pointer
let adapter_ptr = addr_of!((*ip_interface_info).Adapter);
let adapter_ptr = adapter_ptr.cast::<IP_ADAPTER_INDEX_MAP>();
// Combine the pointer and length into a Rust slice
let n_adapters = (*ip_interface_info).NumAdapters;
let n_adapters = n_adapters.try_into().expect("Invalid adapter count");
let adapters = slice::from_raw_parts(adapter_ptr, n_adapters);
println!("Num adapters: {}", adapters.len());
for adapter in adapters {
let IP_ADAPTER_INDEX_MAP {
Index: index,
Name: name,
} = adapter;
// The fixed-size buffer contains data after the UTF-16 NUL character
let name_end = name.iter().position(|&c| c == 0).unwrap_or(name.len());
let name = String::from_utf16_lossy(&name[..name_end]);
println!("Adapter index: {index}\nAdapter name: {name}",);
}
// Free the allocation. This should be wrapped in a type that
// implements `Drop` so we don't leak memory when unwinding a panic.
System.dealloc(base_ptr, layout);
}
}
I am using Godot v3.42-v3.45 to make an implemetation of the boardgame Citadel. In order to make a card move, I develop a tween system. But sometimes the original card node will be "queue_free()"ed immediately after the tween starts, and the card will be gone from the screen and I don't want to wait till it's finished. So I try to make a copy node for just animation, hide the original one, set the final values on the original node, run the tween, show the original node and hide the copied node. But it gets flicky, the copied node seems to blink when the tween is finished. I try a lot of measures but it still blinks. Could anybody help me? Please run the ani_flip_move() function.
extends Node2D
onready var TimerGlobal = get_node("/root/Main/Timer") # a global timer stick to the main scene
onready var Data = get_node("/root/Main/Data") # Data.XXX is just some constants, Data.FAR_AWAY = Vector2(99999, 99999)
onready var Signal = get_node("/root/Main/Signal") # a signal bus stick to the main scene
class Trans:
var motion_list: Array
var copies: Dictionary
func _init() -> void:
motion_list = []
copies = {}
func add(node: Node2D, prop_name: String, start_val, end_val, ani_time: float = 1) -> void:
var copy
if node in copies:
copy = copies[node]
else:
copy = node.duplicate(node.DUPLICATE_USE_INSTANCING)
copies[node] = copy
node.set(prop_name, end_val)
motion_list.append([node, copy, prop_name, start_val, end_val, ani_time])
class Interval:
var wait_time: float
func _init(times: float) -> void:
wait_time = times
func animate(action_list: Array) -> void:
var _useless
var tween = Tween.new()
add_child(tween)
for action in action_list:
if action is Trans:
for motion in action.motion_list:
var orgi_node = motion[0]
var copy_node = motion[1]
var prop_name = motion[2]
var start_val = motion[3]
var end_val = motion[4]
var ani_time = motion[5]
orgi_node.set(prop_name, end_val)
orgi_node.set_visible(false)
if not copy_node.is_inside_tree():
add_child(copy_node)
_useless = tween.interpolate_property(
copy_node,
prop_name,
start_val,
end_val,
ani_time,
Tween.TRANS_CUBIC,
Tween.EASE_IN_OUT
)
_useless = tween.start()
yield(tween, "tween_all_completed")
for motion in action.motion_list:
var orgi_node = motion[0]
var copy_node = motion[1]
if is_instance_valid(orgi_node):
orgi_node.set_visible(true)
orgi_node.set_z_index(0)
if is_instance_valid(copy_node):
copy_node.set_z_index(0)
copy_node.queue_free()
elif action is Interval:
TimerGlobal.set_wait_time(action.wait_time)
TimerGlobal.start()
yield(TimerGlobal, "timeout")
remove_child(tween)
tween.queue_free()
Signal.emit_signal("all_ani_completed")
func ani_flip_move(
obj: Node2D,
end_pos: Vector2 = Data.FAR_AWAY,
end_scale: Vector2 = Data.FAR_AWAY,
end_visible: bool = true,
end_face_up: bool = true,
ani_time: int = 1
) -> void:
if end_scale == Data.FAR_AWAY:
end_scale = obj.scale
if end_pos == Data.FAR_AWAY:
end_pos = obj.global_position
var a1 = Trans.new()
var z_index = obj.z_index
a1.add(obj, "global_position", obj.global_position, end_pos, ani_time)
a1.add(obj, "scale", obj.scale, end_scale, ani_time)
a1.add(obj, "z_index", 1, 1, ani_time)
if "face_up" in obj:
a1.add(obj, "face_up", obj.face_up, end_face_up, ani_time)
animate([a1])
On my adventure to learn Rust I decided to try and print to the cli contents of the clipboard. I've done this before in Swift so thought I would have much issues in Rust.
However I'm having a hard time printing the contents of the returned NSArray. I've spent a few hours playing around with different functions but haven't made much progress.
The Swift code I have that works:
import Foundation
import AppKit
let pasteboard = NSPasteboard.general
func reload() -> [String]{
var clipboardItems: [String] = []
for element in pasteboard.pasteboardItems! {
if let str = element.string(forType: NSPasteboard.PasteboardType(rawValue: "public.utf8-plain-text")) {
clipboardItems.append(str)
}
}
return clipboardItems;
}
// Access the item in the clipboard
while true {
let firstClipboardItem = reload()
print(firstClipboardItem);
sleep(1);
}
Here is the Rust code:
use cocoa::appkit::{NSApp, NSPasteboard, NSPasteboardReading, NSPasteboardTypeString};
use cocoa::foundation::NSArray;
fn main() {
unsafe {
let app = NSApp();
let pid = NSPasteboard::generalPasteboard(app);
let changec = pid.changeCount();
let pid_item = pid.pasteboardItems();
if pid_item.count() != 0 {
let items = &*pid_item.objectAtIndex(0);
println!("{:?}", items);
}
println!("{:?}", *pid.stringForType(NSPasteboardTypeString));
}
}
The code above produces: *<NSPasteboardItem: 0x6000021a3de0>*
EDIT:
I've made a little progress but stuck on one last bit. I've managed to get the first UTF8 char out of the clipboard.
The issue I have is if I copy the text: World the system will loop the correct amount of times for the word length but will only print the first letter, in this case W. Output below:
TEXT 'W'
TEXT 'W'
TEXT 'W'
TEXT 'W'
TEXT 'W'
The bit I'm trying to get my head around is how to move to the next i8. I can't seem to find a way to point to the next i8.
The NSString function UTF8String() returns *const i8. I'm scratching my head with how one would walk the text.
use cocoa::appkit::{NSApp, NSPasteboard, NSPasteboardTypeString};
use cocoa::foundation::{NSArray, NSString};
fn main() {
unsafe {
let app = NSApp();
let pid = NSPasteboard::generalPasteboard(app);
let changec = pid.changeCount();
let nsarray_ptr = pid.pasteboardItems();
if nsarray_ptr.count() != 0 {
for i in 0..NSArray::count(nsarray_ptr) {
let raw_item_ptr = NSArray::objectAtIndex(nsarray_ptr, i);
let itm = raw_item_ptr.stringForType(NSPasteboardTypeString);
for u in 0..itm.len() {
let stri = itm.UTF8String();
println!("TEXT {:?}", *stri as u8 as char);
}
}
}
}
}
To everyone who's looked/commented on this so far thank you.
After reading some tests provided by cocoa I figured out what I needed to do.
The code below prints the contents of the clipboard. Thanks to those who pointed me in the right direction.
use cocoa::appkit::{NSApp, NSPasteboard, NSPasteboardTypeString};
use cocoa::foundation::{NSArray, NSString};
use std::{str, slice};
fn main() {
unsafe {
let app = NSApp();
let pid = NSPasteboard::generalPasteboard(app);
let nsarray_ptr = pid.pasteboardItems();
if nsarray_ptr.count() != 0 {
for i in 0..NSArray::count(nsarray_ptr) {
let raw_item_ptr = NSArray::objectAtIndex(nsarray_ptr, i);
let itm = raw_item_ptr.stringForType(NSPasteboardTypeString);
let stri = itm.UTF8String() as *const u8;
let clipboard = str::from_utf8(slice::from_raw_parts(stri, itm.len()))
.unwrap();
println!("{}", clipboard);
}
}
}
}
I would like to get my username in an std::String using the windows-rs crate.
use bindings::Windows::Win32::{
System::WindowsProgramming::GetUserNameW,
Foundation::PWSTR,
};
fn main() {
let mut pcbbuffer: u32 = 255;
let mut helper: u16 = 0;
let lpbuffer = PWSTR(&mut helper);
println!("lpbuffer: {:?}\npcbbuffer: {:?}", lpbuffer, pcbbuffer);
unsafe {
let success = GetUserNameW(lpbuffer, &mut pcbbuffer);
println!("GetUserNameW succeeded: {:?}\nlpbuffer: {:?}\npcbbuffer: {:?}", success.as_bool(), lpbuffer, pcbbuffer);
}
}
produces the output:
lpbuffer: PWSTR(0xca20f5f76e)
pcbbuffer: 255
GetUserNameW succeeded: true
lpbuffer: PWSTR(0x7200650073)
pcbbuffer: 5
The username is "user" that's 4 + 1 terminating character = 5 which is good. I also see the GetUserNameW function succeeded and the pointer to the string changed.
What are the next steps?
The code as posted works by coincidence alone. It sports a spectacular buffer overflow, hardly what you'd want to see in Rust code. Specifically, you're taking the address of a single u16 value, and pass it into an API, telling it that the pointed-to memory were 255 elements in size.
That needs to be solved: You will have to allocate a buffer large enough to hold the API's output first.
Converting a UTF-16 encoded string to a Rust String with its native encoding can be done using several different ways, such as String::from_utf16_lossy().
The following code roughly sketches out the approach:
fn main() {
let mut cb_buffer = 257_u32;
// Create a buffer of the required size
let mut buffer = Vec::<u16>::with_capacity(cb_buffer as usize);
// Construct a `PWSTR` by taking the address to the first element in the buffer
let lp_buffer = PWSTR(buffer.as_mut_ptr());
let result = unsafe { GetUserNameW(lp_buffer, &mut cb_buffer) };
// If the API returned success, and more than 0 characters were written
if result.as_bool() && cb_buffer > 0 {
// Construct a slice over the valid data
let buffer = unsafe { slice::from_raw_parts(lp_buffer.0, cb_buffer as usize - 1) };
// And convert from UTF-16 to Rust's native encoding
let user_name = String::from_utf16_lossy(buffer);
println!("User name: {}", user_name);
}
}
I'm using Xcode 7 with swift and when I type
class Block {
var Block = SKShapeNode(circleOfRadius: 15)
Block.fillColor = SKColor.redColor() //Error Here
Block.physicsBody = SKPhysicsBody(circleOfRadius: 15)
Block.physicsBody?.affectedByGravity = true
Block.physicsBody?.restitution = 0
Block.physicsbody?.LinearDamping = 0
self.addChild(Block)
It gives me an error that says "expected declaration" (on the line with the comment) and I don't know why
There are some errors:
You have a class and are trying to change class properties outside the scope of a method or an initializer.
The line Block.physicsbody?.LinearDamping = 0 should be Block.physicsBody?.linearDamping = 0; case-sensitivity.
You name your SKShapeNode instance as Block, the same name as your class. By naming convention, class (type) names begin with Capital letters, whereas class properties use small letters in their names.
With these three fixed, we can proceed to looking at your scene.
With help from Leo Dabus (thanks!), we should have enough to set you up with a minimal working example (using your code) of the SKScene:
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
let block = SKShapeNode(circleOfRadius: 15)
// you will also need to set your node initial position
// if you would like your red circle to fall from the middle of the top of your scene you need to use the scene frame midX and maxY (not the view frame). the scene it is not necessarily the same size of your view)
block.position = CGPoint(x: scene!.frame.midX, y: scene!.frame.maxY)
block.fillColor = SKColor.redColor()
block.physicsBody = SKPhysicsBody(circleOfRadius: 15)
block.physicsBody?.affectedByGravity = true
block.physicsBody?.restitution = 0
block.physicsBody?.linearDamping = 0
self.addChild(block)
}
// ...
}