The only way I have found that accepts the indices buffer is:
let (vbuf, slice) = factory.create_vertex_buffer(&verts, &indices);
This creates a new buffer and I can't do it every frame.
I can update the vertex buffer with encoder.update_buffer(&buf, &data, offset), but I don't know how to update indices buffer.
You can update the index buffer by using the slice that comes from creating the vertex buffer.
The slice has a public field, slice.buffer that represents the index buffer itself, although this is a gfx::IndexBuffer, not a gfx::handle::Buffer, which is required for the call to encoder.update_buffer(...).
In order to get the underlying buffer, match on the IndexBuffer to the type you created, as such:
match &slice.buffer {
// On `Auto`, there is no index buffer
gfx::IndexBuffer::Auto => ...,
// On `Index16`, the indices are `u16`
gfx::IndexBuffer::Index16(buffer) => ...,
// On `Index32`, the indices are `u32`
gfx::IndexBuffer::Index32(buffer) => ...,
}
Only one of these will match at runtime, depending on the index buffer you chose when creating the vertex buffer.
On the Index16 and Index32 cases, buffer will be a gfx::handle::Buffer<R, T>, where T is u16 or u32.
Related
I'm trying out Rust and I really like it so far. I'm working on a tool that needs to get arrow key input from the user. So far, I've got something half-working: if I hold a key for a while, the relevant function gets called. However, it's far from instantaneous.
What I've got so far:
let mut stdout = io::stdout().into_raw_mode();
let mut stdin = termion::async_stdin();
// let mut stdin = io::stdin();
let mut it = stdin.keys(); //iterator object
loop {
//copied straight from GitLab: https://gitlab.redox-os.org/redox-os/termion/-/issues/168
let b = it.next();
match b {
Some(x) => match x {
Ok(k) => {
match k {
Key::Left => move_cursor(&mut cursor_char, -1, &enc_chars, &mpt, &status),
Key::Right => move_cursor(&mut cursor_char, 1, &enc_chars, &mpt, &status),
Key::Ctrl('c') => break,
_ => {}
}
},
_ => {}
},
None => {}
}
//this loop might do nothing if no recognized key was pressed.
}
I don't quite understand it myself. I'm using the terminal raw mode, if that has anything to do with it. I've looked at the rustyline crate, but that's really no good as it's more of an interactive shell-thing, and I just want to detect keypresses.
If you're using raw input mode and reading key by key, you'll need to manually buffer the character keys using the same kind of match loop you already have. The Key::Char(ch) enum variant can be used to match regular characters. You can then use either a mutable String or an array like [u8; MAX_SIZE] to store the character data and append characters as they're typed. If the user moves the cursor, you'd need to keep track of the current position within your input buffer and make sure to insert the newly typed characters into the correct spot, moving the existing characters if needed. It is a lot of work, which is why there are crates that will do it for you, but you will have less chance to control how the input behaves. If you want to use an existing crate, then tui-rs might be a good one to check out for a complete solution, or linefeed for something much simpler.
As for the delay, I think it might be because you're using AsyncReader, which according to the docs is using a secondary thread to do blocking reads
I have an iterable PyObject that I need to pass as the list of arguments to a Python callable, ala
xs = [1,2,5,7]
some_function(*xs)
However, PyObject_CallObject only allows tuples to be passed as the arguments' container.
I'm not sure, though, what is the best way to create a new tuple containing the elements of an iterable. Here's a tentative code:
PyObject* unpack_call(PyObject* callable, PyObject* args) {
PyObject* tuple;
if (PyTuple_Check(args)) {
tuple = args;
} else {
PyObject* iter = PyObject_GetIter(args);
if (!iter) return NULL;
tuple = PyTuple_New(0);
for (Py_ssize_t pos=0; ; ++pos) {
PyObject* arg = PyIter_Next(iter);
if (!arg) break;
PyTuple_SetItem(tuple,pos,arg);
}
}
return PyObject_CallObject(callable,tuple);
}
I'm not sure if I need to grow the size of the tuple myself or not. What's confusing me is the sentence in the documentation saying:
The tuple will always grow or shrink at the end.
I'm also not sure if I need to increment or decrement reference counts for any of these objects.
You're much better using PySequence_Tuple which can create a tuple directly from an iterable. There's probably other similar options to do this too.
If you did want to do it your way then you do need to call PyTuple_Resize each time you add to it (or resize it in chunks possibly). What the sentence
The tuple will always grow or shrink at the end.
tells you is that extra space is at the end of the tuple.
PyTuple_SetItem steals a reference, so you don't need to touch the reference count of the items you're adding. You should be doing some error checking though - PyIter_Next can raise an exception. You also need to decref iter and the tuple when you're done with them.
I come from a C# background where System.String is immutable and string concatenation is relatively expensive (as it requires reallocating the string) we know to use the StringBuilder type instead as it preallocates a larger buffer where single characters (Char, a 16-bit value-type) and short strings can be concatenated cheaply without extra allocation.
I'm porting some C# code to Swift which reads from a bit-array ([Bool]) at sub-octet indexes with character lengths less than 8 bits (it's a very space-conscious file format).
My C# code does something like this:
StringBuilder sb = new StringBuilder( expectedCharacterCount );
int idxInBits = 0;
Boolean[] bits = ...;
for(int i = 0; i < someLength; i++) {
Char c = ReadNextCharacter( ref idxInBits, 6 ); // each character is 6 bits in this example
sb.Append( c );
}
In Swift, I assume NSMutableString is the equivalent of .NET's StringBuilder, and I found this QA about appending individual characters ( How to append a character to string in Swift? ) so in Swift I have this:
var buffer: NSMutableString
for i in 0..<charCount {
let charValue: Character = readNextCharacter( ... )
buffer.AppendWithFormat("%c", charValue)
}
return String(buffer)
But I don't know why it goes through a format-string first, that seems inefficient (reparsing the format-string on every iteration) and as my code is running on iOS devices I want to be very conservative with my program's CPU and memory usage.
As I was writing this, I learned my code should really be using UnicodeScalar instead of Character, problem is NSMutableString does not let you append a UnicodeScalar value, you have to use Swift's own mutable String type, so now my code looks like:
var buffer: String
for i in 0..<charCount {
let x: UnicodeScalar = readNextCharacter( ... )
buffer.append(x)
}
return buffer
I thought that String was immutable, but I noticed its append method returns Void.
I still feel uncomfortable doing this because I don't know how Swift's String type is implemented internally, and I don't see how I can preallocate a large buffer to avoid reallocations (assuming Swift's String uses a growing algorithm).
(This answer was written based on documentation and source code valid for Swift 2 and 3: possibly needs updates and amendments once Swift 4 arrives)
Since Swift is now open-source, we can actually have a look at the source code for Swift:s native String
swift/stdlib/public/core/String.swift
From the source above, we have following comment
/// Growth and Capacity
/// ===================
///
/// When a string's contiguous storage fills up, new storage must be
/// allocated and characters must be moved to the new storage.
/// `String` uses an exponential growth strategy that makes `append` a
/// constant time operation *when amortized over many invocations*.
Given the above, you shouldn't need to worry about the performance of appending characters in Swift (be it via append(_: Character), append(_: UniodeScalar) or appendContentsOf(_: String)), as reallocation of the contiguous storage for a certain String instance should not be very frequent w.r.t. number of single characters needed to be appended for this re-allocation to occur.
Also note that NSMutableString is not "purely native" Swift, but belong to the family of bridged Obj-C classes (accessible via Foundation).
A note to your comment
"I thought that String was immutable, but I noticed its append method returns Void."
String is just a (value) type, that may be used by mutable as well as immutable properties
var foo = "foo" // mutable
let bar = "bar" // immutable
/* (both the above inferred to be of type 'String') */
The mutating void-return instance methods append(_: Character) and append(_: UniodeScalar) are accessible to mutable as well as immutable String instances, but naturally using them with the latter will yield a compile time error
let chars : [Character] = ["b","a","r"]
foo.append(chars[0]) // "foob"
bar.append(chars[0]) // error: cannot use mutating member on immutable value ...
So I've been searching for a solution to this problem for some time. I've written a program to take data from two separate text files, parse it, and output to another text file and an ARFF file for analysis by Weka. The problem I'm running into is that the function I wrote to handle the data read and parsing operations doesn't de-allocate memory properly. Every successive call uses an additional 100MB or so and I need call this function over 60 times over the course of the function. Is there a way to force D to de-allocate memory, with respect to arrays, dynamic arrays, and associative arrays in particular?
An example of my problem:
struct Datum {
string Foo;
int Bar;
}
Datum[] Collate() {
Datum[] data;
int[] userDataSet;
int[string] secondarySet;
string[] raw = splitLines(readText(readFile)).dup;
foreach (r; raw) {
userDataSet ~= parse(r);
secondarySet[r.split(",").dup] = parseSomeOtherWay(r);
}
data = doSomeOtherCalculation(userDataSet, secondarySet);
return data;
}
Are the strings in the returned data still pointing inside the original text file?
Array slicing operations in D do not make a copy of the data - instead, they just store a pointer and length. This also applies to splitLines, split, and possibly to doSomeOtherCalculation. This means that as long as a substring of the original file text exists anywhere in the program, the entire file's contents cannot be freed.
If the data you're returning is only a small fraction of the size of the text file you're reading, you can use .dup to make a copy of the string. This will prevent the small strings from pinning the entire file's contents in memory.
If the content of the Collate() result is duplicated after the call, it's probable that it's not collected by the GC and thus resides in memory while it's not used anymore. If so then you can use a global container that you reset for each Collate():
void Collate(out Datum[] data) {
// data content is cleared because of 'out' param storage class
// your processing to fill data
}
I'm currently trying to implement my own DynamicArray data type in Swift. To do so I'm using pointers a bit. As my root I'm using an UnsafeMutablePointer of a generic type T:
struct DynamicArray<T> {
private var root: UnsafeMutablePointer<T> = nil
private var capacity = 0 {
didSet {
//...
}
}
//...
init(capacity: Int) {
root = UnsafeMutablePointer<T>.alloc(capacity)
self.capacity = capacity
}
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
for index in 0..<count {
(root + index).memory = repeatedValue
}
self.count = count
}
//...
}
Now as you can see I've also implemented a capacity property which tells me how much memory is currently allocated for root. Accordingly one can create an instance of DynamicArray using the init(capacity:) initializer, which allocates the appropriate amount of memory, and sets the capacity property.
But then I also implemented the init(count:repeatedValue:) initializer, which first allocates the needed memory using init(capacity: count). It then sets each segment in that part of memory to the repeatedValue.
When using the init(count:repeatedValue:) initializer with number types like Int, Double, or Float it works perfectly fine. Then using Character, or String though it crashes. It doesn't crash consistently though, but actually works sometimes, as can be seen here, by compiling a few times.
var a = DynamicArray<Character>(count: 5, repeatedValue: "A")
println(a.description) //prints [A, A, A, A, A]
//crashes most of the time
var b = DynamicArray<Int>(count: 5, repeatedValue: 1)
println(a.description) //prints [1, 1, 1, 1, 1]
//works consistently
Why is this happening? Does it have to do with String and Character holding values of different length?
Update #1:
Now #AirspeedVelocity addressed the problem with init(count:repeatedValue:). The DynamicArray contains another initializer though, which at first worked in a similar fashion as init(count:repeatedValue:). I changed it to work, as #AirspeedVelocity described for init(count:repeatedValue:) though:
init<C: CollectionType where C.Generator.Element == T, C.Index.Distance == Int>(collection: C) {
let collectionCount = countElements(collection)
self.init(capacity: collectionCount)
root.initializeFrom(collection)
count = collectionCount
}
I'm using the initializeFrom(source:) method as described here. And since collection conforms to CollectionType it should work fine.
I'm now getting this error though:
<stdin>:144:29: error: missing argument for parameter 'count' in call
root.initializeFrom(collection)
^
Is this just a misleading error message again?
Yes, chances are this doesn’t crash with basic inert types like integers but does with strings or arrays because they are more complex and allocate memory for themselves on creation/destruction.
The reason it’s crashing is that UnsafeMutablePointer memory needs to be initialized before it’s used (and similarly, needs to de-inited with destroy before it is deallocated).
So instead of assigning to the memory property, you should use the initialize method:
for index in 0..<count {
(root + index).initialize(repeatedValue)
}
Since initializing from another collection of values is so common, there’s another version of initialize that takes one. You could use that in conjunction with another helper struct, Repeat, that is a collection of the same value repeated multiple times:
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
root.initializeFrom(Repeat(count: count, repeatedValue: repeatedValue))
self.count = count
}
However, there’s something else you need to be aware of which is that this code is currently inevitably going to leak memory. The reason being, you will need to destroy the contents and dealloc the pointed-to memory at some point before your DynamicArray struct is destroyed, otherwise you’ll leak. Since you can’t have a deinit in a struct, only a class, this won’t be possible to do automatically (this is assuming you aren’t expecting users of your array to do this themselves manually before it goes out of scope).
Additionally, if you want to implement value semantics (as with Array and String) via copy-on-write, you’ll also need a way of detecting if your internal buffer is being referenced multiple times. Take a look at ManagedBufferPointer to see a class that handles this for you.