PyGPU: GPUShader: implementation of 'attrs_info_get' method
With the new `attrs_info_get` method, we can get information about the attributes used in a `GPUShader` and thus have more freedom in the automatic creation of `GPUVertFormat`s Reviewed By: fclem, campbellbarton Differential Revision: https://developer.blender.org/D15764
This commit is contained in:
parent
05fe7ca5af
commit
6269d66da2
|
@ -22,15 +22,46 @@ def batch_for_shader(shader, type, content, *, indices=None):
|
|||
GPUBatch,
|
||||
GPUIndexBuf,
|
||||
GPUVertBuf,
|
||||
GPUVertFormat,
|
||||
)
|
||||
|
||||
def recommended_comp_type(attr_type):
|
||||
if attr_type in {'FLOAT', 'VEC2', 'VEC3', 'VEC4', 'MAT3', 'MAT4'}:
|
||||
return 'F32'
|
||||
if attr_type in {'UINT', 'UVEC2', 'UVEC3', 'UVEC4'}:
|
||||
return 'U32'
|
||||
# `attr_type` in {'INT', 'IVEC2', 'IVEC3', 'IVEC4', 'BOOL'}.
|
||||
return 'I32'
|
||||
|
||||
def recommended_attr_len(attr_name):
|
||||
item = content[attr_name][0]
|
||||
attr_len = 1
|
||||
try:
|
||||
while True:
|
||||
attr_len *= len(item)
|
||||
item = item[0]
|
||||
except TypeError:
|
||||
pass
|
||||
return attr_len
|
||||
|
||||
def recommended_fetch_mode(comp_type):
|
||||
if comp_type == 'F32':
|
||||
return 'FLOAT'
|
||||
return 'INT'
|
||||
|
||||
for data in content.values():
|
||||
vbo_len = len(data)
|
||||
break
|
||||
else:
|
||||
raise ValueError("Empty 'content'")
|
||||
|
||||
vbo_format = shader.format_calc()
|
||||
vbo_format = GPUVertFormat()
|
||||
attrs_info = shader.attrs_info_get()
|
||||
for name, attr_type in attrs_info:
|
||||
comp_type = recommended_comp_type(attr_type)
|
||||
attr_len = recommended_attr_len(name)
|
||||
vbo_format.attr_add(id=name, comp_type=comp_type, len=attr_len, fetch_mode=recommended_fetch_mode(comp_type))
|
||||
|
||||
vbo = GPUVertBuf(vbo_format, vbo_len)
|
||||
|
||||
for id, data in content.items():
|
||||
|
|
|
@ -191,7 +191,12 @@ void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const floa
|
|||
void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]);
|
||||
void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]);
|
||||
|
||||
unsigned int GPU_shader_get_attribute_len(const GPUShader *shader);
|
||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
|
||||
bool GPU_shader_get_attribute_info(const GPUShader *shader,
|
||||
int attr_location,
|
||||
char r_name[256],
|
||||
int *r_type);
|
||||
|
||||
void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear);
|
||||
|
||||
|
|
|
@ -612,6 +612,12 @@ int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
|
|||
return tex ? tex->binding : -1;
|
||||
}
|
||||
|
||||
uint GPU_shader_get_attribute_len(const GPUShader *shader)
|
||||
{
|
||||
ShaderInterface *interface = unwrap(shader)->interface;
|
||||
return interface->attr_len_;
|
||||
}
|
||||
|
||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
|
||||
{
|
||||
ShaderInterface *interface = unwrap(shader)->interface;
|
||||
|
@ -619,6 +625,23 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name)
|
|||
return attr ? attr->location : -1;
|
||||
}
|
||||
|
||||
bool GPU_shader_get_attribute_info(const GPUShader *shader,
|
||||
int attr_location,
|
||||
char r_name[256],
|
||||
int *r_type)
|
||||
{
|
||||
ShaderInterface *interface = unwrap(shader)->interface;
|
||||
|
||||
const ShaderInput *attr = interface->attr_get(attr_location);
|
||||
if (!attr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_strncpy(r_name, interface->input_name_get(attr), 256);
|
||||
*r_type = attr->location != -1 ? interface->attr_types_[attr->location] : -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_vertex_format.h" /* GPU_VERT_ATTR_MAX_LEN */
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
@ -58,6 +59,13 @@ class ShaderInterface {
|
|||
int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS];
|
||||
int32_t builtin_buffers_[GPU_NUM_STORAGE_BUFFERS];
|
||||
|
||||
/**
|
||||
* Currently only used for `GPU_shader_get_attribute_info`.
|
||||
* This utility is useful for automatic creation of `GPUVertFormat` in Python.
|
||||
* Use `ShaderInput::location` to identify the `Type`.
|
||||
*/
|
||||
uint8_t attr_types_[GPU_VERT_ATTR_MAX_LEN];
|
||||
|
||||
public:
|
||||
ShaderInterface();
|
||||
ShaderInterface(const shader::ShaderCreateInfo &info);
|
||||
|
@ -69,6 +77,10 @@ class ShaderInterface {
|
|||
{
|
||||
return input_lookup(inputs_, attr_len_, name);
|
||||
}
|
||||
inline const ShaderInput *attr_get(const int binding) const
|
||||
{
|
||||
return input_lookup(inputs_, attr_len_, binding);
|
||||
}
|
||||
|
||||
inline const ShaderInput *ubo_get(const char *name) const
|
||||
{
|
||||
|
|
|
@ -55,8 +55,6 @@ class Shader {
|
|||
virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0;
|
||||
virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0;
|
||||
|
||||
virtual void vertformat_from_shader(GPUVertFormat *) const = 0;
|
||||
|
||||
std::string defines_declare(const shader::ShaderCreateInfo &info) const;
|
||||
virtual std::string resources_declare(const shader::ShaderCreateInfo &info) const = 0;
|
||||
virtual std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include "GPU_vertex_format.h"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
#include "gpu_shader_private.hh"
|
||||
#include "gpu_vertex_format_private.h"
|
||||
|
||||
|
@ -25,6 +26,7 @@
|
|||
#endif
|
||||
|
||||
using namespace blender::gpu;
|
||||
using namespace blender::gpu::shader;
|
||||
|
||||
void GPU_vertformat_clear(GPUVertFormat *format)
|
||||
{
|
||||
|
@ -338,8 +340,83 @@ void VertexFormat_pack(GPUVertFormat *format)
|
|||
format->packed = true;
|
||||
}
|
||||
|
||||
static uint component_size_get(const Type gpu_type)
|
||||
{
|
||||
switch (gpu_type) {
|
||||
case Type::VEC2:
|
||||
case Type::IVEC2:
|
||||
case Type::UVEC2:
|
||||
return 2;
|
||||
case Type::VEC3:
|
||||
case Type::IVEC3:
|
||||
case Type::UVEC3:
|
||||
return 3;
|
||||
case Type::VEC4:
|
||||
case Type::IVEC4:
|
||||
case Type::UVEC4:
|
||||
return 4;
|
||||
case Type::MAT3:
|
||||
return 12;
|
||||
case Type::MAT4:
|
||||
return 16;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void recommended_fetch_mode_and_comp_type(Type gpu_type,
|
||||
GPUVertCompType *r_comp_type,
|
||||
GPUVertFetchMode *r_fetch_mode)
|
||||
{
|
||||
switch (gpu_type) {
|
||||
case Type::FLOAT:
|
||||
case Type::VEC2:
|
||||
case Type::VEC3:
|
||||
case Type::VEC4:
|
||||
case Type::MAT3:
|
||||
case Type::MAT4:
|
||||
*r_comp_type = GPU_COMP_F32;
|
||||
*r_fetch_mode = GPU_FETCH_FLOAT;
|
||||
break;
|
||||
case Type::INT:
|
||||
case Type::IVEC2:
|
||||
case Type::IVEC3:
|
||||
case Type::IVEC4:
|
||||
*r_comp_type = GPU_COMP_I32;
|
||||
*r_fetch_mode = GPU_FETCH_INT;
|
||||
break;
|
||||
case Type::UINT:
|
||||
case Type::UVEC2:
|
||||
case Type::UVEC3:
|
||||
case Type::UVEC4:
|
||||
*r_comp_type = GPU_COMP_U32;
|
||||
*r_fetch_mode = GPU_FETCH_INT;
|
||||
break;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_vertformat_from_shader(GPUVertFormat *format, const struct GPUShader *gpushader)
|
||||
{
|
||||
const Shader *shader = reinterpret_cast<const Shader *>(gpushader);
|
||||
shader->vertformat_from_shader(format);
|
||||
GPU_vertformat_clear(format);
|
||||
|
||||
uint attr_len = GPU_shader_get_attribute_len(gpushader);
|
||||
int location_test = 0, attrs_added = 0;;
|
||||
while (attrs_added < attr_len) {
|
||||
char name[256];
|
||||
Type gpu_type;
|
||||
if (!GPU_shader_get_attribute_info(gpushader, location_test++, name, (int *)&gpu_type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GPUVertCompType comp_type;
|
||||
GPUVertFetchMode fetch_mode;
|
||||
recommended_fetch_mode_and_comp_type(gpu_type, &comp_type, &fetch_mode);
|
||||
|
||||
int comp_len = component_size_get(gpu_type);
|
||||
|
||||
GPU_vertformat_attr_add(format, name, comp_type, comp_len, fetch_mode);
|
||||
attrs_added++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1136,108 +1136,6 @@ void GLShader::uniform_int(int location, int comp_len, int array_size, const int
|
|||
/** \name GPUVertFormat from Shader
|
||||
* \{ */
|
||||
|
||||
static uint calc_component_size(const GLenum gl_type)
|
||||
{
|
||||
switch (gl_type) {
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_INT_VEC2:
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
return 2;
|
||||
case GL_FLOAT_VEC3:
|
||||
case GL_INT_VEC3:
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
return 3;
|
||||
case GL_FLOAT_VEC4:
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_INT_VEC4:
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
return 4;
|
||||
case GL_FLOAT_MAT3:
|
||||
return 9;
|
||||
case GL_FLOAT_MAT4:
|
||||
return 16;
|
||||
case GL_FLOAT_MAT2x3:
|
||||
case GL_FLOAT_MAT3x2:
|
||||
return 6;
|
||||
case GL_FLOAT_MAT2x4:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
return 8;
|
||||
case GL_FLOAT_MAT3x4:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
return 12;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_fetch_mode_and_comp_type(int gl_type,
|
||||
GPUVertCompType *r_comp_type,
|
||||
GPUVertFetchMode *r_fetch_mode)
|
||||
{
|
||||
switch (gl_type) {
|
||||
case GL_FLOAT:
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_FLOAT_VEC3:
|
||||
case GL_FLOAT_VEC4:
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT3:
|
||||
case GL_FLOAT_MAT4:
|
||||
case GL_FLOAT_MAT2x3:
|
||||
case GL_FLOAT_MAT2x4:
|
||||
case GL_FLOAT_MAT3x2:
|
||||
case GL_FLOAT_MAT3x4:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
*r_comp_type = GPU_COMP_F32;
|
||||
*r_fetch_mode = GPU_FETCH_FLOAT;
|
||||
break;
|
||||
case GL_INT:
|
||||
case GL_INT_VEC2:
|
||||
case GL_INT_VEC3:
|
||||
case GL_INT_VEC4:
|
||||
*r_comp_type = GPU_COMP_I32;
|
||||
*r_fetch_mode = GPU_FETCH_INT;
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
*r_comp_type = GPU_COMP_U32;
|
||||
*r_fetch_mode = GPU_FETCH_INT;
|
||||
break;
|
||||
default:
|
||||
BLI_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void GLShader::vertformat_from_shader(GPUVertFormat *format) const
|
||||
{
|
||||
GPU_vertformat_clear(format);
|
||||
|
||||
GLint attr_len;
|
||||
glGetProgramiv(shader_program_, GL_ACTIVE_ATTRIBUTES, &attr_len);
|
||||
|
||||
for (int i = 0; i < attr_len; i++) {
|
||||
char name[256];
|
||||
GLenum gl_type;
|
||||
GLint size;
|
||||
glGetActiveAttrib(shader_program_, i, sizeof(name), nullptr, &size, &gl_type, name);
|
||||
|
||||
/* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
|
||||
if (glGetAttribLocation(shader_program_, name) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GPUVertCompType comp_type;
|
||||
GPUVertFetchMode fetch_mode;
|
||||
get_fetch_mode_and_comp_type(gl_type, &comp_type, &fetch_mode);
|
||||
|
||||
int comp_len = calc_component_size(gl_type) * size;
|
||||
|
||||
GPU_vertformat_attr_add(format, name, comp_type, comp_len, fetch_mode);
|
||||
}
|
||||
}
|
||||
|
||||
int GLShader::program_handle_get() const
|
||||
{
|
||||
return (int)this->shader_program_;
|
||||
|
|
|
@ -67,8 +67,6 @@ class GLShader : public Shader {
|
|||
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
|
||||
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
|
||||
|
||||
void vertformat_from_shader(GPUVertFormat *format) const override;
|
||||
|
||||
/** DEPRECATED: Kept only because of BGL API. */
|
||||
int program_handle_get() const override;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "GPU_capabilities.h"
|
||||
|
||||
using namespace blender::gpu::shader;
|
||||
namespace blender::gpu {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -151,6 +152,52 @@ static inline int ssbo_binding(int32_t program, uint32_t ssbo_index)
|
|||
/** \name Creation / Destruction
|
||||
* \{ */
|
||||
|
||||
static Type gpu_type_from_gl_type(int gl_type)
|
||||
{
|
||||
switch (gl_type) {
|
||||
case GL_FLOAT:
|
||||
return Type::FLOAT;
|
||||
case GL_FLOAT_VEC2:
|
||||
return Type::VEC2;
|
||||
case GL_FLOAT_VEC3:
|
||||
return Type::VEC3;
|
||||
case GL_FLOAT_VEC4:
|
||||
return Type::VEC4;
|
||||
case GL_FLOAT_MAT3:
|
||||
return Type::MAT3;
|
||||
case GL_FLOAT_MAT4:
|
||||
return Type::MAT4;
|
||||
case GL_UNSIGNED_INT:
|
||||
return Type::UINT;
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
return Type::UVEC2;
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
return Type::UVEC3;
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
return Type::UVEC4;
|
||||
case GL_INT:
|
||||
return Type::INT;
|
||||
case GL_INT_VEC2:
|
||||
return Type::IVEC2;
|
||||
case GL_INT_VEC3:
|
||||
return Type::IVEC3;
|
||||
case GL_INT_VEC4:
|
||||
return Type::IVEC4;
|
||||
case GL_BOOL:
|
||||
return Type::BOOL;
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT2x3:
|
||||
case GL_FLOAT_MAT2x4:
|
||||
case GL_FLOAT_MAT3x2:
|
||||
case GL_FLOAT_MAT3x4:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
default:
|
||||
BLI_assert(0);
|
||||
}
|
||||
return Type::FLOAT;
|
||||
}
|
||||
|
||||
GLShaderInterface::GLShaderInterface(GLuint program)
|
||||
{
|
||||
/* Necessary to make #glUniform works. */
|
||||
|
@ -246,6 +293,9 @@ GLShaderInterface::GLShaderInterface(GLuint program)
|
|||
|
||||
name_buffer_offset += set_input_name(input, name, name_len);
|
||||
enabled_attr_mask_ |= (1 << input->location);
|
||||
|
||||
/* Used in `GPU_shader_get_attribute_info`. */
|
||||
attr_types_[input->location] = (uint8_t)gpu_type_from_gl_type(type);
|
||||
}
|
||||
|
||||
/* Uniform Blocks */
|
||||
|
@ -405,7 +455,11 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI
|
|||
}
|
||||
if (input->location != -1) {
|
||||
enabled_attr_mask_ |= (1 << input->location);
|
||||
|
||||
/* Used in `GPU_shader_get_attribute_info`. */
|
||||
attr_types_[input->location] = (uint8_t)attr.type;
|
||||
}
|
||||
|
||||
input++;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "GPU_uniform_buffer.h"
|
||||
|
||||
#include "../generic/py_capi_utils.h"
|
||||
#include "../generic/python_utildefines.h"
|
||||
#include "../mathutils/mathutils.h"
|
||||
|
||||
#include "gpu_py.h"
|
||||
|
@ -614,6 +615,44 @@ static PyObject *pygpu_shader_format_calc(BPyGPUShader *self, PyObject *UNUSED(a
|
|||
return (PyObject *)ret;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
pygpu_shader_attrs_info_get_doc,
|
||||
".. method:: attrs_info_get()\n"
|
||||
"\n"
|
||||
" Information about the attributes used in the Shader.\n"
|
||||
"\n"
|
||||
" :return: tuples containing information about the attributes in order (name, type)\n"
|
||||
" :rtype: tuple\n");
|
||||
static PyObject *pygpu_shader_attrs_info_get(BPyGPUShader *self, PyObject *UNUSED(arg))
|
||||
{
|
||||
uint attr_len = GPU_shader_get_attribute_len(self->shader);
|
||||
int location_test = 0, attrs_added = 0;
|
||||
;
|
||||
PyObject *ret = PyTuple_New(attr_len);
|
||||
while (attrs_added < attr_len) {
|
||||
char name[256];
|
||||
int type;
|
||||
if (!GPU_shader_get_attribute_info(self->shader, location_test++, name, &type)) {
|
||||
continue;
|
||||
}
|
||||
PyObject *py_type;
|
||||
if (type != -1) {
|
||||
py_type = PyUnicode_InternFromString(
|
||||
PyC_StringEnum_FindIDFromValue(pygpu_attrtype_items, type));
|
||||
}
|
||||
else {
|
||||
py_type = Py_None;
|
||||
Py_INCREF(py_type);
|
||||
}
|
||||
|
||||
PyObject *attr_info = PyTuple_New(2);
|
||||
PyTuple_SET_ITEMS(attr_info, PyUnicode_FromString(name), py_type);
|
||||
PyTuple_SetItem(ret, attrs_added, attr_info);
|
||||
attrs_added++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct PyMethodDef pygpu_shader__tp_methods[] = {
|
||||
{"bind", (PyCFunction)pygpu_shader_bind, METH_NOARGS, pygpu_shader_bind_doc},
|
||||
{"uniform_from_name",
|
||||
|
@ -660,6 +699,10 @@ static struct PyMethodDef pygpu_shader__tp_methods[] = {
|
|||
(PyCFunction)pygpu_shader_format_calc,
|
||||
METH_NOARGS,
|
||||
pygpu_shader_format_calc_doc},
|
||||
{"attrs_info_get",
|
||||
(PyCFunction)pygpu_shader_attrs_info_get,
|
||||
METH_NOARGS,
|
||||
pygpu_shader_attrs_info_get_doc},
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include "../generic/py_capi_utils.h"
|
||||
#endif
|
||||
|
||||
/* Make sure that there is always a reference count for PyObjects of type String as the strings are
|
||||
* passed by reference in the #GPUStageInterfaceInfo and #GPUShaderCreateInfo APIs. */
|
||||
#define USE_GPU_PY_REFERENCES
|
||||
|
@ -31,6 +35,7 @@ extern "C" {
|
|||
|
||||
/* gpu_py_shader_create_info.cc */
|
||||
|
||||
extern const struct PyC_StringEnumItems pygpu_attrtype_items[];
|
||||
extern PyTypeObject BPyGPUShaderCreateInfo_Type;
|
||||
extern PyTypeObject BPyGPUStageInterfaceInfo_Type;
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ static const struct PyC_FlagSet pygpu_qualifiers[] = {
|
|||
" - ``IVEC3``\n" \
|
||||
" - ``IVEC4``\n" \
|
||||
" - ``BOOL``\n"
|
||||
static const struct PyC_StringEnumItems pygpu_attrtype_items[] = {
|
||||
const struct PyC_StringEnumItems pygpu_attrtype_items[] = {
|
||||
{(int)Type::FLOAT, "FLOAT"},
|
||||
{(int)Type::VEC2, "VEC2"},
|
||||
{(int)Type::VEC3, "VEC3"},
|
||||
|
|
Loading…
Reference in New Issue