Add ability to cache compiled GLSL shaders, remove unused ShaderUtilization

This commit is contained in:
rdb 2016-01-13 19:58:11 +01:00
parent bc58335214
commit 6eb460c359
16 changed files with 313 additions and 217 deletions

View File

@ -1152,6 +1152,8 @@ extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg) {
////////////////////////////////////////////////////////////////////
void GraphicsEngine::
dispatch_compute(const LVecBase3i &work_groups, const ShaderAttrib *sattr, GraphicsStateGuardian *gsg) {
nassertv(sattr->get_shader() != (Shader *)NULL);
ReMutexHolder holder(_lock);
CPT(RenderState) state = RenderState::make(sattr);
@ -2334,50 +2336,6 @@ auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
}
}
}
if (shader_auto_utilization && (shader_utilization != SUT_none)) {
display_cat.error()
<< "Invalid panda config file: if you set the config-variable\n"
<< "shader_auto_utilization to true, you must set the config-variable"
<< "shader_utilization to 'none'.\n";
shader_utilization = SUT_none; // Not a fix. Just suppresses further error messages.
}
if (shader_auto_utilization && !Shader::have_shader_utilization()) {
if (gsg->get_supports_basic_shaders()) {
Shader::set_shader_utilization(SUT_basic);
} else {
Shader::set_shader_utilization(SUT_none);
}
}
if ((Shader::get_shader_utilization() != SUT_none) &&
(!gsg->get_supports_basic_shaders())) {
// Overaggressive configuration detected
display_cat.error()
<< "The 'shader_utilization' config variable is set, meaning\n"
<< "that panda may try to generate shaders. However, the video \n"
<< "driver I'm trying to use does not support shaders.\n";
if (shader_utilization == SUT_none) {
display_cat.error()
<< "The 'shader_utilization' setting did not come from the config\n"
<< "file. In other words, it was altered procedurally.\n";
if (shader_auto_utilization) {
display_cat.error()
<< "It is possible that it was set by panda's automatic mechanisms,\n"
<< "which are currently enabled, because 'shader_auto_utilization' is\n"
<< "true. Panda's automatic mechanisms assume that if one\n"
<< "window supports shaders, then they all will.\n"
<< "This assumption works for most games, but not all.\n"
<< "In particular, it can fail if the game creates multiple windows\n"
<< "on multiple displays with different video cards.\n";
}
}
}
}
////////////////////////////////////////////////////////////////////

View File

@ -704,6 +704,12 @@ issue_parameters(int altered) {
case Shader::SMP_cell15:
GLf(cgGLSetParameter1)(p, data[15]);
continue;
case Shader::SMP_cell14:
GLf(cgGLSetParameter1)(p, data[14]);
continue;
case Shader::SMP_cell13:
GLf(cgGLSetParameter1)(p, data[13]);
continue;
}
}
}

View File

@ -2492,11 +2492,15 @@ reset() {
if (is_at_least_gl_version(4, 1) || has_extension("GL_ARB_get_program_binary")) {
_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)
get_extension_func("glGetProgramBinary");
_glProgramBinary = (PFNGLPROGRAMBINARYPROC)
get_extension_func("glProgramBinary");
_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)
get_extension_func("glProgramParameteri");
GLint num_binary_formats = 0;
if (_glGetProgramBinary != NULL && _glProgramParameteri != NULL) {
if (_glGetProgramBinary != NULL &&
_glProgramBinary != NULL &&
_glProgramParameteri != NULL) {
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_binary_formats);
}

View File

@ -940,6 +940,7 @@ public:
PFNGLDISPATCHCOMPUTEPROC _glDispatchCompute;
PFNGLMEMORYBARRIERPROC _glMemoryBarrier;
PFNGLGETPROGRAMBINARYPROC _glGetProgramBinary;
PFNGLPROGRAMBINARYPROC _glProgramBinary;
PFNGLGETINTERNALFORMATIVPROC _glGetInternalformativ;
PFNGLVIEWPORTARRAYVPROC _glViewportArrayv;
PFNGLSCISSORARRAYVPROC _glScissorArrayv;

