Blender V5.0
gpu_py_texture.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13
14#include <Python.h>
15
16#include "BLI_math_base.h"
17#include "BLI_string_utf8.h"
18
19#include "DNA_image_types.h"
20
21#include "GPU_context.hh"
22#include "GPU_texture.hh"
23
24#include "BKE_image.hh"
25
27#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
28
29#include "gpu_py.hh"
30#include "gpu_py_buffer.hh"
31
32#include "gpu_py_texture.hh" /* own include */
33
34/* -------------------------------------------------------------------- */
37
39 {int(blender::gpu::TextureFormat::UINT_8_8_8_8), "RGBA8UI"},
40 {int(blender::gpu::TextureFormat::SINT_8_8_8_8), "RGBA8I"},
41 {int(blender::gpu::TextureFormat::UNORM_8_8_8_8), "RGBA8"},
42 {int(blender::gpu::TextureFormat::UINT_32_32_32_32), "RGBA32UI"},
43 {int(blender::gpu::TextureFormat::SINT_32_32_32_32), "RGBA32I"},
44 {int(blender::gpu::TextureFormat::SFLOAT_32_32_32_32), "RGBA32F"},
45 {int(blender::gpu::TextureFormat::UINT_16_16_16_16), "RGBA16UI"},
46 {int(blender::gpu::TextureFormat::SINT_16_16_16_16), "RGBA16I"},
47 {int(blender::gpu::TextureFormat::SFLOAT_16_16_16_16), "RGBA16F"},
48 {int(blender::gpu::TextureFormat::UNORM_16_16_16_16), "RGBA16"},
49 {int(blender::gpu::TextureFormat::UINT_8_8), "RG8UI"},
50 {int(blender::gpu::TextureFormat::SINT_8_8), "RG8I"},
51 {int(blender::gpu::TextureFormat::UNORM_8_8), "RG8"},
52 {int(blender::gpu::TextureFormat::UINT_32_32), "RG32UI"},
53 {int(blender::gpu::TextureFormat::SINT_32_32), "RG32I"},
54 {int(blender::gpu::TextureFormat::SFLOAT_32_32), "RG32F"},
55 {int(blender::gpu::TextureFormat::UINT_16_16), "RG16UI"},
56 {int(blender::gpu::TextureFormat::SINT_16_16), "RG16I"},
57 {int(blender::gpu::TextureFormat::SFLOAT_16_16), "RG16F"},
58 {int(blender::gpu::TextureFormat::UNORM_16_16), "RG16"},
59 {int(blender::gpu::TextureFormat::UINT_8), "R8UI"},
60 {int(blender::gpu::TextureFormat::SINT_8), "R8I"},
61 {int(blender::gpu::TextureFormat::UNORM_8), "R8"},
62 {int(blender::gpu::TextureFormat::UINT_32), "R32UI"},
63 {int(blender::gpu::TextureFormat::SINT_32), "R32I"},
64 {int(blender::gpu::TextureFormat::SFLOAT_32), "R32F"},
65 {int(blender::gpu::TextureFormat::UINT_16), "R16UI"},
66 {int(blender::gpu::TextureFormat::SINT_16), "R16I"},
67 {int(blender::gpu::TextureFormat::SFLOAT_16), "R16F"},
68 {int(blender::gpu::TextureFormat::UNORM_16), "R16"},
69 {int(blender::gpu::TextureFormat::UFLOAT_11_11_10), "R11F_G11F_B10F"},
70 {int(blender::gpu::TextureFormat::SFLOAT_32_DEPTH_UINT_8), "DEPTH32F_STENCIL8"},
71 {GPU_DEPTH24_STENCIL8_DEPRECATED, "DEPTH24_STENCIL8"},
72 {int(blender::gpu::TextureFormat::SRGBA_8_8_8_8), "SRGB8_A8"},
73 {int(blender::gpu::TextureFormat::SFLOAT_16_16_16), "RGB16F"},
74 {int(blender::gpu::TextureFormat::SRGB_DXT1), "SRGB8_A8_DXT1"},
75 {int(blender::gpu::TextureFormat::SRGB_DXT3), "SRGB8_A8_DXT3"},
76 {int(blender::gpu::TextureFormat::SRGB_DXT5), "SRGB8_A8_DXT5"},
77 {int(blender::gpu::TextureFormat::SNORM_DXT1), "RGBA8_DXT1"},
78 {int(blender::gpu::TextureFormat::SNORM_DXT3), "RGBA8_DXT3"},
79 {int(blender::gpu::TextureFormat::SNORM_DXT5), "RGBA8_DXT5"},
80 {int(blender::gpu::TextureFormat::SFLOAT_32_DEPTH), "DEPTH_COMPONENT32F"},
81 {GPU_DEPTH_COMPONENT24_DEPRECATED, "DEPTH_COMPONENT24"},
82 {int(blender::gpu::TextureFormat::UNORM_16_DEPTH), "DEPTH_COMPONENT16"},
83 {0, nullptr},
84};
85
87{
88 if (UNLIKELY(bpygpu_tex->tex == nullptr)) {
89 PyErr_SetString(PyExc_ReferenceError,
91 "GPU texture was freed, no further access is valid"
92#else
93 "GPU texture: internal error"
94#endif
95 );
96
97 return -1;
98 }
99 return 0;
100}
101
102#define BPYGPU_TEXTURE_CHECK_OBJ(bpygpu) \
103 { \
104 if (UNLIKELY(pygpu_texture_valid_check(bpygpu) == -1)) { \
105 return nullptr; \
106 } \
107 } \
108 ((void)0)
109
111
112/* -------------------------------------------------------------------- */
115
116static PyObject *pygpu_texture__tp_new(PyTypeObject * /*self*/, PyObject *args, PyObject *kwds)
117{
119
120 PyObject *py_size;
121 int size[3] = {1, 1, 1};
122 int layers = 0;
123 int is_cubemap = false;
124 PyC_StringEnum pygpu_textureformat = {pygpu_textureformat_items,
125 int(blender::gpu::TextureFormat::UNORM_8_8_8_8)};
126 BPyGPUBuffer *pybuffer_obj = nullptr;
127 char err_out[256] = "unknown error. See console";
128
129 static const char *_keywords[] = {"size", "layers", "is_cubemap", "format", "data", nullptr};
130 static _PyArg_Parser _parser = {
132 "O" /* `size` */
133 "|$" /* Optional keyword only arguments. */
134 "i" /* `layers` */
135 "p" /* `is_cubemap` */
136 "O&" /* `format` */
137 "O!" /* `data` */
138 ":GPUTexture.__new__",
139 _keywords,
140 nullptr,
141 };
142 if (!_PyArg_ParseTupleAndKeywordsFast(args,
143 kwds,
144 &_parser,
145 &py_size,
146 &layers,
147 &is_cubemap,
149 &pygpu_textureformat,
151 &pybuffer_obj))
152 {
153 return nullptr;
154 }
155
156 if (pygpu_textureformat.value_found == GPU_DEPTH24_STENCIL8_DEPRECATED) {
157 pygpu_textureformat.value_found = int(blender::gpu::TextureFormat::SFLOAT_32_DEPTH_UINT_8);
158 PyErr_WarnEx(
159 PyExc_DeprecationWarning, "'DEPTH24_STENCIL8' is deprecated. Use 'DEPTH32F_STENCIL8'.", 1);
160 }
161 if (pygpu_textureformat.value_found == GPU_DEPTH_COMPONENT24_DEPRECATED) {
162 pygpu_textureformat.value_found = int(blender::gpu::TextureFormat::SFLOAT_32_DEPTH);
163 PyErr_WarnEx(PyExc_DeprecationWarning,
164 "'DEPTH_COMPONENT24' is deprecated. Use 'DEPTH_COMPONENT32F'.",
165 1);
166 }
167
168 int len = 1;
169 if (PySequence_Check(py_size)) {
170 len = PySequence_Size(py_size);
171 if ((len < 1) || (len > 3)) {
172 PyErr_Format(PyExc_ValueError,
173 "GPUTexture.__new__: \"size\" must be between 1 and 3 in length (got %d)",
174 len);
175 return nullptr;
176 }
177 if (PyC_AsArray(size, sizeof(*size), py_size, len, &PyLong_Type, "GPUTexture.__new__") == -1) {
178 return nullptr;
179 }
180 }
181 else if (PyLong_Check(py_size)) {
182 size[0] = PyLong_AsLong(py_size);
183 }
184 else {
185 PyErr_SetString(PyExc_ValueError, "GPUTexture.__new__: Expected an int or tuple as first arg");
186 return nullptr;
187 }
188
189 void *data = nullptr;
190 if (pybuffer_obj) {
191 if (pybuffer_obj->format != GPU_DATA_FLOAT) {
192 PyErr_SetString(PyExc_ValueError,
193 "GPUTexture.__new__: Only Buffer of format `FLOAT` is currently supported");
194 return nullptr;
195 }
196
197 int component_len = GPU_texture_component_len(
198 blender::gpu::TextureFormat(pygpu_textureformat.value_found));
199 int component_size_expected = sizeof(float);
200 size_t data_space_expected = size_t(size[0]) * size[1] * size[2] * max_ii(1, layers) *
201 component_len * component_size_expected;
202 if (is_cubemap) {
203 data_space_expected *= 6 * size[0];
204 }
205
206 if (bpygpu_Buffer_size(pybuffer_obj) < data_space_expected) {
207 PyErr_SetString(PyExc_ValueError, "GPUTexture.__new__: Buffer size smaller than requested");
208 return nullptr;
209 }
210 data = pybuffer_obj->buf.as_void;
211 }
212
213 blender::gpu::Texture *tex = nullptr;
214 if (is_cubemap && len != 1) {
216 err_out,
217 "In cubemaps the same dimension represents height, width and depth. No tuple needed");
218 }
219 else if (size[0] < 1 || size[1] < 1 || size[2] < 1) {
220 STRNCPY_UTF8(err_out, "Values less than 1 are not allowed in dimensions");
221 }
222 else if (layers && len == 3) {
223 STRNCPY_UTF8(err_out, "3D textures have no layers");
224 }
225 else if (!GPU_context_active_get()) {
226 STRNCPY_UTF8(err_out, "No active GPU context found");
227 }
228 else {
229 const char *name = "python_texture";
231 if (is_cubemap) {
232 if (layers) {
234 name,
235 size[0],
236 layers,
237 1,
238 blender::gpu::TextureFormat(pygpu_textureformat.value_found),
239 usage,
240 static_cast<const float *>(data));
241 }
242 else {
244 size[0],
245 1,
246 blender::gpu::TextureFormat(pygpu_textureformat.value_found),
247 usage,
248 static_cast<const float *>(data));
249 }
250 }
251 else if (layers) {
252 if (len == 2) {
254 name,
255 size[0],
256 size[1],
257 layers,
258 1,
259 blender::gpu::TextureFormat(pygpu_textureformat.value_found),
260 usage,
261 static_cast<const float *>(data));
262 }
263 else {
265 name,
266 size[0],
267 layers,
268 1,
269 blender::gpu::TextureFormat(pygpu_textureformat.value_found),
270 usage,
271 static_cast<const float *>(data));
272 }
273 }
274 else if (len == 3) {
276 size[0],
277 size[1],
278 size[2],
279 1,
280 blender::gpu::TextureFormat(pygpu_textureformat.value_found),
281 usage,
282 data);
283 }
284 else if (len == 2) {
286 size[0],
287 size[1],
288 1,
289 blender::gpu::TextureFormat(pygpu_textureformat.value_found),
290 usage,
291 static_cast<const float *>(data));
292 }
293 else {
295 size[0],
296 1,
297 blender::gpu::TextureFormat(pygpu_textureformat.value_found),
298 usage,
299 static_cast<const float *>(data));
300 }
301 }
302
303 if (tex == nullptr) {
304 PyErr_Format(PyExc_RuntimeError, "gpu.texture.new(...) failed with '%s'", err_out);
305 return nullptr;
306 }
307
308 return BPyGPUTexture_CreatePyObject(tex, false);
309}
310
312 /* Wrap. */
313 pygpu_texture_width_doc,
314 "Width of the texture.\n"
315 "\n"
316 ":type: int\n");
317static PyObject *pygpu_texture_width_get(BPyGPUTexture *self, void * /*type*/)
318{
320 return PyLong_FromLong(GPU_texture_width(self->tex));
321}
322
324 /* Wrap. */
325 pygpu_texture_height_doc,
326 "Height of the texture.\n"
327 "\n"
328 ":type: int\n");
329static PyObject *pygpu_texture_height_get(BPyGPUTexture *self, void * /*type*/)
330{
332 return PyLong_FromLong(GPU_texture_height(self->tex));
333}
334
336 /* Wrap. */
337 pygpu_texture_format_doc,
338 "Format of the texture.\n"
339 "\n"
340 ":type: str\n");
348
350 /* Wrap. */
351 pygpu_texture_clear_doc,
352 ".. method:: clear(format='FLOAT', value=(0.0, 0.0, 0.0, 1.0))\n"
353 "\n"
354 " Fill texture with specific value.\n"
355 "\n"
356 " :arg format: The format that describes the content of a single item.\n"
357 " Possible values are ``FLOAT``, ``INT``, ``UINT``, ``UBYTE``, ``UINT_24_8`` & "
358 "``10_11_11_REV``.\n"
359 " ``UINT_24_8`` is deprecated, use ``FLOAT`` instead.\n"
360 " :type format: str\n"
361 " :arg value: Sequence each representing the value to fill. Sizes 1..4 are supported.\n"
362 " :type value: Sequence[float]\n");
363static PyObject *pygpu_texture_clear(BPyGPUTexture *self, PyObject *args, PyObject *kwds)
364{
366 PyC_StringEnum pygpu_dataformat = {bpygpu_dataformat_items};
367 union {
368 int i[4];
369 float f[4];
370 char c[4];
371 } values;
372
373 PyObject *py_values;
374
375 static const char *_keywords[] = {"format", "value", nullptr};
376 static _PyArg_Parser _parser = {
378 "$" /* Keyword only arguments. */
379 "O&" /* `format` */
380 "O" /* `value` */
381 ":clear",
382 _keywords,
383 nullptr,
384 };
385 if (!_PyArg_ParseTupleAndKeywordsFast(
386 args, kwds, &_parser, PyC_ParseStringEnum, &pygpu_dataformat, &py_values))
387 {
388 return nullptr;
389 }
390 if (pygpu_dataformat.value_found == GPU_DATA_UINT_24_8_DEPRECATED) {
391 PyErr_WarnEx(PyExc_DeprecationWarning, "`UINT_24_8` is deprecated, use `FLOAT` instead", 1);
392 }
393
394 int shape = PySequence_Size(py_values);
395 if (shape == -1) {
396 return nullptr;
397 }
398
399 if (shape > 4) {
400 PyErr_SetString(PyExc_AttributeError, "too many dimensions, max is 4");
401 return nullptr;
402 }
403
404 if (shape != 1 &&
406 {
407 PyErr_SetString(PyExc_AttributeError,
408 "`UINT_24_8` and `10_11_11_REV` only support single values");
409 return nullptr;
410 }
411
412 memset(&values, 0, sizeof(values));
413 if (PyC_AsArray(&values,
414 (pygpu_dataformat.value_found == GPU_DATA_FLOAT) ? sizeof(*values.f) :
415 sizeof(*values.i),
416 py_values,
417 shape,
418 (pygpu_dataformat.value_found == GPU_DATA_FLOAT) ? &PyFloat_Type : &PyLong_Type,
419 "clear") == -1)
420 {
421 return nullptr;
422 }
423
424 if (pygpu_dataformat.value_found == GPU_DATA_UBYTE) {
425 /* Convert to byte. */
426 values.c[0] = values.i[0];
427 values.c[1] = values.i[1];
428 values.c[2] = values.i[2];
429 values.c[3] = values.i[3];
430 }
431
432 GPU_texture_clear(self->tex, eGPUDataFormat(pygpu_dataformat.value_found), &values);
433 Py_RETURN_NONE;
434}
435
437 /* Wrap. */
438 pygpu_texture_read_doc,
439 ".. method:: read()\n"
440 "\n"
441 " Creates a buffer with the value of all pixels.\n"
442 "\n");
444{
447
448 /* #GPU_texture_read is restricted in combining 'data_format' with 'tex_format'.
449 * So choose data_format here. */
450 eGPUDataFormat best_data_format;
451 switch (tex_format) {
452 case blender::gpu::TextureFormat::UNORM_16_DEPTH:
453 case blender::gpu::TextureFormat::SFLOAT_32_DEPTH:
454 case blender::gpu::TextureFormat::SFLOAT_32_DEPTH_UINT_8:
455 best_data_format = GPU_DATA_FLOAT;
456 break;
457 case blender::gpu::TextureFormat::UINT_8:
458 case blender::gpu::TextureFormat::UINT_16:
459 case blender::gpu::TextureFormat::UINT_16_16:
460 case blender::gpu::TextureFormat::UINT_32:
461 best_data_format = GPU_DATA_UINT;
462 break;
463 case blender::gpu::TextureFormat::SINT_16_16:
464 case blender::gpu::TextureFormat::SINT_16:
465 best_data_format = GPU_DATA_INT;
466 break;
467 case blender::gpu::TextureFormat::UNORM_8:
468 case blender::gpu::TextureFormat::UNORM_8_8:
469 case blender::gpu::TextureFormat::UNORM_8_8_8_8:
470 case blender::gpu::TextureFormat::UINT_8_8_8_8:
471 case blender::gpu::TextureFormat::SRGBA_8_8_8_8:
472 best_data_format = GPU_DATA_UBYTE;
473 break;
474 case blender::gpu::TextureFormat::UFLOAT_11_11_10:
475 best_data_format = GPU_DATA_10_11_11_REV;
476 break;
477 default:
478 best_data_format = GPU_DATA_FLOAT;
479 break;
480 }
481
482 void *buf = GPU_texture_read(self->tex, best_data_format, 0);
483 const Py_ssize_t shape[3] = {GPU_texture_height(self->tex),
485 Py_ssize_t(GPU_texture_component_len(tex_format))};
486
487 int shape_len = (shape[2] == 1) ? 2 : 3;
488 return (PyObject *)BPyGPU_Buffer_CreatePyObject(best_data_format, shape, shape_len, buf);
489}
490
491#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
493 /* Wrap. */
494 pygpu_texture_free_doc,
495 ".. method:: free()\n"
496 "\n"
497 " Free the texture object.\n"
498 " The texture object will no longer be accessible.\n");
499static PyObject *pygpu_texture_free(BPyGPUTexture *self)
500{
502
504 self->tex = nullptr;
505 Py_RETURN_NONE;
506}
507#endif
508
510{
511 if (self->tex) {
512#ifndef GPU_NO_USE_PY_REFERENCES
513 GPU_texture_py_reference_set(self->tex, nullptr);
514#endif
516 }
517 Py_TYPE(self)->tp_free((PyObject *)self);
518}
519
520static PyGetSetDef pygpu_texture__tp_getseters[] = {
521 {"width", (getter)pygpu_texture_width_get, (setter) nullptr, pygpu_texture_width_doc, nullptr},
522 {"height",
524 (setter) nullptr,
525 pygpu_texture_height_doc,
526 nullptr},
527 {"format",
529 (setter) nullptr,
530 pygpu_texture_format_doc,
531 nullptr},
532 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
533};
534
535#ifdef __GNUC__
536# ifdef __clang__
537# pragma clang diagnostic push
538# pragma clang diagnostic ignored "-Wcast-function-type"
539# else
540# pragma GCC diagnostic push
541# pragma GCC diagnostic ignored "-Wcast-function-type"
542# endif
543#endif
544
545static PyMethodDef pygpu_texture__tp_methods[] = {
546 {"clear",
547 (PyCFunction)pygpu_texture_clear,
548 METH_VARARGS | METH_KEYWORDS,
549 pygpu_texture_clear_doc},
550 {"read", (PyCFunction)pygpu_texture_read, METH_NOARGS, pygpu_texture_read_doc},
551#ifdef BPYGPU_USE_GPUOBJ_FREE_METHOD
552 {"free", (PyCFunction)pygpu_texture_free, METH_NOARGS, pygpu_texture_free_doc},
553#endif
554 {nullptr, nullptr, 0, nullptr},
555};
556
557#ifdef __GNUC__
558# ifdef __clang__
559# pragma clang diagnostic pop
560# else
561# pragma GCC diagnostic pop
562# endif
563#endif
564
566 /* Wrap. */
567 pygpu_texture__tp_doc,
568 ".. class:: GPUTexture(size, *, layers=0, is_cubemap=False, format='RGBA8', "
569 "data=None)\n"
570 "\n"
571 " This object gives access to off GPU textures.\n"
572 "\n"
573 " :arg size: Dimensions of the texture 1D, 2D, 3D or cubemap.\n"
574 " :type size: int | Sequence[int]\n"
575 " :arg layers: Number of layers in texture array or number of cubemaps in cubemap array\n"
576 " :type layers: int\n"
577 " :arg is_cubemap: Indicates the creation of a cubemap texture.\n"
578 " :type is_cubemap: int\n"
579 " :arg format: Internal data format inside GPU memory. Possible values are:\n"
580 " ``RGBA8UI``,\n"
581 " ``RGBA8I``,\n"
582 " ``RGBA8``,\n"
583 " ``RGBA32UI``,\n"
584 " ``RGBA32I``,\n"
585 " ``RGBA32F``,\n"
586 " ``RGBA16UI``,\n"
587 " ``RGBA16I``,\n"
588 " ``RGBA16F``,\n"
589 " ``RGBA16``,\n"
590 " ``RG8UI``,\n"
591 " ``RG8I``,\n"
592 " ``RG8``,\n"
593 " ``RG32UI``,\n"
594 " ``RG32I``,\n"
595 " ``RG32F``,\n"
596 " ``RG16UI``,\n"
597 " ``RG16I``,\n"
598 " ``RG16F``,\n"
599 " ``RG16``,\n"
600 " ``R8UI``,\n"
601 " ``R8I``,\n"
602 " ``R8``,\n"
603 " ``R32UI``,\n"
604 " ``R32I``,\n"
605 " ``R32F``,\n"
606 " ``R16UI``,\n"
607 " ``R16I``,\n"
608 " ``R16F``,\n"
609 " ``R16``,\n"
610 " ``R11F_G11F_B10F``,\n"
611 " ``DEPTH32F_STENCIL8``,\n"
612 " ``DEPTH24_STENCIL8`` (deprecated, use ``DEPTH32F_STENCIL8``),\n"
613 " ``SRGB8_A8``,\n"
614 " ``RGB16F``,\n"
615 " ``SRGB8_A8_DXT1``,\n"
616 " ``SRGB8_A8_DXT3``,\n"
617 " ``SRGB8_A8_DXT5``,\n"
618 " ``RGBA8_DXT1``,\n"
619 " ``RGBA8_DXT3``,\n"
620 " ``RGBA8_DXT5``,\n"
621 " ``DEPTH_COMPONENT32F``,\n"
622 " ``DEPTH_COMPONENT24``, (deprecated, use ``DEPTH_COMPONENT32F``),\n"
623 " ``DEPTH_COMPONENT16``.\n"
624 " :type format: str\n"
625 " :arg data: Buffer object to fill the texture.\n"
626 " :type data: :class:`gpu.types.Buffer`\n");
627PyTypeObject BPyGPUTexture_Type = {
628 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
629 /*tp_name*/ "GPUTexture",
630 /*tp_basicsize*/ sizeof(BPyGPUTexture),
631 /*tp_itemsize*/ 0,
632 /*tp_dealloc*/ (destructor)BPyGPUTexture__tp_dealloc,
633 /*tp_vectorcall_offset*/ 0,
634 /*tp_getattr*/ nullptr,
635 /*tp_setattr*/ nullptr,
636 /*tp_as_async*/ nullptr,
637 /*tp_repr*/ nullptr,
638 /*tp_as_number*/ nullptr,
639 /*tp_as_sequence*/ nullptr,
640 /*tp_as_mapping*/ nullptr,
641 /*tp_hash*/ nullptr,
642 /*tp_call*/ nullptr,
643 /*tp_str*/ nullptr,
644 /*tp_getattro*/ nullptr,
645 /*tp_setattro*/ nullptr,
646 /*tp_as_buffer*/ nullptr,
647 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
648 /*tp_doc*/ pygpu_texture__tp_doc,
649 /*tp_traverse*/ nullptr,
650 /*tp_clear*/ nullptr,
651 /*tp_richcompare*/ nullptr,
652 /*tp_weaklistoffset*/ 0,
653 /*tp_iter*/ nullptr,
654 /*tp_iternext*/ nullptr,
655 /*tp_methods*/ pygpu_texture__tp_methods,
656 /*tp_members*/ nullptr,
657 /*tp_getset*/ pygpu_texture__tp_getseters,
658 /*tp_base*/ nullptr,
659 /*tp_dict*/ nullptr,
660 /*tp_descr_get*/ nullptr,
661 /*tp_descr_set*/ nullptr,
662 /*tp_dictoffset*/ 0,
663 /*tp_init*/ nullptr,
664 /*tp_alloc*/ nullptr,
665 /*tp_new*/ pygpu_texture__tp_new,
666 /*tp_free*/ nullptr,
667 /*tp_is_gc*/ nullptr,
668 /*tp_bases*/ nullptr,
669 /*tp_mro*/ nullptr,
670 /*tp_cache*/ nullptr,
671 /*tp_subclasses*/ nullptr,
672 /*tp_weaklist*/ nullptr,
673 /*tp_del*/ nullptr,
674 /*tp_version_tag*/ 0,
675 /*tp_finalize*/ nullptr,
676 /*tp_vectorcall*/ nullptr,
677};
678
680
681/* -------------------------------------------------------------------- */
684
686 /* Wrap. */
687 pygpu_texture_from_image_doc,
688 ".. function:: from_image(image)\n"
689 "\n"
690 " Get GPUTexture corresponding to an Image data-block. The GPUTexture "
691 "memory is "
692 "shared with Blender.\n"
693 " Note: Colors read from the texture will be in scene linear color space and have "
694 "premultiplied or straight alpha matching the image alpha mode.\n"
695 "\n"
696 " :arg image: The Image data-block.\n"
697 " :type image: :class:`bpy.types.Image`\n"
698 " :return: The GPUTexture used by the image.\n"
699 " :rtype: :class:`gpu.types.GPUTexture`\n");
700static PyObject *pygpu_texture_from_image(PyObject * /*self*/, PyObject *arg)
701{
702 Image *ima = static_cast<Image *>(PyC_RNA_AsPointer(arg, "Image"));
703 if (ima == nullptr) {
704 return nullptr;
705 }
706
707 ImageUser iuser;
708 BKE_imageuser_default(&iuser);
710
711 return BPyGPUTexture_CreatePyObject(tex, true);
712}
713
714static PyMethodDef pygpu_texture__m_methods[] = {
715 {"from_image", (PyCFunction)pygpu_texture_from_image, METH_O, pygpu_texture_from_image_doc},
716 {nullptr, nullptr, 0, nullptr},
717};
718
720 /* Wrap. */
721 pygpu_texture__m_doc,
722 "This module provides utilities for textures.");
723static PyModuleDef pygpu_texture_module_def = {
724 /*m_base*/ PyModuleDef_HEAD_INIT,
725 /*m_name*/ "gpu.texture",
726 /*m_doc*/ pygpu_texture__m_doc,
727 /*m_size*/ 0,
728 /*m_methods*/ pygpu_texture__m_methods,
729 /*m_slots*/ nullptr,
730 /*m_traverse*/ nullptr,
731 /*m_clear*/ nullptr,
732 /*m_free*/ nullptr,
733};
734
736
737/* -------------------------------------------------------------------- */
740
741int bpygpu_ParseTexture(PyObject *o, void *p)
742{
743 if (o == Py_None) {
744 *(blender::gpu::Texture **)p = nullptr;
745 return 1;
746 }
747
748 if (!BPyGPUTexture_Check(o)) {
749 PyErr_Format(
750 PyExc_ValueError, "expected a texture or None object, got %s", Py_TYPE(o)->tp_name);
751 return 0;
752 }
753
755 return 0;
756 }
757
758 *(blender::gpu::Texture **)p = ((BPyGPUTexture *)o)->tex;
759 return 1;
760}
761
763{
764 PyObject *submodule;
765 submodule = PyModule_Create(&pygpu_texture_module_def);
766
767 return submodule;
768}
769
771
772/* -------------------------------------------------------------------- */
775
776PyObject *BPyGPUTexture_CreatePyObject(blender::gpu::Texture *tex, bool shared_reference)
777{
779
780 if (shared_reference) {
781#ifndef GPU_NO_USE_PY_REFERENCES
782 void **ref = GPU_texture_py_reference_get(tex);
783 if (ref) {
784 /* Retrieve BPyGPUTexture reference. */
786 BLI_assert(self->tex == tex);
787 Py_INCREF(self);
788 return (PyObject *)self;
789 }
790#endif
791
792 GPU_texture_ref(tex);
793 }
794
795 self = PyObject_New(BPyGPUTexture, &BPyGPUTexture_Type);
796 self->tex = tex;
797
798#ifndef GPU_NO_USE_PY_REFERENCES
800 GPU_texture_py_reference_set(tex, (void **)&self->tex);
801#endif
802
803 return (PyObject *)self;
804}
805
807
808#undef BPYGPU_TEXTURE_CHECK_OBJ
void BKE_imageuser_default(ImageUser *iuser)
blender::gpu::Texture * BKE_image_get_gpu_texture(Image *image, ImageUser *iuser)
Definition image_gpu.cc:496
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE int max_ii(int a, int b)
#define STRNCPY_UTF8(dst, src)
#define UNLIKELY(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
GPUContext * GPU_context_active_get()
void GPU_texture_clear(blender::gpu::Texture *texture, eGPUDataFormat data_format, const void *data)
blender::gpu::Texture * GPU_texture_create_2d_array(const char *name, int width, int height, int layer_len, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
size_t GPU_texture_component_len(blender::gpu::TextureFormat format)
void ** GPU_texture_py_reference_get(blender::gpu::Texture *texture)
int GPU_texture_height(const blender::gpu::Texture *texture)
blender::gpu::Texture * GPU_texture_create_cube(const char *name, int width, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
blender::gpu::Texture * GPU_texture_create_1d_array(const char *name, int width, int layer_len, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
blender::gpu::TextureFormat GPU_texture_format(const blender::gpu::Texture *texture)
int GPU_texture_width(const blender::gpu::Texture *texture)
eGPUDataFormat
@ GPU_DATA_INT
@ GPU_DATA_10_11_11_REV
@ GPU_DATA_UBYTE
@ GPU_DATA_UINT
@ GPU_DATA_UINT_24_8_DEPRECATED
@ GPU_DATA_FLOAT
blender::gpu::Texture * GPU_texture_create_cube_array(const char *name, int width, int layer_len, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_ref(blender::gpu::Texture *texture)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_GENERAL
void * GPU_texture_read(blender::gpu::Texture *texture, eGPUDataFormat data_format, int mip_level)
void GPU_texture_py_reference_set(blender::gpu::Texture *texture, void **py_ref)
blender::gpu::Texture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(blender::gpu::Texture *texture)
blender::gpu::Texture * GPU_texture_create_3d(const char *name, int width, int height, int depth, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const void *data)
blender::gpu::Texture * GPU_texture_create_1d(const char *name, int width, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
BMesh const char void * data
PyObject * self
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
nullptr float
#define offsetof(t, d)
PyC_StringEnumItems bpygpu_dataformat_items[]
Definition gpu_py.cc:40
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition gpu_py.hh:20
PyTypeObject BPyGPU_BufferType
BPyGPUBuffer * BPyGPU_Buffer_CreatePyObject(const int format, const Py_ssize_t *shape, const int shape_len, void *buffer)
size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer)
#define BPYGPU_USE_GPUOBJ_FREE_METHOD
PyTypeObject BPyGPUTexture_Type
static PyObject * pygpu_texture_width_get(BPyGPUTexture *self, void *)
static PyObject * pygpu_texture_clear(BPyGPUTexture *self, PyObject *args, PyObject *kwds)
PyObject * BPyGPUTexture_CreatePyObject(blender::gpu::Texture *tex, bool shared_reference)
PyObject * bpygpu_texture_init()
static void BPyGPUTexture__tp_dealloc(BPyGPUTexture *self)
static int pygpu_texture_valid_check(BPyGPUTexture *bpygpu_tex)
static PyGetSetDef pygpu_texture__tp_getseters[]
#define BPYGPU_TEXTURE_CHECK_OBJ(bpygpu)
static PyObject * pygpu_texture_from_image(PyObject *, PyObject *arg)
PyDoc_STRVAR(pygpu_texture_width_doc, "Width of the texture.\n" "\n" ":type: int\n")
static PyObject * pygpu_texture__tp_new(PyTypeObject *, PyObject *args, PyObject *kwds)
static PyObject * pygpu_texture_height_get(BPyGPUTexture *self, void *)
int bpygpu_ParseTexture(PyObject *o, void *p)
static PyObject * pygpu_texture_read(BPyGPUTexture *self)
const PyC_StringEnumItems pygpu_textureformat_items[]
static PyMethodDef pygpu_texture__m_methods[]
static PyMethodDef pygpu_texture__tp_methods[]
static PyModuleDef pygpu_texture_module_def
static PyObject * pygpu_texture_format_get(BPyGPUTexture *self, void *)
constexpr int GPU_DEPTH24_STENCIL8_DEPRECATED
#define BPyGPUTexture_Check(v)
constexpr int GPU_DEPTH_COMPONENT24_DEPRECATED
format
void * PyC_RNA_AsPointer(PyObject *value, const char *type_name)
int PyC_ParseStringEnum(PyObject *o, void *p)
int PyC_AsArray(void *array, const size_t array_item_size, PyObject *value, const Py_ssize_t length, const PyTypeObject *type, const char *error_prefix)
const char * PyC_StringEnum_FindIDFromValue(const PyC_StringEnumItems *items, const int value)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
const char * name
union BPyGPUBuffer::@121060215011127262115351146023070133300154361035 buf
PyObject_HEAD blender::gpu::Texture * tex
i
Definition text_draw.cc:230
uint len