-
Notifications
You must be signed in to change notification settings - Fork 0
render plan api plan
Matthew Egeler edited this page Dec 16, 2019
·
18 revisions
Implementation details:
- A graffiks render pass can usually be a vulkan subpass
- A graffiks render pass should sometimes be a full vulkan "render pass", such as if the pass has asked for an input that requires multiple pixel inputs from the previous pass for a given fragment in the new pass (this is a subpass limitation). This is required for things like blurring or ambient occlusion
- Multiple graffiks render passes could actually become a single subpass if a set of render passes do not depend on eachother. This could potentially reduce overhead, but needs to be tested.
Notes:
- Right now, our functions are "[set/def]shaderset_attr*" and are provided to the shaderset as a whole, basically assuming that the first shader are receiving the attributes. I feel like "[set/def]_shader_attr" that specifies a specific shader index within the set makes more sense.
- Instead of accepting gfks_mesh objects, we could accept gfks_vertex_buffer objects. This would allow the user of the engine to manage vertex buffers, and prevent us from creating a separate vertex buffer for each mesh. Instead of accepting a mesh array, we could simply accept a single gfks_vertex_buffer. How different mesh topologies (such as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) play into this is TBD. We may want to support different meshes with different topo settings.
- Regardless of dependency settings, the engine needs to put render passes into a linear order. Instead of constructing a dependency graph for this, we could simply require the user of the engine order them for us as well as define dependencies for multithreading/subpass dependency purposes. This would be faster, because we no longer need to spend cpu time determining the order -- and generally the user of the engine knows the static order, and compiles right into that order.
// Create render plan objects
gfks_render_plan *deferred_render_plan = gfks_create_render_plan(context);
gfks_render_pass *geometry_pass = gfks_create_render_pass(context);
gfks_render_pass *diffuse_pass = gfks_create_render_pass(context);
gfks_render_pass *specular_pass = gfks_create_render_pass(context);
gfks_render_pass *composite_pass = gfks_create_render_pass(context);
// Add passes to our plan (order does not matter)
deferred_render_plan->add_render_pass(deferred_render_plan, geometry_pass);
deferred_render_plan->add_render_pass(deferred_render_plan, diffuse_pass);
deferred_render_plan->add_render_pass(deferred_render_plan, specular_pass);
deferred_render_plan->add_render_pass(deferred_render_plan, composite_pass);
// Define dependencies
diffuse_pass->depends_on(diffuse_pass, geometry_pass);
specular_pass->depends_on(specular_pass, geometry_pass);
composite_pass->depends_on(composite_pass, diffuse_pass);
composite_pass->depends_on(composite_pass, specular_pass);
// Set up render pass info
//
// def_shaderset_attr_* defines the existance of an input for a specified chain of shaders -
// the 2nd arg is always the shaderset index within the pass info we want to feed this input to
// the 3nd arg is always an input index for the shader. The data type within the shader depends on the call.
uint32_t shaderset_index = diffuse_pass->add_shaderset(shaders);
diffuse_pass->def_shaderset_attr_vertex_location(diffuse_pass, shaderset_index, 0);
diffuse_pass->def_shaderset_attr_vertex_color(diffuse_pass, shaderset_index, 1);
diffuse_pass->def_shaderset_attr_global_transformation_matrix(diffuse_pass, shaderset_index, 2);
diffuse_pass->def_shaderset_attr_mesh_transformation_matrix(diffuse_pass, shaderset_index, 3);
diffuse_pass->def_shaderset_attr_previous_pass(diffuse_pass, shaderset_index, 4, geometry_pass); // should error here if we don't have the dep
// etc etc for other passes
// Define the surface(s) that we want to be presented to
deferred_render_plan->add_presentation_surface(deferred_render_plan, surface);
// All done planning - finalize the plan!
deferred_render_plan->finalize_plan();
// Define meshes to draw
diffuse_pass->set_draw_meshes_for_shader_set(diffuse_pass, shaderset_index, mesh_array);
// Or, if we wanted to draw some arbitrary vertices not backed by a buffer
diffuse_pass->set_arbitrary_vertex_count(diffuse_pass, 3);
// Give our passes some input data
//
// set_shaderset_attr_* sets the value of a specified attr, and can be called any number of times
// 2nd arg is always the input index for the shader (we already have a unique ID, no need to make another)
diffuse_pass->set_shaderset_attr_vertex_color(diffuse_pass, 1, mesh_index, color_array);
diffuse_pass->set_shaderset_attr_global_transformation_matrix(diffuse_pass, 2, matrix);
diffuse_pass->set_shaderset_attr_mesh_transformation_matrix(diffuse_pass, 3, mesh_index, matrix);
diffuse_pass->apply_settings(diffuse_pass);
// etc etc for other passes
// Draw loop
while (drawing frames) {
deferred_render_plan.execute()
}