FAQ
I've been toying around with the idea of writing a 3D game in Go. And I've
been working through the following OpenGL tutorial for C++, porting
everything to to work in a golang.org/x/mobile/app.

http://www.opengl-tutorial.org

It's been great fun. And I have to say that performance is better and more
consistent than I feared it might be. But honestly I do not like the
package golang.org/x/mobile/exp/f32 and I'm about ready to rewrite it
myself. But given the big warning in its doc comments I was wondering what
people internally were doing or had planned in regards to reworking the
package internals?

The f32 package has some erroneous computational bugs which I don't need to
go into (they are open issues on github). What concerns me most about the
f32 package is that some design decisions it contains seem to be
detrimental to performance. Performance is something I think I need to
conserve in a 3D mobile app. Here are a couple (backwards incompatible)
ideas I have to improve the package design and make it work smoothly with
OpenGL (that's the point, right?).

- First, and most incompatible, I think the matrix types should be flat
arrays that use column-major order (because that's how users have to
serialize things into OpenGL). Currently the user transposes matrices
explicitly for serialization. It is a pain and is potentially worsened
without a Transpose function in f32. But, in general it just wastes CPU
cycles. If Mat4 was defined as [16]float32 in column-major then
serialization to []byte would be trivial.

- Second I think the serialization function, Bytes, is pretty bad. I've
noticed it does crafty things for speed, but it always allocates a slice.
To serialize MVP matrices on each frame you could argue the allocation cost
is minimal. But, going through the OpenGL tutorial has shown me, when you
load a model you need to serialize multiple large slices of f32.Vec3 values
(or Vec2, which isn't actually defined by f32). So a typical application
will allocate boatloads of unnecessary byte slices when it initializes by
calling f32.Bytes() for each f32.Vec3 element in the vertex slice. In a
more specialized case, when an application actually requires models to be
dynamically loaded at runtime they will inject tons of garbage pointers
into the runtime for every model reload. I think f32.Bytes should be
replaced with one or two functions more analogous to the builtin functions
copy() and append(), which take a destination as their first argument.
Something like hex.Encode() would be nice and close to backwards
compatible. This would make serialization of matrices in the render loop
essentially free of allocations.

Do these suggestions make sense and sound good? If you all don't think I'm
crazy I can open an issue and start the proposal process.

The way things are it makes no sense to me why all the linear algebra
functions aren't implemented in the package golang.org/x/image/math/f32,
which uses a row-major order (though also chose to use a flat array, FWIW).

Cheers,
- Bryan

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Laurent Moussault at Mar 29, 2016 at 9:31 pm
    I'm in no way qualified to talk about golang.org/x/mobile/exp/f32, but I've
    been toying with OpenGL and Go for some time, and I have a few question:

    - First, and most incompatible, I think the matrix types should be flat
    arrays that use column-major order[...]
    Why a flat array? As far as I know, on every platform [4][4]float32 has
    exactly the same memory layout than [16]float32, but is way more convenient
    to use. I'm not too familiar with mobile architectures, so maybe it's
    something specific to them? (I don't think the language spec gives anymore
    guaranties about padding in one case or the other; in fact, if my
    interpretation is correct, as long as a flat array has the right layout,
    the two dimensional one should have too).

    About the column-major order for storage, in OpenGL you can do both, as
    long as you use the correct multiplication order (i.e. row vectors with
    row-major matrices). It's true that you have to use column-major storage to
    be able to use the "standard" mathematical order in GLSL, so that's
    probably a safer choice for a library. Row-major makes some optimizations
    possible for affine matrices (at least with the alignment requirements of
    some GPUs), but it would make a difference only in a few specific cases
    (e.g. skeletal animation).

    Finally, I'm not sure I understand the point about serialization in the
    render loop. Again, maybe this is specific to mobile platforms, but on
    desktop you just provides a pointer to your data, the driver handles the
    copy to the GPU. Sure, there is no strong guaranties in the language for
    the exact memory layout, but this is also true with C and C++.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Bryan Matsuo at Mar 29, 2016 at 10:46 pm
    Thanks for the feedback.

    I guess I might not have clarified the serialization situation enough.
    AFAIK you are right about memory layout. [4][4]float32 should layout
    identically to [16]float32. And if you do unsafe type conversions you can
    turn either into the appropriate sized []byte for passing to
    glctx.Uniform4fv, glctx.BindBuffer and OpenGL will copy this data into the
    GPU (this is definitely how people in C and C++ do it). If that's really
    what is **supposed** be done in Go, and it's guaranteed to work, then that
    is OK by me and serialization isn't a concern. But if that is the case then
    defining the serialization function, f32.Bytes, in the first place doesn't
    really much sense, does it?

    Related to this point, one thing I haven't had a definitive answer for in
    my own mind is whether [16]float32 is guaranteed to contain the same bytes
    as [16]C.float. Naively I would say, "yes they are the same," but from what
    I've read elsewhere I'm actually not sure that is guaranteed.

    In regards to multiplication order, yes, because Transpose(A * B) ==
    Transpose(B) * Transpose(A) you can do work on column-major matrices using
    row-major algorithms. But actually recommending that people transpose all
    their matrices and reverse their matrix multiplication sounds quite
    sadistic to me, truly. I really do think column-major should be used, even
    if [4][4]float32 is truly the desired type signature. It sounds like we
    mostly agree there, though.

    But if using a [4][4]float matrix with column-major order things are
    somewhat confusing because matrix literals will look like they are being
    defined in row-major when they are not. I honestly think all access
    problems on flat arrays could be solved with adequate methods for indexing
    and modifying matrices index values.

    // Get returns the value in row i and column j of m.

    func (m *Mat4) Get(i, j int) float32

    // Set stores f in row i of column j in m.

    func (m *Mat4) Set(i, j int, f float32)

    // Cols sets the columns of m to c1, c2, c3, c4 in that order.

    func (m *Mat4) Cols(c1, c2, c3, c4 *f32.Vec4)

    // Rows sets the rows of m to r1, r2, r3, r4 in that order.

    func (m *Mat4) Rows(r1, r2, r3, r4 *f32.Vec4)


    I believe that all the methods above should be candidates for inlining in
    the Go compiler (at least the indexing methods). So I really don't see
    recommending programmers use them for accessing flat matrices as a big
    deal. Do people disagree with that?

    Cheers,
    - Bryan
    On Tuesday, March 29, 2016 at 2:31:48 PM UTC-7, laurent....@gmail.com wrote:

    I'm in no way qualified to talk about golang.org/x/mobile/exp/f32, but
    I've been toying with OpenGL and Go for some time, and I have a few
    question:

    - First, and most incompatible, I think the matrix types should be flat
    arrays that use column-major order[...]
    Why a flat array? As far as I know, on every platform [4][4]float32 has
    exactly the same memory layout than [16]float32, but is way more convenient
    to use. I'm not too familiar with mobile architectures, so maybe it's
    something specific to them? (I don't think the language spec gives anymore
    guaranties about padding in one case or the other; in fact, if my
    interpretation is correct, as long as a flat array has the right layout,
    the two dimensional one should have too).

    About the column-major order for storage, in OpenGL you can do both, as
    long as you use the correct multiplication order (i.e. row vectors with
    row-major matrices). It's true that you have to use column-major storage to
    be able to use the "standard" mathematical order in GLSL, so that's
    probably a safer choice for a library. Row-major makes some optimizations
    possible for affine matrices (at least with the alignment requirements of
    some GPUs), but it would make a difference only in a few specific cases
    (e.g. skeletal animation).

    Finally, I'm not sure I understand the point about serialization in the
    render loop. Again, maybe this is specific to mobile platforms, but on
    desktop you just provides a pointer to your data, the driver handles the
    copy to the GPU. Sure, there is no strong guaranties in the language for
    the exact memory layout, but this is also true with C and C++.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Bryan Matsuo at Mar 29, 2016 at 10:59 pm
    Also, I'm sorry but I can't really comment on affine transformations
    (skeletal animation) and optimizations in the GPU. I am still new to this
    stuff. Though I'm not necessarily suggesting that the f32.Affine type needs
    be changed. I'd be happy to hear other people comment on that, though.
    On Tuesday, March 29, 2016 at 3:46:43 PM UTC-7, Bryan Matsuo wrote:

    Thanks for the feedback.

    I guess I might not have clarified the serialization situation enough.
    AFAIK you are right about memory layout. [4][4]float32 should layout
    identically to [16]float32. And if you do unsafe type conversions you can
    turn either into the appropriate sized []byte for passing to
    glctx.Uniform4fv, glctx.BindBuffer and OpenGL will copy this data into the
    GPU (this is definitely how people in C and C++ do it). If that's really
    what is **supposed** be done in Go, and it's guaranteed to work, then that
    is OK by me and serialization isn't a concern. But if that is the case then
    defining the serialization function, f32.Bytes, in the first place doesn't
    really much sense, does it?

    Related to this point, one thing I haven't had a definitive answer for in
    my own mind is whether [16]float32 is guaranteed to contain the same bytes
    as [16]C.float. Naively I would say, "yes they are the same," but from what
    I've read elsewhere I'm actually not sure that is guaranteed.

    In regards to multiplication order, yes, because Transpose(A * B) ==
    Transpose(B) * Transpose(A) you can do work on column-major matrices using
    row-major algorithms. But actually recommending that people transpose all
    their matrices and reverse their matrix multiplication sounds quite
    sadistic to me, truly. I really do think column-major should be used, even
    if [4][4]float32 is truly the desired type signature. It sounds like we
    mostly agree there, though.

    But if using a [4][4]float matrix with column-major order things are
    somewhat confusing because matrix literals will look like they are being
    defined in row-major when they are not. I honestly think all access
    problems on flat arrays could be solved with adequate methods for indexing
    and modifying matrices index values.

    // Get returns the value in row i and column j of m.

    func (m *Mat4) Get(i, j int) float32

    // Set stores f in row i of column j in m.

    func (m *Mat4) Set(i, j int, f float32)

    // Cols sets the columns of m to c1, c2, c3, c4 in that order.

    func (m *Mat4) Cols(c1, c2, c3, c4 *f32.Vec4)

    // Rows sets the rows of m to r1, r2, r3, r4 in that order.

    func (m *Mat4) Rows(r1, r2, r3, r4 *f32.Vec4)


    I believe that all the methods above should be candidates for inlining in
    the Go compiler (at least the indexing methods). So I really don't see
    recommending programmers use them for accessing flat matrices as a big
    deal. Do people disagree with that?

    Cheers,
    - Bryan

    On Tuesday, March 29, 2016 at 2:31:48 PM UTC-7, laurent....@gmail.com
    wrote:
    I'm in no way qualified to talk about golang.org/x/mobile/exp/f32, but
    I've been toying with OpenGL and Go for some time, and I have a few
    question:

    - First, and most incompatible, I think the matrix types should be flat
    arrays that use column-major order[...]
    Why a flat array? As far as I know, on every platform [4][4]float32 has
    exactly the same memory layout than [16]float32, but is way more convenient
    to use. I'm not too familiar with mobile architectures, so maybe it's
    something specific to them? (I don't think the language spec gives anymore
    guaranties about padding in one case or the other; in fact, if my
    interpretation is correct, as long as a flat array has the right layout,
    the two dimensional one should have too).

    About the column-major order for storage, in OpenGL you can do both, as
    long as you use the correct multiplication order (i.e. row vectors with
    row-major matrices). It's true that you have to use column-major storage to
    be able to use the "standard" mathematical order in GLSL, so that's
    probably a safer choice for a library. Row-major makes some optimizations
    possible for affine matrices (at least with the alignment requirements of
    some GPUs), but it would make a difference only in a few specific cases
    (e.g. skeletal animation).

    Finally, I'm not sure I understand the point about serialization in the
    render loop. Again, maybe this is specific to mobile platforms, but on
    desktop you just provides a pointer to your data, the driver handles the
    copy to the GPU. Sure, there is no strong guaranties in the language for
    the exact memory layout, but this is also true with C and C++.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Laurent Moussault at Mar 30, 2016 at 6:37 am

    But if that is the case then defining the serialization function,
    f32.Bytes, in the first place doesn't really much sense, does it?
      The function might be useful to load assets from the disk, but that would
    probably be done with a more specialized format.

    Related to this point, one thing I haven't had a definitive answer for in
    my own mind is whether [16]float32 is guaranteed to contain the same bytes
    as [16]C.float. Naively I would say, "yes they are the same," but from what
    I've read elsewhere I'm actually not sure that is guaranteed.
    I don't think there's any guarantee, but then again, the situation is
    similar in the C world (relative to the GPU, e.g. for uniform buffers). The
    only difference is that most compilers provide a way to customize the way
    structs are packed. I think that for low-level programming, you can't avoid
    making some assumptions on your compiler.

    In regards to multiplication order, yes, because Transpose(A * B) ==
    Transpose(B) * Transpose(A) you can do work on column-major matrices using
    row-major algorithms. But actually recommending that people transpose all
    their matrices and reverse their matrix multiplication sounds quite
    sadistic to me, truly. I really do think column-major should be used, even
    if [4][4]float32 is truly the desired type signature. It sounds like we
    mostly agree there, though.
    Yes, column-major is now the recommended way, if only because it makes it
    easier to use material from math papers. But it wasn't always like this (I
    think the first few books on graphics programming were using row-vectors),
    and the fact that GPUs registers are 4 floats wide means that with
    row-major storage you can send affine matrices with only 3 fully used
    registers, whereas with column-major you need 4 under-used registers. It
    only matters if you have a lot of affine transforms to pass to the GPU
    (such as in skeletal animation).

    But if using a [4][4]float matrix with column-major order things are
    somewhat confusing because matrix literals will look like they are being
    defined in row-major when they are not.
    The thing is, this is exactly what GLSL does (as well as swapping the
    indices relative to the mathematical norm). And in the end, this is
    programming, not mathematics. When doing graphics coding, you end up
    writing shaders in parallel to Go/C code; having the same notation (or as
    close as possible) in both is IMHO a must.

    On this topic, I'm not too sure about the way matrix operations are exposed
    in golang.org/x/mobile/exp/f32. Mutating the receiver is currently the
    fastest method, but if my benchmarks are correct, returning the result by
    value is only slightly slower (28 ns/op vs 24 ns on my machine), and much
    more convenient. I'm not sure how the compiler currently handle this, but
    my guess is that something similar to C++ move semantic is happening. In
    fact, passing the argument by value doesn't seem to impact performance
    either. I think that "M = M.Times(N)" is easier to read than "M.Mul(M, N)".

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Bryan Matsuo at Mar 30, 2016 at 7:42 am

    On Tuesday, March 29, 2016 at 11:37:25 PM UTC-7, Laurent Moussault wrote:

    But if that is the case then defining the serialization function,
    f32.Bytes, in the first place doesn't really much sense, does it?
    The function might be useful to load assets from the disk, but that would
    probably be done with a more specialized format.

    Related to this point, one thing I haven't had a definitive answer for in
    my own mind is whether [16]float32 is guaranteed to contain the same bytes
    as [16]C.float. Naively I would say, "yes they are the same," but from what
    I've read elsewhere I'm actually not sure that is guaranteed.
    I don't think there's any guarantee, but then again, the situation is
    similar in the C world (relative to the GPU, e.g. for uniform buffers). The
    only difference is that most compilers provide a way to customize the way
    structs are packed. I think that for low-level programming, you can't avoid
    making some assumptions on your compiler.

    In regards to multiplication order, yes, because Transpose(A * B) ==
    Transpose(B) * Transpose(A) you can do work on column-major matrices using
    row-major algorithms. But actually recommending that people transpose all
    their matrices and reverse their matrix multiplication sounds quite
    sadistic to me, truly. I really do think column-major should be used, even
    if [4][4]float32 is truly the desired type signature. It sounds like we
    mostly agree there, though.
    Yes, column-major is now the recommended way, if only because it makes it
    easier to use material from math papers. But it wasn't always like this (I
    think the first few books on graphics programming were using row-vectors),
    and the fact that GPUs registers are 4 floats wide means that with
    row-major storage you can send affine matrices with only 3 fully used
    registers, whereas with column-major you need 4 under-used registers. It
    only matters if you have a lot of affine transforms to pass to the GPU
    (such as in skeletal animation).
    Thanks for filling in that bit about GPU registers. I still haven't gotten
    to a point where I need to use non-square matrices.


    But if using a [4][4]float matrix with column-major order things are
    somewhat confusing because matrix literals will look like they are being
    defined in row-major when they are not.
    The thing is, this is exactly what GLSL does (as well as swapping the
    indices relative to the mathematical norm). And in the end, this is
    programming, not mathematics. When doing graphics coding, you end up
    writing shaders in parallel to Go/C code; having the same notation (or as
    close as possible) in both is IMHO a must.
    That is a valid point. Indeed the first time I saw a matrix being
    constructed from vectors in OpenGL I wasn't positive which way they were
    being oriented. Matching those semantics would make things more intuitive.

    On this topic, I'm not too sure about the way matrix operations are exposed
    in golang.org/x/mobile/exp/f32. Mutating the receiver is currently the
    fastest method, but if my benchmarks are correct, returning the result by
    value is only slightly slower (28 ns/op vs 24 ns on my machine), and much
    more convenient. I'm not sure how the compiler currently handle this, but
    my guess is that something similar to C++ move semantic is happening. In
    fact, passing the argument by value doesn't seem to impact performance
    either. I think that "M = M.Times(N)" is easier to read than "M.Mul(M, N)".
    I wouldn't have expected the difference to be so small. I will poke around
    in that area to investigate as well. Although honestly I was trying to
    deliberately avoid discussion of the API functions/methods when I sent my
    my initial message. I think the API does need work. But I thought that
    solving the impedance mismatch between the package types and OpenGL was a
    more critical problem to solve.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Brendan Tracey at Mar 30, 2016 at 1:31 pm

    On this topic, I'm not too sure about the way matrix operations are exposed in golang.org/x/mobile/exp/f32 <http://golang.org/x/mobile/exp/f32>. Mutating the receiver is currently the fastest method, but if my benchmarks are correct, returning the result by value is only slightly slower (28 ns/op vs 24 ns on my machine), and much more convenient. I'm not sure how the compiler currently handle this, but my guess is that something similar to C++ move semantic is happening. In fact, passing the argument by value doesn't seem to impact performance either. I think that "M = M.Times(N)" is easier to read than "M.Mul(M, N)".

    I wouldn't have expected the difference to be so small. I will poke around in that area to investigate as well. Although honestly I was trying to deliberately avoid discussion of the API functions/methods when I sent my my initial message. I think the API does need work. But I thought that solving the impedance mismatch between the package types and OpenGL was a more critical problem to solve.
    If it matters, M.Mul(M,N) is the approach that gonum/matrix has taken. The use cases are very different, so it may not.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Nigel Tao at Mar 31, 2016 at 6:23 am
    CC'ing crawshaw.

    On Wed, Mar 30, 2016 at 2:30 AM, Bryan Matsuo wrote:
    The f32 package has some erroneous computational bugs which I don't need to
    go into (they are open issues on github).
    I know of these two below. Please let me know if there are others.
    https://github.com/golang/go/issues/14360
    https://github.com/golang/go/issues/14989

    The way things are it makes no sense to me why all the linear algebra
    functions aren't implemented in the package golang.org/x/image/math/f32,
    which uses a row-major order (though also chose to use a flat array, FWIW).
    The x/mobile/exp/f32 package was written first, driven by the
    immediate needs of the x/mobile project. The x/image/math/f32 package
    was written later, with the broader goal of being a canonical matrix
    representation so that different packages (written by different
    people) can co-operate. In the long term, I hope to deprecate the
    x/mobile flavor, and move the rest of x/mobile to use the x/image
    flavor, but the x/image flavor is currently incomplete: we have not
    reached consensus on what the API should look like, e.g. m :=
    m.Times(n) vs m.Mul(m, n). (This is drifting tangentially, but if the
    performance difference is indeed small, I lean towards m.Times(n),
    similar to the image.Point methods instead of the big.Int methods;
    it's necessary for big.Int because a big-int does not occupy a fixed
    number of bytes).

    As for the x/image flavor, there was a previous discussion at
    https://groups.google.com/d/topic/golang-nuts/cuXorkJD6Bg/discussion
    and
    https://groups.google.com/d/topic/golang-dev/9sYm9-2Bc2w/discussion
    that second one links to a doc at
    https://docs.google.com/document/d/1BdQMB7OWzqFyn4VpwkvCVRFZ5KJMQCgyAA5KRMdMId8/edit#heading=h.dfctsvm47oev
    which distills other conversations from further back. But there hasn't
    been a lot of activity on it recently. It hasn't been the highest
    priority thing on my plate or others'.

    That doc notes that we agreed on row-major over column-major order.
    Sure, OpenGL defaults to CMO, but OpenGL is not the only place where
    Go code would like to use matrices, and the gonum folk would know more
    about this than I do, but I suspect that other C libraries also
    (often??) choose RMO.

    As for serialization, yes, having Bytes allocate doesn't look ideal,
    although it was certainly the easy route in getting the "Hello World"
    of OpenGL programs off the ground. I agree that the x/image flavor of
    Bytes should probably take a []byte buffer as an argument.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Bryan Matsuo at Mar 31, 2016 at 7:46 am
    Thanks for the background and the document Nigel. Sorry to be stirring up
    something that was discussed and essentially settled before. I am sorry I
    didn't see/participate then.

    Indeed those two issues are the ones I was referring to. I filed one and
    commented on the other previously. Of course, those are computational
    errors I personally have encountered (having not touch parts of the API
    like the Affine type).

    I haven't looked deeply into the mobile/exp/f32 lineage yet.. But the first
    issue (#14360) may actually be case in point for an earlier comment made by
    Laurent,

    When doing graphics coding, you end up writing shaders in parallel to Go/C
    code; having the same notation (or as close as possible) in both is IMHO a
    must.

    It seems to me that two non-trivial graphics-specific functions in f32,
    Mat4.Perspective() and Mat4.LookAt(), were implemented expecting
    column-major order (possibly from a corresponding implementation in C or
    some literature?). So I think the argument of an existing, strong precedent
    for column-order matrices specifically in the graphics community has merit.
    So, while I agree that having row-major indexing for generic MxN matrices
    is probably OK academically and correct for Go I think that the special
    case of fixed-size matrices for graphics applications may deserve a
    different treatment.

    Furthermore, because of these two functions Perspective and LookAt can the
    package really be fully deprecated? Nigel, this is something I'm quoting
    from one of the discussions you linked to.

    The package will just be the type definitions, and maybe some dumb
    methods (e.g. adding two vectors) that we can all agree on. Smart
    code, such as calculating a projection matrix based on viewpoint,
    angle, etc. are out of scope, and belongs in packages that *use* f32,
    instead of being *in* f32.

    You seem to be discussing these functions specifically; and you are saying
    that image/math/f32 is not their home. Am I misreading things due to
    improper context? If image/math/f32 is not where they will end up then
    mobile/exp/f32 should not disappear, I believe (though trying to import two
    packages called "f32" is a pain in the neck IMO, goimports is already
    messing this one up for me).

    Cheers,
    - Bryan
    On Wednesday, March 30, 2016 at 11:23:07 PM UTC-7, Nigel Tao wrote:

    CC'ing crawshaw.


    On Wed, Mar 30, 2016 at 2:30 AM, Bryan Matsuo <bryan....@gmail.com
    <javascript:>> wrote:
    The f32 package has some erroneous computational bugs which I don't need to
    go into (they are open issues on github).
    I know of these two below. Please let me know if there are others.
    https://github.com/golang/go/issues/14360
    https://github.com/golang/go/issues/14989

    The way things are it makes no sense to me why all the linear algebra
    functions aren't implemented in the package golang.org/x/image/math/f32,
    which uses a row-major order (though also chose to use a flat array,
    FWIW).

    The x/mobile/exp/f32 package was written first, driven by the
    immediate needs of the x/mobile project. The x/image/math/f32 package
    was written later, with the broader goal of being a canonical matrix
    representation so that different packages (written by different
    people) can co-operate. In the long term, I hope to deprecate the
    x/mobile flavor, and move the rest of x/mobile to use the x/image
    flavor, but the x/image flavor is currently incomplete: we have not
    reached consensus on what the API should look like, e.g. m :=
    m.Times(n) vs m.Mul(m, n). (This is drifting tangentially, but if the
    performance difference is indeed small, I lean towards m.Times(n),
    similar to the image.Point methods instead of the big.Int methods;
    it's necessary for big.Int because a big-int does not occupy a fixed
    number of bytes).

    As for the x/image flavor, there was a previous discussion at
    https://groups.google.com/d/topic/golang-nuts/cuXorkJD6Bg/discussion
    and
    https://groups.google.com/d/topic/golang-dev/9sYm9-2Bc2w/discussion
    that second one links to a doc at

    https://docs.google.com/document/d/1BdQMB7OWzqFyn4VpwkvCVRFZ5KJMQCgyAA5KRMdMId8/edit#heading=h.dfctsvm47oev
    which distills other conversations from further back. But there hasn't
    been a lot of activity on it recently. It hasn't been the highest
    priority thing on my plate or others'.

    That doc notes that we agreed on row-major over column-major order.
    Sure, OpenGL defaults to CMO, but OpenGL is not the only place where
    Go code would like to use matrices, and the gonum folk would know more
    about this than I do, but I suspect that other C libraries also
    (often??) choose RMO.

    As for serialization, yes, having Bytes allocate doesn't look ideal,
    although it was certainly the easy route in getting the "Hello World"
    of OpenGL programs off the ground. I agree that the x/image flavor of
    Bytes should probably take a []byte buffer as an argument.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Nigel Tao at Mar 31, 2016 at 9:49 am

    On Thu, Mar 31, 2016 at 6:46 PM, Bryan Matsuo wrote:
    It seems to me that two non-trivial graphics-specific functions in f32,
    Mat4.Perspective() and Mat4.LookAt(), were implemented expecting
    column-major order (possibly from a corresponding implementation in C or
    some literature?).
    IIRC, crawshaw wrote those Go functions. Perhaps he can remember their
    providence. I have a vague memory that some example (3-D viewer??)
    program used it in the past, but I can't remember the details.

    Still, I'd rather just have the one consistent order everywhere, if possible.

    Furthermore, because of these two functions Perspective and LookAt can the
    package really be fully deprecated?
    Note that the "exp" in "x/mobile/exp/f32" stands for experimental. Its
    API is far from set in stone.

    You seem to be discussing these functions specifically; and you are saying
    that image/math/f32 is not their home.
    I'm open to being convinced otherwise, but my instinct is that
    x/image/math/f32 is not their home. It is easier to add API later than
    remove it, so I'd rather err on the side of too little API for now.
    Matrix multiplication seems common enough, across a variety of
    applications, to warrant being inside the x/image/math/f32 package.
    The case for dedicated Perspective or LookAt methods is less obvious.

    If some 3-D graphics package, or program, wants to be able to set up a
    camera via LookAt, it seems plausible to have that function live
    inside that package, or in package main. It's not like a f32.Mat4 has
    non-exported state that only in-package code can access. If its code
    must be shared, it could live inside some f32util package, rather than
    having to be inside x/image/math/f32 per se.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Bryan Matsuo at Mar 31, 2016 at 11:00 am
    OK. I understand. The argument is that LookAt and Perspective are outside
    the scope of something that needs the maintenance and stewardship of the Go
    team. I think that is an acceptable answer. I suppose my expectations were
    not aligned.

    Though, it seems to me that if one of the example programs needs this
    functionality and it should not be part of the exported
    golang.org/x/mobile/... APIs then it should be vendored from another
    3D-math library or implemented in an internal library. I don't think
    letting things stagnate as they are is helping anyone.

    And, maybe I'm missing something but it doesn't look like any exported APIs
    in golang.org/x/mobile/... expose f32 types directly (other than the f32
    package itself). It seems like the entire package could be deleted today
    and an internal/vendored package used until the appropriate arithmetic
    operations are added to x/image/math/f32.

    Is there a reason not to do that?
    On Thursday, March 31, 2016 at 2:49:13 AM UTC-7, Nigel Tao wrote:

    On Thu, Mar 31, 2016 at 6:46 PM, Bryan Matsuo <bryan....@gmail.com
    <javascript:>> wrote:
    It seems to me that two non-trivial graphics-specific functions in f32,
    Mat4.Perspective() and Mat4.LookAt(), were implemented expecting
    column-major order (possibly from a corresponding implementation in C or
    some literature?).
    IIRC, crawshaw wrote those Go functions. Perhaps he can remember their
    providence. I have a vague memory that some example (3-D viewer??)
    program used it in the past, but I can't remember the details.

    Still, I'd rather just have the one consistent order everywhere, if
    possible.

    Furthermore, because of these two functions Perspective and LookAt can the
    package really be fully deprecated?
    Note that the "exp" in "x/mobile/exp/f32" stands for experimental. Its
    API is far from set in stone.

    You seem to be discussing these functions specifically; and you are saying
    that image/math/f32 is not their home.
    I'm open to being convinced otherwise, but my instinct is that
    x/image/math/f32 is not their home. It is easier to add API later than
    remove it, so I'd rather err on the side of too little API for now.
    Matrix multiplication seems common enough, across a variety of
    applications, to warrant being inside the x/image/math/f32 package.
    The case for dedicated Perspective or LookAt methods is less obvious.

    If some 3-D graphics package, or program, wants to be able to set up a
    camera via LookAt, it seems plausible to have that function live
    inside that package, or in package main. It's not like a f32.Mat4 has
    non-exported state that only in-package code can access. If its code
    must be shared, it could live inside some f32util package, rather than
    having to be inside x/image/math/f32 per se.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Nigel Tao at Mar 31, 2016 at 11:33 am

    On Thu, Mar 31, 2016 at 10:00 PM, Bryan Matsuo wrote:
    And, maybe I'm missing something but it doesn't look like any exported APIs
    in golang.org/x/mobile/... expose f32 types directly (other than the f32
    package itself). It seems like the entire package could be deleted today and
    an internal/vendored package used until the appropriate arithmetic
    operations are added to x/image/math/f32.

    Is there a reason not to do that?
    A bunch of example programs under x/mobile/example import
    "golang.org/x/mobile/exp/f32", and the idea is that you should be able
    to copy and tweak those examples.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Bryan Matsuo at Mar 31, 2016 at 11:49 am
    That seems like a valid reason to avoid an internal package. But I would
    still question why not vendor a third-party package?
    On Thursday, March 31, 2016 at 4:33:29 AM UTC-7, Nigel Tao wrote:

    On Thu, Mar 31, 2016 at 10:00 PM, Bryan Matsuo <bryan....@gmail.com
    <javascript:>> wrote:
    And, maybe I'm missing something but it doesn't look like any exported APIs
    in golang.org/x/mobile/... expose f32 types directly (other than the f32
    package itself). It seems like the entire package could be deleted today and
    an internal/vendored package used until the appropriate arithmetic
    operations are added to x/image/math/f32.

    Is there a reason not to do that?
    A bunch of example programs under x/mobile/example import
    "golang.org/x/mobile/exp/f32", and the idea is that you should be able
    to copy and tweak those examples.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Nigel Tao at Mar 31, 2016 at 12:18 pm

    On Thu, Mar 31, 2016 at 10:49 PM, Bryan Matsuo wrote:
    That seems like a valid reason to avoid an internal package. But I would
    still question why not vendor a third-party package?
    Again, crawshaw is probably the best person to answer that, as IIRC he
    wrote the original x/mobile f32 package, but
    https://golang.org/cl/141440043 dates from September 2014, before
    vendoring landed (experimentally) in Go 1.5 (August 2015), let alone
    having to decide exactly which third party package to vendor.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Bryan Matsuo at Mar 31, 2016 at 12:42 pm
    Looking at the set of packages specified in that proposal doc, I don't
    think the choice of a package to vendor is terribly complex.

    github.com/go-gl/mathgl
    github.com/Jragonmiris/mathgl

    The two above are the same (one was merged into the other). And it is even
    using x/image/math/f32 already.

    azul3d.org/lmath.v1 -- This package is in a repository called azul3d-legacy
    and doesn't seem like it is maintained.

    github.com/ungerik/go3d -- This one could work.

    github.com/skelterjohn/geom -- This one is using float64 and also looks
    potentially unmaintained.

    github.com/spate/vectormath -- The API and struct definitions on this one
    don't look right. Also potentially unmaintained.

    So really I think the choice is between two libraries and one is using the
    unified types...

    But if crawshaw is the man in the know then, yes, let's wait to hear what
    his input is.
    On Thursday, March 31, 2016 at 5:18:25 AM UTC-7, Nigel Tao wrote:

    On Thu, Mar 31, 2016 at 10:49 PM, Bryan Matsuo <bryan....@gmail.com
    <javascript:>> wrote:
    That seems like a valid reason to avoid an internal package. But I would
    still question why not vendor a third-party package?
    Again, crawshaw is probably the best person to answer that, as IIRC he
    wrote the original x/mobile f32 package, but
    https://golang.org/cl/141440043 dates from September 2014, before
    vendoring landed (experimentally) in Go 1.5 (August 2015), let alone
    having to decide exactly which third party package to vendor.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • David Crawshaw at Mar 31, 2016 at 12:58 pm
    I wrote x/mobile/exp/f32 early on to support a 3D spinning gopher
    example android app. (I've mostly brought it back as a shiny example
    app, but #6853 is eating all my time. In that app, I've copied the
    relevant parts of f32 into it as unexported functions.)

    There were several discussions with the go-gl folks about how we could
    work together, and x/image/math/f32 came out of that. It was very hard
    to find a common set of image math routines that worked for everyone,
    but we could agree on the types, so that's where that came from. The
    long-term plan was, and I believe still is, that we add any logic that
    is widely applicable to x/image/math/f32.

    Since then, x/mobile/exp/f32 has been on a list of packages for me to
    eventually delete or fold into other work. A lot more effort has gone
    into github.com/go-gl/mathgl, so I suggest starting there.
    On Thu, Mar 31, 2016 at 8:42 AM, Bryan Matsuo wrote:
    Looking at the set of packages specified in that proposal doc, I don't think
    the choice of a package to vendor is terribly complex.

    github.com/go-gl/mathgl
    github.com/Jragonmiris/mathgl

    The two above are the same (one was merged into the other). And it is even
    using x/image/math/f32 already.

    azul3d.org/lmath.v1 -- This package is in a repository called azul3d-legacy
    and doesn't seem like it is maintained.

    github.com/ungerik/go3d -- This one could work.

    github.com/skelterjohn/geom -- This one is using float64 and also looks
    potentially unmaintained.

    github.com/spate/vectormath -- The API and struct definitions on this one
    don't look right. Also potentially unmaintained.

    So really I think the choice is between two libraries and one is using the
    unified types...

    But if crawshaw is the man in the know then, yes, let's wait to hear what
    his input is.
    On Thursday, March 31, 2016 at 5:18:25 AM UTC-7, Nigel Tao wrote:

    On Thu, Mar 31, 2016 at 10:49 PM, Bryan Matsuo <bryan....@gmail.com>
    wrote:
    That seems like a valid reason to avoid an internal package. But I would
    still question why not vendor a third-party package?
    Again, crawshaw is probably the best person to answer that, as IIRC he
    wrote the original x/mobile f32 package, but
    https://golang.org/cl/141440043 dates from September 2014, before
    vendoring landed (experimentally) in Go 1.5 (August 2015), let alone
    having to decide exactly which third party package to vendor.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Laurent Moussault at Mar 31, 2016 at 11:52 am
    As for the x/image flavor, there was a previous discussion at
    https://groups.google.com/d/topic/golang-nuts/cuXorkJD6Bg/discussion
    and
    https://groups.google.com/d/topic/golang-dev/9sYm9-2Bc2w/discussion
    that second one links to a doc at

    https://docs.google.com/document/d/1BdQMB7OWzqFyn4VpwkvCVRFZ5KJMQCgyAA5KRMdMId8/edit#heading=h.dfctsvm47oev
    which distills other conversations from further back. But there hasn't
    been a lot of activity on it recently. It hasn't been the highest
    priority thing on my plate or others'.
    Thanks for the links. But honestly, I'm not sure it's possible to write a
    matrix package in Go that would be both standard and useful for everyone.

    Graphics coding have clearly settled on column vectors in recent years,
    this is how most of the papers and code examples are presented, so trying
    to enforce row-majorness will be a no-go for many people. Also, it's said
    in the doc that Go is "row-major", but this is a common abuse of language:
    Go, just like C, doesn't know anything about columns or rows, its only
    concern is storage order. Saying that Go is row-major implies that the
    indices are in the order M[row][col], because this mirror the indices used
    in math notation. But M[col]row] is very common in less mathematical
    contexts, and this index order suddenly makes Go "column major".

    That being said, the package can be completely agnostic for majorness: as
    long as it contains only standard operations such as the matrix product, it
    will work the same whether the matrix is interpreted as row-major or
    column-major. It should be the user's decision to construct the matrix in
    one way or the other, and use the correct indices, just like in GLSL. Maybe
    this is what a standard package should do: drop any reference to majorness,
    but explain the relation between indices, storage, and multiplication order
    (i.e. use v*M if row-major, M*v if column-major).

    Concerning the implementation, I don't understand the argument behind flat
    arrays: what would be the use of an arbitrary slice of a matrix? Most
    slices would span across rows or columns, which doesn't really make sense.
    Even the few that would be mathematically sensible could not be used as
    sub-matrices without a copy anyway. IMHO the whole point of a matrix is
    that it's structured, and since there is a Go type that directly match this
    structure, it should be use openly.

    Finally, I understand the choice of [4]float32 for vectors instead of
    struct{X,Y,Z,W float32} in a standard package, but on the other hand I
    would not want to use that for graphics coding; it makes it too cumbersome
    to write and read very common operations.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-dev @
categoriesgo
postedMar 29, '16 at 3:30p
activeMar 31, '16 at 12:58p
posts17
users5
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase