Browse Source

optimize light state a bit

David Rose 17 years ago
parent
commit
7b7b973a7a

+ 36 - 28
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -798,6 +798,8 @@ begin_scene() {
 void DXGraphicsStateGuardian8::
 void DXGraphicsStateGuardian8::
 end_scene() {
 end_scene() {
   GraphicsStateGuardian::end_scene();
   GraphicsStateGuardian::end_scene();
+  _dlights.clear();
+
   HRESULT hr = _d3d_device->EndScene();
   HRESULT hr = _d3d_device->EndScene();
 
 
   if (FAILED(hr)) {
   if (FAILED(hr)) {
@@ -2528,35 +2530,41 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian8::
 void DXGraphicsStateGuardian8::
 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
-  // Get the light in "world coordinates" (actually, view
-  // coordinates).  This means the light in the coordinate space of
-  // the camera, converted to DX's coordinate system.
-  CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
-  const LMatrix4f &light_mat = transform->get_mat();
-  LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
-  LVector3f dir = light_obj->get_direction() * rel_mat;
-
-  D3DCOLORVALUE black;
-  black.r = black.g = black.b = black.a = 0.0f;
-
-  D3DLIGHT8 alight;
-  ZeroMemory(&alight, sizeof(D3DLIGHT8));
-
-  alight.Type =  D3DLIGHT_DIRECTIONAL;
-  alight.Diffuse  = get_light_color(light_obj);
-  alight.Ambient  =  black ;
-  alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
-
-  alight.Direction = *(D3DVECTOR *)dir.get_data();
-
-  alight.Range =  __D3DLIGHT_RANGE_MAX;
-  alight.Falloff =  1.0f;
-
-  alight.Attenuation0 = 1.0f;       // constant
-  alight.Attenuation1 = 0.0f;       // linear
-  alight.Attenuation2 = 0.0f;       // quadratic
+  static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
+  PStatTimer timer(_draw_set_state_light_bind_directional_pcollector);
+
+  pair<DirectionalLights::iterator, bool> lookup = _dlights.insert(DirectionalLights::value_type(light, D3DLIGHT8()));
+  D3DLIGHT8 &fdata = (*lookup.first).second;
+  if (lookup.second) {
+    // Get the light in "world coordinates" (actually, view
+    // coordinates).  This means the light in the coordinate space of
+    // the camera, converted to DX's coordinate system.
+    CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
+    const LMatrix4f &light_mat = transform->get_mat();
+    LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
+    LVector3f dir = light_obj->get_direction() * rel_mat;
+    
+    D3DCOLORVALUE black;
+    black.r = black.g = black.b = black.a = 0.0f;
+    
+    ZeroMemory(&fdata, sizeof(D3DLIGHT8));
+    
+    fdata.Type =  D3DLIGHT_DIRECTIONAL;
+    fdata.Diffuse  = get_light_color(light_obj);
+    fdata.Ambient  =  black ;
+    fdata.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
+    
+    fdata.Direction = *(D3DVECTOR *)dir.get_data();
+    
+    fdata.Range =  __D3DLIGHT_RANGE_MAX;
+    fdata.Falloff =  1.0f;
+    
+    fdata.Attenuation0 = 1.0f;       // constant
+    fdata.Attenuation1 = 0.0f;       // linear
+    fdata.Attenuation2 = 0.0f;       // quadratic
+  }
 
 
-  HRESULT hr = _d3d_device->SetLight(light_id, &alight);
+  HRESULT hr = _d3d_device->SetLight(light_id, &fdata);
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     wdxdisplay8_cat.warning()
     wdxdisplay8_cat.warning()
       << "Could not set light properties for " << light
       << "Could not set light properties for " << light

+ 6 - 0
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -252,6 +252,12 @@ protected:
   const DXIndexBufferContext8 *_active_ibuffer;
   const DXIndexBufferContext8 *_active_ibuffer;
 
 
   int _num_active_texture_stages;
   int _num_active_texture_stages;
+  
+  // Cache the data necessary to bind each particular light each
+  // frame, so if we bind a given light multiple times, we only have
+  // to compute its data once.
+  typedef pmap<NodePath, D3DLIGHT8> DirectionalLights;
+  DirectionalLights _dlights;
 
 
   bool _overlay_windows_supported;
   bool _overlay_windows_supported;
   bool _tex_stats_retrieval_impossible;
   bool _tex_stats_retrieval_impossible;

+ 36 - 28
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -1146,6 +1146,8 @@ end_scene() {
     _current_shader_context = (CLP(ShaderContext) *)NULL;
     _current_shader_context = (CLP(ShaderContext) *)NULL;
   }
   }
 
 
+  _dlights.clear();
+
 /*
 /*
   HRESULT hr = _d3d_device->EndScene();
   HRESULT hr = _d3d_device->EndScene();
 
 
@@ -3382,35 +3384,41 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian9::
 void DXGraphicsStateGuardian9::
 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
-  // Get the light in "world coordinates" (actually, view
-  // coordinates).  This means the light in the coordinate space of
-  // the camera, converted to DX's coordinate system.
-  CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
-  const LMatrix4f &light_mat = transform->get_mat();
-  LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
-  LVector3f dir = light_obj->get_direction() * rel_mat;
-
-  D3DCOLORVALUE black;
-  black.r = black.g = black.b = black.a = 0.0f;
-
-  D3DLIGHT9 alight;
-  ZeroMemory(&alight, sizeof(D3DLIGHT9));
-
-  alight.Type =  D3DLIGHT_DIRECTIONAL;
-  alight.Diffuse  = get_light_color(light_obj);
-  alight.Ambient  =  black ;
-  alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
-
-  alight.Direction = *(D3DVECTOR *)dir.get_data();
-
-  alight.Range =  __D3DLIGHT_RANGE_MAX;
-  alight.Falloff =  1.0f;
-
-  alight.Attenuation0 = 1.0f;       // constant
-  alight.Attenuation1 = 0.0f;       // linear
-  alight.Attenuation2 = 0.0f;       // quadratic
+  static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
+  PStatTimer timer(_draw_set_state_light_bind_directional_pcollector);
+
+  pair<DirectionalLights::iterator, bool> lookup = _dlights.insert(DirectionalLights::value_type(light, D3DLIGHT9()));
+  D3DLIGHT9 &fdata = (*lookup.first).second;
+  if (lookup.second) {
+    // Get the light in "world coordinates" (actually, view
+    // coordinates).  This means the light in the coordinate space of
+    // the camera, converted to DX's coordinate system.
+    CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
+    const LMatrix4f &light_mat = transform->get_mat();
+    LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
+    LVector3f dir = light_obj->get_direction() * rel_mat;
+    
+    D3DCOLORVALUE black;
+    black.r = black.g = black.b = black.a = 0.0f;
+    
+    ZeroMemory(&fdata, sizeof(D3DLIGHT9));
+    
+    fdata.Type =  D3DLIGHT_DIRECTIONAL;
+    fdata.Diffuse  = get_light_color(light_obj);
+    fdata.Ambient  =  black ;
+    fdata.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
+    
+    fdata.Direction = *(D3DVECTOR *)dir.get_data();
+    
+    fdata.Range =  __D3DLIGHT_RANGE_MAX;
+    fdata.Falloff =  1.0f;
+    
+    fdata.Attenuation0 = 1.0f;       // constant
+    fdata.Attenuation1 = 0.0f;       // linear
+    fdata.Attenuation2 = 0.0f;       // quadratic
+  }
 
 
-  HRESULT hr = _d3d_device->SetLight(light_id, &alight);
+  HRESULT hr = _d3d_device->SetLight(light_id, &fdata);
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     wdxdisplay9_cat.warning()
     wdxdisplay9_cat.warning()
       << "Could not set light properties for " << light
       << "Could not set light properties for " << light

+ 6 - 0
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -316,6 +316,12 @@ protected:
 
 
   DWORD _last_fvf;
   DWORD _last_fvf;
 
 
+  // Cache the data necessary to bind each particular light each
+  // frame, so if we bind a given light multiple times, we only have
+  // to compute its data once.
+  typedef pmap<NodePath, D3DLIGHT9> DirectionalLights;
+  DirectionalLights _dlights;
+
   #define MAXIMUM_TEXTURES 16
   #define MAXIMUM_TEXTURES 16
 
 
 
 

+ 12 - 4
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1631,6 +1631,8 @@ end_scene() {
     _current_shader = (Shader *)NULL;
     _current_shader = (Shader *)NULL;
     _current_shader_context = (CLP(ShaderContext) *)NULL;
     _current_shader_context = (CLP(ShaderContext) *)NULL;
   }
   }
+
+  _dlights.clear();
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
@@ -4176,6 +4178,15 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
   static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
   static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
   PStatTimer timer(_draw_set_state_light_bind_directional_pcollector);
   PStatTimer timer(_draw_set_state_light_bind_directional_pcollector);
 
 
+  pair<DirectionalLights::iterator, bool> lookup = _dlights.insert(DirectionalLights::value_type(light, DirectionalLightFrameData()));
+  DirectionalLightFrameData &fdata = (*lookup.first).second;
+  if (lookup.second) {
+    // The light was not computed yet this frame.  Compute it now.
+    CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
+    LVector3f dir = light_obj->get_direction() * transform->get_mat();
+    fdata._neg_dir.set(-dir[0], -dir[1], -dir[2], 0);
+  }
+
   float light_color[4];
   float light_color[4];
   GLenum id = get_light_id( light_id );
   GLenum id = get_light_id( light_id );
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
   static const Colorf black(0.0f, 0.0f, 0.0f, 1.0f);
@@ -4185,10 +4196,7 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
 
 
   // Position needs to specify x, y, z, and w.
   // Position needs to specify x, y, z, and w.
   // w == 0 implies light is at infinity
   // w == 0 implies light is at infinity
-  CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
-  LVector3f dir = light_obj->get_direction() * transform->get_mat();
-  LPoint4f fdir(-dir[0], -dir[1], -dir[2], 0);
-  GLP(Lightfv)(id, GL_POSITION, fdir.get_data());
+  GLP(Lightfv)(id, GL_POSITION, fdata._neg_dir.get_data());
 
 
   // GL_SPOT_DIRECTION is not significant when cutoff == 180
   // GL_SPOT_DIRECTION is not significant when cutoff == 180
   // In this case, position x, y, z specifies direction
   // In this case, position x, y, z specifies direction

+ 10 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -395,6 +395,16 @@ protected:
   bool _use_sender;
   bool _use_sender;
 #endif  // SUPPORT_IMMEDIATE_MODE
 #endif  // SUPPORT_IMMEDIATE_MODE
 
 
+  // Cache the data necessary to bind each particular light each
+  // frame, so if we bind a given light multiple times, we only have
+  // to compute its data once.
+  class DirectionalLightFrameData {
+  public:
+    LVector4f _neg_dir;
+  };
+  typedef pmap<NodePath, DirectionalLightFrameData> DirectionalLights;
+  DirectionalLights _dlights;
+
   int _pass_number;
   int _pass_number;
   bool _auto_rescale_normal;
   bool _auto_rescale_normal;
   GLuint _geom_display_list;
   GLuint _geom_display_list;