GPUShader/DRW: Add Transform Feedback support.

This is a usefull feature that can be used to do a lot of precomputation on
the GPU instead of the CPU.

Implementation is simple and only covers the most usefull case.

How to use:
- Create shader with transform feedback.
- Create a pass with DRW_STATE_TRANS_FEEDBACK.
- Create a target Gwn_VertBuf (make sure it's big enough).
- Create a shading group with DRW_shgroup_transform_feedback_create().
- Add your draw calls to the shading group.
- Render your pass normaly.

Current limitation:
- Only one output buffer.
- Cannot pause/resume tfb rendering to interleave with normal drawcalls.
- Cannot get the number of verts drawn.
This commit is contained in:
2018-05-16 12:47:15 +02:00
parent a3f4c72ec9
commit a25856f2a8
8 changed files with 113 additions and 5 deletions

View File

@@ -268,7 +268,10 @@ GPUShader *GPU_shader_create(const char *vertexcode,
geocode,
libcode,
defines,
GPU_SHADER_FLAGS_NONE);
GPU_SHADER_FLAGS_NONE,
GPU_SHADER_TFB_NONE,
NULL,
0);
}
#define DEBUG_SHADER_NONE ""
@@ -323,7 +326,10 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
const char *geocode,
const char *libcode,
const char *defines,
const int flags)
const int flags,
const GPUShaderTFBType tf_type,
const char **tf_names,
const int tf_count)
{
#ifdef WITH_OPENSUBDIV
bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0;
@@ -469,6 +475,13 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
}
#endif
if (tf_names != NULL) {
glTransformFeedbackVaryings(shader->program, tf_count, tf_names, GL_INTERLEAVED_ATTRIBS);
/* Primitive type must be setup */
BLI_assert(tf_type != GPU_SHADER_TFB_NONE);
shader->feedback_transform_type = tf_type;
}
glLinkProgram(shader->program);
glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
if (!status) {
@@ -527,6 +540,27 @@ void GPU_shader_unbind(void)
glUseProgram(0);
}
bool GPU_shader_transform_feedback_enable(GPUShader *shader, unsigned int vbo_id)
{
if (shader->feedback_transform_type == GPU_SHADER_TFB_NONE) {
return false;
}
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo_id);
switch (shader->feedback_transform_type) {
case GPU_SHADER_TFB_POINTS: glBeginTransformFeedback(GL_POINTS); return true;
case GPU_SHADER_TFB_LINES: glBeginTransformFeedback(GL_LINES); return true;
case GPU_SHADER_TFB_TRIANGLES: glBeginTransformFeedback(GL_TRIANGLES); return true;
default: return false;
}
}
void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader))
{
glEndTransformFeedback();
}
void GPU_shader_free(GPUShader *shader)
{
BLI_assert(shader);