From 7b7b973a7ab299effb4a55e766ba33bef95b680e Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 12 Nov 2008 22:20:21 +0000 Subject: [PATCH] optimize light state a bit --- panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 62 +++++++++++-------- panda/src/dxgsg8/dxGraphicsStateGuardian8.h | 6 ++ panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 62 +++++++++++-------- panda/src/dxgsg9/dxGraphicsStateGuardian9.h | 6 ++ .../glstuff/glGraphicsStateGuardian_src.cxx | 16 +++-- .../src/glstuff/glGraphicsStateGuardian_src.h | 10 +++ 6 files changed, 104 insertions(+), 58 deletions(-) diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index f5aa5aa7e2..01a5de8f5c 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -798,6 +798,8 @@ begin_scene() { void DXGraphicsStateGuardian8:: end_scene() { GraphicsStateGuardian::end_scene(); + _dlights.clear(); + HRESULT hr = _d3d_device->EndScene(); if (FAILED(hr)) { @@ -2528,35 +2530,41 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) { //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian8:: 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; + static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional"); + PStatTimer timer(_draw_set_state_light_bind_directional_pcollector); - D3DCOLORVALUE black; - black.r = black.g = black.b = black.a = 0.0f; + pair 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 + } - 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 - - HRESULT hr = _d3d_device->SetLight(light_id, &alight); + HRESULT hr = _d3d_device->SetLight(light_id, &fdata); if (FAILED(hr)) { wdxdisplay8_cat.warning() << "Could not set light properties for " << light diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index c491049430..a5f15d9df7 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -252,6 +252,12 @@ protected: const DXIndexBufferContext8 *_active_ibuffer; 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 DirectionalLights; + DirectionalLights _dlights; bool _overlay_windows_supported; bool _tex_stats_retrieval_impossible; diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index ca364dc5a1..4e79d26adf 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -1146,6 +1146,8 @@ end_scene() { _current_shader_context = (CLP(ShaderContext) *)NULL; } + _dlights.clear(); + /* HRESULT hr = _d3d_device->EndScene(); @@ -3382,35 +3384,41 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) { //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian9:: 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; + static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional"); + PStatTimer timer(_draw_set_state_light_bind_directional_pcollector); - D3DCOLORVALUE black; - black.r = black.g = black.b = black.a = 0.0f; + pair 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 + } - 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 - - HRESULT hr = _d3d_device->SetLight(light_id, &alight); + HRESULT hr = _d3d_device->SetLight(light_id, &fdata); if (FAILED(hr)) { wdxdisplay9_cat.warning() << "Could not set light properties for " << light diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index 489216e785..f344e749ea 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -316,6 +316,12 @@ protected: 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 DirectionalLights; + DirectionalLights _dlights; + #define MAXIMUM_TEXTURES 16 diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index f10b69bab3..ec460f3b05 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -1631,6 +1631,8 @@ end_scene() { _current_shader = (Shader *)NULL; _current_shader_context = (CLP(ShaderContext) *)NULL; } + + _dlights.clear(); 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"); PStatTimer timer(_draw_set_state_light_bind_directional_pcollector); + pair 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]; GLenum id = get_light_id( light_id ); 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. // 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 // In this case, position x, y, z specifies direction diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 241a484443..8257e1bd03 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -395,6 +395,16 @@ protected: bool _use_sender; #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 DirectionalLights; + DirectionalLights _dlights; + int _pass_number; bool _auto_rescale_normal; GLuint _geom_display_list;