Skip to content

Commit af57c82

Browse files
committed
ShaderGenerator: reduce combinatoric explosion of shaders
This is done by: * Not considering the texture pointer when looking up a generated shader, only type * Not requiring different shaders based on RescaleNormalAttrib * Not looking at AlphaTestAttrib unless it is going to be relevant This should dramatically reduce the number of shaders that are being generated for many scenes, especially since the only thing that differs from object to object is often just the texture. These changes are also necessary to make b781995 more usable, since prepare_scene may see a slightly different state than is encountered at render time due to code in CullResult adding in an AlphaTestAttrib or RescaleNormalAttrib.
1 parent b781995 commit af57c82

File tree

8 files changed

+169
-32
lines changed

8 files changed

+169
-32
lines changed

panda/src/pgraph/alphaTestAttrib.cxx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "bamWriter.h"
1919
#include "datagram.h"
2020
#include "datagramIterator.h"
21+
#include "auxBitplaneAttrib.h"
2122

2223
TypeHandle AlphaTestAttrib::_type_handle;
2324
int AlphaTestAttrib::_attrib_slot;
@@ -98,7 +99,15 @@ get_hash_impl() const {
9899
*/
99100
CPT(RenderAttrib) AlphaTestAttrib::
100101
get_auto_shader_attrib_impl(const RenderState *state) const {
101-
return this;
102+
// This is only important if the shader subsumes the alpha test, which only
103+
// happens if there is an AuxBitplaneAttrib with ABO_glow.
104+
const AuxBitplaneAttrib *aux;
105+
if (!state->get_attrib(aux) ||
106+
(aux->get_outputs() & AuxBitplaneAttrib::ABO_glow) == 0) {
107+
return nullptr;
108+
} else {
109+
return this;
110+
}
102111
}
103112

104113
/**

panda/src/pgraph/rescaleNormalAttrib.cxx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,14 @@ get_hash_impl() const {
8686
CPT(RenderAttrib) RescaleNormalAttrib::
8787
get_auto_shader_attrib_impl(const RenderState *state) const {
8888
// We currently only support M_normalize in the ShaderGenerator.
89-
if (_mode == M_none || _mode == M_normalize) {
89+
/*if (_mode == M_none || _mode == M_normalize) {
9090
return this;
9191
} else {
9292
return RescaleNormalAttrib::make(M_normalize);
93-
}
93+
}*/
94+
// Actually, we currently ignore this attribute in the shader generator,
95+
// and always normalize the normals. It's too much of a bother.
96+
return nullptr;
9497
}
9598

