Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipeline State Objects revolution #828

Merged
merged 143 commits into from Jan 22, 2016

Conversation

@sectopod
Copy link
Contributor

commented Nov 9, 2015

Requires gfx-rs/draw_state#34
Fixes #815, fixes #842, fixes #823, fixes #761, fixes #722, fixes #703, fixes #694, fixes #463
Closes #817, closes #640, closes #630, closes #575, closes #571, closes #322, closes #121
Touches #698, #331, #311, #284, #161

Breaking changes:

  • Batch, Mesh, Stream concepts are gone, as well as the old shader parameters interface. PSO is the new paradigm, with it's own macro and interfaces.
  • VAO, FBO, Surface, Plane, Output are gone, they are now hidden GL implementation details. Command enum and state caching have also been moved into GL backend.
  • Texture semantic has changed - now it is just an allocation of some pixel data. For actual rendering, users are required to operate on the strongly-typed target/resource views. The new format specification supports textures, views, and vertex buffers in the uniform way.

See a better overview of the change in this comment. The best source of knowledge to this moment is the example code. We realize such this needs to be well documented and are working on it.

TODO (note: this is a vastly incomplete list of what's actually done):

  • PSO resource - low level
    • resource
    • binding
    • creation
  • High level
    • RenderTargetView and DepthStencilView
      • low-level bindings
      • raw creation
      • typed creation
      • hook up to PSO
    • ShaderResourceView and UnorderedAccessView
      • low-level bindings
      • raw creation
      • typed creation
      • hook up to PSO
    • move core into a separate lib (#703)
    • remove the Copy constraint from the resources
    • layout matching
      • vertex attributes
      • shader data
      • pixel targets
    • strongly-typed initialization
    • hook to the Renderer for drawing
  • helper macros
    • structure definition
    • PSO
    • PSO with static init
    • texture format
    • macros tests
  • Universal data format spec
    • serialized form
    • strongly-typed form
    • replace tex::Format
    • replace attrib::Format
  • GL backend
    • rewrite init() function for windowing backends
    • rewrite CommandBuffer implementation to do the heavy lifting
    • support for structured buffers (can be postponed)
    • Glutin window
    • GLFW window
  • Switch the examples to use PSO
    • blend
    • cube
    • deferred
    • flowmap
    • instancing
    • mipmap
    • performance
    • shadow
    • terrain
    • triangle
    • ubo_tilemap
  • Clean up
    • remove old Resources subtypes
    • remove shader programs
    • remove old meshes and attribute formats
    • remove old shader parameters
    • remove old texture format
    • remove batches
    • remove VAO and FBO
    • remove Plane, Output, and Frame
  • Post-clean
    • rename NewTexture to Texture
    • remove primitive from mesh::Slice
  • Documentation
    • typed PSO
    • universal format

Or, basically, rewrite the whole damn thing ;)

@homu

This comment has been minimized.

Copy link
Contributor

commented Nov 9, 2015

☔️ The latest upstream changes (presumably #829) made this pull request unmergeable. Please resolve the merge conflicts.

@ghost

This comment has been minimized.

Copy link

commented Nov 10, 2015

Sorry @sectopod for creating a conflicts.

@ghost ghost referenced this pull request Nov 10, 2015

Closed

Version 0.9 #821

@sectopod sectopod force-pushed the sectopod:pso branch from 1a7a827 to 5e28e70 Nov 10, 2015

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Nov 10, 2015

@csherratt np!
Heads up - I'm going to change ShaderParam::Resources to be a generic parameter rather than an associated type. This would technically allow the same ShaderParam to be used with different devices in the same program.
Edit: on the other hand, this would make some explicit type definitions longer:

let batch : MyBatch<gfx_device_gl::Resources, MyShaderParam>

This would be highly unfortunate. Perhaps, I'll avoid touching this for now then.

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Nov 14, 2015

I'm going through several iterations internally, and the progress with this PR is slow but steady. If you need to publish a new version for some other changes - please don't wait for me.
The way this PR is heading now changes quite a bit of perspective in these areas:

  1. Shader resources are serialized into data (LinkMap) and passed to the device for program linkage. This is the opposite from what we have now: program linked separately, ProgramInfo generated as a serialized form of shader demands, and then they are generically matched against user data.
  2. The concrete resource types, like vertex attributes, have their layout matching logic inside the hidden type (akin VertexFormat). This type has the names and formats of the data at compile time (static methods), and the actual linkage to the shader expectations at run time (index data). Vertex structure itself becomes purely data with no logic. This is quite different from the current design, where the generate Link structure is just data, and Vertex itself has all the logic.
  3. The PSO defines how the data is processed (inputs, outputs, algorithms, parameters, state), but doesn't have the data itself (unlike our old batches). There is going to be less run-time checks during rendering and stronger type guarantees. Prototype PSO definition:
pub struct PipelineState<
    R: d::Resources,
    I: VertexLayout<R>,
    P: ShaderParam<R>,
    E: PixelLayout<R>
>(d::handle::RawPipelineState<R>, d::PrimitiveType, I, P, E);
@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Nov 15, 2015

Why do we even separate vertex attributes from pixel targets from all the other shader data? If we follow #833, we can just define all the shader interface in a single struct like this one:

gfx_shader_link!( Shader {
    vertex: VertexBuffer<Vertex>, //regular vertex buffer, where `Vertex: VertexFormat`
    vertex_inst: VertexBuffer<Instance>, //instanced buffer, the instance rate is specified somewhere inside the `Instance` struct definition
    const_locals: ConstantBuffer<Local>, //constant buffer
    const_globals: ConstantBuffer<Global>, // another one
    tex_diffuse: TextureView<Dim2, Float4>, // 2D texture SRV
    tex_normal: TextureView<Dim2, Float3>, // same, but of `Float3` type
    sampler_linear: Sampler, // just a sampler, not sure if it would make sense to typify further here
    buf_noise: BufferView<Int4>, // structured buffer SRV
    buf_frequency: UnorderedView<Dim2, Int>, // 2D UAV buffer of `Int`
    pixel_color: TargetView<Dim2, Float4>, // output render target
});

Of course, each of the vertex buffers need to have a special struct behind them too (like the current gfx_vertex), but still it looks rather sleek to me.

@kvark

This comment has been minimized.

Copy link
Member

commented Nov 16, 2015

@sectopod great idea! so we are going to include attributes and targets into a struct what used to be ShaderParam. This would make all the Output, Frame, and even some Mesh stuff irrelevant and simplifies the user side of things: for a draw call, we'd only need a slice, a PSO, and this shader link block. It also simplifies strongly-typed PSO definition: it's only parametrized by the Resources and this ShaderLink type (maybe ShaderData would be better? or PipelineData?).

Overall, I think you are not just on the right track, but onto something big. Having all these *View types, strong PSO, unified shader link, and with all the old GL cruft removed - gfx would become a very different beast: better suited for next-gen APIs, safer, and friendlier to the users. Keep up!

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Nov 22, 2015

It took me a fair bit of persistence to implement this scheme, and it could work if finished (got several large commits locally, hesitating to push yet). The reason I stopped is because I feel that this design is incomplete.

Take the blend state for example: providing it separately in the DrawState struct, one per color attachment, has no link to the actual target views we provide in this shader link structure. This is not just redundant, it's also a failure to allow using a specific blend mode on a specific target. Similar, even if less severe, is the situation with the depth/stencil - it's possible to provide a depth view without a depth test and the opposite, at run-time, which is sub-optimal.

A logical conclusion for me is to somehow provide the blending, depth state and offset, and stencil state as a part of this shader link structure. This would mean we no longer need to pass DrawState for PSO creation, but instead some sort of extended Primitive configuration that would include the topology and multi-sampling (I'd call it Rasterizer). However, there is one big problem here - blend/depth/stencil can not be a part of this structure, since it only has the data needed for run-time execution. The configuration for PSO creation is derived from the types themselves (in the current iteration of the design).

Basically, this shader link has 3 different structures underneath:

  • PSO init data. It has the rasterizer configuration, blend states, depth/stencil, and the shader names of all the fields. It's currently partly raw-data-driven (create_pipeline_state(..., &DrawState, ...)), partly user-defined at compile time (shader symbols), and partly implicitly derived from the types of the declaration fields (e.g. RenderTargetView<R, T> derives the target format from T).
  • PSO meta-data. It has all the register indices for the used fields, constructed based on the shader reflection. The structure is generated from the field types and managed automatically (though we still need to specify the name because of the current Rust macro system limitation - inability to create new identifiers).
  • PSO run-time data. It has the buffer/view handles of the stuff we are binding on each draw. The structure is the one we are providing to the shader link macro.

So, going back to blend/depth/stencil - we are at the crossroads. Here are some extreme routes we can take, or maybe we can figure out a reasonable compromise in-between (if only anyone would be able to follow my essays...).

  1. Extreme types - provide all the initialization data with types. This would mean compile-time fixed depth/blend/stencil states, which is a rather strict limitation. It would also rely heavily on our ability to support more generic versions of the shader links in the macro, which would at least allow some variability of these states. It would also involve a bigger gap between the types we pass at run-time and the types of the declaration, which means more boilerplate code by the user...
  2. Extreme data - provide all the init data with data. It could be achieved by generating this PSO init struct by our macro and requiring the user to fill it up and pass in for PSO creation. This structure would contain the symbol names too, so it would provide the highest flexibility we can ever get without compromising the strong types safety.
    The downside here is mainly the mental load on the user - now they've got to think about this init structure as well, which format they don't observe visually and can only guess (with compiler help) upon filling. For example, RenderTargetView<R, T> in the run-time declaration would imply something like (&'a str, Option<Blend>, ColorMask) it the init struct.

Any ideas/opinions on how to proceed? Am I even nearly close to an efficient design here? Without further instructions I'll go with extreme data path to see where the rabbit whole leads...

@kvark

This comment has been minimized.

Copy link
Member

commented Nov 22, 2015

@sectopod nice to see steady progress! It's exciting to see how far we can reach with this shader link concept in terms of safety and usability. BTW, I vote to rename it to PipelineData (and gfx_pipeline_data correspondingly).

As for your main question, I believe a reasonable compromise between data and types w.r.t DataLink would be to have as little types as needed to ensure no possible errors happening at run-time binding. Blend state, for example, is impossible to screw up at run init time, so we can have it as data. Symbol names - too - should be data. SRV/DSV/RTV formats though have to match, so we should be having them typed.

Edit: now that I think about it more, this is not quite a compromise. Having any data per struct field means exposing this initialization struct type. Dunno how to get this right... cc @csherratt @fkaa

@kvark

This comment has been minimized.

Copy link
Member

commented Nov 26, 2015

Ok, I've been thinking about it some more... I still don't know how to get this right, but at least I know how to definitely get this wrong ;)

First off, using types only for PSO initialization (Extreme types) is a no-go. It harms the flexibility too much (inability to tweak the blend state, depth state, or even the shader-exposed name).

Secondly, generating the PSO init struct in a macro and then expecting the user to instantiate it is another no-go. Everything that user is supposed to create should be either explicitly documented, or declared by the user themselves.

One possible research direction that is left after cutting these paths is - expect the user to provide both init and bind parts explicitly. Reminder: the "init" part is the one passed for PSO creation, the "bind" part is the one provided for each draw call.

color: gfx::RenderTargetView<R, Float4> | (&str, gfx::BlendState, gfx::ColorMask),

This will generate the color field in all init/meta/bind structs, where the user will need to provide the RTV<Float4> for binding, and (name, blend, color_mask) for initialization. If rust typesystem is flexible enough, we'll be able to enforce the Float4 to be a blendable format too. In other words, we should use the init types to help define what the expectactions for the bind ones are: having a depth state means our DSV should have the depth component, having the blend state means our RTV should be blendable, etc.

@kvark

This comment has been minimized.

Copy link
Member

commented Nov 27, 2015

Another idea. If we don't take the shader variable names into account, the only data that we need to pass for the PSO creation is related to render targets: blend states, color masks, target formats, depth/stencil. This fact makes the targets somewhat different from the rest of our magical struct. Also the fact that there can be only one depth/stencil view, while there can be any repeating number of other types of entries. Perhaps, we should not include the render targets into this struct then? Treating them separately would make the rest of the struct clean enough and reduce the confusion. For the targets, we can use nominal types (tuples) to avoid user-specified names.

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Nov 28, 2015

@kvark hmm, looks like there is no clearly superior solution in sight. Specifying both the bind data and init data types is too verbose to my taste (I'd rather have the some staff magically derived). Moving render target stuff out would complicate the interface...
I don't know what to do yet, but I tried to systematize all the data that we need to support for PSO magical struct, minus all the rasterizer stuff. Hope this will help:

prototype init data meta bind data
VertexBuffer<T: Structure> (T::init, InstanceRate) [v#] BufferHandle<R, T>
ConstantBuffer<T: Structure> (T::init, &str) c# BufferHandle<R, T>
Constant<T: Uniform> (&str, T::format) loc T
Texture<T: TextureFormat> (&str, T::format) t# ShaderResourceView<R, T>
Sampler &str s# Sampler<R>
UnorderedBuffer<T: BufferFormat> (&str, T::format) u# UnorderedAccessView<R, T>
RenderTarget<T: RenderFormat> (&str?, T::format, ColorMask) index RenderTargetView<R, T>
BlendTarget<T: BlendFormat> (&str?, T::format, ColorMask, BlendState) index RenderTargetView<R, T>
DepthTarget<T: DepthFormat> (T::format, DepthState) DepthStencilView<R, T>
StencilTarget<T: StencilFormat> (T::format, StencilState) DepthStencilView<R, T>
DepthStencilTarget<T: DepthStencilFormat> (T::format, DepthState, StencilState) DepthStencilView<R, T>
@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Dec 2, 2015

I believe I solved the main problem with PSO internal type hierarchy and getting it all defined by helper macros. The biggest issue right now is generating the identifier names in those macros. Since concat_idents! is useless, I have to demand all the names provided by the user.

I tried a different approach - to create a new internal module with a user-given name and then just use some predefined simple names inside. However, this turns out to be playing very badly with user-given parameters, which the user expects to be visible, while jumping into a sub-module instantly changes the visibility scope...

As always, any ideas are welcome. It would be nice to get this right from the start, since it affects the API verbosity and complexity.

@kvark kvark referenced this pull request Dec 2, 2015

Closed

Add a changelog #838

@sectopod sectopod force-pushed the sectopod:pso branch from b19f000 to 5b63b43 Dec 5, 2015

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Jan 22, 2016

@cmr thanks! you found quite a few important bits to fix.
(1), (2), (3), (4) - fixed
(6) doesn't work for me. Doing cargo fmt produces: No such file or directory (os error 2) followed by the usage info (for the cargo fmt). We can do it later on.
(7), (8), (9) - fixed
(5), (10) - left for TODO outside of this PR
(11) - doesn't matter for now, since we are only using VAOs whenever GL forces us to do that. EXT versions don't force it. Maybe if we find a better use for them, we'll need to query for EXT stuff too.
(12) not fixed intentionally. It's not a performance critical code, and using mem_unitialized! would only confuse us during any debugging.

@cmr

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

Who gets the honor of pushing the big green button? :)

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Jan 22, 2016

homu!

@cmr

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

Oh right, I forget we use homu now!

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Jan 22, 2016

I wonder if we should could volunterely strip ourselves of the power of the green button. Just looking at it gives me goose bumps. Only @homu should guard the star gate to upstream.

@cmr

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

@homu

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

⌛️ Testing commit 736b0c3 with merge ad9c403...

homu added a commit that referenced this pull request Jan 22, 2016

Auto merge of #828 - sectopod:pso, r=cmr
Pipeline State Objects revolution

Requires gfx-rs/draw_state#34
Fixes #815, fixes #842, fixes #823, fixes #761, fixes #722, fixes #703, fixes #694, fixes #463
Closes #817, closes #640, closes #630, closes #575, closes #571, closes #322, closes #121
Touches #698, #331, #311, #284, #161

Breaking changes:
- `Batch` concept is gone, PSO is the new paradigm
- `Mesh` is gone, but `Slice` is still with us, even if slightly modified
- shader parameters are superseded by the PSO configuration
- VAO, FBO, `Surface`, `Plane` are all gone, they are now hidden GL implementation details
- Users are required to operate on the strongly-typed target/resource views

TODO (note: this is a vastly incomplete list of what's actually done):
- [x] PSO resource - low level
  - [x] resource
  - [x] binding
  - [x] creation
- [x] High level
  - [x] `RenderTargetView` and `DepthStencilView`
    - [x] low-level bindings
    - [x] raw creation
    - [x] typed creation
    - [x] hook up to PSO
  - [x] `ShaderResourceView` and `UnorderedAccessView`
    - [x] low-level bindings
    - [x] raw creation
    - [x] typed creation
    - [x] hook up to PSO
  - [x] move core into a separate lib (#703)
  - [x] remove the Copy constraint from the resources
  - [x] layout matching
      - [x] vertex attributes
      - [x] shader data
      - [x] pixel targets
  - [x] strongly-typed initialization
  - [x] hook to the `Renderer` for drawing
- [x] helper macros
  - [x] structure definition
  - [x] PSO
  - [x] PSO with static init
  - [x] texture format
  - [x] macros tests
- [x] Universal data format spec
    - [x] serialized form
    - [x] strongly-typed form
    - [x] replace `tex::Format`
    - [x] replace `attrib::Format`
- [x] GL backend
    - [x] rewrite `init()` function for windowing backends
    - [x] rewrite `CommandBuffer` implementation to do the heavy lifting
    - [ ] ~~support for structured buffers~~ (can be postponed)
    - [x] Glutin window
    - [x] GLFW window
- [x] Switch the examples to use PSO
  - [x] blend
  - [x] cube
  - [x] deferred
  - [x] flowmap
  - [x] instancing
  - [x] mipmap
  - [x] performance
  - [x] shadow
  - [x] terrain
  - [x] triangle
  - [x] ubo_tilemap
- [x] Clean up
  - [x] remove old `Resources` subtypes
  - [ ] ~~remove shader programs~~
  - [x] remove old meshes and attribute formats
  - [x] remove old shader parameters
  - [x] remove old texture format
  - [x] remove batches
  - [x] remove VAO and FBO
  - [x] remove `Plane`, `Output`, and `Frame`
- [x] Post-clean
  - [x] rename `NewTexture` to `Texture`
  - [x] remove `primitive` from `mesh::Slice`
- [x] Documentation
  - [x] typed PSO
  - [x] universal format

Or, basically, rewrite the whole damn thing ;)
@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Jan 22, 2016

@cmr hohoho, it's happening!
btw, why did you select the commit explicitly? It's not like I can sneak anything in between your comment and @homu response

@cmr

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

habit, nothing personal ;)

@homu

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

💔 Test failed - status

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Jan 22, 2016

@cmr here comes the problem: if I push a fix for beta/nightly and politely ask homu to retry, will it retry the same commit you specified?..

@cmr

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

Not actually sure...

@sectopod

This comment has been minimized.

Copy link
Contributor Author

commented Jan 22, 2016

Well, it should be fixed now. The error was real, and I'm glad that beta/nightly caught it.

@cmr

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

@homu

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

⌛️ Testing commit 3f92272 with merge 64d8fce...

homu added a commit that referenced this pull request Jan 22, 2016

Auto merge of #828 - sectopod:pso, r=cmr
Pipeline State Objects revolution

Requires gfx-rs/draw_state#34
Fixes #815, fixes #842, fixes #823, fixes #761, fixes #722, fixes #703, fixes #694, fixes #463
Closes #817, closes #640, closes #630, closes #575, closes #571, closes #322, closes #121
Touches #698, #331, #311, #284, #161

Breaking changes:
- `Batch` concept is gone, PSO is the new paradigm
- `Mesh` is gone, but `Slice` is still with us, even if slightly modified
- shader parameters are superseded by the PSO configuration
- VAO, FBO, `Surface`, `Plane` are all gone, they are now hidden GL implementation details
- Users are required to operate on the strongly-typed target/resource views

TODO (note: this is a vastly incomplete list of what's actually done):
- [x] PSO resource - low level
  - [x] resource
  - [x] binding
  - [x] creation
- [x] High level
  - [x] `RenderTargetView` and `DepthStencilView`
    - [x] low-level bindings
    - [x] raw creation
    - [x] typed creation
    - [x] hook up to PSO
  - [x] `ShaderResourceView` and `UnorderedAccessView`
    - [x] low-level bindings
    - [x] raw creation
    - [x] typed creation
    - [x] hook up to PSO
  - [x] move core into a separate lib (#703)
  - [x] remove the Copy constraint from the resources
  - [x] layout matching
      - [x] vertex attributes
      - [x] shader data
      - [x] pixel targets
  - [x] strongly-typed initialization
  - [x] hook to the `Renderer` for drawing
- [x] helper macros
  - [x] structure definition
  - [x] PSO
  - [x] PSO with static init
  - [x] texture format
  - [x] macros tests
- [x] Universal data format spec
    - [x] serialized form
    - [x] strongly-typed form
    - [x] replace `tex::Format`
    - [x] replace `attrib::Format`
- [x] GL backend
    - [x] rewrite `init()` function for windowing backends
    - [x] rewrite `CommandBuffer` implementation to do the heavy lifting
    - [ ] ~~support for structured buffers~~ (can be postponed)
    - [x] Glutin window
    - [x] GLFW window
- [x] Switch the examples to use PSO
  - [x] blend
  - [x] cube
  - [x] deferred
  - [x] flowmap
  - [x] instancing
  - [x] mipmap
  - [x] performance
  - [x] shadow
  - [x] terrain
  - [x] triangle
  - [x] ubo_tilemap
- [x] Clean up
  - [x] remove old `Resources` subtypes
  - [ ] ~~remove shader programs~~
  - [x] remove old meshes and attribute formats
  - [x] remove old shader parameters
  - [x] remove old texture format
  - [x] remove batches
  - [x] remove VAO and FBO
  - [x] remove `Plane`, `Output`, and `Frame`
- [x] Post-clean
  - [x] rename `NewTexture` to `Texture`
  - [x] remove `primitive` from `mesh::Slice`
- [x] Documentation
  - [x] typed PSO
  - [x] universal format

Or, basically, rewrite the whole damn thing ;)
@homu

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

☀️ Test successful - status

@homu homu merged commit 3f92272 into gfx-rs:master Jan 22, 2016

2 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details
@cmr

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

🎊 🎉 Great work @sectopod

@gaudecker

This comment has been minimized.

Copy link
Contributor

commented Jan 22, 2016

Oh wow, this finally merged? Maybe I should try to raise Rust Theft Auto back from the dead and try this out 🎉

@kvark

This comment has been minimized.

Copy link
Member

commented Jan 22, 2016

Hooray! 🎆
@gaudecker this should be fun ;) Don't forget to check up with us on gitter in case you have any questions.

@sectopod sectopod deleted the sectopod:pso branch Jan 22, 2016

@kvark kvark referenced this pull request Jan 28, 2016

Closed

Weak PSO and components #853

@kvark kvark referenced this pull request Feb 19, 2016

Closed

Typification #537

@kvark kvark referenced this pull request Mar 9, 2016

Closed

Multi-block PSO #903

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants
You can’t perform that action at this time.