> On Jul 9, 2017, at 4:49 PM, Jens Persson via swift-evolution > <[email protected]> wrote: > > Sorry for making so much off topic noise in this thread, but I made a mistake > regarding the Metal tutorial: > Looking more carefully I see now that they rebuild a vertedData: [Float] from > their vertices: [Vertex] using the floatBuffer() method of the Vertex struct, > which returns an Array with the stored properties of Vertex in correct order. > > While searching the internet about this I saw Joe Groff mentioning on Twitter > that: > "We plan to sort fields in padding order to minimize size, and may also > automatically pack bools and enums in bitfields." > > So AFAICS my current image processing code is making the possibly invalid > assumption that eg > struct S { > var a, b, c, d: Float > } > will have a memory layout of 4*4=16 bytes (stride and size == 16) and an > alignment of 4, and most importantly that a, b, c, d will be in that order.
This is currently true, but may not always be. We want to reserve the right to re-order the fields even if it doesn't improve packing — for example, if two fields are frequently accessed together, field reordering could yield substantial locality benefits. We've also discussed reordering fields to put them in a canonical order for resilience, since it's a little counter-intuitive that reordering the fields of a struct should be ABI-breaking. (There are arguments against doing that as well, of course — for example, the programmer may have chosen the current order for their own locality optimizations.) > It looks like I should be defining my structs (the ones for which memory > layout is important) in C and import them. This should always work, yes. > Although I would be surprised if a Swift-struct containing only same-sized > fields (all of the same primitive type) would be reordered, and such changes > to the language would probably include some per-struct way to express some > sort of layout control (since being able to define structs to be used for low > level data manipulation is important in a systems language). Exactly. In the long term, Swift will have some explicit tools for layout control. John. > > /Jens > > > On Sun, Jul 9, 2017 at 7:01 PM, Jens Persson via swift-evolution > <[email protected] <mailto:[email protected]>> wrote: > I should perhaps add that in my image processing code, I use code like this: > > func withVImageBuffer<Data, R>(for table: Table<Data>, body: (vImage_Buffer) > -> R) -> R > where > Data.Coordinate.Index == VectorIndex2 > { > let vib = vImage_Buffer( > data: table.baseAddress, > height: vImagePixelCount(table.size.e1), > width: vImagePixelCount(table.size.e0), > rowBytes: table.stride.e1 > ) > return withExtendedLifetime(table) { body(vib) } > } > > Here, Table<Data> is the raster image. Data.Coordinate == VectorIndex2 makes > it a 2D table, and a Table's Data also has a type parameter Data.Value which > can be eg one of the "pixel"-struct I showed before. > This works without any problems (I've tested and used the some variant of > this type of code for years) but it would surely break if the memory layout > of simple structs changed. > > I can't see how this usage is much different from the one in the Metal > tutorial. It too uses pointers to point into a data created using the (Swift) > struct "Vertex", and the GPU hardware has its expectations on the memory > layout of that data, so the code would break if the memory layout of the > Vertex struct changed. > > /Jens > > > On Sun, Jul 9, 2017 at 6:35 PM, Jens Persson <[email protected] > <mailto:[email protected]>> wrote: > I don't think I'm misunderstanding you, but I might be, so I'll add more > detail: > > If you look at the Metal article, you'll see that the (Swift) struct "Vertex" > is used to specify the data that is sent to Metal for creating a buffer > (using MTLDevice.makeBuffer). The result that the GPU will produce surely > depends on the fields of the Vertex struct (x, y, z, r, g, b, a) being in the > specified order (ie swapping the red channel with the x coordinate would > produce an unexpected result). > > And regarding the second example, pixel structs used for manipulating raster > image data. Manipulating raster image data presumably includes stuff like > displaying to screen, loading and saving raster images. > I currently use this way of doing this right now without any problems, but if > the order of the fields (eg a, r, g, b) should change in the future, then my > code would break (the colors of the images would at least not come out as > expected). > > /Jens > > > > > > > On Sun, Jul 9, 2017 at 5:53 PM, Chris Lattner <[email protected] > <mailto:[email protected]>> wrote: > >> On Jul 9, 2017, at 12:23 AM, Jens Persson <[email protected] >> <mailto:[email protected]>> wrote: >> >> >> On Sat, Jul 8, 2017 at 6:28 PM, Chris Lattner via swift-evolution >> <[email protected] <mailto:[email protected]>> wrote: >> Hi Susan, >> >> Swift does not currently specify a layout for Swift structs. You shouldn’t >> be using them for memory mapped i/o or writing to a file, because their >> layout can change. When ABI stability for fragile structs lands, you will >> be able to count on it, but until then something like this is probably a bad >> idea. >> >> -Chris >> >> Does this imply that you should never use Swift structs to eg interact with >> Metal? > > No. > >> This seems to be a very common practice. Here is a typical example (from a >> Metal tutorial at raywenderlich.com <http://raywenderlich.com/>): >> >> struct Vertex { >> var x,y,z: Float // position data >> var r,g,b,a: Float // color data >> >> func floatBuffer() -> [Float] { >> return [x,y,z,r,g,b,a] >> } >> } > > This doesn’t appear to expose the layout of the struct. >> Also, does it imply that we cannot use structs (of only primitive types) >> like: >> >> struct RgbaFloatsLinearGamma { >> var r, g, b, a: Float >> … >> } >> struct BgraBytesSrgbGamma { >> var b, g, r, a: UInt8 >> } >> >> for manipulating raster image data? > > I don’t see why that would be a problem. > >> I vaguely remember a swift evo discussion where it was concluded that such >> usage was considered OK provided the stored properties of the structs was >> only primitive types, but I can't find it now. >> >> Perhaps it could be considered OK at least when the intended platforms are >> known to be only iOS devices? > > I think you’re misunderstanding what I’m saying. It isn’t correct to take > (e.g.) an unsafepointer to the beginning of a struct, and serialize that out > to disk, and expect that the fields are emitted in some order with some > specific padding between them. None of the uses above try to do this. > > -Chris > > > > > > _______________________________________________ > swift-evolution mailing list > [email protected] <mailto:[email protected]> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution> > > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