9699
/**

panda/src/pgraph/shaderAttrib.cxx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -523,14 +523,15 @@ void ShaderAttrib::
523523
output(ostream &out) const {
524524
out << "ShaderAttrib:";
525525

526-
if (_has_shader) {
527-
if (_shader == NULL) {
526+
if (_auto_shader) {
527+
out << "auto";
528+
return;
529+
} else if (_has_shader) {
530+
if (_shader == nullptr) {
528531
out << "off";
529532
} else {
530533
out << _shader->get_filename().get_basename();
531534
}
532-
} else if (_auto_shader) {
533-
out << "auto";
534535
}
535536

536537
out << "," << _inputs.size() << " inputs";

panda/src/pgraph/textureAttrib.I

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,26 @@ get_on_texture(TextureStage *stage) const {
140140
return NULL;
141141
}
142142

143+
/**
144+
* Returns the type of the texture associated with the indicated stage. It is
145+
* an error to call this if has_on_stage(stage) returns false.
146+
*
147+
* This method is no different than get_on_texture(stage)->get_texture_type();
148+
* it merely exists to address a corner case for the shader generator.
149+
*/
150+
INLINE Texture::TextureType TextureAttrib::
151+
get_on_texture_type(TextureStage *stage) const {
152+
Stages::const_iterator si;
153+
si = _on_stages.find(StageNode(stage));
154+
nassertr(si != _on_stages.end(), Texture::TT_2d_texture);
155+
156+
if ((*si)._texture == nullptr) {
157+
return (*si)._texture_type;
158+
} else {
159+
return (*si)._texture->get_texture_type();
160+
}
161+
}
162+
143163
/**
144164
* Returns the sampler associated with the indicated stage, or the one
145165
* associated with its texture if no custom stage has been specified. It is
@@ -215,6 +235,26 @@ is_identity() const {
215235
return _on_stages.empty() && _off_stages.empty() && !_off_all_stages;
216236
}
217237

238+
/**
239+
* Call only on a state returned by get_auto_shader_attrib.
240+
*/
241+
bool TextureAttrib::
242+
on_stage_affects_rgb(size_t n) const {
243+
nassertr(n < _render_stages.size(), false);
244+
StageNode *stage = _render_stages[n];
245+
return stage->_texture_affects_rgb;
246+
}
247+
248+
/**
249+
* Call only on a state returned by get_auto_shader_attrib.
250+
*/
251+
bool TextureAttrib::
252+
on_stage_affects_alpha(size_t n) const {
253+
nassertr(n < _render_stages.size(), false);
254+
StageNode *stage = _render_stages[n];
255+
return stage->_texture_affects_alpha;
256+
}
257+
218258
/**
219259
* Confirms whether the _on_stages list is still sorted. It will become
220260
* unsorted if someone calls TextureStage::set_sort().

panda/src/pgraph/textureAttrib.cxx

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ find_on_stage(const TextureStage *stage) const {
106106
*/
107107
CPT(RenderAttrib) TextureAttrib::
108108
add_on_stage(TextureStage *stage, Texture *tex, int override) const {
109+
nassertr(tex != nullptr, this);
110+
109111
TextureAttrib *attrib = new TextureAttrib(*this);
110112
Stages::iterator si = attrib->_on_stages.insert(StageNode(stage)).first;
111113
(*si)._override = override;
@@ -127,6 +129,8 @@ add_on_stage(TextureStage *stage, Texture *tex, int override) const {
127129
*/
128130
CPT(RenderAttrib) TextureAttrib::
129131
add_on_stage(TextureStage *stage, Texture *tex, const SamplerState &sampler, int override) const {
132+
nassertr(tex != nullptr, this);
133+
130134
TextureAttrib *attrib = new TextureAttrib(*this);
131135
Stages::iterator si = attrib->_on_stages.insert(StageNode(stage)).first;
132136
(*si)._override = override;
@@ -381,10 +385,19 @@ output(ostream &out) const {
381385
const StageNode &sn = *(*ri);
382386
TextureStage *stage = sn._stage;
383387
Texture *tex = sn._texture;
384-
if (tex != NULL) {
388+
if (tex != nullptr) {
385389
out << " " << stage->get_name() << ":" << tex->get_name();
386390
} else {
387-
out << " " << stage->get_name();
391+
out << " " << stage->get_name() << ":(" << sn._texture_type;
392+
if (sn._texture_affects_rgb) {
393+
out << " rgb";
394+
if (sn._texture_affects_alpha) {
395+
out << "a";
396+
}
397+
} else if (sn._texture_affects_alpha) {
398+
out << " alpha";
399+
}
400+
out << ")";
388401
}
389402
if (sn._override != 0) {
390403
out << "^" << sn._override;
@@ -500,6 +513,19 @@ compare_to_impl(const RenderAttrib *other) const {
500513
}
501514
}
502515

516+
if (texture == nullptr) {
517+
// This is an attribute returned by get_auto_shader_attrib_impl.
518+
if ((*si)._texture_type != (*osi)._texture_type) {
519+
return (*si)._texture_type < (*osi)._texture_type ? -1 : 1;
520+
}
521+
if ((*si)._texture_affects_rgb != (*osi)._texture_affects_rgb) {
522+
return (*si)._texture_affects_rgb < (*osi)._texture_affects_rgb ? -1 : 1;
523+
}
524+
if ((*si)._texture_affects_alpha != (*osi)._texture_affects_alpha) {
525+
return (*si)._texture_affects_alpha < (*osi)._texture_affects_alpha ? -1 : 1;
526+
}
527+
}
528+
503529
++si;
504530
++osi;
505531
}
@@ -563,6 +589,13 @@ get_hash_impl() const {
563589
hash = pointer_hash::add_hash(hash, sn._texture);
564590
hash = int_hash::add_hash(hash, (int)sn._implicit_sort);
565591
hash = int_hash::add_hash(hash, sn._override);
592+
593+
if (sn._texture == nullptr) {
594+
// This is an attribute returned by get_auto_shader_attrib_impl.
595+
hash = int_hash::add_hash(hash, (int)sn._texture_type);
596+
hash = int_hash::add_hash(hash, (int)sn._texture_affects_rgb);
597+
hash = int_hash::add_hash(hash, (int)sn._texture_affects_alpha);
598+
}
566599
}
567600

568601
// This bool value goes here, between the two lists, to differentiate
@@ -739,7 +772,42 @@ invert_compose_impl(const RenderAttrib *other) const {
739772
*/
740773
CPT(RenderAttrib) TextureAttrib::
741774
get_auto_shader_attrib_impl(const RenderState *state) const {
742-
return this;
775+
if (_on_stages.empty()) {
776+
// Having no stages is the same as not applying a texture attribute.
777+
return nullptr;
778+
}
779+
780+
// We make a texture attribute that does not store the texture and sampler,
781+
// so that we don't have to generate a shader for every possible texture.
782+
// We do have to store the few texture properties that do affect the
783+
// generated shader.
784+
PT(TextureAttrib) attrib = new TextureAttrib;
785+
attrib->_on_stages = _on_stages;
786+
attrib->sort_on_stages();
787+
788+
Stages::iterator si;
789+
for (si = attrib->_on_stages.begin(); si != attrib->_on_stages.end(); ++si) {
790+
Texture::Format format = (*si)._texture->get_format();
791+
(*si)._texture_type = (*si)._texture->get_texture_type();
792+
(*si)._texture_affects_rgb = (format != Texture::F_alpha);
793+
(*si)._texture_affects_alpha = Texture::has_alpha(format);
794+
(*si)._texture = nullptr;
795+
(*si)._has_sampler = false;
796+
797+
// We will no longer be composing or sorting this state so we can get rid
798+
// of these values.
799+
(*si)._override = 0;
800+
(*si)._implicit_sort = 0;
801+
802+
// Exception to optimize a common case: if the first texture is an RGB
803+
// texture, we don't care about whether it affects the alpha channel.
804+
if (attrib->_render_stages[0] == &(*si) &&
805+
(*si)._texture_affects_rgb && !(*si)._texture_affects_alpha) {
806+
(*si)._texture_affects_alpha = true;
807+
}
808+
}
809+
810+
return return_new(attrib);
743811
}
744812

745813
/**

panda/src/pgraph/textureAttrib.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class EXPCL_PANDA_PGRAPH TextureAttrib : public RenderAttrib {
5959
INLINE int get_ff_tc_index(int n) const;
6060
INLINE bool has_on_stage(TextureStage *stage) const;
6161
INLINE Texture *get_on_texture(TextureStage *stage) const;
62+
INLINE Texture::TextureType get_on_texture_type(TextureStage *stage) const;
6263
INLINE const SamplerState &get_on_sampler(TextureStage *stage) const;
6364
INLINE int get_on_stage_override(TextureStage *stage) const;
6465

@@ -81,6 +82,8 @@ class EXPCL_PANDA_PGRAPH TextureAttrib : public RenderAttrib {
8182
CPT(RenderAttrib) unify_texture_stages(TextureStage *stage) const;
8283

8384
public:
85+
INLINE bool on_stage_affects_rgb(size_t n) const;
86+
INLINE bool on_stage_affects_alpha(size_t n) const;
8487
CPT(TextureAttrib) filter_to_max(int max_texture_stages) const;
8588

8689
virtual bool lower_attrib_can_override() const;
@@ -114,6 +117,11 @@ class EXPCL_PANDA_PGRAPH TextureAttrib : public RenderAttrib {
114117
int _ff_tc_index;
115118
unsigned int _implicit_sort;
116119
int _override;
120+
121+
// These fields are used by the shader generator.
122+
Texture::TextureType _texture_type : 16;
123+
bool _texture_affects_rgb : 8;
124+
bool _texture_affects_alpha : 8;
117125
};
118126

119127
class CompareTextureStagePriorities {

panda/src/pgraph/transparencyAttrib.cxx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,14 @@ get_hash_impl() const {
114114
*/
115115
CPT(RenderAttrib) TransparencyAttrib::
116116
get_auto_shader_attrib_impl(const RenderState *state) const {
117-
return this;
117+
if (_mode == TransparencyAttrib::M_alpha) {
118+
return this;
119+
} else if (_mode == TransparencyAttrib::M_premultiplied_alpha ||
120+
_mode == TransparencyAttrib::M_dual) {
121+
return return_new(new TransparencyAttrib(M_alpha));
122+
} else {
123+
return nullptr;
124+
}
118125
}
119126

120127
/**

panda/src/pgraphnodes/shaderGenerator.cxx

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,14 @@ analyze_renderstate(const RenderState *rs) {
357357
}
358358

359359
// Determine whether we should normalize the normals.
360-
const RescaleNormalAttrib *rescale;
360+
/*const RescaleNormalAttrib *rescale;
361361
rs->get_attrib_def(rescale);
362362
363363
_normalize_normals = (rescale->get_mode() != RescaleNormalAttrib::M_none);
364+
*/
365+
// Actually, let's always normalize the normals for now. This helps to
366+
// reduce combinatoric explosion of shaders.
367+
_normalize_normals = true;
364368

365369
// Decide which material modes need to be calculated.
366370

@@ -823,11 +827,10 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
823827
text << "\t in float4 l_" << it->first->join("_") << " : " << it->second << ",\n";
824828
}
825829
const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
826-
for (int i=0; i<_num_textures; i++) {
830+
for (int i = 0; i < _num_textures; ++i) {
827831
TextureStage *stage = texture->get_on_stage(i);
828-
Texture *tex = texture->get_on_texture(stage);
829-
nassertr(tex != NULL, NULL);
830-
text << "\t uniform sampler" << texture_type_as_string(tex->get_texture_type()) << " tex_" << i << ",\n";
832+
Texture::TextureType type = texture->get_on_texture_type(stage);
833+
text << "\t uniform sampler" << texture_type_as_string(type) << " tex_" << i << ",\n";
831834
if (tex_matrix->has_stage(stage)) {
832835
text << "\t uniform float4x4 texmat_" << i << ",\n";
833836
}
@@ -935,11 +938,10 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
935938
}
936939
text << "\t // Fetch all textures.\n";
937940
if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
938-
Texture *tex = texture->get_on_texture(texture->get_on_stage(_map_index_height));
939-
nassertr(tex != NULL, NULL);
940-
text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(tex->get_texture_type());
941+
Texture::TextureType type = texture->get_on_texture_type(texture->get_on_stage(_map_index_height));
942+
text << "\t float4 tex" << _map_index_height << " = tex" << texture_type_as_string(type);
941943
text << "(tex_" << _map_index_height << ", texcoord" << _map_index_height << ".";
942-
switch (tex->get_texture_type()) {
944+
switch (type) {
943945
case Texture::TT_cube_map:
944946
case Texture::TT_3d_texture:
945947
case Texture::TT_2d_texture_array:
@@ -972,18 +974,17 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
972974
text << " * 2.0 - 1.0)) * " << 0.5 * parallax_mapping_scale << ";\n";
973975
}
974976
}
975-
for (int i=0; i<_num_textures; i++) {
977+
for (int i = 0; i < _num_textures; ++i) {
976978
if (i != _map_index_height) {
977-
Texture *tex = texture->get_on_texture(texture->get_on_stage(i));
978-
nassertr(tex != NULL, NULL);
979+
Texture::TextureType type = texture->get_on_texture_type(texture->get_on_stage(i));
979980
// Parallax mapping pushes the texture coordinates of the other textures
980981
// away from the camera.
981982
if (_map_index_height >= 0 && parallax_mapping_samples > 0) {
982983
text << "\t texcoord" << i << ".xyz -= parallax_offset;\n";
983984
}
984-
text << "\t float4 tex" << i << " = tex" << texture_type_as_string(tex->get_texture_type());
985+
text << "\t float4 tex" << i << " = tex" << texture_type_as_string(type);
985986
text << "(tex_" << i << ", texcoord" << i << ".";
986-
switch(tex->get_texture_type()) {
987+
switch (type) {
987988
case Texture::TT_cube_map:
988989
case Texture::TT_3d_texture:
989990
case Texture::TT_2d_texture_array:
@@ -1263,20 +1264,20 @@ synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
12631264
}
12641265

12651266
// Now loop through the textures to compose our magic blending formulas.
1266-
for (int i=0; i<_num_textures; i++) {
1267+
for (int i = 0; i < _num_textures; ++i) {
12671268
TextureStage *stage = texture->get_on_stage(i);
12681269
switch (stage->get_mode()) {
12691270
case TextureStage::M_modulate: {
1270-
int num_components = texture->get_on_texture(texture->get_on_stage(i))->get_num_components();
1271+
bool affects_rgb = texture->on_stage_affects_rgb(i);
1272+
bool affects_alpha = texture->on_stage_affects_alpha(i);
12711273

1272-
if (num_components == 1) {
1274+
if (affects_rgb && affects_alpha) {
1275+
text << "\t result.rgba *= tex" << i << ".rgba;\n";
1276+
} else if (affects_alpha) {
12731277
text << "\t result.a *= tex" << i << ".a;\n";
1274-
} else if (num_components == 3) {
1278+
} else if (affects_rgb) {
12751279
text << "\t result.rgb *= tex" << i << ".rgb;\n";
1276-
} else {
1277-
text << "\t result.rgba *= tex" << i << ".rgba;\n";
12781280
}
1279-
12801281
break; }
12811282
case TextureStage::M_modulate_glow:
12821283
case TextureStage::M_modulate_gloss:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy