Implement support for SSBOs

This commit is contained in:
rdb 2016-12-13 21:22:17 +01:00
parent 23645cc407
commit 34068dc0c1
28 changed files with 1014 additions and 15 deletions

View File

@ -62,6 +62,14 @@ release_all_index_buffers() {
return _prepared_objects->release_all_index_buffers();
}
/**
* Frees the resources for all index buffers associated with this GSG.
*/
INLINE int GraphicsStateGuardian::
release_all_shader_buffers() {
return _prepared_objects->release_all_shader_buffers();
}
/**
* Sets the active flag associated with the GraphicsStateGuardian. If the
* GraphicsStateGuardian is marked inactive, nothing is rendered. This is not

View File

@ -62,12 +62,15 @@
#include <algorithm>
#include <limits.h>
PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Vertex buffer switch:Vertex");
PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Vertex buffer switch:Index");
PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Buffer switch:Vertex");
PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Buffer switch:Index");
PStatCollector GraphicsStateGuardian::_shader_buffer_switch_pcollector("Buffer switch:Shader");
PStatCollector GraphicsStateGuardian::_load_vertex_buffer_pcollector("Draw:Transfer data:Vertex buffer");
PStatCollector GraphicsStateGuardian::_load_index_buffer_pcollector("Draw:Transfer data:Index buffer");
PStatCollector GraphicsStateGuardian::_load_shader_buffer_pcollector("Draw:Transfer data:Shader buffer");
PStatCollector GraphicsStateGuardian::_create_vertex_buffer_pcollector("Draw:Transfer data:Create Vertex buffer");
PStatCollector GraphicsStateGuardian::_create_index_buffer_pcollector("Draw:Transfer data:Create Index buffer");
PStatCollector GraphicsStateGuardian::_create_shader_buffer_pcollector("Draw:Transfer data:Create Shader buffer");
PStatCollector GraphicsStateGuardian::_load_texture_pcollector("Draw:Transfer data:Texture");
PStatCollector GraphicsStateGuardian::_data_transferred_pcollector("Data transferred");
PStatCollector GraphicsStateGuardian::_texmgrmem_total_pcollector("Texture manager");
@ -104,6 +107,7 @@ PStatCollector GraphicsStateGuardian::_prepare_geom_pcollector("Draw:Prepare:Geo
PStatCollector GraphicsStateGuardian::_prepare_shader_pcollector("Draw:Prepare:Shader");
PStatCollector GraphicsStateGuardian::_prepare_vertex_buffer_pcollector("Draw:Prepare:Vertex buffer");
PStatCollector GraphicsStateGuardian::_prepare_index_buffer_pcollector("Draw:Prepare:Index buffer");
PStatCollector GraphicsStateGuardian::_prepare_shader_buffer_pcollector("Draw:Prepare:Shader buffer");
PStatCollector GraphicsStateGuardian::_draw_set_state_transform_pcollector("Draw:Set State:Transform");
PStatCollector GraphicsStateGuardian::_draw_set_state_alpha_test_pcollector("Draw:Set State:Alpha test");
@ -657,6 +661,22 @@ void GraphicsStateGuardian::
release_index_buffer(IndexBufferContext *) {
}
/**
* Prepares the indicated buffer for retained-mode rendering.
*/
BufferContext *GraphicsStateGuardian::
prepare_shader_buffer(ShaderBuffer *) {
return (BufferContext *)NULL;
}
/**
* Frees the resources previously allocated via a call to prepare_data(),
* including deleting the BufferContext itself, if necessary.
*/
void GraphicsStateGuardian::
release_shader_buffer(BufferContext *) {
}
/**
* Begins a new occlusion query. After this call, you may call
* begin_draw_primitives() and draw_triangles()/draw_whatever() repeatedly.

View File

@ -88,6 +88,7 @@ PUBLISHED:
INLINE int release_all_geoms();
INLINE int release_all_vertex_buffers();
INLINE int release_all_index_buffers();
INLINE int release_all_shader_buffers();
INLINE void set_active(bool active);
INLINE bool is_active() const;
@ -307,6 +308,9 @@ public:
virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
virtual void release_index_buffer(IndexBufferContext *ibc);
virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data);
virtual void release_shader_buffer(BufferContext *ibc);
virtual void begin_occlusion_query();
virtual PT(OcclusionQueryContext) end_occlusion_query();
@ -640,10 +644,13 @@ public:
// Statistics
static PStatCollector _vertex_buffer_switch_pcollector;
static PStatCollector _index_buffer_switch_pcollector;
static PStatCollector _shader_buffer_switch_pcollector;
static PStatCollector _load_vertex_buffer_pcollector;
static PStatCollector _load_index_buffer_pcollector;
static PStatCollector _load_shader_buffer_pcollector;
static PStatCollector _create_vertex_buffer_pcollector;
static PStatCollector _create_index_buffer_pcollector;
static PStatCollector _create_shader_buffer_pcollector;
static PStatCollector _load_texture_pcollector;
static PStatCollector _data_transferred_pcollector;
static PStatCollector _texmgrmem_total_pcollector;
@ -680,6 +687,7 @@ public:
static PStatCollector _prepare_shader_pcollector;
static PStatCollector _prepare_vertex_buffer_pcollector;
static PStatCollector _prepare_index_buffer_pcollector;
static PStatCollector _prepare_shader_buffer_pcollector;
// A whole slew of collectors to measure the cost of individual state
// changes. These are disabled by default.

View File

@ -0,0 +1,25 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file glBufferContext_src.I
* @author rdb
* @date 2016-12-12
*/
/**
*
*/
INLINE CLP(BufferContext)::
CLP(BufferContext)(CLP(GraphicsStateGuardian) *glgsg,
PreparedGraphicsObjects *pgo) :
BufferContext(&pgo->_sbuffer_residency),
AdaptiveLruPage(0),
_glgsg(glgsg)
{
_index = 0;
}