View File

@ -25,7 +25,7 @@
#include "fogAttrib.h"
#include "lightAttrib.h"
#include "clipPlaneAttrib.h"
#include "ambientLight.h"
#include "bamCache.h"
TypeHandle CLP(ShaderContext)::_type_handle;
@ -2872,6 +2872,32 @@ glsl_compile_and_link() {
_glgsg->_glObjectLabel(GL_PROGRAM, _glsl_program, name.size(), name.data());
}
#ifndef OPENGLES
// Do we have a compiled program? Try to load that.
unsigned int format;
string binary;
if (_shader->get_compiled(format, binary)) {
_glgsg->_glProgramBinary(_glsl_program, format, binary.data(), binary.size());
GLint status;
_glgsg->_glGetProgramiv(_glsl_program, GL_LINK_STATUS, &status);
if (status == GL_TRUE) {
// Hooray, the precompiled shader worked.
if (GLCAT.is_debug()) {
GLCAT.debug() << "Loaded precompiled binary for GLSL shader "
<< _shader->get_filename() << "\n";
}
return true;
}
// Bummer, it didn't work.. Oh well, just recompile the shader.
if (GLCAT.is_debug()) {
GLCAT.debug() << "Failure loading precompiled binary for GLSL shader "
<< _shader->get_filename() << "\n";
}
}
#endif
bool valid = true;
if (!_shader->get_text(Shader::ST_vertex).empty()) {
@ -2936,8 +2962,17 @@ glsl_compile_and_link() {
}
// If we requested to retrieve the shader, we should indicate that before linking.
#if !defined(NDEBUG) && !defined(OPENGLES)
if (gl_dump_compiled_shaders && _glgsg->_supports_get_program_binary) {
#ifndef OPENGLES
bool retrieve_binary = false;
if (_glgsg->_supports_get_program_binary) {
retrieve_binary = _shader->get_cache_compiled_shader();
#ifndef NDEBUG
if (gl_dump_compiled_shaders) {
retrieve_binary = true;
}
#endif
_glgsg->_glProgramParameteri(_glsl_program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
}
#endif
@ -2961,33 +2996,38 @@ glsl_compile_and_link() {
// Report any warnings.
glsl_report_program_errors(_glsl_program, false);
// Dump the binary if requested.
#if !defined(NDEBUG) && !defined(OPENGLES)
if (gl_dump_compiled_shaders && _glgsg->_supports_get_program_binary) {
#ifndef OPENGLES
if (retrieve_binary) {
GLint length = 0;
_glgsg->_glGetProgramiv(_glsl_program, GL_PROGRAM_BINARY_LENGTH, &length);
length += 2;
char filename[64];
static int gl_dump_count = 0;
sprintf(filename, "glsl_program%d.dump", gl_dump_count++);
char *binary = new char[length];
char *binary = (char *)alloca(length);
GLenum format;
GLsizei num_bytes;
GLsizei num_bytes = 0;
_glgsg->_glGetProgramBinary(_glsl_program, length, &num_bytes, &format, (void*)binary);
pofstream s;
s.open(filename, ios::out | ios::binary | ios::trunc);
s.write(binary, num_bytes);
s.close();
_shader->set_compiled(format, binary, num_bytes);
GLCAT.info()
<< "Dumped " << num_bytes << " bytes of program binary with format 0x"
<< hex << format << dec << " to " << filename << "\n";
delete[] binary;
}
#ifndef NDEBUG
// Dump the binary if requested.
if (gl_dump_compiled_shaders) {
char filename[64];
static int gl_dump_count = 0;
sprintf(filename, "glsl_program%d.dump", gl_dump_count++);
pofstream s;
s.open(filename, ios::out | ios::binary | ios::trunc);
s.write(binary, num_bytes);
s.close();
GLCAT.info()
<< "Dumped " << num_bytes << " bytes of program binary with format 0x"
<< hex << format << dec << " to " << filename << "\n";
}
#endif // NDEBUG
}
#endif // OPENGLES
_glgsg->report_my_gl_errors();
return true;

View File

@ -362,23 +362,6 @@ ConfigVariableDouble simple_image_threshold
"simple images. Generally the value should be considerably "
"less than 1."));
ConfigVariableEnum<ShaderUtilization> shader_utilization
("shader-utilization", SUT_none,
PRC_DESC("At times, panda may generate shaders. This variable controls what "
"kinds of shaders can be generated. If you set it to SUT_none, "
"shader generation will be be disabled. If you set it to SUT_basic, "
"then DX9 shaders may be generated, if you set it to SUT_advanced, "
"then DX10 shaders may be generated."));
ConfigVariableBool shader_auto_utilization
("shader-auto-utilization", false,
PRC_DESC("If this is true, then panda will wait until you open a window, "
"and then ask the window if it supports basic or advanced shaders. "
"If so, then the config variable shader-utilization will "
"automatically be adusted. The pitfall of doing this is that if "
"you then open a second window that doesn't support the same "
"capabilities, it will have no choice but to print an error message."));
ConfigVariableInt geom_cache_size
("geom-cache-size", 5000,
PRC_DESC("Specifies the maximum number of entries in the cache "
@ -651,50 +634,3 @@ ConfigureFn(config_gobj) {
UserVertexSlider::register_with_read_factory();
UserVertexTransform::register_with_read_factory();
}
ostream &
operator << (ostream &out, ShaderUtilization sgc) {
switch (sgc) {
case SUT_none:
return out << "none";
case SUT_basic:
return out << "basic";
case SUT_advanced:
return out << "advanced";
case SUT_unspecified:
return out << "unspecified";
}
return out << "**invalid ShaderUtilization (" << (int)sgc << ")**";
}
istream &
operator >> (istream &in, ShaderUtilization &sgc) {
string word;
in >> word;
if (cmp_nocase(word, "none") == 0 ||
cmp_nocase(word, "0") == 0 ||
cmp_nocase(word, "#f") == 0 ||
(!word.empty() && tolower(word[0]) == 'f')) {
sgc = SUT_none;
} else if (cmp_nocase(word, "basic") == 0 ||
cmp_nocase(word, "1") == 0 ||
cmp_nocase(word, "#t") == 0 ||
(!word.empty() && tolower(word[0]) == 't')) {
sgc = SUT_basic;
} else if (cmp_nocase(word, "advanced") == 0) {
sgc = SUT_advanced;
} else {
gobj_cat->error() << "Invalid ShaderUtilization value: " << word << "\n";
sgc = SUT_none;
}
return in;
}

View File

@ -29,18 +29,6 @@
NotifyCategoryDecl(gobj, EXPCL_PANDA_GOBJ, EXPTP_PANDA_GOBJ);
NotifyCategoryDecl(shader, EXPCL_PANDA_GOBJ, EXPTP_PANDA_GOBJ);
BEGIN_PUBLISH
enum ShaderUtilization {
SUT_none,
SUT_basic,
SUT_advanced,
SUT_unspecified,
};
END_PUBLISH
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, ShaderUtilization sut);
EXPCL_PANDA_GOBJ istream &operator >> (istream &in, ShaderUtilization &sut);
// Configure variables for gobj package.
extern EXPCL_PANDA_GOBJ ConfigVariableInt max_texture_dimension;
extern EXPCL_PANDA_GOBJ ConfigVariableDouble texture_scale;
@ -77,9 +65,6 @@ extern EXPCL_PANDA_GOBJ ConfigVariableBool textures_header_only;
extern EXPCL_PANDA_GOBJ ConfigVariableInt simple_image_size;
extern EXPCL_PANDA_GOBJ ConfigVariableDouble simple_image_threshold;
extern EXPCL_PANDA_GOBJ ConfigVariableEnum<ShaderUtilization> shader_utilization;
extern EXPCL_PANDA_GOBJ ConfigVariableBool shader_auto_utilization;
extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_size;
extern EXPCL_PANDA_GOBJ ConfigVariableInt geom_cache_min_frames;
extern EXPCL_PANDA_GOBJ ConfigVariableInt released_vbuffer_cache_size;

View File

@ -101,49 +101,6 @@ get_error_flag() const {
return _error_flag;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::set_shader_utilization
// Access: Published, Static
// Description: Set this flag to SUT_none, SUT_basic, or
// SUT_advanced to limit panda's automatic shader
// generation facilities.
////////////////////////////////////////////////////////////////////
INLINE void Shader::
set_shader_utilization(ShaderUtilization sut) {
_shader_utilization = sut;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::get_shader_utilization
// Access: Published, Static
// Description: This flag returns SUT_none, SUT_basic, or
// SUT_advanced and controls the automatic generation
// of shaders. It is initialized from the config
// variable of the same name, but it can be
// subsequently adjusted.
////////////////////////////////////////////////////////////////////
INLINE ShaderUtilization Shader::
get_shader_utilization() {
if (_shader_utilization == SUT_unspecified) {
return shader_utilization;
} else {
return _shader_utilization;
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::have_shader_utilization
// Access: Published, Static
// Description: If true, then get_shader_utilization has been
// set using set_shader_utilization.
// If false, then get_shader_utilization simply
// returns the config variable of the same name.
////////////////////////////////////////////////////////////////////
INLINE bool Shader::
have_shader_utilization() {
return (_shader_utilization != SUT_unspecified);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::get_language
// Access: Published
@ -155,6 +112,58 @@ get_language() const {
return _language;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::has_fullpath
// Access: Published
// Description: Returns true if the fullpath has been set and
// is available. See set_fullpath().
////////////////////////////////////////////////////////////////////
INLINE bool Shader::
has_fullpath() const {
return !_fullpath.empty();
}
////////////////////////////////////////////////////////////////////
// Function: Shader::get_fullpath
// Access: Published
// Description: Returns the fullpath that has been set. This is
// the full path to the file as it was found along the
// model-path.
////////////////////////////////////////////////////////////////////
INLINE const Filename &Shader::
get_fullpath() const {
return _fullpath;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::get_cache_compiled_shader
// Access: Public
// Description: Returns the setting of the cache_compiled_shader
// flag. See set_cache_compiled_shader().
////////////////////////////////////////////////////////////////////
INLINE bool Shader::
get_cache_compiled_shader() const {
return _cache_compiled_shader;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::set_cache_compiled_shader
// Access: Public
// Description: Sets the cache_compiled_shader flag. When this is
// set, the next time the Shader is loaded on a GSG, it
// will automatically extract the compiled shader from
// the GSG and save it to the global BamCache.
//
// This is used to store compiled shaders in the
// BamCache. This flag should not be set explicitly; it
// is set automatically by the ShaderPool when
// model-cache-compiled-shaders is set true.
////////////////////////////////////////////////////////////////////
INLINE void Shader::
set_cache_compiled_shader(bool flag) {
_cache_compiled_shader = flag;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::ShaderCapabilities Constructor
// Access: Public
@ -802,6 +811,7 @@ INLINE void Shader::ShaderFile::
read_datagram(DatagramIterator &scan) {
short count = scan.get_uint8();
if (count > 0) {
_separate = true;
if (count-- > 0) _vertex = scan.get_string();
if (count-- > 0) _fragment = scan.get_string();
if (count-- > 0) _geometry = scan.get_string();
@ -812,6 +822,7 @@ read_datagram(DatagramIterator &scan) {
scan.get_string();
}
} else {
_separate = false;
_shared = scan.get_string();
}
}

View File

@ -18,6 +18,7 @@
#include "preparedGraphicsObjects.h"
#include "virtualFileSystem.h"
#include "config_util.h"
#include "bamCache.h"
#ifdef HAVE_CG
#include <Cg/cg.h>
@ -28,7 +29,6 @@ Shader::ShaderTable Shader::_load_table;
Shader::ShaderTable Shader::_make_table;
Shader::ShaderCaps Shader::_default_caps;
int Shader::_shaders_generated;
ShaderUtilization Shader::_shader_utilization = SUT_unspecified;
#ifdef HAVE_CG
CGcontext Shader::_cg_context = 0;
@ -1460,7 +1460,6 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::clear_parameters
// Access: Private
@ -1473,6 +1472,38 @@ clear_parameters() {
_tex_spec.clear();
}
////////////////////////////////////////////////////////////////////
// Function: Shader::set_compiled
// Access: Private
// Description: Called by the back-end when the shader has compiled
// data available.
////////////////////////////////////////////////////////////////////
void Shader::
set_compiled(unsigned int format, const char *data, size_t length) {
_compiled_format = format;
_compiled_binary.assign(data, length);
// Store the compiled shader in the cache.
if (_cache_compiled_shader && !_record.is_null()) {
_record->set_data(this);
BamCache *cache = BamCache::get_global_ptr();
cache->store(_record);
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::get_compiled
// Access: Private
// Description: Called by the back-end to retrieve compiled data.
////////////////////////////////////////////////////////////////////
bool Shader::
get_compiled(unsigned int &format, string &binary) const {
format = _compiled_format;
binary = _compiled_binary;
return !binary.empty();
}
#ifdef HAVE_CG
////////////////////////////////////////////////////////////////////
// Function: Shader::cg_parameter_type
@ -2204,7 +2235,8 @@ Shader(ShaderLanguage lang) :
_loaded(false),
_language(lang),
_last_modified(0),
_mat_deps(0)
_mat_deps(0),
_cache_compiled_shader(false)
{
#ifdef HAVE_CG
_cg_vprogram = 0;
@ -2234,7 +2266,7 @@ Shader(ShaderLanguage lang) :
// Returns a boolean indicating success or failure.
////////////////////////////////////////////////////////////////////
bool Shader::
read(const ShaderFile &sfile) {
read(const ShaderFile &sfile, BamCacheRecord *record) {
_text._separate = sfile._separate;
if (sfile._separate) {
@ -2244,30 +2276,37 @@ read(const ShaderFile &sfile) {
return false;
}
if (!sfile._vertex.empty() && !do_read_source(_text._vertex, sfile._vertex)) {
if (!sfile._vertex.empty() &&
!do_read_source(_text._vertex, sfile._vertex, record)) {
return false;
}
if (!sfile._fragment.empty() && !do_read_source(_text._fragment, sfile._fragment)) {
if (!sfile._fragment.empty() &&
!do_read_source(_text._fragment, sfile._fragment, record)) {
return false;
}
if (!sfile._geometry.empty() && !do_read_source(_text._geometry, sfile._geometry)) {
if (!sfile._geometry.empty() &&
!do_read_source(_text._geometry, sfile._geometry, record)) {
return false;
}
if (!sfile._tess_control.empty() && !do_read_source(_text._tess_control, sfile._tess_control)) {
if (!sfile._tess_control.empty() &&
!do_read_source(_text._tess_control, sfile._tess_control, record)) {
return false;
}
if (!sfile._tess_evaluation.empty() && !do_read_source(_text._tess_evaluation, sfile._tess_evaluation)) {
if (!sfile._tess_evaluation.empty() &&
!do_read_source(_text._tess_evaluation, sfile._tess_evaluation, record)) {
return false;
}
if (!sfile._compute.empty() && !do_read_source(_text._compute, sfile._compute)) {
if (!sfile._compute.empty() &&
!do_read_source(_text._compute, sfile._compute, record)) {
return false;
}
_filename = sfile;
} else {
if (!do_read_source(_text._shared, sfile._shared)) {
if (!do_read_source(_text._shared, sfile._shared, record)) {
return false;
}
_fullpath = _source_files[0];
_filename = sfile;
// Determine which language the shader is written in.
@ -2323,12 +2362,12 @@ read(const ShaderFile &sfile) {
// bad enough to consider it 'invalid'.
////////////////////////////////////////////////////////////////////
bool Shader::
do_read_source(string &into, const Filename &fn) {
do_read_source(string &into, const Filename &fn, BamCacheRecord *record) {
if (_language == SL_GLSL && glsl_preprocess) {
// Preprocess the GLSL file as we read it.
set<Filename> open_files;
ostringstream sstr;
if (!r_preprocess_source(sstr, fn, Filename(), open_files)) {
if (!r_preprocess_source(sstr, fn, Filename(), open_files, record)) {
return false;
}
into = sstr.str();
@ -2350,6 +2389,9 @@ do_read_source(string &into, const Filename &fn) {
return false;
}
if (record != (BamCacheRecord *)NULL) {
record->add_dependent_file(vf);
}
_last_modified = max(_last_modified, vf->get_timestamp());
_source_files.push_back(vf->get_filename());
}
@ -2368,7 +2410,8 @@ do_read_source(string &into, const Filename &fn) {
bool Shader::
r_preprocess_source(ostream &out, const Filename &fn,
const Filename &source_dir,
set<Filename> &once_files, int depth) {
set<Filename> &once_files,
BamCacheRecord *record, int depth) {
if (depth > glsl_include_recursion_limit) {
shader_cat.error()
@ -2402,6 +2445,9 @@ r_preprocess_source(ostream &out, const Filename &fn,
return false;
}
if (record != (BamCacheRecord *)NULL) {
record->add_dependent_file(vf);
}
_last_modified = max(_last_modified, vf->get_timestamp());
_source_files.push_back(full_fn);
@ -2483,7 +2529,7 @@ r_preprocess_source(ostream &out, const Filename &fn,
}
// OK, great. Process the include.
if (!r_preprocess_source(out, incfn, source_dir, once_files, depth + 1)) {
if (!r_preprocess_source(out, incfn, source_dir, once_files, record, depth + 1)) {
// An error occurred. Pass on the failure.
shader_cat.error(false) << "included at line "
<< lineno << " of file " << fn << ":\n " << line << "\n";
@ -2768,6 +2814,14 @@ load_compute(ShaderLanguage lang, const Filename &fn) {
return NULL;
}
Filename fullpath(fn);
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (!vfs->resolve_filename(fullpath, get_model_path())) {
shader_cat.error()
<< "Could not find compute shader file: " << fn << "\n";
return NULL;
}
ShaderFile sfile;
sfile._separate = true;
sfile._compute = fn;
@ -2785,11 +2839,29 @@ load_compute(ShaderLanguage lang, const Filename &fn) {
}
}
BamCache *cache = BamCache::get_global_ptr();
PT(BamCacheRecord) record = cache->lookup(fullpath, "sho");
if (record != (BamCacheRecord *)NULL) {
if (record->has_data()) {
shader_cat.info()
<< "Compute shader " << fn << " was found in disk cache.\n";
return DCAST(Shader, record->get_data());
}
}
PT(Shader) shader = new Shader(lang);
if (!shader->read(sfile)) {
if (!shader->read(sfile, record)) {
return NULL;
}
// It makes little sense to cache the shader before compilation, so
// we keep the record for when we have the compiled the shader.
swap(shader->_record, record);
shader->_cache_compiled_shader = BamCache::get_global_ptr()->get_cache_compiled_shaders();
shader->_fullpath = shader->_source_files[0];
_load_table[sfile] = shader;
return shader;
}
@ -3195,11 +3267,9 @@ clear() {
_active_vprofile = CG_PROFILE_UNKNOWN;
_active_fprofile = CG_PROFILE_UNKNOWN;
_active_gprofile = CG_PROFILE_UNKNOWN;
_active_fprofile = CG_PROFILE_UNKNOWN;
_ultimate_vprofile = CG_PROFILE_UNKNOWN;
_ultimate_fprofile = CG_PROFILE_UNKNOWN;
_ultimate_gprofile = CG_PROFILE_UNKNOWN;
_ultimate_fprofile = CG_PROFILE_UNKNOWN;
#endif
}
@ -3211,7 +3281,7 @@ clear() {
////////////////////////////////////////////////////////////////////
void Shader::
register_with_read_factory() {
//BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
@ -3226,6 +3296,9 @@ write_datagram(BamWriter *manager, Datagram &dg) {
dg.add_bool(_loaded);
_filename.write_datagram(dg);
_text.write_datagram(dg);
dg.add_uint32(_compiled_format);
dg.add_string(_compiled_binary);
}
////////////////////////////////////////////////////////////////////
@ -3260,4 +3333,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_loaded = scan.get_bool();
_filename.read_datagram(scan);
_text.read_datagram(scan);
_compiled_format = scan.get_uint32();
_compiled_binary = scan.get_string();
}

View File

@ -40,6 +40,8 @@ typedef struct _CGprogram *CGprogram;
typedef struct _CGparameter *CGparameter;
#endif
class BamCacheRecord;
////////////////////////////////////////////////////////////////////
// Class : Shader
// Summary: The Shader class is meant to select the Shader Language,
@ -103,9 +105,11 @@ PUBLISHED:
INLINE bool get_error_flag() const;
INLINE ShaderLanguage get_language() const;
INLINE static ShaderUtilization get_shader_utilization();
INLINE static void set_shader_utilization(ShaderUtilization utl);
INLINE static bool have_shader_utilization();
INLINE bool has_fullpath() const;
INLINE const Filename &get_fullpath() const;
INLINE bool get_cache_compiled_shader() const;
INLINE void set_cache_compiled_shader(bool flag);
void prepare(PreparedGraphicsObjects *prepared_objects);
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
@ -507,6 +511,9 @@ public:
void clear_parameters();
void set_compiled(unsigned int format, const char *data, size_t length);
bool get_compiled(unsigned int &format, string &binary) const;
private:
#ifdef HAVE_CG
ShaderArgClass cg_parameter_class(CGparameter p);
@ -557,18 +564,25 @@ public:
protected:
ShaderFile _filename;
Filename _fullpath;
int _parse;
bool _loaded;
ShaderLanguage _language;
pvector<Filename> _included_files;
typedef pvector<Filename> Filenames;
Filenames _included_files;
// Stores full paths, and includes the fullpaths of the shaders
// themselves as well as the includes.
pvector<Filename> _source_files;
Filenames _source_files;
time_t _last_modified;
PT(BamCacheRecord) _record;
bool _cache_compiled_shader;
unsigned int _compiled_format;
string _compiled_binary;
static ShaderCaps _default_caps;
static ShaderUtilization _shader_utilization;
static int _shaders_generated;
typedef pmap<ShaderFile, PT(Shader)> ShaderTable;
@ -587,11 +601,12 @@ private:
Shader(ShaderLanguage lang);
bool read(const ShaderFile &sfile);
bool do_read_source(string &into, const Filename &fn);
bool read(const ShaderFile &sfile, BamCacheRecord *record = NULL);
bool do_read_source(string &into, const Filename &fn, BamCacheRecord *record);
bool r_preprocess_source(ostream &out, const Filename &fn,
const Filename &source_dir,
set<Filename> &open_files, int depth = 0);
set<Filename> &open_files,
BamCacheRecord *record, int depth = 0);
bool check_modified() const;

View File

@ -504,7 +504,6 @@ init_libpgraph() {
ShadeModelAttrib::register_with_read_factory();
ShaderInput::register_with_read_factory();
ShaderAttrib::register_with_read_factory();
Shader::register_with_read_factory();
ShowBoundsEffect::register_with_read_factory();
TexMatrixAttrib::register_with_read_factory();
TexProjectorEffect::register_with_read_factory();

View File

@ -142,6 +142,35 @@ get_cache_compressed_textures() const {
return _cache_compressed_textures && _active;
}
////////////////////////////////////////////////////////////////////
// Function: BamCache::set_cache_compiled_shaders
// Access: Published
// Description: Indicates whether compiled shader programs will be
// stored in the cache, as binary .sho files. This
// may not be supported by all shader languages or
// graphics renderers.
////////////////////////////////////////////////////////////////////
INLINE void BamCache::
set_cache_compiled_shaders(bool flag) {
ReMutexHolder holder(_lock);
_cache_compiled_shaders = flag;
}
////////////////////////////////////////////////////////////////////
// Function: BamCache::get_cache_compiled_shaders
// Access: Published
// Description: Returns whether compiled shader programs will be
// stored in the cache, as binary .txo files. See
// set_cache_compiled_shaders().
//
// This also returns false if get_active() is false.
////////////////////////////////////////////////////////////////////
INLINE bool BamCache::
get_cache_compiled_shaders() const {
ReMutexHolder holder(_lock);
return _cache_compiled_shaders && _active;
}
////////////////////////////////////////////////////////////////////
// Function: BamCache::get_root
// Access: Published

View File

@ -74,6 +74,12 @@ BamCache() :
"by the GSG. This may be set in conjunction with "
"model-cache-textures, or it may be independent."));
ConfigVariableBool model_cache_compiled_shaders
("model-cache-compiled-shaders", false,
PRC_DESC("If this is set to true, compiled shaders will be cached "
"in the model cache, in their binary form as downloaded "
"by the GSG."));
ConfigVariableInt model_cache_max_kbytes
("model-cache-max-kbytes", 10485760,
PRC_DESC("This is the maximum size of the model cache, in kilobytes."));
@ -81,6 +87,7 @@ BamCache() :
_cache_models = model_cache_models;
_cache_textures = model_cache_textures;
_cache_compressed_textures = model_cache_compressed_textures;
_cache_compiled_shaders = model_cache_compiled_shaders;
_flush_time = model_cache_flush;
_max_kbytes = model_cache_max_kbytes;

View File

@ -61,6 +61,9 @@ PUBLISHED:
INLINE void set_cache_compressed_textures(bool flag);
INLINE bool get_cache_compressed_textures() const;
INLINE void set_cache_compiled_shaders(bool flag);
INLINE bool get_cache_compiled_shaders() const;
void set_root(const Filename &root);
INLINE Filename get_root() const;
@ -92,6 +95,8 @@ PUBLISHED:
MAKE_PROPERTY(cache_textures, get_cache_textures, set_cache_textures);
MAKE_PROPERTY(cache_compressed_textures, get_cache_compressed_textures,
set_cache_compressed_textures);
MAKE_PROPERTY(cache_compiled_shaders, get_cache_compiled_shaders,
set_cache_compiled_shaders);
MAKE_PROPERTY(root, get_root, set_root);
MAKE_PROPERTY(flush_time, get_flush_time, set_flush_time);
MAKE_PROPERTY(cache_max_kbytes, get_cache_max_kbytes, set_cache_max_kbytes);
@ -130,6 +135,7 @@ private:
bool _cache_models;
bool _cache_textures;
bool _cache_compressed_textures;
bool _cache_compiled_shaders;
bool _read_only;
Filename _root;
int _flush_time;

View File

@ -188,6 +188,27 @@ add_dependent_file(const Filename &pathname) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BamCacheRecord::add_dependent_file
// Access: Published
// Description: Variant of add_dependent_file that takes an already
// opened VirtualFile.
////////////////////////////////////////////////////////////////////
void BamCacheRecord::
add_dependent_file(const VirtualFile *file) {
_files.push_back(DependentFile());
DependentFile &dfile = _files.back();
dfile._pathname = file->get_filename();
dfile._pathname.make_absolute();
dfile._timestamp = file->get_timestamp();
dfile._size = file->get_file_size();
if (dfile._pathname == _source_pathname) {
_source_timestamp = dfile._timestamp;
}
}
////////////////////////////////////////////////////////////////////
// Function: BamCacheRecord::output
// Access: Published

View File

@ -26,6 +26,7 @@ class Datagram;
class DatagramIterator;
class FactoryParams;
class BamCacheRecord;
class VirtualFile;
////////////////////////////////////////////////////////////////////
// Class : BamCacheRecord
@ -66,6 +67,7 @@ PUBLISHED:
bool dependents_unchanged() const;
void clear_dependent_files();
void add_dependent_file(const Filename &pathname);
void add_dependent_file(const VirtualFile *file);
INLINE bool has_data() const;
INLINE void clear_data();