Add support for instance arrays via vertex attrib divisors

This commit is contained in:
rdb 2015-01-22 17:04:25 +01:00
parent 0ad0d4ec33
commit 77c9e6cf6c
10 changed files with 116 additions and 40 deletions

View File

@ -1359,6 +1359,22 @@ reset() {
} }
#endif #endif
_supports_vertex_attrib_divisor = false;
#ifndef OPENGLES
if (is_at_least_gl_version(3, 3)) {
_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
get_extension_func("glVertexAttribDivisor");
_supports_vertex_attrib_divisor = true;
} else if (has_extension("GL_ARB_instanced_arrays")) {
_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
get_extension_func("glVertexAttribDivisorARB");
_supports_vertex_attrib_divisor = true;
}
#endif
#ifdef OPENGLES_2 #ifdef OPENGLES_2
// In OpenGL ES 2.x, FBO's are supported in the core. // In OpenGL ES 2.x, FBO's are supported in the core.
_supports_framebuffer_object = true; _supports_framebuffer_object = true;

View File

@ -182,6 +182,7 @@ typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
#endif // OPENGLES_1 #endif // OPENGLES_1
#ifndef OPENGLES #ifndef OPENGLES
typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
@ -572,6 +573,8 @@ protected:
bool _use_sender; bool _use_sender;
#endif // SUPPORT_IMMEDIATE_MODE #endif // SUPPORT_IMMEDIATE_MODE
bool _supports_vertex_attrib_divisor;
// Cache the data necessary to bind each particular light each // Cache the data necessary to bind each particular light each
// frame, so if we bind a given light multiple times, we only have // frame, so if we bind a given light multiple times, we only have
// to compute its data once. // to compute its data once.
@ -785,6 +788,7 @@ public:
PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer; PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer;
PFNGLVERTEXATTRIBIPOINTERPROC _glVertexAttribIPointer; PFNGLVERTEXATTRIBIPOINTERPROC _glVertexAttribIPointer;
PFNGLVERTEXATTRIBLPOINTERPROC _glVertexAttribLPointer; PFNGLVERTEXATTRIBLPOINTERPROC _glVertexAttribLPointer;
PFNGLVERTEXATTRIBDIVISORPROC _glVertexAttribDivisor;
#endif // OPENGLES_1 #endif // OPENGLES_1
#ifndef OPENGLES #ifndef OPENGLES
PFNGLGENSAMPLERSPROC _glGenSamplers; PFNGLGENSAMPLERSPROC _glGenSamplers;

View File

@ -998,6 +998,9 @@ disable_shader_vertex_arrays() {
for (int i=0; i<(int)_shader->_var_spec.size(); i++) { for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
const Shader::ShaderVarSpec &bind = _shader->_var_spec[i]; const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
const GLint p = _glsl_parameter_map[bind._id._seqno]; const GLint p = _glsl_parameter_map[bind._id._seqno];
if (_glgsg->_supports_vertex_attrib_divisor) {
_glgsg->_glVertexAttribDivisor(p, 0);
}
_glgsg->_glDisableVertexAttribArray(p); _glgsg->_glDisableVertexAttribArray(p);
} }
@ -1052,10 +1055,10 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
} }
GLint p = _glsl_parameter_map[bind._id._seqno]; GLint p = _glsl_parameter_map[bind._id._seqno];
int num_elements, element_stride; int num_elements, element_stride, divisor;
if (_glgsg->_data_reader->get_array_info(name, array_reader, if (_glgsg->_data_reader->get_array_info(name, array_reader,
num_values, numeric_type, num_values, numeric_type,
start, stride, start, stride, divisor,
num_elements, element_stride)) { num_elements, element_stride)) {
const unsigned char *client_pointer; const unsigned char *client_pointer;
if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) { if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
@ -1066,12 +1069,12 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
for (int i = 0; i < num_elements; ++i) { for (int i = 0; i < num_elements; ++i) {
_glgsg->_glEnableVertexAttribArray(p); _glgsg->_glEnableVertexAttribArray(p);
#ifndef OPENGLES #ifndef OPENGLES
if (bind._integer) { if (bind._integer) {
_glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type), _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
stride, client_pointer); stride, client_pointer);
} else } else
#endif #endif
if (numeric_type == GeomEnums::NT_packed_dabc) { if (numeric_type == GeomEnums::NT_packed_dabc) {
_glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE, _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
GL_TRUE, stride, client_pointer); GL_TRUE, stride, client_pointer);
@ -1079,6 +1082,11 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
_glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type), _glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
GL_TRUE, stride, client_pointer); GL_TRUE, stride, client_pointer);
} }
if (_glgsg->_supports_vertex_attrib_divisor) {
_glgsg->_glVertexAttribDivisor(p, divisor);
}
++p; ++p;
client_pointer += element_stride; client_pointer += element_stride;
} }