View File

@ -0,0 +1,49 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file glBufferContext_src.cxx
* @author rdb
* @date 2016-12-12
*/
TypeHandle CLP(BufferContext)::_type_handle;
/**
* Evicts the page from the LRU. Called internally when the LRU determines
* that it is full. May also be called externally when necessary to
* explicitly evict the page.
*
* It is legal for this method to either evict the page as requested, do
* nothing (in which case the eviction will be requested again at the next
* epoch), or requeue itself on the tail of the queue (in which case the
* eviction will be requested again much later).
*/
void CLP(BufferContext)::
evict_lru() {
dequeue_lru();
// Make sure the buffer is unbound before we delete it.
if (_glgsg->_current_ibuffer_index == _index) {
if (GLCAT.is_debug() && gl_debug_buffers) {
GLCAT.debug()
<< "unbinding index buffer\n";
}
_glgsg->_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
_glgsg->_current_ibuffer_index = 0;
}
// Free the buffer.
_glgsg->_glDeleteBuffers(1, &_index);
// We still need a valid index number, though, in case we want to re-load
// the buffer later.
_glgsg->_glGenBuffers(1, &_index);
update_data_size_bytes(0);
set_resident(false);
}

View File

@ -0,0 +1,52 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file glBufferContext_src.h
* @author rdb
* @date 2016-12-12
*/
#include "pandabase.h"
#include "bufferContext.h"
#include "deletedChain.h"
/**
* Caches a GeomPrimitive on the GL as a buffer object.
*/
class EXPCL_GL CLP(BufferContext) : public BufferContext, public AdaptiveLruPage {
public:
INLINE CLP(BufferContext)(CLP(GraphicsStateGuardian) *glgsg,
PreparedGraphicsObjects *pgo);
ALLOC_DELETED_CHAIN(CLP(BufferContext));
virtual void evict_lru();
CLP(GraphicsStateGuardian) *_glgsg;
// This is the GL "name" of the data object.
GLuint _index;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
BufferContext::init_type();
register_type(_type_handle, CLASSPREFIX_QUOTED "BufferContext",
BufferContext::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "glBufferContext_src.I"

View File

@ -1796,7 +1796,7 @@ reset() {
}
#endif
#ifndef OPENGLES
#ifndef OPENGLES_1
// Check for uniform buffers.
#ifdef OPENGLES
if (is_at_least_gl_version(3, 1) || has_extension("GL_ARB_uniform_buffer_object")) {
@ -1810,12 +1810,30 @@ reset() {
get_extension_func("glGetActiveUniformBlockiv");
_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)
get_extension_func("glGetActiveUniformBlockName");
_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)
get_extension_func("glBindBufferBase");
} else {
_supports_uniform_buffers = false;
}
#ifndef OPENGLES
// Check for SSBOs.
if (is_at_least_gl_version(4, 3) || has_extension("ARB_shader_storage_buffer_object")) {
_supports_shader_buffers = true;
_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC)
get_extension_func("glGetProgramInterfaceiv");
_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)
get_extension_func("glGetProgramResourceName");
_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC)
get_extension_func("glGetProgramResourceiv");
} else
#endif
{
_supports_shader_buffers = false;
}
if (_supports_uniform_buffers || _supports_shader_buffers) {
_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)
get_extension_func("glBindBufferBase");
}
#endif
// Check whether we support geometry instancing and instanced vertex
@ -3031,6 +3049,9 @@ reset() {
_current_vertex_buffers.clear();
_current_vertex_format.clear();
memset(_vertex_attrib_columns, 0, sizeof(const GeomVertexColumn *) * 32);
_current_sbuffer_index = 0;
_current_sbuffer_base.clear();
#endif
report_my_gl_errors();
@ -5873,6 +5894,122 @@ setup_primitive(const unsigned char *&client_pointer,
return true;
}
#ifndef OPENGLES
/**
* Creates a new retained-mode representation of the given data, and returns a
* newly-allocated BufferContext pointer to reference it. It is the
* responsibility of the calling function to later call release_shader_buffer()
* with this same pointer (which will also delete the pointer).
*
* This function should not be called directly to prepare a buffer. Instead,
* call ShaderBuffer::prepare().
*/
BufferContext *CLP(GraphicsStateGuardian)::
prepare_shader_buffer(ShaderBuffer *data) {
if (_supports_shader_buffers) {
PStatGPUTimer timer(this, _prepare_shader_buffer_pcollector);
CLP(BufferContext) *gbc = new CLP(BufferContext)(this, _prepared_objects);
_glGenBuffers(1, &gbc->_index);
if (GLCAT.is_debug() && gl_debug_buffers) {
GLCAT.debug()
<< "creating shader buffer " << (int)gbc->_index << ": "<< *data << "\n";
}
_glBindBuffer(GL_SHADER_STORAGE_BUFFER, gbc->_index);
_current_sbuffer_index = gbc->_index;
if (_use_object_labels) {
string name = data->get_name();
_glObjectLabel(GL_SHADER_STORAGE_BUFFER, gbc->_index, name.size(), name.data());
}
uint64_t num_bytes = data->get_data_size_bytes();
if (_supports_buffer_storage) {
_glBufferStorage(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), 0);
} else {
_glBufferData(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), get_usage(data->get_usage_hint()));
}
gbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
report_my_gl_errors();
return gbc;
}
return NULL;
}
/**
* Binds the given shader buffer to the given binding slot.
*/
void CLP(GraphicsStateGuardian)::
apply_shader_buffer(GLuint base, ShaderBuffer *buffer) {
GLuint index = 0;
if (buffer != NULL) {
BufferContext *bc = buffer->prepare_now(get_prepared_objects(), this);
if (bc != NULL) {
CLP(BufferContext) *gbc = DCAST(CLP(BufferContext), bc);
index = gbc->_index;
gbc->set_active(true);
}
}
if (base >= _current_sbuffer_base.size()) {
_current_sbuffer_base.resize(base + 1, 0);
}
if (_current_sbuffer_base[base] != index) {
if (GLCAT.is_spam() && gl_debug_buffers) {
GLCAT.spam()
<< "binding shader buffer " << (int)index
<< " to index " << base << "\n";
}
_glBindBufferBase(GL_SHADER_STORAGE_BUFFER, base, index);
_current_sbuffer_base[base] = index;
_current_sbuffer_index = index;
report_my_gl_errors();
}
}
/**
* Frees the GL resources previously allocated for the data. This function
* should never be called directly; instead, call Data::release() (or simply
* let the Data destruct).
*/
void CLP(GraphicsStateGuardian)::
release_shader_buffer(BufferContext *bc) {
nassertv(_supports_buffers);
CLP(BufferContext) *gbc = DCAST(CLP(BufferContext), bc);
if (GLCAT.is_debug() && gl_debug_buffers) {
GLCAT.debug()
<< "deleting shader buffer " << (int)gbc->_index << "\n";
}
// Make sure the buffer is unbound before we delete it. Not strictly
// necessary according to the OpenGL spec, but it might help out a flaky
// driver, and we need to keep our internal state consistent anyway.
if (_current_sbuffer_index == gbc->_index) {
if (GLCAT.is_spam() && gl_debug_buffers) {
GLCAT.spam()
<< "unbinding shader buffer\n";
}
_glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
_current_sbuffer_index = 0;
}
_glDeleteBuffers(1, &gbc->_index);
report_my_gl_errors();
gbc->_index = 0;
delete gbc;
}
#endif
#ifndef OPENGLES
/**
* Begins a new occlusion query. After this call, you may call
@ -6499,7 +6636,7 @@ do_issue_shade_model() {
#ifndef OPENGLES_1
/**
*
* Called when the current ShaderAttrib state has changed.
*/
void CLP(GraphicsStateGuardian)::
do_issue_shader() {
@ -6512,21 +6649,30 @@ do_issue_shader() {
shader = _default_shader;
nassertv(shader != NULL);
}
#endif
if (shader) {
context = shader->prepare_now(get_prepared_objects(), this);
if (_current_shader != shader) {
context = shader->prepare_now(get_prepared_objects(), this);
} else {
context = _current_shader_context;
}
}
#ifndef SUPPORT_FIXED_FUNCTION
// If it failed, try applying the default shader.
if (shader != _default_shader && (context == 0 || !context->valid())) {
shader = _default_shader;
nassertv(shader != NULL);
context = shader->prepare_now(get_prepared_objects(), this);
if (_current_shader != shader) {
context = shader->prepare_now(get_prepared_objects(), this);
} else {
context = _current_shader_context;
}
}
#endif
if (context == 0 || (context->valid() == false)) {
if (context == 0 || !context->valid()) {
if (_current_shader_context != 0) {
_current_shader_context->unbind();
_current_shader = 0;
@ -6538,12 +6684,16 @@ do_issue_shader() {
// bind the new one.
if (_current_shader_context != NULL &&
_current_shader->get_language() != shader->get_language()) {
// If it's a different type of shader, make sure to unbind the old.
_current_shader_context->unbind();
}
context->bind();
_current_shader = shader;
_current_shader_context = context;
}
// Bind the shader storage buffers.
context->update_shader_buffer_bindings(_current_shader_context);
_current_shader_context = context;
}
#ifndef OPENGLES
@ -10116,6 +10266,7 @@ set_state_and_transform(const RenderState *target,
}
#endif
// Update all of the state that is bound to the shader program.
if (_current_shader_context != NULL) {
_current_shader_context->set_state_and_transform(target, transform, _projection_mat);
}

View File

@ -344,6 +344,12 @@ public:
const GeomPrimitivePipelineReader *reader,
bool force);
#ifndef OPENGLES
virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data);
void apply_shader_buffer(GLuint base, ShaderBuffer *buffer);
virtual void release_shader_buffer(BufferContext *bc);
#endif
#ifndef OPENGLES
virtual void begin_occlusion_query();
virtual PT(OcclusionQueryContext) end_occlusion_query();
@ -685,6 +691,9 @@ protected:
bool _use_vertex_attrib_binding;
CPT(GeomVertexFormat) _current_vertex_format;
const GeomVertexColumn *_vertex_attrib_columns[32];
GLuint _current_sbuffer_index;
pvector<GLuint> _current_sbuffer_base;
#endif
int _active_texture_stage;
@ -811,6 +820,7 @@ public:
#ifndef OPENGLES_1
bool _supports_uniform_buffers;
bool _supports_shader_buffers;
PFNGLBINDBUFFERBASEPROC _glBindBufferBase;
bool _supports_buffer_storage;
@ -995,6 +1005,9 @@ public:
PFNGLMAKETEXTUREHANDLENONRESIDENTPROC _glMakeTextureHandleNonResident;
PFNGLUNIFORMHANDLEUI64PROC _glUniformHandleui64;
PFNGLUNIFORMHANDLEUI64VPROC _glUniformHandleui64v;
PFNGLGETPROGRAMINTERFACEIVPROC _glGetProgramInterfaceiv;
PFNGLGETPROGRAMRESOURCENAMEPROC _glGetProgramResourceName;
PFNGLGETPROGRAMRESOURCEIVPROC _glGetProgramResourceiv;
#endif // !OPENGLES
GLenum _edge_clamp;
@ -1090,6 +1103,7 @@ private:
friend class CLP(VertexBufferContext);
friend class CLP(IndexBufferContext);
friend class CLP(BufferContext);
friend class CLP(ShaderContext);
friend class CLP(CgShaderContext);
friend class CLP(GraphicsBuffer);

View File

@ -324,6 +324,34 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
}
}
#ifndef OPENGLES
// Get the used shader storage blocks.
if (_glgsg->_supports_shader_buffers) {
GLint block_count = 0, block_maxlength = 0;
_glgsg->_glGetProgramInterfaceiv(_glsl_program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &block_count);
_glgsg->_glGetProgramInterfaceiv(_glsl_program, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &block_maxlength);
block_maxlength = max(64, block_maxlength);
char *block_name_cstr = (char *)alloca(block_maxlength);
for (int i = 0; i < block_count; ++i) {
block_name_cstr[0] = 0;
_glgsg->_glGetProgramResourceName(_glsl_program, GL_SHADER_STORAGE_BLOCK, i, block_maxlength, NULL, block_name_cstr);
const GLenum props[] = {GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE};
GLint values[2];
_glgsg->_glGetProgramResourceiv(_glsl_program, GL_SHADER_STORAGE_BLOCK, i, 2, props, 2, NULL, values);
StorageBlock block;
block._name = InternalName::make(block_name_cstr);
block._binding_index = values[0];
block._min_size = values[1];
_storage_blocks.push_back(block);
}
}
#endif
// Bind the program, so that we can call glUniform1i for the textures.
_glgsg->_glUseProgram(_glsl_program);
@ -2659,6 +2687,31 @@ update_shader_texture_bindings(ShaderContext *prev) {
_glgsg->report_my_gl_errors();
}
/**
* Updates the shader buffer bindings for this shader.
*/
void CLP(ShaderContext)::
update_shader_buffer_bindings(ShaderContext *prev) {
#ifndef OPENGLES
// Update the shader storage buffer bindings.
const ShaderAttrib *attrib = _glgsg->_target_shader;
for (size_t i = 0; i < _storage_blocks.size(); ++i) {
StorageBlock &block = _storage_blocks[i];
ShaderBuffer *buffer = attrib->get_shader_input_buffer(block._name);
#ifndef NDEBUG
if (buffer->get_data_size_bytes() < block._min_size) {
GLCAT.error()
<< "cannot bind " << *buffer << " to shader because it is too small"
" (expected at least " << block._min_size << " bytes)\n";
}
#endif
_glgsg->apply_shader_buffer(block._binding_index, buffer);
}
#endif
}
/**
* This subroutine prints the infolog for a shader.
*/

View File

@ -55,6 +55,7 @@ public:
bool update_shader_vertex_arrays(ShaderContext *prev, bool force);
void disable_shader_texture_bindings() OVERRIDE;
void update_shader_texture_bindings(ShaderContext *prev) OVERRIDE;
void update_shader_buffer_bindings(ShaderContext *prev) OVERRIDE;
INLINE bool uses_standard_vertex_arrays(void);
INLINE bool uses_custom_vertex_arrays(void);
@ -87,6 +88,17 @@ private:
pmap<GLint, GLuint64> _glsl_uniform_handles;
#endif
#ifndef OPENGLES
struct StorageBlock {
CPT(InternalName) _name;
GLuint _binding_index;
GLint _min_size;
};
typedef pvector<StorageBlock> StorageBlocks;
StorageBlocks _storage_blocks;
BitArray _used_storage_bindings;
#endif
struct ImageInput {
CPT(InternalName) _name;
CLP(TextureContext) *_gtc;

View File

@ -331,6 +331,7 @@ void CLP(init_classes)() {
CLP(SamplerContext)::init_type();
#endif
CLP(VertexBufferContext)::init_type();
CLP(BufferContext)::init_type();
CLP(GraphicsBuffer)::init_type();
#ifndef OPENGLES

View File

@ -21,6 +21,7 @@
#include "glSamplerContext_src.cxx"
#include "glVertexBufferContext_src.cxx"
#include "glIndexBufferContext_src.cxx"
#include "glBufferContext_src.cxx"
#include "glOcclusionQueryContext_src.cxx"
#include "glTimerQueryContext_src.cxx"
#include "glLatencyQueryContext_src.cxx"

View File

@ -33,6 +33,7 @@
#include "glSamplerContext_src.h"
#include "glVertexBufferContext_src.h"
#include "glIndexBufferContext_src.h"
#include "glBufferContext_src.h"
#include "glOcclusionQueryContext_src.h"
#include "glTimerQueryContext_src.h"
#include "glLatencyQueryContext_src.h"

View File

@ -5,6 +5,7 @@
#include "samplerContext.cxx"
#include "samplerState.cxx"
#include "savedContext.cxx"
#include "shaderBuffer.cxx"
#include "shaderContext.cxx"
#include "shader.cxx"
#include "simpleAllocator.cxx"

View File

@ -45,6 +45,7 @@ release_all() {
_texture_residency.set_levels();
_vbuffer_residency.set_levels();
_ibuffer_residency.set_levels();
_sbuffer_residency.set_levels();
}
/**
@ -58,7 +59,8 @@ get_num_queued() const {
get_num_queued_geoms() +
get_num_queued_shaders() +
get_num_queued_vertex_buffers() +
get_num_queued_index_buffers());
get_num_queued_index_buffers() +
get_num_queued_shader_buffers());
}
/**
@ -72,7 +74,8 @@ get_num_prepared() const {
get_num_prepared_geoms() +
get_num_prepared_shaders() +
get_num_prepared_vertex_buffers() +
get_num_prepared_index_buffers());
get_num_prepared_index_buffers() +
get_num_prepared_shader_buffers());
}
/**

View File

@ -41,6 +41,7 @@ PreparedGraphicsObjects() :
_texture_residency(_name, "texture"),
_vbuffer_residency(_name, "vbuffer"),
_ibuffer_residency(_name, "ibuffer"),
_sbuffer_residency(_name, "sbuffer"),
_graphics_memory_lru("graphics_memory_lru", graphics_memory_limit),
_sampler_object_lru("sampler_object_lru", sampler_object_limit)
{
@ -121,6 +122,16 @@ PreparedGraphicsObjects::
delete ibc;
}
_released_index_buffers.clear();
release_all_shader_buffers();
Buffers::iterator bci;
for (bci = _released_shader_buffers.begin();
bci != _released_shader_buffers.end();
++bci) {
BufferContext *bc = (BufferContext *)(*bci);
delete bc;
}
_released_shader_buffers.clear();
}
/**
@ -167,6 +178,9 @@ show_residency_trackers(ostream &out) const {
out << "\nIndex buffers:\n";
_ibuffer_residency.write(out, 2);
out << "\nShader buffers:\n";
_sbuffer_residency.write(out, 2);
}
/**
@ -1195,6 +1209,155 @@ prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg) {
return ibc;
}
/**
* Indicates that a buffer would like to be put on the list to be prepared
* when the GSG is next ready to do this (presumably at the next frame).
*/
void PreparedGraphicsObjects::
enqueue_shader_buffer(ShaderBuffer *data) {
ReMutexHolder holder(_lock);
_enqueued_shader_buffers.insert(data);
}
/**
* Returns true if the index buffer has been queued on this GSG, false
* otherwise.
*/
bool PreparedGraphicsObjects::
is_shader_buffer_queued(const ShaderBuffer *data) const {
ReMutexHolder holder(_lock);
EnqueuedShaderBuffers::const_iterator qi = _enqueued_shader_buffers.find((ShaderBuffer *)data);
return (qi != _enqueued_shader_buffers.end());
}
/**
* Removes a buffer from the queued list of data arrays to be prepared.
* Normally it is not necessary to call this, unless you change your mind
* about preparing it at the last minute, since the data will automatically be
* dequeued and prepared at the next frame.
*
* The return value is true if the buffer is successfully dequeued, false if
* it had not been queued.
*/
bool PreparedGraphicsObjects::
dequeue_shader_buffer(ShaderBuffer *data) {
ReMutexHolder holder(_lock);
EnqueuedShaderBuffers::iterator qi = _enqueued_shader_buffers.find(data);
if (qi != _enqueued_shader_buffers.end()) {
_enqueued_shader_buffers.erase(qi);
return true;
}
return false;
}
/**
* Returns true if the index buffer has been prepared on this GSG, false
* otherwise.
*/
bool PreparedGraphicsObjects::
is_shader_buffer_prepared(const ShaderBuffer *data) const {
return data->is_prepared((PreparedGraphicsObjects *)this);
}
/**
* Indicates that a data context, created by a previous call to
* prepare_shader_buffer(), is no longer needed. The driver resources will not
* be freed until some GSG calls update(), indicating it is at a stage where
* it is ready to release datas--this prevents conflicts from threading or
* multiple GSG's sharing datas (we have no way of knowing which graphics
* context is currently active, or what state it's in, at the time
* release_shader_buffer is called).
*/
void PreparedGraphicsObjects::
release_shader_buffer(BufferContext *bc) {
ReMutexHolder holder(_lock);
bool removed = (_prepared_shader_buffers.erase(bc) != 0);
nassertv(removed);
_released_shader_buffers.insert(bc);
}
/**
* Releases all datas at once. This will force them to be reloaded into data
* memory for all GSG's that share this object. Returns the number of datas
* released.
*/
int PreparedGraphicsObjects::
release_all_shader_buffers() {
ReMutexHolder holder(_lock);
int num_shader_buffers = (int)_prepared_shader_buffers.size() + (int)_enqueued_shader_buffers.size();
Buffers::iterator bci;
for (bci = _prepared_shader_buffers.begin();
bci != _prepared_shader_buffers.end();
++bci) {
BufferContext *bc = (BufferContext *)(*bci);
_released_shader_buffers.insert(bc);
}
_prepared_shader_buffers.clear();
_enqueued_shader_buffers.clear();
return num_shader_buffers;
}
/**
* Returns the number of index buffers that have been enqueued to be prepared
* on this GSG.
*/
int PreparedGraphicsObjects::
get_num_queued_shader_buffers() const {
return _enqueued_shader_buffers.size();
}
/**
* Returns the number of index buffers that have already been prepared on this
* GSG.
*/
int PreparedGraphicsObjects::
get_num_prepared_shader_buffers() const {
return _prepared_shader_buffers.size();
}
/**
* Immediately creates a new BufferContext for the indicated data and
* returns it. This assumes that the GraphicsStateGuardian is the currently
* active rendering context and that it is ready to accept new datas. If this
* is not necessarily the case, you should use enqueue_shader_buffer() instead.
*
* Normally, this function is not called directly. Call Data::prepare_now()
* instead.
*
* The BufferContext contains all of the pertinent information needed by
* the GSG to keep track of this one particular data, and will exist as long
* as the data is ready to be rendered.
*
* When either the Data or the PreparedGraphicsObjects object destructs, the
* BufferContext will be deleted.
*/
BufferContext *PreparedGraphicsObjects::
prepare_shader_buffer_now(ShaderBuffer *data, GraphicsStateGuardianBase *gsg) {
ReMutexHolder holder(_lock);
// Ask the GSG to create a brand new BufferContext. There might be
// several GSG's sharing the same set of datas; if so, it doesn't matter
// which of them creates the context (since they're all shared anyway).
BufferContext *bc = gsg->prepare_shader_buffer(data);
if (bc != (BufferContext *)NULL) {
bool prepared = _prepared_shader_buffers.insert(bc).second;
nassertr(prepared, bc);
}
return bc;
}
/**
* This is called by the GraphicsStateGuardian to indicate that it is about to
* begin processing of the frame.
@ -1276,6 +1439,7 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) {
_texture_residency.begin_frame(current_thread);
_vbuffer_residency.begin_frame(current_thread);
_ibuffer_residency.begin_frame(current_thread);
_sbuffer_residency.begin_frame(current_thread);
// Now prepare all the textures, geoms, and buffers awaiting preparation.
EnqueuedTextures::iterator qti;
@ -1359,6 +1523,7 @@ end_frame(Thread *current_thread) {
_texture_residency.end_frame(current_thread);
_vbuffer_residency.end_frame(current_thread);
_ibuffer_residency.end_frame(current_thread);
_sbuffer_residency.end_frame(current_thread);
}
/**

View File

@ -22,6 +22,7 @@
#include "geomVertexArrayData.h"
#include "geomPrimitive.h"
#include "shader.h"
#include "shaderBuffer.h"
#include "pointerTo.h"
#include "pStatCollector.h"
#include "pset.h"
@ -35,6 +36,7 @@ class GeomContext;
class ShaderContext;
class VertexBufferContext;
class IndexBufferContext;
class BufferContext;
class GraphicsStateGuardianBase;
/**
@ -142,6 +144,19 @@ PUBLISHED:
prepare_index_buffer_now(GeomPrimitive *data,
GraphicsStateGuardianBase *gsg);
void enqueue_shader_buffer(ShaderBuffer *data);
bool is_shader_buffer_queued(const ShaderBuffer *data) const;
bool dequeue_shader_buffer(ShaderBuffer *data);
bool is_shader_buffer_prepared(const ShaderBuffer *data) const;
void release_shader_buffer(BufferContext *bc);
int release_all_shader_buffers();
int get_num_queued_shader_buffers() const;
int get_num_prepared_shader_buffers() const;
BufferContext *
prepare_shader_buffer_now(ShaderBuffer *data,
GraphicsStateGuardianBase *gsg);
public:
void begin_frame(GraphicsStateGuardianBase *gsg,
Thread *current_thread);
@ -160,6 +175,7 @@ private:
typedef phash_set<BufferContext *, pointer_hash> Buffers;
typedef phash_set< PT(GeomVertexArrayData) > EnqueuedVertexBuffers;
typedef phash_set< PT(GeomPrimitive) > EnqueuedIndexBuffers;
typedef phash_set< PT(ShaderBuffer) > EnqueuedShaderBuffers;
// Sampler states are stored a little bit differently, as they are mapped by
// value and can't store the list of prepared samplers.
@ -207,6 +223,8 @@ private:
EnqueuedVertexBuffers _enqueued_vertex_buffers;
Buffers _prepared_index_buffers, _released_index_buffers;
EnqueuedIndexBuffers _enqueued_index_buffers;
Buffers _prepared_shader_buffers, _released_shader_buffers;
EnqueuedShaderBuffers _enqueued_shader_buffers;
BufferCache _vertex_buffer_cache;
BufferCacheLRU _vertex_buffer_cache_lru;
@ -220,6 +238,7 @@ public:
BufferResidencyTracker _texture_residency;
BufferResidencyTracker _vbuffer_residency;
BufferResidencyTracker _ibuffer_residency;
BufferResidencyTracker _sbuffer_residency;
AdaptiveLru _graphics_memory_lru;
SimpleLru _sampler_object_lru;

View File

@ -0,0 +1,63 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file shaderBuffer.I
* @author rdb
* @date 2016-12-12
*/
/**
* Creates an uninitialized buffer object with the given size. For now, these
* parameters cannot be modified, but this may change in the future.
*/
INLINE ShaderBuffer::
ShaderBuffer(const string &name, uint64_t size, UsageHint usage_hint) :
Namable(name),
_data_size_bytes(size),
_usage_hint(usage_hint) {
}
/**
* Creates a buffer object initialized with the given data. For now, these
* parameters cannot be modified, but this may change in the future.
*/
INLINE ShaderBuffer::
ShaderBuffer(const string &name, pvector<unsigned char> initial_data, UsageHint usage_hint) :
Namable(name),
_data_size_bytes(initial_data.size()),
_usage_hint(usage_hint),
_initial_data(initial_data) {
}
/**
* Returns the buffer size in bytes.
*/
INLINE uint64_t ShaderBuffer::
get_data_size_bytes() const {
return _data_size_bytes;
}
/**
* Returns the buffer usage hint.
*/
INLINE GeomEnums::UsageHint ShaderBuffer::
get_usage_hint() const {
return _usage_hint;
}
/**
* Returns a pointer to the initial buffer data, or NULL if not specified.
*/
INLINE const unsigned char *ShaderBuffer::
get_initial_data() const {
if (_initial_data.empty()) {
return NULL;
} else {
return &_initial_data[0];
}
}

View File

@ -0,0 +1,193 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file shaderBuffer.cxx
* @author rdb
* @date 2016-12-12
*/
#include "shaderBuffer.h"
#include "preparedGraphicsObjects.h"
TypeHandle ShaderBuffer::_type_handle;
/**
*
*/
void ShaderBuffer::
output(ostream &out) const {
out << "buffer " << get_name() << ", " << _data_size_bytes << "B, " << _usage_hint;
}
/**
* Indicates that the data should be enqueued to be prepared in the indicated
* prepared_objects at the beginning of the next frame. This will ensure the
* data is already loaded into the GSG if it is expected to be rendered soon.
*
* Use this function instead of prepare_now() to preload datas from a user
* interface standpoint.
*/
void ShaderBuffer::
prepare(PreparedGraphicsObjects *prepared_objects) {
prepared_objects->enqueue_shader_buffer(this);
}
/**
* Returns true if the data has already been prepared or enqueued for
* preparation on the indicated GSG, false otherwise.
*/
bool ShaderBuffer::
is_prepared(PreparedGraphicsObjects *prepared_objects) const {
if (_contexts == (Contexts *)NULL) {
return false;
}
Contexts::const_iterator ci;
ci = _contexts->find(prepared_objects);
if (ci != _contexts->end()) {
return true;
}
return prepared_objects->is_shader_buffer_queued(this);
}
/**
* Creates a context for the data on the particular GSG, if it does not
* already exist. Returns the new (or old) BufferContext. This assumes
* that the GraphicsStateGuardian is the currently active rendering context
* and that it is ready to accept new datas. If this is not necessarily the
* case, you should use prepare() instead.
*
* Normally, this is not called directly except by the GraphicsStateGuardian;
* a data does not need to be explicitly prepared by the user before it may be
* rendered.
*/
BufferContext *ShaderBuffer::
prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg) {
if (_contexts == (Contexts *)NULL) {
_contexts = new Contexts;
}
Contexts::const_iterator ci;
ci = _contexts->find(prepared_objects);
if (ci != _contexts->end()) {
return (*ci).second;
}
BufferContext *vbc = prepared_objects->prepare_shader_buffer_now(this, gsg);
if (vbc != (BufferContext *)NULL) {
(*_contexts)[prepared_objects] = vbc;
}
return vbc;
}
/**
* Frees the data context only on the indicated object, if it exists there.
* Returns true if it was released, false if it had not been prepared.
*/
bool ShaderBuffer::
release(PreparedGraphicsObjects *prepared_objects) {
if (_contexts != (Contexts *)NULL) {
Contexts::iterator ci;
ci = _contexts->find(prepared_objects);
if (ci != _contexts->end()) {
BufferContext *vbc = (*ci).second;
prepared_objects->release_shader_buffer(vbc);
return true;
}
}
// Maybe it wasn't prepared yet, but it's about to be.
return prepared_objects->dequeue_shader_buffer(this);
}
/**
* Frees the context allocated on all objects for which the data has been
* declared. Returns the number of contexts which have been freed.
*/
int ShaderBuffer::
release_all() {
int num_freed = 0;
if (_contexts != (Contexts *)NULL) {
// We have to traverse a copy of the _contexts list, because the
// PreparedGraphicsObjects object will call clear_prepared() in response
// to each release_shader_buffer(), and we don't want to be modifying the
// _contexts list while we're traversing it.
Contexts temp = *_contexts;
num_freed = (int)_contexts->size();
Contexts::const_iterator ci;
for (ci = temp.begin(); ci != temp.end(); ++ci) {
PreparedGraphicsObjects *prepared_objects = (*ci).first;
BufferContext *vbc = (*ci).second;
prepared_objects->release_shader_buffer(vbc);
}
// Now that we've called release_shader_buffer() on every known context,
// the _contexts list should have completely emptied itself.
nassertr(_contexts == NULL, num_freed);
}
return num_freed;
}
/**
* Tells the BamReader how to create objects of type ParamValue.
*/
void ShaderBuffer::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
/**
* Writes the contents of this object to the datagram for shipping out to a
* Bam file.
*/
void ShaderBuffer::
write_datagram(BamWriter *manager, Datagram &dg) {
dg.add_string(get_name());
dg.add_uint64(_data_size_bytes);
dg.add_uint8(_usage_hint);
dg.add_bool(!_initial_data.empty());
dg.append_data(_initial_data.data(), _initial_data.size());
}
/**
* This function is called by the BamReader's factory when a new object of
* type ParamValue is encountered in the Bam file. It should create the
* ParamValue and extract its information from the file.
*/
TypedWritable *ShaderBuffer::
make_from_bam(const FactoryParams &params) {
ShaderBuffer *param = new ShaderBuffer;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
param->fillin(scan, manager);
return param;
}
/**
* This internal function is called by make_from_bam to read in all of the
* relevant data from the BamFile for the new ParamValue.
*/
void ShaderBuffer::
fillin(DatagramIterator &scan, BamReader *manager) {
set_name(scan.get_string());
_data_size_bytes = scan.get_uint64();
_usage_hint = (UsageHint)scan.get_uint8();
if (scan.get_bool() && _data_size_bytes > 0) {
nassertv_always(_data_size_bytes <= scan.get_remaining_size());
_initial_data.resize(_data_size_bytes);
scan.extract_bytes(&_initial_data[0], _data_size_bytes);
} else {
_initial_data.clear();
}
}

View File

@ -0,0 +1,97 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file shaderBuffer.h
* @author rdb
* @date 2016-12-12
*/
#ifndef SHADERBUFFER_H
#define SHADERBUFFER_H
#include "pandabase.h"
#include "namable.h"
#include "geomEnums.h"
class BufferContext;
class PreparedGraphicsObjects;
/**
* This is a generic buffer object that lives in graphics memory.
*/
class EXPCL_PANDA_GOBJ ShaderBuffer : public TypedWritableReferenceCount, public Namable, public GeomEnums {
private:
INLINE ShaderBuffer() DEFAULT_CTOR;
PUBLISHED:
INLINE ShaderBuffer(const string &name, uint64_t size, UsageHint usage_hint);
INLINE ShaderBuffer(const string &name, pvector<unsigned char> initial_data, UsageHint usage_hint);
public:
INLINE uint64_t get_data_size_bytes() const;
INLINE UsageHint get_usage_hint() const;
INLINE const unsigned char *get_initial_data() const;
virtual void output(ostream &out) const;
PUBLISHED:
MAKE_PROPERTY(data_size_bytes, get_data_size_bytes);
MAKE_PROPERTY(usage_hint, get_usage_hint);
void prepare(PreparedGraphicsObjects *prepared_objects);
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
BufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg);
bool release(PreparedGraphicsObjects *prepared_objects);
int release_all();
private:
uint64_t _data_size_bytes;
UsageHint _usage_hint;
pvector<unsigned char> _initial_data;
typedef pmap<PreparedGraphicsObjects *, BufferContext *> Contexts;
Contexts *_contexts;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
Namable::init_type();
register_type(_type_handle, "ShaderBuffer",
TypedWritableReferenceCount::get_class_type(),
Namable::get_class_type());
}
private:
static TypeHandle _type_handle;
};
INLINE ostream &operator << (ostream &out, const ShaderBuffer &m) {
m.output(out);
return out;
}
#include "shaderBuffer.I"
#endif

