Initial exposure of compute dispatch and image store in Python API

Motivation: When discussing with @Jeroen-Bakker and @aras_p about how to
approach sorting when rendering Gaussian splats in Blender, we realised that
compute shaders could help there (and have many other use cases), and that also
due to Blender 4.0 being on OpenGL >= 4.3, we can now rely on compute shaders
existing.

This PR is an initial pass for that functionality. It comes with a Python example, which
runs a compute shader and saves the output to a texture, which is then rendered in the
viewport.

There is no exposed support for storage buffers yet, but I expect I'll be able to work on
them soon if this is accepted.

The newly added parts are:
1. `gpu.compute.dispatch()`
2. a way set the compute source to `GPUShaderCreateInfo`: `shader_info.compute_source()`
3. a way to set the image store for `GPUShaderCreateInfo`: `shader_info.image()`
4. a way to set the `local_group_size` for `GPUShaderCreateInfo`: `shader_info.local_group_size(x,y,z)`
5. a way to get `max_work_group_size` from capabilities: `gpu.capabilities.max_work_group_size_get(index)`
6. a way to get `max_work_group_count` from capabilities: `gpu.capabilities.max_work_group_count_get(index)`

Pull Request: https://projects.blender.org/blender/blender/pulls/114238
This commit is contained in:
Jure Triglav
2023-11-23 14:23:26 +01:00
committed by Jeroen Bakker
parent b12a87b28a
commit 319ff28b7b
12 changed files with 487 additions and 4 deletions

View File

@@ -550,6 +550,38 @@ static PyObject *pygpu_shader_uniform_sampler(BPyGPUShader *self, PyObject *args
Py_RETURN_NONE;
}
PyDoc_STRVAR(pygpu_shader_image_doc,
".. method:: image(name, texture)\n"
"\n"
" Specify the value of an image variable for the current GPUShader.\n"
"\n"
" :arg name: Name of the image variable to which the texture is to be bound.\n"
" :type name: str\n"
" :arg texture: Texture to attach.\n"
" :type texture: :class:`gpu.types.GPUTexture`\n");
static PyObject *pygpu_shader_image(BPyGPUShader *self, PyObject *args)
{
const char *name;
BPyGPUTexture *py_texture;
if (!PyArg_ParseTuple(
args, "sO!:GPUShader.image", &name, &BPyGPUTexture_Type, &py_texture))
{
return nullptr;
}
GPU_shader_bind(self->shader);
int image_unit = GPU_shader_get_sampler_binding(self->shader, name);
if (image_unit == -1) {
PyErr_Format(PyExc_ValueError, "Image '%s' not found in shader", name);
return nullptr;
}
GPU_texture_image_bind(py_texture->tex, image_unit);
Py_RETURN_NONE;
}
PyDoc_STRVAR(
pygpu_shader_uniform_block_doc,
".. method:: uniform_block(name, ubo)\n"
@@ -700,6 +732,10 @@ static PyMethodDef pygpu_shader__tp_methods[] = {
(PyCFunction)pygpu_shader_uniform_sampler,
METH_VARARGS,
pygpu_shader_uniform_sampler_doc},
{"image",
(PyCFunction)pygpu_shader_image,
METH_VARARGS,
pygpu_shader_image_doc},
{"uniform_block",
(PyCFunction)pygpu_shader_uniform_block,
METH_VARARGS,