Panda3D
 All Classes Functions Variables Enumerations
dxShaderContext9.cxx
1 // Filename: dxShaderContext9.cxx
2 // Created by: jyelon (01Sep05), conversion aignacio (Jan-Mar06)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "dxGraphicsStateGuardian9.h"
16 #include "dxShaderContext9.h"
17 #include "dxVertexBufferContext9.h"
18 
19 #include <io.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 
26 #ifdef HAVE_CG
27 #include <Cg/cgD3D9.h>
28 #endif
29 
30 #define DEBUG_SHADER 0
31 
32 TypeHandle CLP(ShaderContext)::_type_handle;
33 
34 ////////////////////////////////////////////////////////////////////
35 // Function: DXShaderContext9::Constructor
36 // Access: Public
37 // Description: xyz
38 ////////////////////////////////////////////////////////////////////
39 CLP(ShaderContext)::
40 CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
41  _vertex_element_array = NULL;
42  _vertex_declaration = NULL;
43 
44  _num_bound_streams = 0;
45 
46  _name = s->get_filename();
47 
48 #ifdef HAVE_CG
49  CGcontext context = DCAST(DXGraphicsStateGuardian9, gsg)->_cg_context;
50 
51  if (s->get_language() == Shader::SL_Cg) {
52 
53  // Ask the shader to compile itself for us and
54  // to give us the resulting Cg program objects.
55  if (!s->cg_compile_for(gsg->_shader_caps, context,
56  _cg_program, _cg_parameter_map)) {
57  return;
58  }
59 
60  // Load the program.
61  DWORD assembly_flags = 0;
62 #if DEBUG_SHADER
63  assembly_flags |= D3DXSHADER_DEBUG;
64 #endif
65 
66  HRESULT hr;
67  bool success = true;
68  hr = cgD3D9LoadProgram(_cg_program, FALSE, assembly_flags);
69  if (FAILED (hr)) {
70  dxgsg9_cat.error()
71  << "cgD3D9LoadProgram failed " << D3DERRORSTRING(hr);
72 
73  CGerror error = cgGetError();
74  if (error != CG_NO_ERROR) {
75  dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n";
76  }
77  release_resources();
78  }
79  }
80 #endif
81 }
82 
83 ////////////////////////////////////////////////////////////////////
84 // Function: DXShaderContext9::Destructor
85 // Access: Public
86 // Description: xyz
87 ////////////////////////////////////////////////////////////////////
88 CLP(ShaderContext)::
89 ~CLP(ShaderContext)() {
90  release_resources();
91 
92  if ( _vertex_declaration != NULL ) {
93  _vertex_declaration->Release();
94  _vertex_declaration = NULL;
95  }
96 
97  if ( _vertex_element_array != NULL ) {
98  delete _vertex_element_array;
99  _vertex_element_array = NULL;
100  }
101 }
102 
103 // int save_file (int size, void *data, char *file_path)
104 // {
105 // int state;
106 // int file_handle;
107 //
108 // state = false;
109 // file_handle = _open (file_path, _O_CREAT | _O_RDWR | _O_TRUNC, _S_IREAD | _S_IWRITE);
110 // if (file_handle != -1) {
111 // if (_write (file_handle, data, size) == size) {
112 // state = true;
113 // }
114 // _close (file_handle);
115 // }
116 //
117 // return state;
118 // }
119 //
120 // if (dxgsg9_cat.is_debug()) {
121 // // DEBUG: output the generated program
122 // const char *vertex_program;
123 // const char *pixel_program;
124 //
125 // vertex_program = cgGetProgramString (_cg_program[0], CG_COMPILED_PROGRAM);
126 // pixel_program = cgGetProgramString (_cg_program[1], CG_COMPILED_PROGRAM);
127 //
128 // dxgsg9_cat.debug() << vertex_program << "\n";
129 // dxgsg9_cat.debug() << pixel_program << "\n";
130 //
131 // // save the generated program to a file
132 // int size;
133 // char file_path [512];
134 //
135 // char drive[_MAX_DRIVE];
136 // char dir[_MAX_DIR];
137 // char fname[_MAX_FNAME];
138 // char ext[_MAX_EXT];
139 //
140 // _splitpath (_name.c_str ( ), drive, dir, fname, ext);
141 //
142 // size = strlen (vertex_program);
143 // sprintf (file_path, "%s.vasm", fname);
144 // save_file (size, (void *) vertex_program, file_path);
145 //
146 // size = strlen (pixel_program);
147 // sprintf (file_path, "%s.pasm", fname);
148 // save_file (size, (void *) pixel_program, file_path);
149 // }
150 
151 ////////////////////////////////////////////////////////////////////
152 // Function: DXShaderContext9::release_resources
153 // Access: Public
154 // Description: Should deallocate all system resources (such as
155 // vertex program handles or Cg contexts).
156 ////////////////////////////////////////////////////////////////////
157 void CLP(ShaderContext)::
158 release_resources() {
159 #ifdef HAVE_CG
160  if (_cg_program) {
161  cgDestroyProgram(_cg_program);
162  _cg_program = 0;
163  _cg_parameter_map.clear();
164  }
165 #endif
166 
167  // I think we need to call SetStreamSource for _num_bound_streams -- basically the logic from
168  // disable_shader_vertex_arrays -- but to do that we need to introduce logic like the GL code
169  // has to manage _last_gsg, so we can get at the device. Sigh.
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: DXShaderContext9::bind
174 // Access: Public
175 // Description: This function is to be called to enable a new
176 // shader. It also initializes all of the shader's
177 // input parameters.
178 ////////////////////////////////////////////////////////////////////
179 bool CLP(ShaderContext)::
180 bind(GSG *gsg) {
181 
182  bool bind_state = false;
183 
184 #ifdef HAVE_CG
185  if (_cg_program) {
186  // clear the last cached FVF to make sure the next SetFVF call goes through
187 
188  gsg -> _last_fvf = 0;
189 
190  // Pass in k-parameters and transform-parameters
191  issue_parameters(gsg, Shader::SSD_general);
192 
193  HRESULT hr;
194 
195  // Bind the shaders.
196  bind_state = true;
197  hr = cgD3D9BindProgram(_cg_program);
198  if (FAILED (hr)) {
199  dxgsg9_cat.error() << "cgD3D9BindProgram failed " << D3DERRORSTRING(hr);
200 
201  CGerror error = cgGetError();
202  if (error != CG_NO_ERROR) {
203  dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n";
204  }
205 
206  bind_state = false;
207  }
208  }
209 #endif
210 
211  return bind_state;
212 }
213 
214 ////////////////////////////////////////////////////////////////////
215 // Function: DXShaderContext9::unbind
216 // Access: Public
217 // Description: This function disables a currently-bound shader.
218 ////////////////////////////////////////////////////////////////////
219 void CLP(ShaderContext)::
220 unbind(GSG *gsg) {
221 
222 #ifdef HAVE_CG
223  if (_cg_program) {
224  HRESULT hr;
225  hr = cgD3D9UnbindProgram(_cg_program);
226  if (FAILED(hr)) {
227  dxgsg9_cat.error()
228  << "cgD3D9UnbindProgram failed " << D3DERRORSTRING(hr);
229  }
230  }
231 #endif
232 }
233 
234 ////////////////////////////////////////////////////////////////////
235 // Function: DXShaderContext9::issue_parameters
236 // Access: Public
237 // Description: This function gets called whenever the RenderState
238 // or TransformState has changed, but the Shader
239 // itself has not changed. It loads new values into the
240 // shader's parameters.
241 //
242 // If "altered" is false, that means you promise that
243 // the parameters for this shader context have already
244 // been issued once, and that since the last time the
245 // parameters were issued, no part of the render
246 // state has changed except the external and internal
247 // transforms.
248 ////////////////////////////////////////////////////////////////////
249 
250 #if DEBUG_SHADER
251 PN_stdfloat *global_data = 0;
252 ShaderContext::ShaderMatSpec *global_shader_mat_spec = 0;
253 InternalName *global_internal_name_0 = 0;
254 InternalName *global_internal_name_1 = 0;
255 #endif
256 
257 void CLP(ShaderContext)::
258 issue_parameters(GSG *gsg, int altered) {
259 #ifdef HAVE_CG
260  if (_cg_program) {
261 
262  // Iterate through _ptr parameters
263  for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
264  if(altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])){
265 #ifdef HAVE_CG
266  const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i];
267  Shader::ShaderPtrData* _ptr_data =
268  const_cast< Shader::ShaderPtrData*>(gsg->fetch_ptr_parameter(_ptr));
269 
270  if (_ptr_data == NULL){ //the input is not contained in ShaderPtrData
271  release_resources();
272  return;
273  }
274 
275  CGparameter p = _cg_parameter_map[_ptr._id._seqno];
276 
277  switch(_ptr_data->_type) {
278  case Shader::SPT_float:
279  cgD3D9SetUniform(p, (PN_stdfloat*)_ptr_data->_ptr);
280  break;
281 
282  default:
283  dxgsg9_cat.error()
284  << _ptr._id._name << ":" << "unrecognized parameter type\n";
285  release_resources();
286  return;
287  }
288  }
289 #endif
290  }
291 
292  for (int i=0; i<(int)_shader->_mat_spec.size(); i++) {
293  if (altered & (_shader->_mat_spec[i]._dep[0] | _shader->_mat_spec[i]._dep[1])) {
294  CGparameter p = _cg_parameter_map[_shader->_mat_spec[i]._id._seqno];
295  if (p == NULL) {
296  continue;
297  }
298  const LMatrix4 *val = gsg->fetch_specified_value(_shader->_mat_spec[i], altered);
299  if (val) {
300  HRESULT hr;
301  PN_stdfloat v [4];
302  LMatrix4f temp_matrix = LCAST(float, *val);
303 
304  hr = D3D_OK;
305 
306  const float *data;
307  data = temp_matrix.get_data();
308 
309  #if DEBUG_SHADER
310  // DEBUG
311  global_data = (PN_stdfloat *) data;
312  global_shader_mat_spec = &_shader->_mat_spec[i];
313  global_internal_name_0 = global_shader_mat_spec -> _arg [0];
314  global_internal_name_1 = global_shader_mat_spec -> _arg [1];
315  #endif
316 
317  switch (_shader->_mat_spec[i]._piece) {
318  case Shader::SMP_whole:
319  // TRANSPOSE REQUIRED
320  temp_matrix.transpose_in_place();
321  data = temp_matrix.get_data();
322 
323  hr = cgD3D9SetUniform (p, data);
324  break;
325 
326  case Shader::SMP_transpose:
327  // NO TRANSPOSE REQUIRED
328  hr = cgD3D9SetUniform (p, data);
329  break;
330 
331  case Shader::SMP_row0:
332  hr = cgD3D9SetUniform (p, data + 0);
333  break;
334  case Shader::SMP_row1:
335  hr = cgD3D9SetUniform (p, data + 4);
336  break;
337  case Shader::SMP_row2:
338  hr = cgD3D9SetUniform (p, data + 8);
339  break;
340  case Shader::SMP_row3x1:
341  case Shader::SMP_row3x2:
342  case Shader::SMP_row3x3:
343  case Shader::SMP_row3:
344  hr = cgD3D9SetUniform (p, data + 12);
345  break;
346 
347  case Shader::SMP_col0:
348  v[0] = data[0]; v[1] = data[4]; v[2] = data[8]; v[3] = data[12];
349  hr = cgD3D9SetUniform (p, v);
350  break;
351  case Shader::SMP_col1:
352  v[0] = data[1]; v[1] = data[5]; v[2] = data[9]; v[3] = data[13];
353  hr = cgD3D9SetUniform (p, v);
354  break;
355  case Shader::SMP_col2:
356  v[0] = data[2]; v[1] = data[6]; v[2] = data[10]; v[3] = data[14];
357  hr = cgD3D9SetUniform (p, v);
358  break;
359  case Shader::SMP_col3:
360  v[0] = data[3]; v[1] = data[7]; v[2] = data[11]; v[3] = data[15];
361  hr = cgD3D9SetUniform (p, v);
362  break;
363 
364  default:
365  dxgsg9_cat.error()
366  << "issue_parameters ( ) SMP parameter type not implemented " << _shader->_mat_spec[i]._piece << "\n";
367  break;
368  }
369 
370  if (FAILED (hr)) {
371 
372  string name = "unnamed";
373 
374  if (_shader->_mat_spec[i]._arg [0]) {
375  name = _shader->_mat_spec[i]._arg [0] -> get_basename ( );
376  }
377 
378  dxgsg9_cat.error()
379  << "NAME " << name << "\n"
380  << "MAT TYPE "
381  << _shader->_mat_spec[i]._piece
382  << " cgD3D9SetUniform failed "
383  << D3DERRORSTRING(hr);
384 
385  CGerror error = cgGetError ();
386  if (error != CG_NO_ERROR) {
387  dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n";
388  }
389  }
390  }
391  }
392  }
393  }
394 #endif
395 }
396 
397 ////////////////////////////////////////////////////////////////////
398 // Function: DXShaderContext9::disable_shader_vertex_arrays
399 // Access: Public
400 // Description: Disable all the vertex arrays used by this shader.
401 ////////////////////////////////////////////////////////////////////
402 void CLP(ShaderContext)::
403 disable_shader_vertex_arrays(GSG *gsg) {
404  LPDIRECT3DDEVICE9 device = gsg->_screen->_d3d_device;
405 
406  for ( int array_index = 0; array_index < _num_bound_streams; ++array_index )
407  {
408  device->SetStreamSource( array_index, NULL, 0, 0 );
409  }
410  _num_bound_streams = 0;
411 }
412 
413 ////////////////////////////////////////////////////////////////////
414 // Function: DXShaderContext9::update_shader_vertex_arrays
415 // Access: Public
416 // Description: Disables all vertex arrays used by the previous
417 // shader, then enables all the vertex arrays needed
418 // by this shader. Extracts the relevant vertex array
419 // data from the gsg.
420 // The current implementation is inefficient, because
421 // it may unnecessarily disable arrays then immediately
422 // reenable them. We may optimize this someday.
423 ////////////////////////////////////////////////////////////////////
424 bool CLP(ShaderContext)::
425 update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg, bool force) {
426  if (prev) prev->disable_shader_vertex_arrays(gsg);
427 #ifdef HAVE_CG
428  if (!_cg_program) {
429  return true;
430  }
431 
432 #ifdef SUPPORT_IMMEDIATE_MODE
433 /*
434  if (gsg->_use_sender) {
435  dxgsg9_cat.error() << "immediate mode shaders not implemented yet\n";
436  } else
437 */
438 #endif // SUPPORT_IMMEDIATE_MODE
439  {
440  int nvarying = _shader->_var_spec.size();
441  LPDIRECT3DDEVICE9 device = gsg->_screen->_d3d_device;
442  HRESULT hr;
443 
444  // Discard and recreate the VertexElementArray. This thrashes pretty bad....
445  if ( _vertex_element_array != NULL ) {
446  delete _vertex_element_array;
447  }
448  _vertex_element_array = new VertexElementArray(nvarying + 2);
449  VertexElementArray* vertex_element_array = _vertex_element_array;
450 
451  // Experimentally determined that DX doesn't like us crossing the streams!
452  // It seems to be okay with out-of-order offsets in both source and destination,
453  // but it wants all stream X entries grouped together, then all stream Y entries, etc.
454  // To accomplish this out outer loop processes arrays ("streams"), and we repeatedly
455  // iterate the parameters to pull out only those for a single stream.
456 
457  int number_of_arrays = gsg->_data_reader->get_num_arrays();
458  for ( int array_index = 0; array_index < number_of_arrays; ++array_index ) {
459  const GeomVertexArrayDataHandle* array_reader =
460  gsg->_data_reader->get_array_reader( array_index );
461  if ( array_reader == NULL ) {
462  dxgsg9_cat.error() << "Unable to get reader for array " << array_index << "\n";
463  continue;
464  }
465 
466  for ( int var_index = 0; var_index < nvarying; ++var_index ) {
467  CGparameter p = _cg_parameter_map[_shader->_var_spec[var_index]._id._seqno];
468  if ( p == NULL ) {
469  dxgsg9_cat.info() <<
470  "No parameter in map for parameter " << var_index <<
471  " (probably optimized away)\n";
472  continue;
473  }
474 
475  InternalName *name = _shader->_var_spec[var_index]._name;
476 
477  // This is copied from the GL version of this function, and I've yet to 100% convince
478  // myself that it works properly....
479  int texslot = _shader->_var_spec[var_index]._append_uv;
480  if (texslot >= 0 && texslot < gsg->_state_texture->get_num_on_stages()) {
481  TextureStage *stage = gsg->_state_texture->get_on_stage(texslot);
482  InternalName *texname = stage->get_texcoord_name();
483  if (name == InternalName::get_texcoord()) {
484  name = texname;
485  } else if (texname != InternalName::get_texcoord()) {
486  name = name->append(texname->get_basename());
487  }
488  }
489 
490  const GeomVertexArrayDataHandle* param_array_reader;
491  Geom::NumericType numeric_type;
492  int num_values;
493  int start;
494  int stride;
495  if ( gsg->_data_reader->get_array_info( name,
496  param_array_reader, num_values, numeric_type,
497  start, stride ) == false ) {
498  // This is apparently not an error (actually I think it is, just not a fatal one).
499  //
500  // The GL implementation fails silently in this case, but the net result is that we
501  // end up not supplying input for a shader parameter, which can cause Bad Things to
502  // happen so I'd like to at least get a hint as to what's gone wrong.
503  dxgsg9_cat.info() << "Geometry contains no data for shader parameter " << *name << "\n";
504  continue;
505  }
506 
507  // If not associated with the array we're working on, move on.
508  if ( param_array_reader != array_reader ) {
509  continue;
510  }
511 
512  const char* semantic = cgGetParameterSemantic( p );
513  if ( semantic == NULL ) {
514  dxgsg9_cat.error() << "Unable to retrieve semantic for parameter " << var_index << "\n";
515  continue;
516  }
517 
518  if ( strncmp( semantic, "POSITION", strlen( "POSITION" ) ) == 0 ) {
519  if (numeric_type == Geom::NT_float32) {
520  switch (num_values) {
521  case 3:
522  vertex_element_array->add_position_xyz_vertex_element(array_index, start);
523  break;
524  case 4:
525  vertex_element_array->add_position_xyzw_vertex_element(array_index, start);
526  break;
527  default:
528  dxgsg9_cat.error() << "VE ERROR: invalid number of vertex coordinate elements " << num_values << "\n";
529  break;
530  }
531  } else {
532  dxgsg9_cat.error() << "VE ERROR: invalid vertex type " << numeric_type << "\n";
533  }
534  } else if ( strncmp( semantic, "TEXCOORD", strlen( "TEXCOORD" ) ) == 0 ) {
535  int slot = atoi( semantic + strlen( "TEXCOORD" ) );
536  if (numeric_type == Geom::NT_float32) {
537  switch (num_values) {
538  case 1:
539  vertex_element_array->add_u_vertex_element(array_index, start, slot);
540  break;
541  case 2:
542  vertex_element_array->add_uv_vertex_element(array_index, start, slot);
543  break;
544  case 3:
545  vertex_element_array->add_uvw_vertex_element(array_index, start, slot);
546  break;
547  case 4:
548  vertex_element_array->add_xyzw_vertex_element(array_index, start, slot);
549  break;
550  default:
551  dxgsg9_cat.error() << "VE ERROR: invalid number of vertex texture coordinate elements " << num_values << "\n";
552  break;
553  }
554  } else {
555  dxgsg9_cat.error() << "VE ERROR: invalid texture coordinate type " << numeric_type << "\n";
556  }
557  } else if ( strncmp( semantic, "COLOR", strlen( "COLOR" ) ) == 0 ) {
558  if (numeric_type == Geom::NT_packed_dcba ||
559  numeric_type == Geom::NT_packed_dabc ||
560  numeric_type == Geom::NT_uint8) {
561  switch (num_values) {
562  case 4:
563  vertex_element_array->add_diffuse_color_vertex_element(array_index, start);
564  break;
565  default:
566  dxgsg9_cat.error() << "VE ERROR: invalid color coordinates " << num_values << "\n";
567  break;
568  }
569  } else {
570  dxgsg9_cat.error() << "VE ERROR: invalid color type " << numeric_type << "\n";
571  }
572  } else if ( strncmp( semantic, "NORMAL", strlen( "NORMAL" ) ) == 0 ) {
573  if (numeric_type == Geom::NT_float32) {
574  switch (num_values) {
575  case 3:
576  vertex_element_array->add_normal_vertex_element(array_index, start);
577  break;
578  default:
579  dxgsg9_cat.error() << "VE ERROR: invalid number of normal coordinate elements " << num_values << "\n";
580  break;
581  }
582  } else {
583  dxgsg9_cat.error() << "VE ERROR: invalid normal type " << numeric_type << "\n";
584  }
585  } else if ( strncmp( semantic, "BINORMAL", strlen( "BINORMAL" ) ) == 0 ) {
586  if (numeric_type == Geom::NT_float32) {
587  switch (num_values) {
588  case 3:
589  vertex_element_array->add_binormal_vertex_element(array_index, start);
590  break;
591  default:
592  dxgsg9_cat.error() << "VE ERROR: invalid number of binormal coordinate elements " << num_values << "\n";
593  break;
594  }
595  } else {
596  dxgsg9_cat.error() << "VE ERROR: invalid binormal type " << numeric_type << "\n";
597  }
598  } else if ( strncmp( semantic, "TANGENT", strlen( "TANGENT" ) ) == 0 ) {
599  if (numeric_type == Geom::NT_float32) {
600  switch (num_values) {
601  case 3:
602  vertex_element_array->add_tangent_vertex_element(array_index, start);
603  break;
604  default:
605  dxgsg9_cat.error() << "VE ERROR: invalid number of tangent coordinate elements " << num_values << "\n";
606  break;
607  }
608  } else {
609  dxgsg9_cat.error() << "VE ERROR: invalid tangent type " << numeric_type << "\n";
610  }
611  } else {
612  dxgsg9_cat.error() << "Unsupported semantic " << semantic << " for parameter " << var_index << "\n";
613  }
614  }
615 
616  // Get the vertex buffer for this array.
617  CLP(VertexBufferContext)* dvbc;
618  if (!gsg->setup_array_data(dvbc, array_reader, force)) {
619  dxgsg9_cat.error() << "Unable to setup vertex buffer for array " << array_index << "\n";
620  continue;
621  }
622 
623  // Bind this array as the data source for the corresponding stream.
624  const GeomVertexArrayFormat* array_format = array_reader->get_array_format();
625  hr = device->SetStreamSource( array_index, dvbc->_vbuffer, 0, array_format->get_stride() );
626  if (FAILED(hr)) {
627  dxgsg9_cat.error() << "SetStreamSource failed" << D3DERRORSTRING(hr);
628  }
629  }
630 
631  _num_bound_streams = number_of_arrays;
632 
633  if (( _vertex_element_array != NULL ) &&
634  ( _vertex_element_array->add_end_vertex_element() != false )) {
635  if (dxgsg9_cat.is_debug()) {
636  // Note that the currently generated vertex declaration works but never validates.
637  // My theory is that this is due to the shader programs always using float4 whereas
638  // the vertex declaration correctly sets the number of inputs (float2, float3, etc.).
639  if (cgD3D9ValidateVertexDeclaration(_cg_program,
640  _vertex_element_array->_vertex_element_array) == CG_TRUE) {
641  dxgsg9_cat.debug() << "cgD3D9ValidateVertexDeclaration succeeded\n";
642  } else {
643  dxgsg9_cat.debug() << "cgD3D9ValidateVertexDeclaration failed\n";
644  }
645  }
646 
647  // Discard the old VertexDeclaration. This thrashes pretty bad....
648  if ( _vertex_declaration != NULL ) {
649  _vertex_declaration->Release();
650  _vertex_declaration = NULL;
651  }
652 
653  hr = device->CreateVertexDeclaration( _vertex_element_array->_vertex_element_array,
654  &_vertex_declaration );
655  if (FAILED (hr)) {
656  dxgsg9_cat.error() << "CreateVertexDeclaration failed" << D3DERRORSTRING(hr);
657  } else {
658  hr = device->SetVertexDeclaration( _vertex_declaration );
659  if (FAILED(hr)) {
660  dxgsg9_cat.error() << "SetVertexDeclaration failed" << D3DERRORSTRING(hr);
661  }
662  }
663  } else {
664  dxgsg9_cat.error() << "VertexElementArray creation failed\n";
665  }
666  }
667 #endif // HAVE_CG
668 
669  return true;
670 }
671 
672 ////////////////////////////////////////////////////////////////////
673 // Function: DXShaderContext9::disable_shader_texture_bindings
674 // Access: Public
675 // Description: Disable all the texture bindings used by this shader.
676 ////////////////////////////////////////////////////////////////////
677 void CLP(ShaderContext)::
678 disable_shader_texture_bindings(GSG *gsg)
679 {
680 #ifdef HAVE_CG
681  if (_cg_program) {
682  for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
683  CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
684  if (p == NULL) {
685  continue;
686  }
687  int texunit = cgGetParameterResourceIndex(p);
688 
689  HRESULT hr;
690 
691  hr = gsg -> _d3d_device -> SetTexture (texunit, NULL);
692  if (FAILED (hr)) {
693  dxgsg9_cat.error()
694  << "SetTexture ("
695  << texunit
696  << ", NULL) failed "
697  << D3DERRORSTRING(hr);
698  }
699  }
700  }
701 #endif
702 }
703 
704 ////////////////////////////////////////////////////////////////////
705 // Function: DXShaderContext9::update_shader_texture_bindings
706 // Access: Public
707 // Description: Disables all texture bindings used by the previous
708 // shader, then enables all the texture bindings needed
709 // by this shader. Extracts the relevant vertex array
710 // data from the gsg.
711 // The current implementation is inefficient, because
712 // it may unnecessarily disable textures then immediately
713 // reenable them. We may optimize this someday.
714 ////////////////////////////////////////////////////////////////////
715 void CLP(ShaderContext)::
716 update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg)
717 {
718  if (prev) prev->disable_shader_texture_bindings(gsg);
719 
720 #ifdef HAVE_CG
721  if (_cg_program) {
722 
723  for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
724  CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno];
725  if (p == NULL) {
726  continue;
727  }
728  Texture *tex = NULL;
729  int view = gsg->get_current_tex_view_offset();
730  InternalName *id = _shader->_tex_spec[i]._name;
731  SamplerState sampler;
732 
733  if (id != NULL) {
734  const ShaderInput *input = gsg->_target_shader->get_shader_input(id);
735  tex = input->get_texture();
736  sampler = input->get_sampler();
737 
738  } else {
739  // We get the TextureAttrib directly from the _target_rs, not the
740  // filtered TextureAttrib in _target_texture.
741  const TextureAttrib *texattrib = DCAST(TextureAttrib, gsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
742  nassertv(texattrib != (TextureAttrib *)NULL);
743 
744  if (_shader->_tex_spec[i]._stage >= texattrib->get_num_on_stages()) {
745  continue;
746  }
747  TextureStage *stage = texattrib->get_on_stage(_shader->_tex_spec[i]._stage);
748  tex = texattrib->get_on_texture(stage);
749  sampler = texattrib->get_on_sampler(stage);
750  view += stage->get_tex_view_offset();
751  }
752  if (_shader->_tex_spec[i]._suffix != 0) {
753  // The suffix feature is inefficient. It is a temporary hack.
754  if (tex == 0) {
755  continue;
756  }
757  tex = tex->load_related(_shader->_tex_spec[i]._suffix);
758  }
759  if ((tex == 0) || (tex->get_texture_type() != _shader->_tex_spec[i]._desired_type)) {
760  continue;
761  }
762  TextureContext *tc = tex->prepare_now(view, gsg->_prepared_objects, gsg);
763  if (tc == (TextureContext*)NULL) {
764  continue;
765  }
766 
767  int texunit = cgGetParameterResourceIndex(p);
768 
769  gsg->apply_texture(texunit, tc, sampler);
770  }
771  }
772 #endif
773 }
774 
775 // DEBUG CODE TO TEST ASM CODE GENERATED BY Cg
776 void assemble_shader_test(char *file_path)
777 {
778  int flags;
779  D3DXMACRO *defines;
780  LPD3DXINCLUDE include;
781  LPD3DXBUFFER shader;
782  LPD3DXBUFFER error_messages;
783 
784  flags = 0;
785  defines = 0;
786  include = 0;
787  shader = 0;
788  error_messages = 0;
789 
790  D3DXAssembleShaderFromFile (file_path, defines, include, flags, &shader, &error_messages);
791  if (error_messages)
792  {
793  char *error_message;
794 
795  error_message = (char *) (error_messages -> GetBufferPointer ( ));
796  if (error_message)
797  {
798  dxgsg9_cat.error() << error_message;
799  }
800 
801  error_messages -> Release ( );
802  }
803 }
A GraphicsStateGuardian for rendering into DirectX9 contexts.
Texture * load_related(const InternalName *suffix) const
Loads a texture whose filename is derived by concatenating a suffix to the filename of this texture...
Definition: texture.cxx:777
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
Definition: shader.h:50
This is a special class object that holds all the information returned by a particular GSG to indicat...
int get_num_on_stages() const
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.I:91
This is a small container class that can hold any one of the value types that can be passed as input ...
Definition: shaderInput.h:41
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
TextureStage * get_on_stage(int n) const
Returns the nth stage turned on by the attribute, sorted in render order.
const float * get_data() const
Returns the address of the first of the nine data elements in the matrix.
Definition: lmatrix.h:1468
The ShaderContext is meant to contain the compiled version of a shader string.
Definition: shaderContext.h:35
This class gives the ability for a user-friendly way of creating a vertex declaration for DirectX 9...
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:34
InternalName * get_texcoord_name() const
See set_texcoord_name.
Definition: textureStage.I:148
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
const SamplerState & get_on_sampler(TextureStage *stage) const
Returns the sampler associated with the indicated stage, or the one associated with its texture if no...
Texture * get_on_texture(TextureStage *stage) const
Returns the texture associated with the indicated stage, or NULL if no texture is associated...
TextureType get_texture_type() const
Returns the overall interpretation of the texture.
Definition: texture.I:859
int get_tex_view_offset() const
Returns the current setting of the tex_view_offset.
Definition: textureStage.I:349
Represents a set of settings that indicate how a texture is sampled.
Definition: samplerState.h:39
TextureContext * prepare_now(int view, PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the texture on the particular GSG, if it does not already exist.
Definition: texture.cxx:1808
This is a special class object that holds all the information returned by a particular GSG to indicat...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:38