View File

@ -42,6 +42,7 @@ public:
INLINE virtual bool update_shader_vertex_arrays(ShaderContext *prev, bool force) { return false; };
INLINE virtual void disable_shader_texture_bindings() {};
INLINE virtual void update_shader_texture_bindings(ShaderContext *prev) {};
INLINE virtual void update_shader_buffer_bindings(ShaderContext *prev) {};
INLINE virtual bool uses_standard_vertex_arrays(void) { return true; };
INLINE virtual bool uses_custom_vertex_arrays(void) { return false; };

View File

@ -31,6 +31,7 @@ class GraphicsOutputBase;
class VertexBufferContext;
class IndexBufferContext;
class BufferContext;
class GeomContext;
class GeomNode;
class Geom;
@ -57,6 +58,7 @@ class SamplerContext;
class SamplerState;
class Shader;
class ShaderContext;
class ShaderBuffer;
class RenderState;
class TransformState;
class Material;
@ -162,6 +164,9 @@ public:
virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data)=0;
virtual void release_index_buffer(IndexBufferContext *ibc)=0;
virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data)=0;
virtual void release_shader_buffer(BufferContext *ibc)=0;
virtual void dispatch_compute(int size_x, int size_y, int size_z)=0;
virtual PT(GeomMunger) get_geom_munger(const RenderState *state,

View File

@ -1253,6 +1253,14 @@ set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z
set_shader_input(new ShaderInput(id, tex, read, write, z, n, priority));
}
/**
*
*/
INLINE void NodePath::
set_shader_input(CPT_InternalName id, ShaderBuffer *buf, int priority) {
set_shader_input(new ShaderInput(id, buf, priority));
}
/**
*
*/

