From ce55dd495672fe79fb25156f26340ccd9b7abc07 Mon Sep 17 00:00:00 2001 From: aignacio_sf <> Date: Tue, 7 Mar 2006 20:06:19 +0000 Subject: [PATCH] Initial version of shader pool (this was ported from the font pool code). --- panda/src/pgraph/Sources.pp | 3 + panda/src/pgraph/pgraph_composite4.cxx | 1 + panda/src/pgraph/shaderPool.I | 131 +++++++++++++ panda/src/pgraph/shaderPool.cxx | 258 +++++++++++++++++++++++++ panda/src/pgraph/shaderPool.h | 76 ++++++++ 5 files changed, 469 insertions(+) create mode 100644 panda/src/pgraph/shaderPool.I create mode 100644 panda/src/pgraph/shaderPool.cxx create mode 100644 panda/src/pgraph/shaderPool.h diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 1e6296cd58..07bb9f57f0 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -98,6 +98,7 @@ shader.I shader.h \ shaderAttrib.I shaderAttrib.h \ shaderInput.I shaderInput.h \ + shaderPool.I shaderPool.h \ showBoundsEffect.I showBoundsEffect.h \ spotlight.I spotlight.h \ stateMunger.I stateMunger.h \ @@ -205,6 +206,7 @@ shader.cxx \ shaderAttrib.cxx \ shaderInput.cxx \ + shaderPool.cxx \ showBoundsEffect.cxx \ spotlight.cxx \ stateMunger.cxx \ @@ -308,6 +310,7 @@ shader.I shader.h \ shaderAttrib.I shaderAttrib.h \ shaderInput.I shaderInput.h \ + shaderPool.I shaderPool.h \ showBoundsEffect.I showBoundsEffect.h \ spotlight.I spotlight.h \ stateMunger.I stateMunger.h \ diff --git a/panda/src/pgraph/pgraph_composite4.cxx b/panda/src/pgraph/pgraph_composite4.cxx index 4312e800e7..98d5ee70d7 100644 --- a/panda/src/pgraph/pgraph_composite4.cxx +++ b/panda/src/pgraph/pgraph_composite4.cxx @@ -12,6 +12,7 @@ #include "shader.cxx" #include "shaderInput.cxx" #include "shaderAttrib.cxx" +#include "shaderPool.cxx" #include "showBoundsEffect.cxx" #include "spotlight.cxx" #include "stateMunger.cxx" diff --git a/panda/src/pgraph/shaderPool.I b/panda/src/pgraph/shaderPool.I new file mode 100644 index 0000000000..8347082d83 --- /dev/null +++ b/panda/src/pgraph/shaderPool.I @@ -0,0 +1,131 @@ +// Filename: shaderPool.I +// Created by: aignacio (Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// 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: ShaderPool::has_shader +// Access: Public, Static +// Description: Returns true if the shader has ever been loaded, +// false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool ShaderPool:: +has_shader(const string &filename) { + return get_ptr()->ns_has_shader(filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::verify_shader +// Access: Public, Static +// Description: Loads the given filename up into a shader, if it has +// not already been loaded, and returns true to indicate +// success, or false to indicate failure. If this +// returns true, it is guaranteed that a subsequent call +// to load_shader() with the same shader name will +// return a valid Shader pointer. +//////////////////////////////////////////////////////////////////// +INLINE bool ShaderPool:: +verify_shader(const string &filename) { + return load_shader(filename) != (Shader *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::load_shader +// Access: Public, Static +// Description: Loads the given filename up into a shader, if it has +// not already been loaded, and returns the new shader. +// If a shader with the same filename was previously +// loaded, returns that one instead. If the shader +// file cannot be found, returns NULL. +//////////////////////////////////////////////////////////////////// +INLINE CPT(Shader) ShaderPool:: +load_shader(const string &filename) { + return get_ptr()->ns_load_shader(filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::add_shader +// Access: Public, Static +// Description: Adds the indicated already-loaded shader to the +// pool. The shader will always replace any +// previously-loaded shader in the pool that had the +// same filename. +//////////////////////////////////////////////////////////////////// +INLINE void ShaderPool:: +add_shader(const string &filename, Shader *shader) { + get_ptr()->ns_add_shader(filename, shader); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::release_shader +// Access: Public, Static +// Description: Removes the indicated shader from the pool, +// indicating it will never be loaded again; the shader +// may then be freed. If this function is never called, +// a reference count will be maintained on every shader +// every loaded, and shaders will never be freed. +//////////////////////////////////////////////////////////////////// +INLINE void ShaderPool:: +release_shader(const string &filename) { + get_ptr()->ns_release_shader(filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::release_all_shaders +// Access: Public, Static +// Description: Releases all shaders in the pool and restores the +// pool to the empty state. +//////////////////////////////////////////////////////////////////// +INLINE void ShaderPool:: +release_all_shaders() { + get_ptr()->ns_release_all_shaders(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::garbage_collect +// Access: Public, Static +// Description: Releases only those shaders in the pool that have a +// reference count of exactly 1; i.e. only those +// shaders that are not being used outside of the pool. +// Returns the number of shaders released. +//////////////////////////////////////////////////////////////////// +INLINE int ShaderPool:: +garbage_collect() { + return get_ptr()->ns_garbage_collect(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::list_contents +// Access: Public, Static +// Description: Lists the contents of the shader pool to the +// indicated output stream. +//////////////////////////////////////////////////////////////////// +INLINE void ShaderPool:: +list_contents(ostream &out) { + get_ptr()->ns_list_contents(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::Constructor +// Access: Private +// Description: The constructor is not intended to be called +// directly; there's only supposed to be one ShaderPool +// in the universe and it constructs itself. +//////////////////////////////////////////////////////////////////// +INLINE ShaderPool:: +ShaderPool() { +} diff --git a/panda/src/pgraph/shaderPool.cxx b/panda/src/pgraph/shaderPool.cxx new file mode 100644 index 0000000000..168d1a0487 --- /dev/null +++ b/panda/src/pgraph/shaderPool.cxx @@ -0,0 +1,258 @@ +// Filename: shaderPool.cxx +// Created by: aignacio (Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2006, 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 "shaderPool.h" +#include "config_util.h" +#include "config_express.h" +#include "virtualFileSystem.h" +#include "loader.h" +#include "shader.h" + +ShaderPool *ShaderPool::_global_ptr = (ShaderPool *)NULL; + +// ??? Is this needed ??? +static Loader model_loader; + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::write +// Access: Published, Static +// Description: Lists the contents of the shader pool to the +// indicated output stream. +//////////////////////////////////////////////////////////////////// +void ShaderPool:: +write(ostream &out) { + get_ptr()->ns_list_contents(out); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::ns_has_shader +// Access: Private +// Description: The nonstatic implementation of has_shader(). +//////////////////////////////////////////////////////////////////// +bool ShaderPool:: +ns_has_shader(const string &str) { + string index_str; + Filename filename; + int face_index; + lookup_filename(str, index_str, filename, face_index); + + Shaders::const_iterator ti; + ti = _shaders.find(index_str); + if (ti != _shaders.end()) { + // This shader was previously loaded. + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::ns_load_shader +// Access: Private +// Description: The nonstatic implementation of load_shader(). +//////////////////////////////////////////////////////////////////// +CPT(Shader) ShaderPool:: +ns_load_shader(const string &str) { + string index_str; + Filename filename; + int face_index; + lookup_filename(str, index_str, filename, face_index); + + Shaders::const_iterator ti; + ti = _shaders.find(index_str); + if (ti != _shaders.end()) { + // This shader was previously loaded. + return (*ti).second; + } + +/* + shader_cat.info() + << "Loading shader " << filename << "\n"; +*/ + + CPT(Shader) shader; + + shader = (CPT(Shader)) NULL; + string extension = filename.get_extension(); + + if (extension.empty() || extension == "cg" || extension == "hlsl") { + // this does nothing for now + } + +// ***** face_index ??? + + if (shader == (CPT(Shader)) NULL) { + int preprocessor; + + preprocessor = 0; + shader = Shader::load (filename, preprocessor); + if (shader) { + if (shader -> get_load_error ( )) { +// delete shader; + shader = (CPT(Shader)) NULL; + } + } + } + + if (shader == (CPT(Shader)) NULL) { + // This shader was not found or could not be read. + return NULL; + } + + _shaders[index_str] = shader; + return shader; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::ns_add_shader +// Access: Private +// Description: The nonstatic implementation of add_shader(). +//////////////////////////////////////////////////////////////////// +void ShaderPool:: +ns_add_shader(const string &str, Shader *shader) { + string index_str; + Filename filename; + int face_index; + lookup_filename(str, index_str, filename, face_index); + + // We blow away whatever shader was there previously, if any. + _shaders[index_str] = shader; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::ns_release_shader +// Access: Private +// Description: The nonstatic implementation of release_shader(). +//////////////////////////////////////////////////////////////////// +void ShaderPool:: +ns_release_shader(const string &filename) { + Shaders::iterator ti; + ti = _shaders.find(filename); + if (ti != _shaders.end()) { + _shaders.erase(ti); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::ns_release_all_shaders +// Access: Private +// Description: The nonstatic implementation of release_all_shaders(). +//////////////////////////////////////////////////////////////////// +void ShaderPool:: +ns_release_all_shaders() { + _shaders.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::ns_garbage_collect +// Access: Private +// Description: The nonstatic implementation of garbage_collect(). +//////////////////////////////////////////////////////////////////// +int ShaderPool:: +ns_garbage_collect() { + int num_released = 0; + Shaders new_set; + + Shaders::iterator ti; + for (ti = _shaders.begin(); ti != _shaders.end(); ++ti) { + CPT(Shader) shader = (*ti).second; + if (shader->get_ref_count() == 1) { +/* + if (shader_cat.is_debug()) { + shader_cat.debug() + << "Releasing " << (*ti).first << "\n"; + } +*/ + num_released++; + } else { + new_set.insert(new_set.end(), *ti); + } + } + + _shaders.swap(new_set); + return num_released; +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::ns_list_contents +// Access: Private +// Description: The nonstatic implementation of list_contents(). +//////////////////////////////////////////////////////////////////// +void ShaderPool:: +ns_list_contents(ostream &out) const { + out << _shaders.size() << " shaders:\n"; + Shaders::const_iterator ti; + for (ti = _shaders.begin(); ti != _shaders.end(); ++ti) { + CPT(Shader) shader = (*ti).second; + out << " " << (*ti).first + << " (count = " << shader->get_ref_count() << ")\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::lookup_filename +// Access: Private, Static +// Description: Accepts a shader "filename", which might consist of a +// filename followed by an optional colon and a face +// index, and splits it out into its two components. +// Then it looks up the filename on the model path. +// Sets the filename and face index accordingly. Also +// sets index_str to be the concatenation of the +// found filename with the face index, thus restoring +// the original input (but normalized to contain the +// full path.) +//////////////////////////////////////////////////////////////////// +void ShaderPool:: +lookup_filename(const string &str, string &index_str, + Filename &filename, int &face_index) { + int colon = (int)str.length() - 1; + // Scan backwards over digits for a colon. + while (colon >= 0 && isdigit(str[colon])) { + --colon; + } + if (colon >= 0 && str[colon] == ':') { + string digits = str.substr(colon + 1); + filename = str.substr(0, colon); + face_index = atoi(digits.c_str()); + } else { + filename = str; + face_index = 0; + } + + // Now look up the filename on the model path. + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + vfs->resolve_filename(filename, get_model_path()); + + ostringstream strm; + strm << filename << ":" << face_index; + index_str = strm.str(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ShaderPool::get_ptr +// Access: Private, Static +// Description: Initializes and/or returns the global pointer to the +// one ShaderPool object in the system. +//////////////////////////////////////////////////////////////////// +ShaderPool *ShaderPool:: +get_ptr() { + if (_global_ptr == (ShaderPool *)NULL) { + _global_ptr = new ShaderPool; + } + return _global_ptr; +} diff --git a/panda/src/pgraph/shaderPool.h b/panda/src/pgraph/shaderPool.h new file mode 100644 index 0000000000..3e6ee2f9cb --- /dev/null +++ b/panda/src/pgraph/shaderPool.h @@ -0,0 +1,76 @@ +// Filename: shaderPool.h +// Created by: aignacio (Mar06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2006, 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 SHADERPOOL_H +#define SHADERPOOL_H + +#include "pandabase.h" + +#include "shader.h" + +#include "filename.h" +#include "pmap.h" + +//////////////////////////////////////////////////////////////////// +// Class : ShaderPool +// Description : This is the preferred interface for loading shaders for +// the TextNode system. It is similar to ModelPool and +// TexturePool in that it unifies references to the same +// filename. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ShaderPool { +PUBLISHED: + // These functions take string parameters instead of Filenames + // because that's somewhat more convenient to the scripting + // language. + INLINE static bool has_shader(const string &filename); + INLINE static bool verify_shader(const string &filename); + INLINE static CPT(Shader) load_shader(const string &filename); + INLINE static void add_shader(const string &filename, Shader *shader); + INLINE static void release_shader(const string &filename); + INLINE static void release_all_shaders(); + + INLINE static int garbage_collect(); + + INLINE static void list_contents(ostream &out); + static void write(ostream &out); + +private: + INLINE ShaderPool(); + + bool ns_has_shader(const string &str); + CPT(Shader) ns_load_shader(const string &str); + void ns_add_shader(const string &str, Shader *shader); + void ns_release_shader(const string &filename); + void ns_release_all_shaders(); + int ns_garbage_collect(); + void ns_list_contents(ostream &out) const; + + static void lookup_filename(const string &str, string &index_str, + Filename &filename, int &face_index); + + static ShaderPool *get_ptr(); + + static ShaderPool *_global_ptr; + typedef pmap Shaders; + Shaders _shaders; +}; + +#include "shaderPool.I" + +#endif