diff --git a/doc/python_api/examples/gpu.11.py b/doc/python_api/examples/gpu.11.py new file mode 100644 index 00000000000..3988b379af9 --- /dev/null +++ b/doc/python_api/examples/gpu.11.py @@ -0,0 +1,92 @@ +""" +Custom compute shader (using image store) and vertex/fragment shader +-------------------------------------------------------------------- + +This is an example of how to use a custom compute shader to write to a texture and then use that texture in a vertex/fragment shader. +The expected result is a 2x2 plane (size of the default cube), which changes color from a green-black gradient to a green-red gradient, +based on current time. +""" +import bpy +import gpu +from mathutils import Matrix +from gpu_extras.batch import batch_for_shader +import array +import time + +start_time = time.time() + +size = 128 +texture = gpu.types.GPUTexture((size, size), format='RGBA32F') + +# Create the compute shader to write to the texture +compute_shader_info = gpu.types.GPUShaderCreateInfo() +compute_shader_info.image(0, 'RGBA32F', "FLOAT_2D", "img_output", qualifiers={"WRITE"}) +compute_shader_info.compute_source(''' +void main() +{ + vec4 pixel = vec4( + sin(time / 1.0), + gl_GlobalInvocationID.y/128.0, + 0.0, + 1.0 + ); + imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel); +}''') +compute_shader_info.push_constant('FLOAT', "time") +compute_shader_info.local_group_size(1, 1) +compute_shader = gpu.shader.create_from_info(compute_shader_info) + +# Create the shader to draw the texture +vert_out = gpu.types.GPUStageInterfaceInfo("my_interface") +vert_out.smooth('VEC2', "uvInterp") +shader_info = gpu.types.GPUShaderCreateInfo() +shader_info.push_constant('MAT4', "viewProjectionMatrix") +shader_info.push_constant('MAT4', "modelMatrix") +shader_info.sampler(0, 'FLOAT_2D', "img_input") +shader_info.vertex_in(0, 'VEC2', "position") +shader_info.vertex_in(1, 'VEC2', "uv") +shader_info.vertex_out(vert_out) +shader_info.fragment_out(0, 'VEC4', "FragColor") + +shader_info.vertex_source( + "void main()" + "{" + " uvInterp = uv;" + " gl_Position = viewProjectionMatrix * modelMatrix * vec4(position, 0.0, 1.0);" + "}" +) + +shader_info.fragment_source( + "void main()" + "{" + " FragColor = texture(img_input, uvInterp);" + "}" +) + +shader = gpu.shader.create_from_info(shader_info) + +batch = batch_for_shader( + shader, 'TRI_FAN', + { + "position": ((-1, -1), (1, -1), (1, 1), (-1, 1)), + "uv": ((0, 0), (1, 0), (1, 1), (0, 1)), + }, +) + +def draw(): + shader.uniform_float("modelMatrix", Matrix.Translation((0, 0, 0)) @ Matrix.Scale(1, 4)) + shader.uniform_float("viewProjectionMatrix", bpy.context.region_data.perspective_matrix) + shader.uniform_sampler("img_input", texture) + batch.draw(shader) + compute_shader.image('img_output', texture) + compute_shader.uniform_float("time", time.time() - start_time) + gpu.compute.dispatch(compute_shader, 128, 128, 1) + +def drawTimer(): + for area in bpy.context.screen.areas: + if area.type == 'VIEW_3D': + area.tag_redraw() + return 1.0 / 60.0 + +bpy.app.timers.register(drawTimer) +bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW') diff --git a/source/blender/python/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt index 868eb1c713c..d3fad4318c3 100644 --- a/source/blender/python/gpu/CMakeLists.txt +++ b/source/blender/python/gpu/CMakeLists.txt @@ -34,6 +34,7 @@ set(SRC gpu_py_uniformbuffer.cc gpu_py_vertex_buffer.cc gpu_py_vertex_format.cc + gpu_py_compute.cc gpu_py.h gpu_py_api.h @@ -53,6 +54,7 @@ set(SRC gpu_py_uniformbuffer.h gpu_py_vertex_buffer.h gpu_py_vertex_format.h + gpu_py_compute.h ) set(LIB diff --git a/source/blender/python/gpu/gpu_py_api.cc b/source/blender/python/gpu/gpu_py_api.cc index fea6b0e4be0..2043405ce2d 100644 --- a/source/blender/python/gpu/gpu_py_api.cc +++ b/source/blender/python/gpu/gpu_py_api.cc @@ -22,6 +22,7 @@ #include "gpu_py_select.h" #include "gpu_py_state.h" #include "gpu_py_types.h" +#include "gpu_py_compute.h" #include "gpu_py.h" #include "gpu_py_api.h" /* Own include. */ @@ -77,6 +78,9 @@ PyObject *BPyInit_gpu() PyModule_AddObject(mod, "texture", (submodule = bpygpu_texture_init())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + PyModule_AddObject(mod, "compute", (submodule = bpygpu_compute_init())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + return mod; } diff --git a/source/blender/python/gpu/gpu_py_capabilities.cc b/source/blender/python/gpu/gpu_py_capabilities.cc index c141d7cc22b..bdd2544ab47 100644 --- a/source/blender/python/gpu/gpu_py_capabilities.cc +++ b/source/blender/python/gpu/gpu_py_capabilities.cc @@ -230,6 +230,48 @@ static PyObject *pygpu_hdr_support_get(PyObject * /*self*/) return PyBool_FromLong(GPU_hdr_support()); } +PyDoc_STRVAR(pygpu_max_work_group_count_get_doc, + ".. function:: max_work_group_count_get(index)\n" + "\n" + " Get maximum number of work groups that may be dispatched to a compute shader.\n" + "\n" + " :arg index: Index of the dimension.\n" + " :type index: int\n" + " :return: Maximum number of work groups for the queried dimension.\n" + " :rtype: int\n"); +static PyObject *pygpu_max_work_group_count_get(PyObject * /*self*/, PyObject *args) +{ + int index; + if (!PyArg_ParseTuple(args, "i", &index)) { + return nullptr; + } + + const int max_work_group_count = GPU_max_work_group_count(index); + + return PyLong_FromLong(max_work_group_count); +} + +PyDoc_STRVAR(pygpu_max_work_group_size_get_doc, + ".. function:: max_work_group_size_get(index)\n" + "\n" + " Get maximum size of a work group that may be dispatched to a compute shader.\n" + "\n" + " :arg index: Index of the dimension.\n" + " :type index: int\n" + " :return: Maximum size of a work group for the queried dimension.\n" + " :rtype: int\n"); +static PyObject *pygpu_max_work_group_size_get(PyObject * /*self*/, PyObject *args) +{ + int index; + if (!PyArg_ParseTuple(args, "i", &index)) { + return nullptr; + } + + const int max_work_group_size = GPU_max_work_group_size(index); + + return PyLong_FromLong(max_work_group_size); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -304,7 +346,16 @@ static PyMethodDef pygpu_capabilities__tp_methods[] = { (PyCFunction)pygpu_hdr_support_get, METH_NOARGS, pygpu_hdr_support_get_doc}, - + {"max_work_group_count_get", + (PyCFunction)pygpu_max_work_group_count_get, + METH_VARARGS, + pygpu_max_work_group_count_get_doc, + }, + {"max_work_group_size_get", + (PyCFunction)pygpu_max_work_group_size_get, + METH_VARARGS, + pygpu_max_work_group_size_get_doc, + }, {nullptr, nullptr, 0, nullptr}, }; diff --git a/source/blender/python/gpu/gpu_py_compute.cc b/source/blender/python/gpu/gpu_py_compute.cc new file mode 100644 index 00000000000..79052c7047e --- /dev/null +++ b/source/blender/python/gpu/gpu_py_compute.cc @@ -0,0 +1,145 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bpygpu + * + * - Use `bpygpu_` for local API. + * - Use `BPyGPU` for public API. + */ + +#include + +#include "BLI_utildefines.h" + +#include "GPU_shader.h" +#include "GPU_texture.h" +#include "GPU_uniform_buffer.h" +#include "GPU_compute.h" +#include "GPU_state.h" +#include "GPU_capabilities.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_compat.h" +#include "../generic/python_utildefines.h" + +#include "../mathutils/mathutils.h" + +#include "gpu_py.h" +#include "gpu_py_texture.h" +#include "gpu_py_uniformbuffer.h" +#include "gpu_py_vertex_format.h" +#include "gpu_py_shader.h" +#include "gpu_py_compute.h" /* own include */ + +PyDoc_STRVAR( + pygpu_compute_dispatch_doc, + ".. function:: dispatch(shader, groups_x_len, groups_y_len, groups_z_len)\n" + "\n" + " Dispatches GPU compute.\n" + "\n" + " :arg shader: The shader that you want to dispatch.\n" + " :type shader: :class:`gpu.types.GPUShader`\n" + " :arg groups_x_len: Int for group x length:\n" + " :type groups_x_len: int\n" + " :arg groups_y_len: Int for group y length:\n" + " :type groups_y_len: int\n" + " :arg groups_z_len: Int for group z length:\n" + " :type groups_z_len: int\n" + " :return: Shader object.\n" + " :rtype: :class:`bpy.types.GPUShader`\n"); +static PyObject *pygpu_compute_dispatch(PyObject * /*self*/, PyObject *args, PyObject *kwds) +{ + BPyGPUShader *py_shader; + int groups_x_len; + int groups_y_len; + int groups_z_len; + + static const char *_keywords[] = {"shader", "groups_x_len", "groups_y_len", "groups_z_len", nullptr}; + static _PyArg_Parser _parser = { + PY_ARG_PARSER_HEAD_COMPAT() + "O" /* `shader` */ + "i" /* `groups_x_len` */ + "i" /* `groups_y_len` */ + "i" /* `groups_z_len` */ + ":dispatch", + _keywords, + nullptr, + }; + if (_PyArg_ParseTupleAndKeywordsFast(args, + kwds, + &_parser, + &py_shader, + &groups_x_len, + &groups_y_len, + &groups_z_len)) + { + + if (!BPyGPUShader_Check(py_shader)) { + PyErr_Format(PyExc_TypeError, "Expected a GPUShader, got %s", Py_TYPE(py_shader)->tp_name); + return nullptr; + } + + // Check that groups do not exceed GPU_max_work_group_count() + const int max_work_group_count_x = GPU_max_work_group_count(0); + const int max_work_group_count_y = GPU_max_work_group_count(1); + const int max_work_group_count_z = GPU_max_work_group_count(2); + + // Report back to the user both the requested and the maximum supported value + if (groups_x_len > GPU_max_work_group_count(0)) { + PyErr_Format(PyExc_ValueError, "groups_x_len (%d) exceeds maximum supported value (max work group count: %d)", groups_x_len, max_work_group_count_x); + return nullptr; + } + if (groups_y_len > GPU_max_work_group_count(1)) { + PyErr_Format(PyExc_ValueError, "groups_y_len (%d) exceeds maximum supported value (max work group count: %d)", groups_y_len, max_work_group_count_y); + return nullptr; + } + if (groups_z_len > GPU_max_work_group_count(2)) { + PyErr_Format(PyExc_ValueError, "groups_z_len (%d) exceeds maximum supported value (max work group count: %d)", groups_z_len, max_work_group_count_z); + return nullptr; + } + + GPUShader *shader = py_shader->shader; + GPU_compute_dispatch(shader, groups_x_len, groups_y_len, groups_z_len); + GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); + } + Py_RETURN_NONE; +} + +/* -------------------------------------------------------------------- */ +/** \name Module + * \{ */ + +static PyMethodDef pygpu_compute__tp_methods[] = { + {"dispatch", (PyCFunction)pygpu_compute_dispatch, METH_VARARGS | METH_KEYWORDS, pygpu_compute_dispatch_doc}, + {nullptr, nullptr, 0, nullptr}, +}; + +#if (defined(__GNUC__) && !defined(__clang__)) +# pragma GCC diagnostic pop +#endif + +PyDoc_STRVAR(pygpu_compute__tp_doc, "This module provides access to the global GPU compute functions"); +static PyModuleDef pygpu_compute_module_def = { + /*m_base*/ PyModuleDef_HEAD_INIT, + /*m_name*/ "gpu.compute", + /*m_doc*/ pygpu_compute__tp_doc, + /*m_size*/ 0, + /*m_methods*/ pygpu_compute__tp_methods, + /*m_slots*/ nullptr, + /*m_traverse*/ nullptr, + /*m_clear*/ nullptr, + /*m_free*/ nullptr, +}; + +PyObject *bpygpu_compute_init() +{ + PyObject *submodule; + + submodule = bpygpu_create_module(&pygpu_compute_module_def); + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_compute.h b/source/blender/python/gpu/gpu_py_compute.h new file mode 100644 index 00000000000..75d930e7329 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_compute.h @@ -0,0 +1,19 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bpygpu + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject *bpygpu_compute_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/python/gpu/gpu_py_shader.cc b/source/blender/python/gpu/gpu_py_shader.cc index 23f601f0ab5..aa860c8e238 100644 --- a/source/blender/python/gpu/gpu_py_shader.cc +++ b/source/blender/python/gpu/gpu_py_shader.cc @@ -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, diff --git a/source/blender/python/gpu/gpu_py_shader.h b/source/blender/python/gpu/gpu_py_shader.h index f0faa8165ce..28f6883c2ad 100644 --- a/source/blender/python/gpu/gpu_py_shader.h +++ b/source/blender/python/gpu/gpu_py_shader.h @@ -60,6 +60,7 @@ typedef struct BPyGPUShaderCreateInfo { /* Just to keep a user to prevent freeing buf's we're using. */ PyObject *vertex_source; PyObject *fragment_source; + PyObject *compute_source; PyObject *typedef_source; PyObject *references; #endif diff --git a/source/blender/python/gpu/gpu_py_shader_create_info.cc b/source/blender/python/gpu/gpu_py_shader_create_info.cc index d144f8901ec..32db4a19ef5 100644 --- a/source/blender/python/gpu/gpu_py_shader_create_info.cc +++ b/source/blender/python/gpu/gpu_py_shader_create_info.cc @@ -20,8 +20,9 @@ #include "../generic/python_compat.h" #include "gpu_py_shader.h" /* own include */ +#include "gpu_py_texture.h" -//#define USE_PYGPU_SHADER_INFO_IMAGE_METHOD +#define USE_PYGPU_SHADER_INFO_IMAGE_METHOD using blender::gpu::shader::DualBlend; using blender::gpu::shader::Frequency; @@ -156,6 +157,53 @@ static const PyC_StringEnumItems pygpu_dualblend_items[] = { {0, nullptr}, }; +#define PYDOC_TEX_FORMAT_ITEMS \ + " - ``RGBA8UI``\n" \ + " - ``RGBA8I``\n" \ + " - ``RGBA8``\n" \ + " - ``RGBA32UI``\n" \ + " - ``RGBA32I``\n" \ + " - ``RGBA32F``\n" \ + " - ``RGBA16UI``\n" \ + " - ``RGBA16I``\n" \ + " - ``RGBA16F``\n" \ + " - ``RGBA16``\n" \ + " - ``RG8UI``\n" \ + " - ``RG8I``\n" \ + " - ``RG8``\n" \ + " - ``RG32UI``\n" \ + " - ``RG32I``\n" \ + " - ``RG32F``\n" \ + " - ``RG16UI``\n" \ + " - ``RG16I``\n" \ + " - ``RG16F``\n" \ + " - ``RG16``\n" \ + " - ``R8UI``\n" \ + " - ``R8I``\n" \ + " - ``R8``\n" \ + " - ``R32UI``\n" \ + " - ``R32I``\n" \ + " - ``R32F``\n" \ + " - ``R16UI``\n" \ + " - ``R16I``\n" \ + " - ``R16F``\n" \ + " - ``R16``\n" \ + " - ``R11F_G11F_B10F``\n" \ + " - ``DEPTH32F_STENCIL8``\n" \ + " - ``DEPTH24_STENCIL8``\n" \ + " - ``SRGB8_A8``\n" \ + " - ``RGB16F``\n" \ + " - ``SRGB8_A8_DXT1``\n" \ + " - ``SRGB8_A8_DXT3``\n" \ + " - ``SRGB8_A8_DXT5``\n" \ + " - ``RGBA8_DXT1``\n" \ + " - ``RGBA8_DXT3``\n" \ + " - ``RGBA8_DXT5``\n" \ + " - ``DEPTH_COMPONENT32F``\n" \ + " - ``DEPTH_COMPONENT24``\n" \ + " - ``DEPTH_COMPONENT16``\n" +extern const PyC_StringEnumItems pygpu_tex_format_items[]; + /* -------------------------------------------------------------------- */ /** \name GPUStageInterfaceInfo Methods * \{ */ @@ -607,7 +655,7 @@ PyDoc_STRVAR( " :arg slot: The image resource index.\n" " :type slot: int\n" " :arg format: The GPUTexture format that is passed to the shader. Possible values are:\n" - "" PYDOC_TEX_FORMAT_ITEMS + "\n" PYDOC_TEX_FORMAT_ITEMS " :type format: str\n" " :arg type: The data type describing how the image is to be read in the shader. " "Possible values are:\n" @@ -902,6 +950,51 @@ static PyObject *pygpu_shader_info_vertex_source(BPyGPUShaderCreateInfo *self, P Py_RETURN_NONE; } +PyDoc_STRVAR( + pygpu_shader_info_compute_source_doc, + ".. method:: compute_source(source)\n" + "\n" + " compute shader source code written in GLSL.\n" + "\n" + " Example:\n" + "\n" + " .. code-block:: python\n" + "\n" + " \"\"\"void main() {\n" + " int2 index = int2(gl_GlobalInvocationID.xy);\n" + " vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n" + " imageStore(img_output, index, color);\n" + " }\"\"\"\n" + "\n" + " :arg source: The compute shader source code.\n" + " :type source: str\n" + "\n" + " .. seealso:: `GLSL Cross Compilation " + "`__\n"); +static PyObject *pygpu_shader_info_compute_source(BPyGPUShaderCreateInfo *self, PyObject *o) +{ + const char *compute_source = PyUnicode_AsUTF8(o); + if (compute_source == nullptr) { + PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name); + return nullptr; + } + +#ifdef USE_GPU_PY_REFERENCES + if (self->compute_source) { + Py_DECREF(self->compute_source); + } + + self->compute_source = o; + Py_INCREF(o); +#endif + + ShaderCreateInfo *info = reinterpret_cast(self->info); + info->compute_source("common_colormanagement_lib.glsl"); + info->compute_source_generated = compute_source; + + Py_RETURN_NONE; +} + PyDoc_STRVAR( pygpu_shader_info_fragment_source_doc, ".. method:: fragment_source(source)\n" @@ -1025,6 +1118,31 @@ static PyObject *pygpu_shader_info_define(BPyGPUShaderCreateInfo *self, PyObject Py_RETURN_NONE; } +PyDoc_STRVAR(pygpu_shader_info_local_group_size_doc, + ".. method:: local_group_size(x, y=-1, z=-1)\n" + "\n" + " Specify the local group size for compute shaders.\n" + "\n" + " :arg x: The local group size in the x dimension.\n" + " :type x: int\n" + " :arg y: The local group size in the y dimension. Optional. Defaults to -1.\n" + " :type y: int\n" + " :arg z: The local group size in the z dimension. Optional. Defaults to -1.\n" + " :type z: int\n"); +static PyObject *pygpu_shader_info_local_group_size(BPyGPUShaderCreateInfo *self, PyObject *args) +{ + int x = -1, y = -1, z = -1; + + if (!PyArg_ParseTuple(args, "i|ii:local_group_size", &x, &y, &z)) { + return nullptr; + } + + ShaderCreateInfo *info = reinterpret_cast(self->info); + info->local_group_size(x, y, z); + + Py_RETURN_NONE; +} + static PyMethodDef pygpu_shader_info__tp_methods[] = { {"vertex_in", (PyCFunction)pygpu_shader_info_vertex_in, @@ -1064,11 +1182,19 @@ static PyMethodDef pygpu_shader_info__tp_methods[] = { (PyCFunction)pygpu_shader_info_fragment_source, METH_O, pygpu_shader_info_fragment_source_doc}, + {"compute_source", + (PyCFunction)pygpu_shader_info_compute_source, + METH_O, + pygpu_shader_info_compute_source_doc}, {"typedef_source", (PyCFunction)pygpu_shader_info_typedef_source, METH_O, pygpu_shader_info_typedef_source_doc}, {"define", (PyCFunction)pygpu_shader_info_define, METH_VARARGS, pygpu_shader_info_define_doc}, + {"local_group_size", + (PyCFunction)pygpu_shader_info_local_group_size, + METH_VARARGS, + pygpu_shader_info_local_group_size_doc}, {nullptr, nullptr, 0, nullptr}, }; @@ -1098,6 +1224,7 @@ static int pygpu_shader_info__tp_traverse(PyObject *self, visitproc visit, void BPyGPUShaderCreateInfo *py_info = reinterpret_cast(self); Py_VISIT(py_info->vertex_source); Py_VISIT(py_info->fragment_source); + Py_VISIT(py_info->compute_source); Py_VISIT(py_info->references); return 0; } @@ -1107,6 +1234,7 @@ static int pygpu_shader_info__tp_clear(PyObject *self) BPyGPUShaderCreateInfo *py_info = reinterpret_cast(self); Py_CLEAR(py_info->vertex_source); Py_CLEAR(py_info->fragment_source); + Py_CLEAR(py_info->compute_source); Py_CLEAR(py_info->references); return 0; } @@ -1125,8 +1253,10 @@ static void pygpu_shader_info__tp_dealloc(PyObject *self) pygpu_shader_info__tp_clear(self); Py_XDECREF(py_info->vertex_source); Py_XDECREF(py_info->fragment_source); + Py_XDECREF(py_info->compute_source); Py_XDECREF(py_info->references); } + #endif Py_TYPE(self)->tp_free((PyObject *)self); @@ -1231,6 +1361,7 @@ PyObject *BPyGPUShaderCreateInfo_CreatePyObject(GPUShaderCreateInfo *info) self = (BPyGPUShaderCreateInfo *)_PyObject_GC_New(&BPyGPUShaderCreateInfo_Type); self->vertex_source = nullptr; self->fragment_source = nullptr; + self->compute_source = nullptr; self->typedef_source = nullptr; self->references = PyList_New(0); #else diff --git a/source/blender/python/gpu/gpu_py_texture.cc b/source/blender/python/gpu/gpu_py_texture.cc index ab347bf9131..e017340feb7 100644 --- a/source/blender/python/gpu/gpu_py_texture.cc +++ b/source/blender/python/gpu/gpu_py_texture.cc @@ -34,7 +34,7 @@ /** \name GPUTexture Common Utilities * \{ */ -static const PyC_StringEnumItems pygpu_textureformat_items[] = { +const PyC_StringEnumItems pygpu_textureformat_items[] = { {GPU_RGBA8UI, "RGBA8UI"}, {GPU_RGBA8I, "RGBA8I"}, {GPU_RGBA8, "RGBA8"}, diff --git a/source/blender/python/gpu/gpu_py_texture.h b/source/blender/python/gpu/gpu_py_texture.h index c2ab528bcee..ad49ccbec4f 100644 --- a/source/blender/python/gpu/gpu_py_texture.h +++ b/source/blender/python/gpu/gpu_py_texture.h @@ -15,6 +15,7 @@ extern "C" { #endif extern PyTypeObject BPyGPUTexture_Type; +extern const struct PyC_StringEnumItems pygpu_textureformat_items[]; #define BPyGPUTexture_Check(v) (Py_TYPE(v) == &BPyGPUTexture_Type) diff --git a/source/blender/python/gpu/gpu_py_types.h b/source/blender/python/gpu/gpu_py_types.h index 91be58ac4e7..8e391aa3889 100644 --- a/source/blender/python/gpu/gpu_py_types.h +++ b/source/blender/python/gpu/gpu_py_types.h @@ -19,6 +19,7 @@ #include "gpu_py_uniformbuffer.h" #include "gpu_py_vertex_buffer.h" #include "gpu_py_vertex_format.h" +#include "gpu_py_compute.h" #ifdef __cplusplus extern "C" {