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