New shader system

This commit is contained in:
Josh Yelon 2005-09-04 19:49:55 +00:00
parent 97d233303b
commit f7ee3b5729
12 changed files with 651 additions and 1 deletions

View File

@ -44,6 +44,7 @@
preparedGraphicsObjects.I preparedGraphicsObjects.h \
lens.h lens.I \
savedContext.I savedContext.h \
shader.I shader.h \
sliderTable.I sliderTable.h \
texture.I texture.h \
textureContext.I textureContext.h \
@ -92,6 +93,7 @@
preparedGraphicsObjects.cxx \
lens.cxx \
savedContext.cxx \
shader.cxx \
sliderTable.cxx \
texture.cxx textureContext.cxx texturePool.cxx \
textureStage.cxx \
@ -140,6 +142,7 @@
preparedGraphicsObjects.I preparedGraphicsObjects.h \
lens.h lens.I \
savedContext.I savedContext.h \
shader.h shaderContext.h \
sliderTable.I sliderTable.h \
texture.I texture.h \
textureContext.I textureContext.h \

View File

@ -42,6 +42,8 @@
#include "texture.h"
#include "textureStage.h"
#include "textureContext.h"
#include "shader.h"
#include "shaderContext.h"
#include "transformBlendTable.h"
#include "transformTable.h"
#include "userVertexSlider.h"
@ -254,6 +256,8 @@ ConfigureFn(config_gobj) {
Texture::init_type();
dDrawable::init_type();
TextureStage::init_type();
Shader::init_type();
ShaderContext::init_type();
TransformBlendTable::init_type();
TransformTable::init_type();
UserVertexSlider::init_type();
@ -280,6 +284,7 @@ ConfigureFn(config_gobj) {
MatrixLens::register_with_read_factory();
PerspectiveLens::register_with_read_factory();
SliderTable::register_with_read_factory();
Shader::register_with_read_factory();
Texture::register_with_read_factory();
TextureStage::register_with_read_factory();
TransformBlendTable::register_with_read_factory();

View File

@ -16,6 +16,8 @@
#include "textureContext.cxx"
#include "texturePool.cxx"
#include "textureStage.cxx"
#include "shader.cxx"
#include "shaderContext.cxx"
#include "transformBlend.cxx"
#include "transformBlendTable.cxx"
#include "transformTable.cxx"

View File

@ -26,6 +26,7 @@ INLINE void PreparedGraphicsObjects::
release_all() {
release_all_textures();
release_all_geoms();
release_all_shaders();
release_all_vertex_buffers();
release_all_index_buffers();
}

View File

@ -24,6 +24,7 @@
#include "geom.h"
#include "geomVertexArrayData.h"
#include "geomPrimitive.h"
#include "shader.h"
#include "mutexHolder.h"
PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage");
@ -77,6 +78,18 @@ PreparedGraphicsObjects::
_released_geoms.clear();
_enqueued_geoms.clear();
Shaders::iterator sci;
for (sci = _prepared_shaders.begin();
sci != _prepared_shaders.end();
++sci) {
ShaderContext *sc = (*sci);
sc->_shader->clear_prepared(this);
}
_prepared_shaders.clear();
_released_shaders.clear();
_enqueued_shaders.clear();
VertexBuffers::iterator vbci;
for (vbci = _prepared_vertex_buffers.begin();
vbci != _prepared_vertex_buffers.end();
@ -249,7 +262,6 @@ prepare_texture_now(Texture *tex, GraphicsStateGuardianBase *gsg) {
return tc;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::enqueue_geom
// Access: Public
@ -390,6 +402,146 @@ prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg) {
return gc;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::enqueue_shader
// Access: Public
// Description: Indicates that a shader 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(Shader *shader) {
MutexHolder holder(_lock);
_enqueued_shaders.insert(shader);
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::dequeue_shader
// Access: Public
// Description: Removes a shader from the queued list of shaders 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 shader will
// automatically be dequeued and prepared at the next
// frame.
//
// The return value is true if the shader is
// successfully dequeued, false if it had not been
// queued.
////////////////////////////////////////////////////////////////////
bool PreparedGraphicsObjects::
dequeue_shader(Shader *shader) {
MutexHolder holder(_lock);
EnqueuedShaders::iterator qi = _enqueued_shaders.find(shader);
if (qi != _enqueued_shaders.end()) {
_enqueued_shaders.erase(qi);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::release_shader
// Access: Public
// Description: Indicates that a shader context, created by a
// previous call to prepare_shader(), 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 shaders--this
// prevents conflicts from threading or multiple GSG's
// sharing shaders (we have no way of knowing which
// graphics context is currently active, or what state
// it's in, at the time release_shader is called).
////////////////////////////////////////////////////////////////////
void PreparedGraphicsObjects::
release_shader(ShaderContext *sc) {
MutexHolder holder(_lock);
sc->_shader->clear_prepared(this);
// We have to set the Shader pointer to NULL at this point, since
// the Shader itself might destruct at any time after it has been
// released.
sc->_shader = (Shader *)NULL;
bool removed = (_prepared_shaders.erase(sc) != 0);
nassertv(removed);
_released_shaders.insert(sc);
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::release_all_shaders
// Access: Public
// Description: Releases all shaders at once. This will force them
// to be reloaded into shader memory for all GSG's that
// share this object. Returns the number of shaders
// released.
////////////////////////////////////////////////////////////////////
int PreparedGraphicsObjects::
release_all_shaders() {
MutexHolder holder(_lock);
int num_shaders = (int)_prepared_shaders.size();
Shaders::iterator sci;
for (sci = _prepared_shaders.begin();
sci != _prepared_shaders.end();
++sci) {
ShaderContext *sc = (*sci);
sc->_shader->clear_prepared(this);
sc->_shader = (Shader *)NULL;
_released_shaders.insert(sc);
}
_prepared_shaders.clear();
return num_shaders;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::prepare_shader_now
// Access: Public
// Description: Immediately creates a new ShaderContext for the
// indicated shader and returns it. This assumes that
// the GraphicsStateGuardian is the currently active
// rendering context and that it is ready to accept new
// shaders. If this is not necessarily the case, you
// should use enqueue_shader() instead.
//
// Normally, this function is not called directly. Call
// Shader::prepare_now() instead.
//
// The ShaderContext contains all of the pertinent
// information needed by the GSG to keep track of this
// one particular shader, and will exist as long as the
// shader is ready to be rendered.
//
// When either the Shader or the
// PreparedGraphicsObjects object destructs, the
// ShaderContext will be deleted.
////////////////////////////////////////////////////////////////////
ShaderContext *PreparedGraphicsObjects::
prepare_shader_now(Shader *shader, GraphicsStateGuardianBase *gsg) {
MutexHolder holder(_lock);
// Ask the GSG to create a brand new ShaderContext. There might
// be several GSG's sharing the same set of shaders; if so, it
// doesn't matter which of them creates the context (since they're
// all shared anyway).
ShaderContext *sc = gsg->prepare_shader(shader);
if (sc != (ShaderContext *)NULL) {
bool prepared = _prepared_shaders.insert(sc).second;
nassertr(prepared, sc);
}
return sc;
}
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::enqueue_vertex_buffer
// Access: Public
@ -722,6 +874,16 @@ update(GraphicsStateGuardianBase *gsg) {
_released_geoms.clear();
Shaders::iterator sci;
for (sci = _released_shaders.begin();
sci != _released_shaders.end();
++sci) {
ShaderContext *sc = (*sci);
gsg->release_shader(sc);
}
_released_shaders.clear();
VertexBuffers::iterator vbci;
for (vbci = _released_vertex_buffers.begin();
vbci != _released_vertex_buffers.end();
@ -764,6 +926,16 @@ update(GraphicsStateGuardianBase *gsg) {
_enqueued_geoms.clear();
EnqueuedShaders::iterator qsi;
for (qsi = _enqueued_shaders.begin();
qsi != _enqueued_shaders.end();
++qsi) {
Shader *shader = (*qsi);
shader->prepare_now(this, gsg);
}
_enqueued_shaders.clear();
EnqueuedVertexBuffers::iterator qvbi;
for (qvbi = _enqueued_vertex_buffers.begin();
qvbi != _enqueued_vertex_buffers.end();

View File

@ -25,6 +25,7 @@
#include "geom.h"
#include "geomVertexArrayData.h"
#include "geomPrimitive.h"
#include "shader.h"
#include "pointerTo.h"
#include "pStatCollector.h"
#include "pset.h"
@ -32,6 +33,7 @@
class TextureContext;
class GeomContext;
class ShaderContext;
class VertexBufferContext;
class IndexBufferContext;
class GraphicsStateGuardianBase;
@ -76,6 +78,13 @@ public:
GeomContext *prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg);
void enqueue_shader(Shader *shader);
bool dequeue_shader(Shader *shader);
void release_shader(ShaderContext *sc);
int release_all_shaders();
ShaderContext *prepare_shader_now(Shader *shader, GraphicsStateGuardianBase *gsg);
void enqueue_vertex_buffer(GeomVertexArrayData *data);
bool dequeue_vertex_buffer(GeomVertexArrayData *data);
void release_vertex_buffer(VertexBufferContext *vbc);
@ -101,6 +110,8 @@ private:
typedef phash_set< PT(Texture) > EnqueuedTextures;
typedef phash_set<GeomContext *, pointer_hash> Geoms;
typedef phash_set< PT(Geom) > EnqueuedGeoms;
typedef phash_set<ShaderContext *, pointer_hash> Shaders;
typedef phash_set< PT(Shader) > EnqueuedShaders;
typedef phash_set<VertexBufferContext *, pointer_hash> VertexBuffers;
typedef phash_set< PT(GeomVertexArrayData) > EnqueuedVertexBuffers;
typedef phash_set<IndexBufferContext *, pointer_hash> IndexBuffers;
@ -111,6 +122,8 @@ private:
EnqueuedTextures _enqueued_textures;
Geoms _prepared_geoms, _released_geoms;
EnqueuedGeoms _enqueued_geoms;
Shaders _prepared_shaders, _released_shaders;
EnqueuedShaders _enqueued_shaders;
VertexBuffers _prepared_vertex_buffers, _released_vertex_buffers;
EnqueuedVertexBuffers _enqueued_vertex_buffers;
IndexBuffers _prepared_index_buffers, _released_index_buffers;

38
panda/src/gobj/shader.I Executable file
View File

@ -0,0 +1,38 @@
// Filename: shader.I
// Heavily Modified: jyelon (Sep05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: Shader::get_text
// Access: Public
// Description: Return the shader's text.
////////////////////////////////////////////////////////////////////
INLINE const string &Shader::
get_text(void) {
return _text;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::get_file
// Access: Public
// Description: Return the shader's filename, or null string.
////////////////////////////////////////////////////////////////////
INLINE const Filename &Shader::
get_file(void) {
return _file;
}

196
panda/src/gobj/shader.cxx Executable file
View File

@ -0,0 +1,196 @@
// Filename: shader.cxx
// Created by: jyelon (Sep05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "shader.h"
TypeHandle Shader::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: Shader::Constructor
// Access: Public
// Description: Construct a Shader.
////////////////////////////////////////////////////////////////////
Shader::
Shader(const string &text, const string &file) {
_text = text;
_file = file;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::Destructor
// Access: Public
// Description: Delete the compiled code, if it exists.
////////////////////////////////////////////////////////////////////
Shader::
~Shader() {
release_all();
}
////////////////////////////////////////////////////////////////////
// Function: Shader::arg_index
// Access: Public
// Description: Allocates an integer index to the given
// shader parameter name.
////////////////////////////////////////////////////////////////////
INLINE int Shader::
arg_index(const string &id) {
for (int i=0; i<(int)(_args.size()); i++)
if (_args[i] == id)
return i;
_args.push_back(id);
return _args.size() - 1;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::prepare
// Access: Published
// Description: Indicates that the shader should be enqueued to be
// prepared in the indicated prepared_objects at the
// beginning of the next frame. This will ensure the
// texture is already loaded into texture memory if it
// is expected to be rendered soon.
//
// Use this function instead of prepare_now() to preload
// textures from a user interface standpoint.
////////////////////////////////////////////////////////////////////
void Shader::
prepare(PreparedGraphicsObjects *prepared_objects) {
prepared_objects->enqueue_shader(this);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::release
// Access: Published
// Description: Frees the texture context only on the indicated object,
// if it exists there. Returns true if it was released,
// false if it had not been prepared.
////////////////////////////////////////////////////////////////////
bool Shader::
release(PreparedGraphicsObjects *prepared_objects) {
Contexts::iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
ShaderContext *sc = (*ci).second;
if (sc != (ShaderContext *)NULL) {
prepared_objects->release_shader(sc);
} else {
_contexts.erase(ci);
}
return true;
}
// Maybe it wasn't prepared yet, but it's about to be.
return prepared_objects->dequeue_shader(this);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::prepare_now
// Access: Public
// Description: Creates a context for the texture on the particular
// GSG, if it does not already exist. Returns the new
// (or old) ShaderContext. This assumes that the
// GraphicsStateGuardian is the currently active
// rendering context and that it is ready to accept new
// textures. If this is not necessarily the case, you
// should use prepare() instead.
//
// Normally, this is not called directly except by the
// GraphicsStateGuardian; a texture does not need to be
// explicitly prepared by the user before it may be
// rendered.
////////////////////////////////////////////////////////////////////
ShaderContext *Shader::
prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg) {
Contexts::const_iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
return (*ci).second;
}
ShaderContext *tc = prepared_objects->prepare_shader_now(this, gsg);
_contexts[prepared_objects] = tc;
return tc;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::clear_prepared
// Access: Private
// Description: Removes the indicated PreparedGraphicsObjects table
// from the Shader's table, without actually releasing
// the texture. This is intended to be called only from
// PreparedGraphicsObjects::release_texture(); it should
// never be called by user code.
////////////////////////////////////////////////////////////////////
void Shader::
clear_prepared(PreparedGraphicsObjects *prepared_objects) {
Contexts::iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
_contexts.erase(ci);
} else {
// If this assertion fails, clear_prepared() was given a
// prepared_objects which the texture didn't know about.
nassertv(false);
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::release_all
// Access: Published
// Description: Frees the context allocated on all objects for which
// the texture has been declared. Returns the number of
// contexts which have been freed.
////////////////////////////////////////////////////////////////////
int Shader::
release_all() {
// We have to traverse a copy of the _contexts list, because the
// PreparedGraphicsObjects object will call clear_prepared() in response
// to each release_texture(), and we don't want to be modifying the
// _contexts list while we're traversing it.
Contexts temp = _contexts;
int num_freed = (int)_contexts.size();
Contexts::const_iterator ci;
for (ci = temp.begin(); ci != temp.end(); ++ci) {
PreparedGraphicsObjects *prepared_objects = (*ci).first;
ShaderContext *sc = (*ci).second;
if (sc != (ShaderContext *)NULL) {
prepared_objects->release_shader(sc);
}
}
// There might still be some outstanding contexts in the map, if
// there were any NULL pointers there. Eliminate them.
_contexts.clear();
return num_freed;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::register_with_read_factory
// Access: Public, Static
// Description: Factory method to generate a Shader object
////////////////////////////////////////////////////////////////////
void Shader::
register_with_read_factory() {
// IMPLEMENT ME
}

105
panda/src/gobj/shader.h Executable file
View File

@ -0,0 +1,105 @@
// Filename: shader.h
// Created by: jyelon (01Sep05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//
// Current Loose Ends:
// - BAM reading/writing not implemented on most classes.
// - ShaderPool not implemented.
// - compilation of shaders for OpenGL not implemented.
// - compilation of shaders for DirectX8 not implemented.
// - compilation of shaders for DirectX9 not implemented.
//
////////////////////////////////////////////////////////////////////
#ifndef SHADER_H
#define SHADER_H
#include "pandabase.h"
#include "typedWritableReferenceCount.h"
#include "internalName.h"
////////////////////////////////////////////////////////////////////
// Class : Shader
// Summary: The Shader object contains the string which
// is the shader's text, a filename that indicates
// where the shader came from (optional), and an
// argument-name to argument-index allocator. The
// allocator is there so that all the Shader and
// ShaderContext objects associated with this Shader
// can refer to arguments by index instead of by name,
// which could make the bind process significantly
// faster.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Shader: public TypedWritableReferenceCount {
PUBLISHED:
Shader(const string &text, const string &file);
~Shader(void);
INLINE const string &get_text(void);
INLINE const Filename &get_file(void);
void prepare(PreparedGraphicsObjects *prepared_objects);
bool release(PreparedGraphicsObjects *prepared_objects);
int release_all();
public:
INLINE int arg_count(void);
int arg_index(const string &id);
string _text;
Filename _file;
vector<string> _args;
typedef pmap<PreparedGraphicsObjects *, ShaderContext *> Contexts;
Contexts _contexts;
static void register_with_read_factory(void);
friend class ShaderContext;
friend class PreparedGraphicsObjects;
ShaderContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg);
private:
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "Shader",
TypedWritableReferenceCount::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 "shader.I"
#endif

30
panda/src/gobj/shaderContext.I Executable file
View File

@ -0,0 +1,30 @@
// Filename: shaderContext.I
// Created by: jyelon (01Sep05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: ShaderContext::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE ShaderContext::
ShaderContext(Shader *s) :
_shader(s)
{
}

View File

@ -0,0 +1,20 @@
// Filename: shaderContext.cxx
// Created by: jyelon (01Sep05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
TypeHandle ShaderContext::_type_handle;

65
panda/src/gobj/shaderContext.h Executable file
View File

@ -0,0 +1,65 @@
// Filename: shaderContext.h
// Created by: jyelon (01Sep05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef SHADERCONTEXT_H
#define SHADERCONTEXT_H
#include "pandabase.h"
#include "internalName.h"
#include "savedContext.h"
#include "shader.h"
////////////////////////////////////////////////////////////////////
// Class : ShaderContext
// Description : The ShaderContext is meant to contain the compiled
// version of a shader string. ShaderContext is an
// abstract base class, there will be a subclass of it
// for each shader language and graphics API.
// Since the languages are so different and the
// graphics APIs have so little in common, the base
// class contains almost nothing. All the implementation
// details are in the subclasses.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA ShaderContext: public SavedContext {
public:
INLINE ShaderContext(Shader *shader);
Shader *_shader;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedObject::init_type();
register_type(_type_handle, "ShaderContext",
TypedObject::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 "shaderContext.I"
#endif