View File

@ -106,6 +106,33 @@ set_pad_to(int pad_to) {
_stride = ((_stride + _pad_to - 1) / _pad_to) * _pad_to; _stride = ((_stride + _pad_to - 1) / _pad_to) * _pad_to;
} }
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayFormat::get_divisor
// Access: Published
// Description: Returns the divisor attribute for the data in this
// array. If 0, it contains per-vertex data. If 1,
// it contains per-instance data. If higher than 1,
// the read row is advanced for each n instances.
////////////////////////////////////////////////////////////////////
INLINE int GeomVertexArrayFormat::
get_divisor() const {
return _divisor;
}
////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayFormat::set_divisor
// Access: Published
// Description: Set this to 0 to indicate that this array contains
// per-vertex data, or to 1 to indicate that it
// contains per-instance data. If higher than 1,
// the read row is advanced for each n instances.
////////////////////////////////////////////////////////////////////
INLINE void GeomVertexArrayFormat::
set_divisor(int divisor) {
nassertv(divisor >= 0);
_divisor = divisor;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GeomVertexArrayFormat::get_total_bytes // Function: GeomVertexArrayFormat::get_total_bytes
// Access: Published // Access: Published

View File

@ -36,6 +36,7 @@ GeomVertexArrayFormat() :
_stride(0), _stride(0),
_total_bytes(0), _total_bytes(0),
_pad_to(1), _pad_to(1),
_divisor(0),
_columns_unsorted(false) _columns_unsorted(false)
{ {
} }
@ -53,6 +54,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
_stride(0), _stride(0),
_total_bytes(0), _total_bytes(0),
_pad_to(1), _pad_to(1),
_divisor(0),
_columns_unsorted(false) _columns_unsorted(false)
{ {
add_column(name0, num_components0, numeric_type0, contents0); add_column(name0, num_components0, numeric_type0, contents0);
@ -74,6 +76,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
_stride(0), _stride(0),
_total_bytes(0), _total_bytes(0),
_pad_to(1), _pad_to(1),
_divisor(0),
_columns_unsorted(false) _columns_unsorted(false)
{ {
add_column(name0, num_components0, numeric_type0, contents0); add_column(name0, num_components0, numeric_type0, contents0);
@ -99,6 +102,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
_stride(0), _stride(0),
_total_bytes(0), _total_bytes(0),
_pad_to(1), _pad_to(1),
_divisor(0),
_columns_unsorted(false) _columns_unsorted(false)
{ {
add_column(name0, num_components0, numeric_type0, contents0); add_column(name0, num_components0, numeric_type0, contents0);
@ -128,6 +132,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
_stride(0), _stride(0),
_total_bytes(0), _total_bytes(0),
_pad_to(1), _pad_to(1),
_divisor(0),
_columns_unsorted(false) _columns_unsorted(false)
{ {
add_column(name0, num_components0, numeric_type0, contents0); add_column(name0, num_components0, numeric_type0, contents0);
@ -147,6 +152,7 @@ GeomVertexArrayFormat(const GeomVertexArrayFormat &copy) :
_stride(copy._stride), _stride(copy._stride),
_total_bytes(copy._total_bytes), _total_bytes(copy._total_bytes),
_pad_to(copy._pad_to), _pad_to(copy._pad_to),
_divisor(copy._divisor),
_columns_unsorted(copy._columns_unsorted) _columns_unsorted(copy._columns_unsorted)
{ {
Columns::const_iterator dti; Columns::const_iterator dti;
@ -166,6 +172,7 @@ operator = (const GeomVertexArrayFormat &copy) {
_stride = copy._stride; _stride = copy._stride;
_total_bytes = copy._total_bytes; _total_bytes = copy._total_bytes;
_pad_to = copy._pad_to; _pad_to = copy._pad_to;
_divisor = copy._divisor;
_columns.clear(); _columns.clear();
_columns_by_name.clear(); _columns_by_name.clear();
@ -671,6 +678,9 @@ compare_to(const GeomVertexArrayFormat &other) const {
if (_pad_to != other._pad_to) { if (_pad_to != other._pad_to) {
return _pad_to - other._pad_to; return _pad_to - other._pad_to;
} }
if (_divisor != other._divisor) {
return _divisor - other._divisor;
}
if (_columns.size() != other._columns.size()) { if (_columns.size() != other._columns.size()) {
return (int)_columns.size() - (int)other._columns.size(); return (int)_columns.size() - (int)other._columns.size();
} }
@ -756,6 +766,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
dg.add_uint16(_stride); dg.add_uint16(_stride);
dg.add_uint16(_total_bytes); dg.add_uint16(_total_bytes);
dg.add_uint8(_pad_to); dg.add_uint8(_pad_to);
dg.add_uint16(_divisor);
consider_sort_columns(); consider_sort_columns();
@ -845,6 +856,11 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_stride = scan.get_uint16(); _stride = scan.get_uint16();
_total_bytes = scan.get_uint16(); _total_bytes = scan.get_uint16();
_pad_to = scan.get_uint8(); _pad_to = scan.get_uint8();
if (manager->get_file_minor_ver() > 36) {
_divisor = scan.get_uint16();
} else {
_divisor = 0;
}
int num_columns = scan.get_uint16(); int num_columns = scan.get_uint16();
_columns.reserve(num_columns); _columns.reserve(num_columns);

View File

@ -88,6 +88,9 @@ PUBLISHED:
INLINE int get_pad_to() const; INLINE int get_pad_to() const;
INLINE void set_pad_to(int pad_to); INLINE void set_pad_to(int pad_to);
INLINE int get_divisor() const;
INLINE void set_divisor(int divisor);
INLINE int get_total_bytes() const; INLINE int get_total_bytes() const;
int add_column(InternalName *name, int num_components, int add_column(InternalName *name, int num_components,
@ -135,6 +138,7 @@ private:
int _stride; int _stride;
int _total_bytes; int _total_bytes;
int _pad_to; int _pad_to;
int _divisor;
typedef pvector<GeomVertexColumn *> Columns; typedef pvector<GeomVertexColumn *> Columns;
Columns _columns; Columns _columns;

View File

@ -98,12 +98,10 @@ get_num_rows() const {
// was changed, false if the object already contained n // was changed, false if the object already contained n
// rows (or if there was some error). // rows (or if there was some error).
// //
// Although this method is Published, application code // This can be used when you know exactly how many
// only very rarely has any need to call it. Instead, // rows you will be needing. It is faster than
// you should use the GeomVertexWriter to build up the // reserve_num_rows(). Also see unclean_set_num_rows()
// rows in a GeomVertexData object automatically, // if you are planning to fill in all the data yourself.
// without need to explicitly set the number of
// rows.
// //
// Don't call this in a downstream thread unless you // Don't call this in a downstream thread unless you
// don't mind it blowing away other changes you might // don't mind it blowing away other changes you might
@ -129,12 +127,9 @@ set_num_rows(int n) {
// anyway; it provides a tiny performance boost over // anyway; it provides a tiny performance boost over
// set_num_rows(). // set_num_rows().
// //
// Although this method is Published, application code // This can be used when you know exactly how many
// only very rarely has any need to call it. Instead, // rows you will be needing. It is faster than
// you should use the GeomVertexWriter to build up the // reserve_num_rows().
// rows in a GeomVertexData object automatically,
// without need to explicitly set the number of
// rows.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexData:: INLINE bool GeomVertexData::
unclean_set_num_rows(int n) { unclean_set_num_rows(int n) {
@ -152,6 +147,10 @@ unclean_set_num_rows(int n) {
// This is a performance optimization only; it is // This is a performance optimization only; it is
// especially useful when you know ahead of time that // especially useful when you know ahead of time that
// you will be adding n rows to the data. // you will be adding n rows to the data.
//
// If you know exactly how many rows you will be
// needing, it is significantly faster to use
// set_num_rows() or unclean_set_num_rows() instead.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE bool GeomVertexData:: INLINE bool GeomVertexData::
reserve_num_rows(int n) { reserve_num_rows(int n) {

View File

@ -2368,7 +2368,7 @@ get_array_info(const InternalName *name,
const GeomVertexArrayDataHandle *&array_reader, const GeomVertexArrayDataHandle *&array_reader,
int &num_values, int &num_values,
GeomVertexDataPipelineReader::NumericType &numeric_type, GeomVertexDataPipelineReader::NumericType &numeric_type,
int &start, int &stride, int &start, int &stride, int &divisor,
int &num_elements, int &element_stride) const { int &num_elements, int &element_stride) const {
nassertr(_got_array_readers, false); nassertr(_got_array_readers, false);
int array_index; int array_index;
@ -2379,6 +2379,7 @@ get_array_info(const InternalName *name,
numeric_type = column->get_numeric_type(); numeric_type = column->get_numeric_type();
start = column->get_start(); start = column->get_start();
stride = _cdata->_format->get_array(array_index)->get_stride(); stride = _cdata->_format->get_array(array_index)->get_stride();
divisor = _cdata->_format->get_array(array_index)->get_divisor();
num_elements = column->get_num_elements(); num_elements = column->get_num_elements();
element_stride = column->get_element_stride(); element_stride = column->get_element_stride();
return true; return true;

View File

@ -453,7 +453,7 @@ public:
bool get_array_info(const InternalName *name, bool get_array_info(const InternalName *name,
const GeomVertexArrayDataHandle *&array_reader, const GeomVertexArrayDataHandle *&array_reader,
int &num_values, NumericType &numeric_type, int &num_values, NumericType &numeric_type,
int &start, int &stride, int &start, int &stride, int &divisor,
int &num_elements, int &element_stride) const; int &num_elements, int &element_stride) const;
INLINE bool has_vertex() const; INLINE bool has_vertex() const;

View File

@ -33,7 +33,7 @@ static const unsigned short _bam_major_ver = 6;
// Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData. // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
static const unsigned short _bam_first_minor_ver = 14; static const unsigned short _bam_first_minor_ver = 14;
static const unsigned short _bam_minor_ver = 36; static const unsigned short _bam_minor_ver = 37;
// Bumped to minor version 14 on 12/19/07 to change default ColorAttrib. // Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
// Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort. // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
// Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level. // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
@ -57,5 +57,6 @@ static const unsigned short _bam_minor_ver = 36;
// Bumped to minor version 34 on 9/16/14 to add ScissorAttrib::_off. // Bumped to minor version 34 on 9/16/14 to add ScissorAttrib::_off.
// Bumped to minor version 35 on 12/3/14 to change StencilAttrib. // Bumped to minor version 35 on 12/3/14 to change StencilAttrib.
// Bumped to minor version 36 on 12/9/14 to add samplers and lod settings. // Bumped to minor version 36 on 12/9/14 to add samplers and lod settings.
// Bumped to minor version 37 on 1/22/15 to add GeomVertexArrayFormat::_divisor.
#endif #endif