View File

@ -61,6 +61,7 @@ class GlobPattern;
class PreparedGraphicsObjects;
class SamplerState;
class Shader;
class ShaderBuffer;
class ShaderInput;
//
@ -632,6 +633,7 @@ PUBLISHED:
INLINE void set_shader_input(CPT_InternalName id, Texture *tex, int priority=0);
INLINE void set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, int priority=0);
INLINE void set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0);
INLINE void set_shader_input(CPT_InternalName id, ShaderBuffer *buf, int priority=0);
INLINE void set_shader_input(CPT_InternalName id, const NodePath &np, int priority=0);
INLINE void set_shader_input(CPT_InternalName id, const PTA_float &v, int priority=0);
INLINE void set_shader_input(CPT_InternalName id, const PTA_double &v, int priority=0);

View File

@ -25,6 +25,7 @@
#include "datagram.h"
#include "datagramIterator.h"
#include "nodePath.h"
#include "shaderBuffer.h"
TypeHandle ShaderAttrib::_type_handle;
int ShaderAttrib::_attrib_slot;
@ -461,6 +462,34 @@ get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const {
}
}
/**
* Returns the ShaderInput as a ShaderBuffer. Assertion fails if there is
* none, or if it is not a ShaderBuffer.
*/
ShaderBuffer *ShaderAttrib::
get_shader_input_buffer(const InternalName *id) const {
Inputs::const_iterator i = _inputs.find(id);
if (i == _inputs.end()) {
ostringstream strm;
strm << "Shader input " << id->get_name() << " is not present.\n";
nassert_raise(strm.str());
return NULL;
} else {
const ShaderInput *p = (*i).second;
if (p->get_value_type() == ShaderInput::M_buffer) {
ShaderBuffer *value;
DCAST_INTO_R(value, p->_value, NULL);
return value;
}
ostringstream strm;
strm << "Shader input " << id->get_name() << " is not a ShaderBuffer.\n";
nassert_raise(strm.str());
return NULL;
}
}
/**
* Returns the shader object associated with the node. If get_override
* returns true, but get_shader returns NULL, that means that this attribute

View File

@ -111,6 +111,7 @@ PUBLISHED:
Texture *get_shader_input_texture(const InternalName *id, SamplerState *sampler=NULL) const;
const Shader::ShaderPtrData *get_shader_input_ptr(const InternalName *id) const;
const LMatrix4 &get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const;
ShaderBuffer *get_shader_input_buffer(const InternalName *id) const;
static void register_with_read_factory();

View File

@ -55,6 +55,18 @@ ShaderInput(CPT_InternalName name, ParamValueBase *param, int priority) :
{
}
/**
*
*/
INLINE ShaderInput::
ShaderInput(CPT_InternalName name, ShaderBuffer *buf, int priority) :
_name(MOVE(name)),
_type(M_buffer),
_priority(priority),
_value(buf)
{
}
/**
*
*/

