Panda3D
|
00001 // Filename: dxShaderContext9.cxx 00002 // Created by: jyelon (01Sep05), conversion aignacio (Jan-Mar06) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "dxGraphicsStateGuardian9.h" 00016 #include "dxShaderContext9.h" 00017 #include "dxVertexBufferContext9.h" 00018 00019 #include <io.h> 00020 #include <stdio.h> 00021 #include <stdlib.h> 00022 #include <fcntl.h> 00023 #include <sys/types.h> 00024 #include <sys/stat.h> 00025 #ifdef HAVE_CG 00026 #include "Cg/cgD3D9.h" 00027 #endif 00028 00029 #define DEBUG_SHADER 0 00030 00031 TypeHandle CLP(ShaderContext)::_type_handle; 00032 00033 //////////////////////////////////////////////////////////////////// 00034 // Function: DXShaderContext9::Constructor 00035 // Access: Public 00036 // Description: xyz 00037 //////////////////////////////////////////////////////////////////// 00038 CLP(ShaderContext):: 00039 CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) { 00040 00041 _vertex_element_array = NULL; 00042 _vertex_declaration = NULL; 00043 00044 _num_bound_streams = 0; 00045 00046 _name = s->get_filename ( ); 00047 00048 #ifdef HAVE_CG 00049 _cg_context = 0; 00050 if (s->get_language() == Shader::SL_Cg) { 00051 00052 // Ask the shader to compile itself for us and 00053 // to give us the resulting Cg program objects. 00054 00055 if (!s->cg_compile_for(gsg->_shader_caps, 00056 _cg_context, 00057 _cg_vprogram, 00058 _cg_fprogram, 00059 _cg_gprogram, // CG2 CHANGE 00060 _cg_parameter_map)) { 00061 return; 00062 } 00063 00064 // Load the program. 00065 00066 BOOL paramater_shadowing; 00067 DWORD assembly_flags; 00068 00069 paramater_shadowing = FALSE; 00070 assembly_flags = 0; 00071 00072 #if DEBUG_SHADER 00073 assembly_flags |= D3DXSHADER_DEBUG; 00074 #endif 00075 00076 HRESULT hr; 00077 bool success = true; 00078 hr = cgD3D9LoadProgram(_cg_vprogram, paramater_shadowing, assembly_flags); 00079 if (FAILED (hr)) { 00080 dxgsg9_cat.error() 00081 << "vertex shader cgD3D9LoadProgram failed " 00082 << D3DERRORSTRING(hr); 00083 00084 CGerror error = cgGetError(); 00085 if (error != CG_NO_ERROR) { 00086 dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; 00087 } 00088 success = false; 00089 } 00090 00091 hr = cgD3D9LoadProgram(_cg_fprogram, paramater_shadowing, assembly_flags); 00092 if (FAILED (hr)) { 00093 dxgsg9_cat.error() 00094 << "pixel shader cgD3D9LoadProgram failed " 00095 << D3DERRORSTRING(hr); 00096 00097 CGerror error = cgGetError(); 00098 if (error != CG_NO_ERROR) { 00099 dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; 00100 } 00101 success = false; 00102 } 00103 00104 // BEGIN CG2 CHANGE 00105 if (_cg_gprogram != 0) 00106 { 00107 hr = cgD3D9LoadProgram(_cg_gprogram, paramater_shadowing, assembly_flags); 00108 if (FAILED (hr)) { 00109 dxgsg9_cat.error() 00110 << "geometry shader cgD3D9LoadProgram failed " 00111 << D3DERRORSTRING(hr); 00112 00113 CGerror error = cgGetError(); 00114 if (error != CG_NO_ERROR) { 00115 dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; 00116 } 00117 success = false; 00118 } 00119 } 00120 // END CG2 CHANGE 00121 00122 if (!success) { 00123 release_resources(); 00124 } 00125 } 00126 #endif 00127 } 00128 00129 //////////////////////////////////////////////////////////////////// 00130 // Function: DXShaderContext9::Destructor 00131 // Access: Public 00132 // Description: xyz 00133 //////////////////////////////////////////////////////////////////// 00134 CLP(ShaderContext):: 00135 ~CLP(ShaderContext)() { 00136 release_resources(); 00137 00138 if ( _vertex_declaration != NULL ) { 00139 _vertex_declaration->Release(); 00140 _vertex_declaration = NULL; 00141 } 00142 00143 if ( _vertex_element_array != NULL ) { 00144 delete _vertex_element_array; 00145 _vertex_element_array = NULL; 00146 } 00147 } 00148 00149 // int save_file (int size, void *data, char *file_path) 00150 // { 00151 // int state; 00152 // int file_handle; 00153 // 00154 // state = false; 00155 // file_handle = _open (file_path, _O_CREAT | _O_RDWR | _O_TRUNC, _S_IREAD | _S_IWRITE); 00156 // if (file_handle != -1) { 00157 // if (_write (file_handle, data, size) == size) { 00158 // state = true; 00159 // } 00160 // _close (file_handle); 00161 // } 00162 // 00163 // return state; 00164 // } 00165 // 00166 // if (dxgsg9_cat.is_debug()) { 00167 // // DEBUG: output the generated program 00168 // const char *vertex_program; 00169 // const char *pixel_program; 00170 // 00171 // vertex_program = cgGetProgramString (_cg_program[0], CG_COMPILED_PROGRAM); 00172 // pixel_program = cgGetProgramString (_cg_program[1], CG_COMPILED_PROGRAM); 00173 // 00174 // dxgsg9_cat.debug() << vertex_program << "\n"; 00175 // dxgsg9_cat.debug() << pixel_program << "\n"; 00176 // 00177 // // save the generated program to a file 00178 // int size; 00179 // char file_path [512]; 00180 // 00181 // char drive[_MAX_DRIVE]; 00182 // char dir[_MAX_DIR]; 00183 // char fname[_MAX_FNAME]; 00184 // char ext[_MAX_EXT]; 00185 // 00186 // _splitpath (_name.c_str ( ), drive, dir, fname, ext); 00187 // 00188 // size = strlen (vertex_program); 00189 // sprintf (file_path, "%s.vasm", fname); 00190 // save_file (size, (void *) vertex_program, file_path); 00191 // 00192 // size = strlen (pixel_program); 00193 // sprintf (file_path, "%s.pasm", fname); 00194 // save_file (size, (void *) pixel_program, file_path); 00195 // } 00196 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: DXShaderContext9::release_resources 00199 // Access: Public 00200 // Description: Should deallocate all system resources (such as 00201 // vertex program handles or Cg contexts). 00202 //////////////////////////////////////////////////////////////////// 00203 void CLP(ShaderContext):: 00204 release_resources() { 00205 #ifdef HAVE_CG 00206 if (_cg_context) { 00207 cgDestroyContext(_cg_context); 00208 _cg_context = 0; 00209 _cg_vprogram = 0; 00210 _cg_fprogram = 0; 00211 _cg_gprogram = 0; // CG2 CHANGE 00212 _cg_parameter_map.clear(); 00213 } 00214 #endif 00215 00216 // I think we need to call SetStreamSource for _num_bound_streams -- basically the logic from 00217 // disable_shader_vertex_arrays -- but to do that we need to introduce logic like the GL code 00218 // has to manage _last_gsg, so we can get at the device. Sigh. 00219 } 00220 00221 //////////////////////////////////////////////////////////////////// 00222 // Function: DXShaderContext9::bind 00223 // Access: Public 00224 // Description: This function is to be called to enable a new 00225 // shader. It also initializes all of the shader's 00226 // input parameters. 00227 //////////////////////////////////////////////////////////////////// 00228 bool CLP(ShaderContext):: 00229 bind(GSG *gsg) { 00230 00231 bool bind_state; 00232 00233 bind_state = false; 00234 #ifdef HAVE_CG 00235 if (_cg_context) { 00236 // clear the last cached FVF to make sure the next SetFVF call goes through 00237 00238 gsg -> _last_fvf = 0; 00239 00240 // Pass in k-parameters and transform-parameters 00241 issue_parameters(gsg, Shader::SSD_general); 00242 00243 HRESULT hr; 00244 00245 // Bind the shaders. 00246 bind_state = true; 00247 hr = cgD3D9BindProgram(_cg_vprogram); 00248 if (FAILED (hr)) { 00249 dxgsg9_cat.error() << "cgD3D9BindProgram vertex shader failed " << D3DERRORSTRING(hr); 00250 00251 CGerror error = cgGetError(); 00252 if (error != CG_NO_ERROR) { 00253 dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; 00254 } 00255 00256 bind_state = false; 00257 } 00258 hr = cgD3D9BindProgram(_cg_fprogram); 00259 if (FAILED (hr)) { 00260 dxgsg9_cat.error() << "cgD3D9BindProgram pixel shader failed " << D3DERRORSTRING(hr); 00261 00262 CGerror error = cgGetError(); 00263 if (error != CG_NO_ERROR) { 00264 dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; 00265 } 00266 00267 bind_state = false; 00268 } 00269 00270 // BEGIN CG2 CHANGE 00271 if (_cg_gprogram != 0) 00272 { 00273 hr = cgD3D9BindProgram(_cg_gprogram); 00274 if (FAILED (hr)) { 00275 dxgsg9_cat.error() << "cgD3D9BindProgram geometry shader failed " << D3DERRORSTRING(hr); 00276 00277 CGerror error = cgGetError(); 00278 if (error != CG_NO_ERROR) { 00279 dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; 00280 } 00281 00282 bind_state = false; 00283 } 00284 } 00285 // END CG2 CHANGE 00286 } 00287 #endif 00288 00289 return bind_state; 00290 } 00291 00292 //////////////////////////////////////////////////////////////////// 00293 // Function: DXShaderContext9::unbind 00294 // Access: Public 00295 // Description: This function disables a currently-bound shader. 00296 //////////////////////////////////////////////////////////////////// 00297 void CLP(ShaderContext):: 00298 unbind(GSG *gsg) { 00299 00300 #ifdef HAVE_CG 00301 if (_cg_context) { 00302 HRESULT hr; 00303 00304 hr = gsg -> _d3d_device -> SetVertexShader (NULL); 00305 if (FAILED (hr)) { 00306 dxgsg9_cat.error() 00307 << "SetVertexShader (NULL) failed " << D3DERRORSTRING(hr); 00308 } 00309 hr = gsg -> _d3d_device -> SetPixelShader (NULL); 00310 if (FAILED (hr)) { 00311 dxgsg9_cat.error() 00312 << "SetPixelShader (NULL) failed " << D3DERRORSTRING(hr); 00313 } 00314 } 00315 #endif 00316 } 00317 00318 //////////////////////////////////////////////////////////////////// 00319 // Function: DXShaderContext9::issue_parameters 00320 // Access: Public 00321 // Description: This function gets called whenever the RenderState 00322 // or TransformState has changed, but the Shader 00323 // itself has not changed. It loads new values into the 00324 // shader's parameters. 00325 // 00326 // If "altered" is false, that means you promise that 00327 // the parameters for this shader context have already 00328 // been issued once, and that since the last time the 00329 // parameters were issued, no part of the render 00330 // state has changed except the external and internal 00331 // transforms. 00332 //////////////////////////////////////////////////////////////////// 00333 00334 #if DEBUG_SHADER 00335 PN_stdfloat *global_data = 0; 00336 ShaderContext::ShaderMatSpec *global_shader_mat_spec = 0; 00337 InternalName *global_internal_name_0 = 0; 00338 InternalName *global_internal_name_1 = 0; 00339 #endif 00340 00341 void CLP(ShaderContext):: 00342 issue_parameters(GSG *gsg, int altered) 00343 { 00344 #ifdef HAVE_CG 00345 if (_cg_context) { 00346 00347 // Iterate through _ptr parameters 00348 for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) { 00349 if(altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])){ 00350 #ifdef HAVE_CG 00351 const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i]; 00352 Shader::ShaderPtrData* _ptr_data = 00353 const_cast< Shader::ShaderPtrData*>(gsg->fetch_ptr_parameter(_ptr)); 00354 00355 if (_ptr_data == NULL){ //the input is not contained in ShaderPtrData 00356 release_resources(); 00357 return; 00358 } 00359 00360 CGparameter p = _cg_parameter_map[_ptr._id._seqno]; 00361 00362 switch(_ptr_data->_type) { 00363 case Shader::SPT_float: 00364 cgD3D9SetUniform(p, (PN_stdfloat*)_ptr_data->_ptr); 00365 break; 00366 00367 default: 00368 dxgsg9_cat.error() 00369 << _ptr._id._name << ":" << "unrecognized parameter type\n"; 00370 release_resources(); 00371 return; 00372 } 00373 } 00374 #endif 00375 } 00376 00377 for (int i=0; i<(int)_shader->_mat_spec.size(); i++) { 00378 if (altered & (_shader->_mat_spec[i]._dep[0] | _shader->_mat_spec[i]._dep[1])) { 00379 CGparameter p = _cg_parameter_map[_shader->_mat_spec[i]._id._seqno]; 00380 if (p == NULL) { 00381 continue; 00382 } 00383 const LMatrix4 *val = gsg->fetch_specified_value(_shader->_mat_spec[i], altered); 00384 if (val) { 00385 HRESULT hr; 00386 PN_stdfloat v [4]; 00387 LMatrix4f temp_matrix = LCAST(float, *val); 00388 00389 hr = D3D_OK; 00390 00391 const float *data; 00392 data = temp_matrix.get_data(); 00393 00394 #if DEBUG_SHADER 00395 // DEBUG 00396 global_data = (PN_stdfloat *) data; 00397 global_shader_mat_spec = &_shader->_mat_spec[i]; 00398 global_internal_name_0 = global_shader_mat_spec -> _arg [0]; 00399 global_internal_name_1 = global_shader_mat_spec -> _arg [1]; 00400 #endif 00401 00402 switch (_shader->_mat_spec[i]._piece) { 00403 case Shader::SMP_whole: 00404 // TRANSPOSE REQUIRED 00405 temp_matrix.transpose_in_place(); 00406 data = temp_matrix.get_data(); 00407 00408 hr = cgD3D9SetUniform (p, data); 00409 break; 00410 00411 case Shader::SMP_transpose: 00412 // NO TRANSPOSE REQUIRED 00413 hr = cgD3D9SetUniform (p, data); 00414 break; 00415 00416 case Shader::SMP_row0: 00417 hr = cgD3D9SetUniform (p, data + 0); 00418 break; 00419 case Shader::SMP_row1: 00420 hr = cgD3D9SetUniform (p, data + 4); 00421 break; 00422 case Shader::SMP_row2: 00423 hr = cgD3D9SetUniform (p, data + 8); 00424 break; 00425 case Shader::SMP_row3x1: 00426 case Shader::SMP_row3x2: 00427 case Shader::SMP_row3x3: 00428 case Shader::SMP_row3: 00429 hr = cgD3D9SetUniform (p, data + 12); 00430 break; 00431 00432 case Shader::SMP_col0: 00433 v[0] = data[0]; v[1] = data[4]; v[2] = data[8]; v[3] = data[12]; 00434 hr = cgD3D9SetUniform (p, v); 00435 break; 00436 case Shader::SMP_col1: 00437 v[0] = data[1]; v[1] = data[5]; v[2] = data[9]; v[3] = data[13]; 00438 hr = cgD3D9SetUniform (p, v); 00439 break; 00440 case Shader::SMP_col2: 00441 v[0] = data[2]; v[1] = data[6]; v[2] = data[10]; v[3] = data[14]; 00442 hr = cgD3D9SetUniform (p, v); 00443 break; 00444 case Shader::SMP_col3: 00445 v[0] = data[3]; v[1] = data[7]; v[2] = data[11]; v[3] = data[15]; 00446 hr = cgD3D9SetUniform (p, v); 00447 break; 00448 00449 default: 00450 dxgsg9_cat.error() 00451 << "issue_parameters ( ) SMP parameter type not implemented " << _shader->_mat_spec[i]._piece << "\n"; 00452 break; 00453 } 00454 00455 if (FAILED (hr)) { 00456 00457 string name = "unnamed"; 00458 00459 if (_shader->_mat_spec[i]._arg [0]) { 00460 name = _shader->_mat_spec[i]._arg [0] -> get_basename ( ); 00461 } 00462 00463 dxgsg9_cat.error() 00464 << "NAME " << name << "\n" 00465 << "MAT TYPE " 00466 << _shader->_mat_spec[i]._piece 00467 << " cgD3D9SetUniform failed " 00468 << D3DERRORSTRING(hr); 00469 00470 CGerror error = cgGetError (); 00471 if (error != CG_NO_ERROR) { 00472 dxgsg9_cat.error() << " CG ERROR: " << cgGetErrorString(error) << "\n"; 00473 } 00474 } 00475 } 00476 } 00477 } 00478 } 00479 #endif 00480 } 00481 00482 //////////////////////////////////////////////////////////////////// 00483 // Function: DXShaderContext9::disable_shader_vertex_arrays 00484 // Access: Public 00485 // Description: Disable all the vertex arrays used by this shader. 00486 //////////////////////////////////////////////////////////////////// 00487 void CLP(ShaderContext):: 00488 disable_shader_vertex_arrays(GSG *gsg) { 00489 LPDIRECT3DDEVICE9 device = gsg->_screen->_d3d_device; 00490 00491 for ( int array_index = 0; array_index < _num_bound_streams; ++array_index ) 00492 { 00493 device->SetStreamSource( array_index, NULL, 0, 0 ); 00494 } 00495 _num_bound_streams = 0; 00496 } 00497 00498 //////////////////////////////////////////////////////////////////// 00499 // Function: DXShaderContext9::update_shader_vertex_arrays 00500 // Access: Public 00501 // Description: Disables all vertex arrays used by the previous 00502 // shader, then enables all the vertex arrays needed 00503 // by this shader. Extracts the relevant vertex array 00504 // data from the gsg. 00505 // The current implementation is inefficient, because 00506 // it may unnecessarily disable arrays then immediately 00507 // reenable them. We may optimize this someday. 00508 //////////////////////////////////////////////////////////////////// 00509 bool CLP(ShaderContext):: 00510 update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg, bool force) { 00511 if (prev) prev->disable_shader_vertex_arrays(gsg); 00512 #ifdef HAVE_CG 00513 if (!_cg_context) { 00514 return true; 00515 } 00516 00517 #ifdef SUPPORT_IMMEDIATE_MODE 00518 /* 00519 if (gsg->_use_sender) { 00520 dxgsg9_cat.error() << "immediate mode shaders not implemented yet\n"; 00521 } else 00522 */ 00523 #endif // SUPPORT_IMMEDIATE_MODE 00524 { 00525 int nvarying = _shader->_var_spec.size(); 00526 LPDIRECT3DDEVICE9 device = gsg->_screen->_d3d_device; 00527 HRESULT hr; 00528 00529 // Discard and recreate the VertexElementArray. This thrashes pretty bad.... 00530 if ( _vertex_element_array != NULL ) { 00531 delete _vertex_element_array; 00532 } 00533 _vertex_element_array = new VertexElementArray(nvarying + 2); 00534 VertexElementArray* vertex_element_array = _vertex_element_array; 00535 00536 // Experimentally determined that DX doesn't like us crossing the streams! 00537 // It seems to be okay with out-of-order offsets in both source and destination, 00538 // but it wants all stream X entries grouped together, then all stream Y entries, etc. 00539 // To accomplish this out outer loop processes arrays ("streams"), and we repeatedly 00540 // iterate the parameters to pull out only those for a single stream. 00541 00542 int number_of_arrays = gsg->_data_reader->get_num_arrays(); 00543 for ( int array_index = 0; array_index < number_of_arrays; ++array_index ) { 00544 const GeomVertexArrayDataHandle* array_reader = 00545 gsg->_data_reader->get_array_reader( array_index ); 00546 if ( array_reader == NULL ) { 00547 dxgsg9_cat.error() << "Unable to get reader for array " << array_index << "\n"; 00548 continue; 00549 } 00550 00551 for ( int var_index = 0; var_index < nvarying; ++var_index ) { 00552 CGparameter p = _cg_parameter_map[_shader->_var_spec[var_index]._id._seqno]; 00553 if ( p == NULL ) { 00554 dxgsg9_cat.info() << 00555 "No parameter in map for parameter " << var_index << 00556 " (probably optimized away)\n"; 00557 continue; 00558 } 00559 00560 InternalName *name = _shader->_var_spec[var_index]._name; 00561 00562 // This is copied from the GL version of this function, and I've yet to 100% convince 00563 // myself that it works properly.... 00564 int texslot = _shader->_var_spec[var_index]._append_uv; 00565 if (texslot >= 0 && texslot < gsg->_state_texture->get_num_on_stages()) { 00566 TextureStage *stage = gsg->_state_texture->get_on_stage(texslot); 00567 InternalName *texname = stage->get_texcoord_name(); 00568 if (name == InternalName::get_texcoord()) { 00569 name = texname; 00570 } else if (texname != InternalName::get_texcoord()) { 00571 name = name->append(texname->get_basename()); 00572 } 00573 } 00574 00575 const GeomVertexArrayDataHandle* param_array_reader; 00576 Geom::NumericType numeric_type; 00577 int num_values; 00578 int start; 00579 int stride; 00580 if ( gsg->_data_reader->get_array_info( name, 00581 param_array_reader, num_values, numeric_type, 00582 start, stride ) == false ) { 00583 // This is apparently not an error (actually I think it is, just not a fatal one). 00584 // 00585 // The GL implementation fails silently in this case, but the net result is that we 00586 // end up not supplying input for a shader parameter, which can cause Bad Things to 00587 // happen so I'd like to at least get a hint as to what's gone wrong. 00588 dxgsg9_cat.info() << "Geometry contains no data for shader parameter " << *name << "\n"; 00589 continue; 00590 } 00591 00592 // If not associated with the array we're working on, move on. 00593 if ( param_array_reader != array_reader ) { 00594 continue; 00595 } 00596 00597 const char* semantic = cgGetParameterSemantic( p ); 00598 if ( semantic == NULL ) { 00599 dxgsg9_cat.error() << "Unable to retrieve semantic for parameter " << var_index << "\n"; 00600 continue; 00601 } 00602 00603 if ( strncmp( semantic, "POSITION", strlen( "POSITION" ) ) == 0 ) { 00604 if (numeric_type == Geom::NT_float32) { 00605 switch (num_values) { 00606 case 3: 00607 vertex_element_array->add_position_xyz_vertex_element(array_index, start); 00608 break; 00609 case 4: 00610 vertex_element_array->add_position_xyzw_vertex_element(array_index, start); 00611 break; 00612 default: 00613 dxgsg9_cat.error() << "VE ERROR: invalid number of vertex coordinate elements " << num_values << "\n"; 00614 break; 00615 } 00616 } else { 00617 dxgsg9_cat.error() << "VE ERROR: invalid vertex type " << numeric_type << "\n"; 00618 } 00619 } else if ( strncmp( semantic, "TEXCOORD", strlen( "TEXCOORD" ) ) == 0 ) { 00620 int slot = atoi( semantic + strlen( "TEXCOORD" ) ); 00621 if (numeric_type == Geom::NT_float32) { 00622 switch (num_values) { 00623 case 1: 00624 vertex_element_array->add_u_vertex_element(array_index, start, slot); 00625 break; 00626 case 2: 00627 vertex_element_array->add_uv_vertex_element(array_index, start, slot); 00628 break; 00629 case 3: 00630 vertex_element_array->add_uvw_vertex_element(array_index, start, slot); 00631 break; 00632 case 4: 00633 vertex_element_array->add_xyzw_vertex_element(array_index, start, slot); 00634 break; 00635 default: 00636 dxgsg9_cat.error() << "VE ERROR: invalid number of vertex texture coordinate elements " << num_values << "\n"; 00637 break; 00638 } 00639 } else { 00640 dxgsg9_cat.error() << "VE ERROR: invalid texture coordinate type " << numeric_type << "\n"; 00641 } 00642 } else if ( strncmp( semantic, "COLOR", strlen( "COLOR" ) ) == 0 ) { 00643 if (numeric_type == Geom::NT_packed_dcba || 00644 numeric_type == Geom::NT_packed_dabc || 00645 numeric_type == Geom::NT_uint8) { 00646 switch (num_values) { 00647 case 4: 00648 vertex_element_array->add_diffuse_color_vertex_element(array_index, start); 00649 break; 00650 default: 00651 dxgsg9_cat.error() << "VE ERROR: invalid color coordinates " << num_values << "\n"; 00652 break; 00653 } 00654 } else { 00655 dxgsg9_cat.error() << "VE ERROR: invalid color type " << numeric_type << "\n"; 00656 } 00657 } else if ( strncmp( semantic, "NORMAL", strlen( "NORMAL" ) ) == 0 ) { 00658 if (numeric_type == Geom::NT_float32) { 00659 switch (num_values) { 00660 case 3: 00661 vertex_element_array->add_normal_vertex_element(array_index, start); 00662 break; 00663 default: 00664 dxgsg9_cat.error() << "VE ERROR: invalid number of normal coordinate elements " << num_values << "\n"; 00665 break; 00666 } 00667 } else { 00668 dxgsg9_cat.error() << "VE ERROR: invalid normal type " << numeric_type << "\n"; 00669 } 00670 } else if ( strncmp( semantic, "BINORMAL", strlen( "BINORMAL" ) ) == 0 ) { 00671 if (numeric_type == Geom::NT_float32) { 00672 switch (num_values) { 00673 case 3: 00674 vertex_element_array->add_binormal_vertex_element(array_index, start); 00675 break; 00676 default: 00677 dxgsg9_cat.error() << "VE ERROR: invalid number of binormal coordinate elements " << num_values << "\n"; 00678 break; 00679 } 00680 } else { 00681 dxgsg9_cat.error() << "VE ERROR: invalid binormal type " << numeric_type << "\n"; 00682 } 00683 } else if ( strncmp( semantic, "TANGENT", strlen( "TANGENT" ) ) == 0 ) { 00684 if (numeric_type == Geom::NT_float32) { 00685 switch (num_values) { 00686 case 3: 00687 vertex_element_array->add_tangent_vertex_element(array_index, start); 00688 break; 00689 default: 00690 dxgsg9_cat.error() << "VE ERROR: invalid number of tangent coordinate elements " << num_values << "\n"; 00691 break; 00692 } 00693 } else { 00694 dxgsg9_cat.error() << "VE ERROR: invalid tangent type " << numeric_type << "\n"; 00695 } 00696 } else { 00697 dxgsg9_cat.error() << "Unsupported semantic " << semantic << " for parameter " << var_index << "\n"; 00698 } 00699 } 00700 00701 // Get the vertex buffer for this array. 00702 CLP(VertexBufferContext)* dvbc; 00703 if (!gsg->setup_array_data(dvbc, array_reader, force)) { 00704 dxgsg9_cat.error() << "Unable to setup vertex buffer for array " << array_index << "\n"; 00705 continue; 00706 } 00707 00708 // Bind this array as the data source for the corresponding stream. 00709 const GeomVertexArrayFormat* array_format = array_reader->get_array_format(); 00710 hr = device->SetStreamSource( array_index, dvbc->_vbuffer, 0, array_format->get_stride() ); 00711 if (FAILED(hr)) { 00712 dxgsg9_cat.error() << "SetStreamSource failed" << D3DERRORSTRING(hr); 00713 } 00714 } 00715 00716 _num_bound_streams = number_of_arrays; 00717 00718 if (( _vertex_element_array != NULL ) && 00719 ( _vertex_element_array->add_end_vertex_element() != false )) { 00720 if ( dxgsg9_cat.is_debug() ) { 00721 // Note that the currently generated vertex declaration works but never validates. 00722 // My theory is that this is due to the shader programs always using float4 whereas 00723 // the vertex declaration correctly sets the number of inputs (float2, float3, etc.). 00724 if (cgD3D9ValidateVertexDeclaration(_cg_vprogram, 00725 _vertex_element_array->_vertex_element_array) == CG_TRUE) { 00726 dxgsg9_cat.debug() << "cgD3D9ValidateVertexDeclaration succeeded\n"; 00727 } else { 00728 dxgsg9_cat.debug() << "cgD3D9ValidateVertexDeclaration failed\n"; 00729 } 00730 } 00731 00732 // Discard the old VertexDeclaration. This thrashes pretty bad.... 00733 if ( _vertex_declaration != NULL ) { 00734 _vertex_declaration->Release(); 00735 _vertex_declaration = NULL; 00736 } 00737 00738 hr = device->CreateVertexDeclaration( _vertex_element_array->_vertex_element_array, 00739 &_vertex_declaration ); 00740 if (FAILED (hr)) { 00741 dxgsg9_cat.error() << "CreateVertexDeclaration failed" << D3DERRORSTRING(hr); 00742 } else { 00743 hr = device->SetVertexDeclaration( _vertex_declaration ); 00744 if (FAILED(hr)) { 00745 dxgsg9_cat.error() << "SetVertexDeclaration failed" << D3DERRORSTRING(hr); 00746 } 00747 } 00748 } else { 00749 dxgsg9_cat.error() << "VertexElementArray creation failed\n"; 00750 } 00751 } 00752 #endif // HAVE_CG 00753 00754 return true; 00755 } 00756 00757 //////////////////////////////////////////////////////////////////// 00758 // Function: DXShaderContext9::disable_shader_texture_bindings 00759 // Access: Public 00760 // Description: Disable all the texture bindings used by this shader. 00761 //////////////////////////////////////////////////////////////////// 00762 void CLP(ShaderContext):: 00763 disable_shader_texture_bindings(GSG *gsg) 00764 { 00765 #ifdef HAVE_CG 00766 if (_cg_context) { 00767 for (int i=0; i<(int)_shader->_tex_spec.size(); i++) { 00768 CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno]; 00769 if (p == NULL) { 00770 continue; 00771 } 00772 int texunit = cgGetParameterResourceIndex(p); 00773 00774 HRESULT hr; 00775 00776 hr = gsg -> _d3d_device -> SetTexture (texunit, NULL); 00777 if (FAILED (hr)) { 00778 dxgsg9_cat.error() 00779 << "SetTexture (" 00780 << texunit 00781 << ", NULL) failed " 00782 << D3DERRORSTRING(hr); 00783 } 00784 } 00785 } 00786 #endif 00787 } 00788 00789 //////////////////////////////////////////////////////////////////// 00790 // Function: DXShaderContext9::update_shader_texture_bindings 00791 // Access: Public 00792 // Description: Disables all texture bindings used by the previous 00793 // shader, then enables all the texture bindings needed 00794 // by this shader. Extracts the relevant vertex array 00795 // data from the gsg. 00796 // The current implementation is inefficient, because 00797 // it may unnecessarily disable textures then immediately 00798 // reenable them. We may optimize this someday. 00799 //////////////////////////////////////////////////////////////////// 00800 void CLP(ShaderContext):: 00801 update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) 00802 { 00803 if (prev) prev->disable_shader_texture_bindings(gsg); 00804 00805 #ifdef HAVE_CG 00806 if (_cg_context) { 00807 00808 for (int i=0; i<(int)_shader->_tex_spec.size(); i++) { 00809 CGparameter p = _cg_parameter_map[_shader->_tex_spec[i]._id._seqno]; 00810 if (p == NULL) { 00811 continue; 00812 } 00813 Texture *tex = 0; 00814 int view = gsg->get_current_tex_view_offset(); 00815 InternalName *id = _shader->_tex_spec[i]._name; 00816 if (id != 0) { 00817 const ShaderInput *input = gsg->_target_shader->get_shader_input(id); 00818 tex = input->get_texture(); 00819 } else { 00820 // We get the TextureAttrib directly from the _target_rs, not the 00821 // filtered TextureAttrib in _target_texture. 00822 const TextureAttrib *texattrib = DCAST(TextureAttrib, gsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot())); 00823 nassertv(texattrib != (TextureAttrib *)NULL); 00824 00825 if (_shader->_tex_spec[i]._stage >= texattrib->get_num_on_stages()) { 00826 continue; 00827 } 00828 TextureStage *stage = texattrib->get_on_stage(_shader->_tex_spec[i]._stage); 00829 tex = texattrib->get_on_texture(stage); 00830 view += stage->get_tex_view_offset(); 00831 } 00832 if (_shader->_tex_spec[i]._suffix != 0) { 00833 // The suffix feature is inefficient. It is a temporary hack. 00834 if (tex == 0) { 00835 continue; 00836 } 00837 tex = tex->load_related(_shader->_tex_spec[i]._suffix); 00838 } 00839 if ((tex == 0) || (tex->get_texture_type() != _shader->_tex_spec[i]._desired_type)) { 00840 continue; 00841 } 00842 TextureContext *tc = tex->prepare_now(view, gsg->_prepared_objects, gsg); 00843 if (tc == (TextureContext*)NULL) { 00844 continue; 00845 } 00846 00847 int texunit = cgGetParameterResourceIndex(p); 00848 00849 gsg->apply_texture(texunit, tc); 00850 } 00851 } 00852 #endif 00853 } 00854 00855 // DEBUG CODE TO TEST ASM CODE GENERATED BY Cg 00856 void assemble_shader_test(char *file_path) 00857 { 00858 int flags; 00859 D3DXMACRO *defines; 00860 LPD3DXINCLUDE include; 00861 LPD3DXBUFFER shader; 00862 LPD3DXBUFFER error_messages; 00863 00864 flags = 0; 00865 defines = 0; 00866 include = 0; 00867 shader = 0; 00868 error_messages = 0; 00869 00870 D3DXAssembleShaderFromFile (file_path, defines, include, flags, &shader, &error_messages); 00871 if (error_messages) 00872 { 00873 char *error_message; 00874 00875 error_message = (char *) (error_messages -> GetBufferPointer ( )); 00876 if (error_message) 00877 { 00878 dxgsg9_cat.error() << error_message; 00879 } 00880 00881 error_messages -> Release ( ); 00882 } 00883 }