mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
Add ability to cache compiled GLSL shaders, remove unused ShaderUtilization
This commit is contained in:
parent
bc58335214
commit
6eb460c359
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -940,6 +940,7 @@ public:
|
||||
PFNGLDISPATCHCOMPUTEPROC _glDispatchCompute;
|
||||
PFNGLMEMORYBARRIERPROC _glMemoryBarrier;
|
||||
PFNGLGETPROGRAMBINARYPROC _glGetProgramBinary;
|
||||
PFNGLPROGRAMBINARYPROC _glProgramBinary;
|
||||
PFNGLGETINTERNALFORMATIVPROC _glGetInternalformativ;
|
||||
PFNGLVIEWPORTARRAYVPROC _glViewportArrayv;
|
||||
PFNGLSCISSORARRAYVPROC _glScissorArrayv;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user