View File

@ -31,6 +31,7 @@
#include "samplerState.h"
#include "shader.h"
#include "texture.h"
#include "shaderBuffer.h"
/**
* This is a small container class that can hold any one of the value types
@ -52,6 +53,7 @@ PUBLISHED:
INLINE ShaderInput(CPT_InternalName name, int priority=0);
INLINE ShaderInput(CPT_InternalName name, Texture *tex, int priority=0);
INLINE ShaderInput(CPT_InternalName name, ParamValueBase *param, int priority=0);
INLINE ShaderInput(CPT_InternalName name, ShaderBuffer *buf, int priority=0);
INLINE ShaderInput(CPT_InternalName name, const PTA_float &ptr, int priority=0);
INLINE ShaderInput(CPT_InternalName name, const PTA_LVecBase4f &ptr, int priority=0);
INLINE ShaderInput(CPT_InternalName name, const PTA_LVecBase3f &ptr, int priority=0);
@ -96,7 +98,8 @@ PUBLISHED:
M_numeric,
M_texture_sampler,
M_param,
M_texture_image
M_texture_image,
M_buffer,
};
INLINE const InternalName *get_name() const;
@ -123,6 +126,8 @@ private:
int _priority;
int _type;
friend class ShaderAttrib;
public:
static TypeHandle get_class_type() {
return _type_handle;