Bläddra i källkod

Merge branch 'master' into cmake

Sam Edwards 11 år sedan
förälder
incheckning
62d08ec8bf
100 ändrade filer med 3341 tillägg och 1179 borttagningar
  1. 1 0
      contrib/src/ai/aiBehaviors.cxx
  2. 4 3
      direct/src/directscripts/Doxyfile.cxx
  3. 3 3
      direct/src/directscripts/Doxyfile.python
  4. 135 101
      direct/src/filter/CommonFilters.py
  5. 7 11
      direct/src/http/baseincomingset.h
  6. 60 60
      direct/src/http/baseincomingset.i
  7. 64 29
      direct/src/p3d/p3dWrapper.c
  8. 12 3
      direct/src/plugin_installer/make_installer.py
  9. 76 21
      direct/src/plugin_installer/p3d_installer.nsi
  10. 0 70
      direct/src/showbase/PythonUtil.py
  11. 2 1
      direct/src/showbase/ShowBase.py
  12. 6 3
      direct/src/showbase/VFSImporter.py
  13. 4 3
      direct/src/showutil/pfreeze.py
  14. 0 8
      dtool/src/dtoolbase/cmath.I
  15. 20 0
      dtool/src/dtoolutil/executionEnvironment.I
  16. 53 13
      dtool/src/dtoolutil/executionEnvironment.cxx
  17. 3 0
      dtool/src/dtoolutil/executionEnvironment.h
  18. 29 6
      dtool/src/dtoolutil/filename.cxx
  19. 5 0
      dtool/src/dtoolutil/filename.h
  20. 34 2
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  21. 85 1
      dtool/src/interrogate/typeManager.cxx
  22. 4 0
      dtool/src/interrogate/typeManager.h
  23. 6 0
      dtool/src/parser-inc/Python.h
  24. 2 0
      dtool/src/parser-inc/android/asset_manager.h
  25. 39 0
      dtool/src/parser-inc/jni.h
  26. 8 0
      dtool/src/pystub/pystub.cxx
  27. 80 62
      makepanda/makepanda.py
  28. 124 71
      makepanda/makepandacore.py
  29. 30 2
      panda/src/android/android_main.cxx
  30. 11 2
      panda/src/androiddisplay/androidGraphicsWindow.cxx
  31. 2 0
      panda/src/display/Sources.pp
  32. 4 4
      panda/src/display/displayRegion.I
  33. 130 113
      panda/src/display/graphicsEngine.cxx
  34. 52 3
      panda/src/display/graphicsStateGuardian.I
  35. 213 39
      panda/src/display/graphicsStateGuardian.cxx
  36. 41 7
      panda/src/display/graphicsStateGuardian.h
  37. 61 0
      panda/src/display/pStatGPUTimer.I
  38. 67 0
      panda/src/display/pStatGPUTimer.h
  39. 8 2
      panda/src/display/standardMunger.cxx
  40. 1 1
      panda/src/dxgsg8/Sources.pp
  41. 2 2
      panda/src/dxgsg8/wdxGraphicsWindow8.cxx
  42. 1 1
      panda/src/dxgsg9/Sources.pp
  43. 77 57
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  44. 5 5
      panda/src/dxgsg9/dxGraphicsStateGuardian9.h
  45. 87 58
      panda/src/dxgsg9/dxTextureContext9.cxx
  46. 4 4
      panda/src/dxgsg9/wdxGraphicsPipe9.cxx
  47. 14 14
      panda/src/dxgsg9/wdxGraphicsWindow9.cxx
  48. 1 1
      panda/src/express/virtualFileMountAndroidAsset.I
  49. 1 1
      panda/src/express/virtualFileMountAndroidAsset.cxx
  50. 1 0
      panda/src/glesgsg/glesgsg.h
  51. 12 12
      panda/src/glstuff/glCgShaderContext_src.cxx
  52. 34 7
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  53. 14 9
      panda/src/glstuff/glGraphicsBuffer_src.h
  54. 9 5
      panda/src/glstuff/glGraphicsStateGuardian_src.I
  55. 361 107
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  56. 58 33
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  57. 14 0
      panda/src/glstuff/glLatencyQueryContext_src.I
  58. 54 0
      panda/src/glstuff/glLatencyQueryContext_src.cxx
  59. 57 0
      panda/src/glstuff/glLatencyQueryContext_src.h
  60. 28 19
      panda/src/glstuff/glShaderContext_src.cxx
  61. 10 1
      panda/src/glstuff/glTextureContext_src.cxx
  62. 28 0
      panda/src/glstuff/glTimerQueryContext_src.I
  63. 104 0
      panda/src/glstuff/glTimerQueryContext_src.cxx
  64. 68 0
      panda/src/glstuff/glTimerQueryContext_src.h
  65. 11 1
      panda/src/glstuff/glmisc_src.cxx
  66. 1 0
      panda/src/glstuff/glmisc_src.h
  67. 2 0
      panda/src/glstuff/glstuff_src.cxx
  68. 2 0
      panda/src/glstuff/glstuff_src.h
  69. 8 3
      panda/src/glstuff/panda_glext.h
  70. 4 0
      panda/src/gobj/Sources.pp
  71. 5 3
      panda/src/gobj/config_gobj.cxx
  72. 3 1
      panda/src/gobj/geomEnums.h
  73. 51 2
      panda/src/gobj/geomLinestrips.cxx
  74. 4 0
      panda/src/gobj/geomLinestrips.h
  75. 52 1
      panda/src/gobj/geomPrimitive.I
  76. 209 75
      panda/src/gobj/geomPrimitive.cxx
  77. 11 4
      panda/src/gobj/geomPrimitive.h
  78. 16 4
      panda/src/gobj/geomTristrips.cxx
  79. 1 0
      panda/src/gobj/geomTristrips.h
  80. 4 0
      panda/src/gobj/internalName.cxx
  81. 20 4
      panda/src/gobj/internalName.h
  82. 87 0
      panda/src/gobj/internalName_ext.cxx
  83. 44 0
      panda/src/gobj/internalName_ext.h
  84. 3 0
      panda/src/gobj/p3gobj_composite1.cxx
  85. 1 3
      panda/src/gobj/p3gobj_composite2.cxx
  86. 6 6
      panda/src/gobj/shader.I
  87. 2 2
      panda/src/gobj/shader.h
  88. 26 0
      panda/src/gobj/timerQueryContext.I
  89. 35 0
      panda/src/gobj/timerQueryContext.cxx
  90. 60 0
      panda/src/gobj/timerQueryContext.h
  91. 3 6
      panda/src/gsgbase/graphicsStateGuardianBase.h
  92. 7 2
      panda/src/net/connectionManager.cxx
  93. 39 37
      panda/src/pgraph/cullableObject.cxx
  94. 1 1
      panda/src/pgraph/lightRampAttrib.cxx
  95. 1 1
      panda/src/pgraph/transformState.cxx
  96. 3 4
      panda/src/pgraphnodes/shaderGenerator.cxx
  97. 11 0
      panda/src/pstatclient/config_pstats.cxx
  98. 1 0
      panda/src/pstatclient/config_pstats.h
  99. 72 37
      panda/src/pstatclient/pStatClient.cxx
  100. 5 2
      panda/src/pstatclient/pStatClient.h

+ 1 - 0
contrib/src/ai/aiBehaviors.cxx

@@ -1184,6 +1184,7 @@ string AIBehaviors::behavior_status(string ai_type) {
 
 
       default:
       default:
         cout<<"Invalid value!"<<endl;
         cout<<"Invalid value!"<<endl;
+        return "invalid";
     }
     }
   }
   }
 
 

+ 4 - 3
direct/src/directscripts/Doxyfile.cxx

@@ -880,13 +880,13 @@ HTML_STYLESHEET        = $(DOXYGEN_HTML_STYLESHEET)
 # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
 # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
 # The allowed range is 0 to 359.
 # The allowed range is 0 to 359.
 
 
-HTML_COLORSTYLE_HUE    = 220
+HTML_COLORSTYLE_HUE    = 228
 
 
 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
 # the colors in the HTML output. For a value of 0 the output will use 
 # the colors in the HTML output. For a value of 0 the output will use 
 # grayscales only. A value of 255 will produce the most vivid colors.
 # grayscales only. A value of 255 will produce the most vivid colors.
 
 
-HTML_COLORSTYLE_SAT    = 100
+HTML_COLORSTYLE_SAT    = 99
 
 
 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
 # the luminance component of the colors in the HTML output. Values below 
 # the luminance component of the colors in the HTML output. Values below 
@@ -895,7 +895,7 @@ HTML_COLORSTYLE_SAT    = 100
 # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
 # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
 # and 100 does not change the gamma.
 # and 100 does not change the gamma.
 
 
-HTML_COLORSTYLE_GAMMA  = 80
+HTML_COLORSTYLE_GAMMA  = 56
 
 
 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
 # page will contain the date and time when the page was generated. Setting 
 # page will contain the date and time when the page was generated. Setting 
@@ -1451,6 +1451,7 @@ INCLUDE_FILE_PATTERNS  =
 PREDEFINED             = TVOLATILE= \
 PREDEFINED             = TVOLATILE= \
                          INLINE=inline \
                          INLINE=inline \
                          PUBLISHED=public \
                          PUBLISHED=public \
+                         protected=private \
                          INLINE_LINMATH=inline \
                          INLINE_LINMATH=inline \
                          INLINE_MATHUTIL=inline \
                          INLINE_MATHUTIL=inline \
                          EXTENSION(x)= \
                          EXTENSION(x)= \

+ 3 - 3
direct/src/directscripts/Doxyfile.python

@@ -863,13 +863,13 @@ HTML_STYLESHEET        = $(DOXYGEN_HTML_STYLESHEET)
 # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
 # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
 # The allowed range is 0 to 359.
 # The allowed range is 0 to 359.
 
 
-HTML_COLORSTYLE_HUE    = 220
+HTML_COLORSTYLE_HUE    = 228
 
 
 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
 # the colors in the HTML output. For a value of 0 the output will use 
 # the colors in the HTML output. For a value of 0 the output will use 
 # grayscales only. A value of 255 will produce the most vivid colors.
 # grayscales only. A value of 255 will produce the most vivid colors.
 
 
-HTML_COLORSTYLE_SAT    = 100
+HTML_COLORSTYLE_SAT    = 99
 
 
 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
 # the luminance component of the colors in the HTML output. Values below 
 # the luminance component of the colors in the HTML output. Values below 
@@ -878,7 +878,7 @@ HTML_COLORSTYLE_SAT    = 100
 # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
 # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
 # and 100 does not change the gamma.
 # and 100 does not change the gamma.
 
 
-HTML_COLORSTYLE_GAMMA  = 80
+HTML_COLORSTYLE_GAMMA  = 56
 
 
 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
 # page will contain the date and time when the page was generated. Setting 
 # page will contain the date and time when the page was generated. Setting 

+ 135 - 101
direct/src/filter/CommonFilters.py

@@ -20,21 +20,17 @@ from pandac.PandaModules import Point3, Vec3, Vec4, Point2
 from pandac.PandaModules import NodePath, PandaNode
 from pandac.PandaModules import NodePath, PandaNode
 from pandac.PandaModules import Filename
 from pandac.PandaModules import Filename
 from pandac.PandaModules import AuxBitplaneAttrib
 from pandac.PandaModules import AuxBitplaneAttrib
-from pandac.PandaModules import RenderState, Texture, Shader
+from pandac.PandaModules import RenderState, Texture, Shader, ATSNone
 import sys,os
 import sys,os
 
 
 CARTOON_BODY="""
 CARTOON_BODY="""
 float4 cartoondelta = k_cartoonseparation * texpix_txaux.xwyw;
 float4 cartoondelta = k_cartoonseparation * texpix_txaux.xwyw;
-float4 cartoon_p0 = l_texcoordN + cartoondelta.xyzw;
-float4 cartoon_c0 = tex2D(k_txaux, cartoon_p0.xy);
-float4 cartoon_p1 = l_texcoordN - cartoondelta.xyzw;
-float4 cartoon_c1 = tex2D(k_txaux, cartoon_p1.xy);
-float4 cartoon_p2 = l_texcoordN + cartoondelta.wzyx;
-float4 cartoon_c2 = tex2D(k_txaux, cartoon_p2.xy);
-float4 cartoon_p3 = l_texcoordN - cartoondelta.wzyx;
-float4 cartoon_c3 = tex2D(k_txaux, cartoon_p3.xy);
-float4 cartoon_mx = max(cartoon_c0,max(cartoon_c1,max(cartoon_c2,cartoon_c3)));
-float4 cartoon_mn = min(cartoon_c0,min(cartoon_c1,min(cartoon_c2,cartoon_c3)));
+float4 cartoon_c0 = tex2D(k_txaux, %(texcoord)s + cartoondelta.xy);
+float4 cartoon_c1 = tex2D(k_txaux, %(texcoord)s - cartoondelta.xy);
+float4 cartoon_c2 = tex2D(k_txaux, %(texcoord)s + cartoondelta.wz);
+float4 cartoon_c3 = tex2D(k_txaux, %(texcoord)s - cartoondelta.wz);
+float4 cartoon_mx = max(cartoon_c0, max(cartoon_c1, max(cartoon_c2, cartoon_c3)));
+float4 cartoon_mn = min(cartoon_c0, min(cartoon_c1, min(cartoon_c2, cartoon_c3)));
 float cartoon_thresh = saturate(dot(cartoon_mx - cartoon_mn, float4(3,3,0,0)) - 0.5);
 float cartoon_thresh = saturate(dot(cartoon_mx - cartoon_mn, float4(3,3,0,0)) - 0.5);
 o_color = lerp(o_color, k_cartooncolor, cartoon_thresh);
 o_color = lerp(o_color, k_cartooncolor, cartoon_thresh);
 """
 """
@@ -125,7 +121,6 @@ class CommonFilters:
           self.task = None
           self.task = None
 
 
     def reconfigure(self, fullrebuild, changed):
     def reconfigure(self, fullrebuild, changed):
-
         """ Reconfigure is called whenever any configuration change is made. """
         """ Reconfigure is called whenever any configuration change is made. """
 
 
         configuration = self.configuration
         configuration = self.configuration
@@ -138,36 +133,46 @@ class CommonFilters:
                 return
                 return
 
 
             auxbits = 0
             auxbits = 0
-            needtex = {}
-            needtex["color"] = True
+            needtex = set(["color"])
+            needtexcoord = set(["color"])
+
             if ("CartoonInk" in configuration):
             if ("CartoonInk" in configuration):
-                needtex["aux"] = True
+                needtex.add("aux")
                 auxbits |= AuxBitplaneAttrib.ABOAuxNormal
                 auxbits |= AuxBitplaneAttrib.ABOAuxNormal
+                needtexcoord.add("aux")
+
             if ("AmbientOcclusion" in configuration):
             if ("AmbientOcclusion" in configuration):
-                needtex["depth"] = True
-                needtex["ssao0"] = True
-                needtex["ssao1"] = True
-                needtex["ssao2"] = True
-                needtex["aux"] = True
+                needtex.add("depth")
+                needtex.add("ssao0")
+                needtex.add("ssao1")
+                needtex.add("ssao2")
+                needtex.add("aux")
                 auxbits |= AuxBitplaneAttrib.ABOAuxNormal
                 auxbits |= AuxBitplaneAttrib.ABOAuxNormal
+                needtexcoord.add("ssao2")
+
             if ("BlurSharpen" in configuration):
             if ("BlurSharpen" in configuration):
-                needtex["blur0"] = True
-                needtex["blur1"] = True
+                needtex.add("blur0")
+                needtex.add("blur1")
+                needtexcoord.add("blur1")
+
             if ("Bloom" in configuration):
             if ("Bloom" in configuration):
-                needtex["bloom0"] = True
-                needtex["bloom1"] = True
-                needtex["bloom2"] = True
-                needtex["bloom3"] = True
+                needtex.add("bloom0")
+                needtex.add("bloom1")
+                needtex.add("bloom2")
+                needtex.add("bloom3")
                 auxbits |= AuxBitplaneAttrib.ABOGlow
                 auxbits |= AuxBitplaneAttrib.ABOGlow
+                needtexcoord.add("bloom3")
+
             if ("ViewGlow" in configuration):
             if ("ViewGlow" in configuration):
                 auxbits |= AuxBitplaneAttrib.ABOGlow
                 auxbits |= AuxBitplaneAttrib.ABOGlow
+
             if ("VolumetricLighting" in configuration):
             if ("VolumetricLighting" in configuration):
                 needtex[configuration["VolumetricLighting"].source] = True
                 needtex[configuration["VolumetricLighting"].source] = True
+
             for tex in needtex:
             for tex in needtex:
-                self.textures[tex] = Texture("scene-"+tex)
+                self.textures[tex] = Texture("scene-" + tex)
                 self.textures[tex].setWrapU(Texture.WMClamp)
                 self.textures[tex].setWrapU(Texture.WMClamp)
                 self.textures[tex].setWrapV(Texture.WMClamp)
                 self.textures[tex].setWrapV(Texture.WMClamp)
-                needtexpix = True
 
 
             self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits)
             self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits)
             if (self.finalQuad == None):
             if (self.finalQuad == None):
@@ -228,97 +233,112 @@ class CommonFilters:
                 self.bloom[3].setShaderInput("src", bloom2)
                 self.bloom[3].setShaderInput("src", bloom2)
                 self.bloom[3].setShader(self.loadShader("filter-bloomy.sha"))
                 self.bloom[3].setShader(self.loadShader("filter-bloomy.sha"))
 
 
+            texcoords = {}
+            texcoordPadding = {}
+
+            for tex in needtexcoord:
+                if self.textures[tex].getAutoTextureScale() != ATSNone or \
+                                           "HalfPixelShift" in configuration:
+                    texcoords[tex] = "l_texcoord_" + tex
+                    texcoordPadding["l_texcoord_" + tex] = tex
+                else:
+                    # Share unpadded texture coordinates.
+                    texcoords[tex] = "l_texcoord"
+                    texcoordPadding["l_texcoord"] = None
+
+            texcoordSets = list(enumerate(texcoordPadding.keys()))
+
             text = "//Cg\n"
             text = "//Cg\n"
             text += "void vshader(float4 vtx_position : POSITION,\n"
             text += "void vshader(float4 vtx_position : POSITION,\n"
-            text += " out float4 l_position : POSITION,\n"
-            text += " uniform float4 texpad_txcolor,\n"
-            text += " uniform float4 texpix_txcolor,\n"
-            text += " out float4 l_texcoordC : TEXCOORD0,\n"
-            if ("CartoonInk" in configuration):
-                text += " uniform float4 texpad_txaux,\n"
-                text += " uniform float4 texpix_txaux,\n"
-                text += " out float4 l_texcoordN : TEXCOORD1,\n"
-            if ("Bloom" in configuration):
-                text += " uniform float4 texpad_txbloom3,\n"
-                text += " out float4 l_texcoordB : TEXCOORD2,\n"
-            if ("BlurSharpen" in configuration):
-                text += " uniform float4 texpad_txblur1,\n"
-                text += " out float4 l_texcoordBS : TEXCOORD3,\n"
-            if ("AmbientOcclusion" in configuration):
-                text += " uniform float4 texpad_txssao2,\n"
-                text += " out float4 l_texcoordAO : TEXCOORD4,\n"
-            text += " uniform float4x4 mat_modelproj)\n"
+            text += "  out float4 l_position : POSITION,\n"
+
+            for texcoord, padTex in texcoordPadding.items():
+                if padTex is not None:
+                    text += "  uniform float4 texpad_tx%s,\n" % (padTex)
+                    if ("HalfPixelShift" in configuration):
+                        text += "  uniform float4 texpix_tx%s,\n" % (padTex)
+
+            for i, name in texcoordSets:
+                text += "  out float2 %s : TEXCOORD%d,\n" % (name, i)
+
+            text += "  uniform float4x4 mat_modelproj)\n"
             text += "{\n"
             text += "{\n"
-            text += " l_position=mul(mat_modelproj, vtx_position);\n"
-            text += " l_texcoordC=(vtx_position.xzxz * texpad_txcolor) + texpad_txcolor;\n"
-            if ("CartoonInk" in configuration):
-                text += " l_texcoordN=(vtx_position.xzxz * texpad_txaux) + texpad_txaux;\n"
-            if ("Bloom" in configuration):
-                text += " l_texcoordB=(vtx_position.xzxz * texpad_txbloom3) + texpad_txbloom3;\n"
-            if ("BlurSharpen" in configuration):
-                text += " l_texcoordBS=(vtx_position.xzxz * texpad_txblur1) + texpad_txblur1;\n"
-            if ("AmbientOcclusion" in configuration):
-                text += " l_texcoordAO=(vtx_position.xzxz * texpad_txssao2) + texpad_txssao2;\n"
-            if ("HalfPixelShift" in configuration):
-                text += " l_texcoordC+=texpix_txcolor*0.5;\n"
-                if ("CartoonInk" in configuration):
-                    text += " l_texcoordN+=texpix_txaux*0.5;\n"
+            text += "  l_position = mul(mat_modelproj, vtx_position);\n"
+
+            for texcoord, padTex in texcoordPadding.items():
+                if padTex is None:
+                    text += "  %s = vtx_position.xz * float2(0.5, 0.5) + float2(0.5, 0.5);\n" % (texcoord)
+                else:
+                    text += "  %s = (vtx_position.xz * texpad_tx%s.xy) + texpad_tx%s.xy;\n" % (texcoord, padTex, padTex)
+
+                    if ("HalfPixelShift" in configuration):
+                        text += "  %s += texpix_tx%s.xy * 0.5;\n" % (texcoord, padTex)
+
             text += "}\n"
             text += "}\n"
 
 
             text += "void fshader(\n"
             text += "void fshader(\n"
-            text += "float4 l_texcoordC : TEXCOORD0,\n"
-            text += "uniform float4 texpix_txcolor,\n"
-            if ("CartoonInk" in configuration):
-                text += "float4 l_texcoordN : TEXCOORD1,\n"
-                text += "uniform float4 texpix_txaux,\n"
-            if ("Bloom" in configuration):
-                text += "float4 l_texcoordB : TEXCOORD2,\n"
-            if ("BlurSharpen" in configuration):
-                text += "float4 l_texcoordBS : TEXCOORD3,\n"
-                text += "uniform float4 k_blurval,\n"
-            if ("AmbientOcclusion" in configuration):
-                text += "float4 l_texcoordAO : TEXCOORD4,\n"
+
+            for i, name in texcoordSets:
+                text += "  float2 %s : TEXCOORD%d,\n" % (name, i)
+
             for key in self.textures:
             for key in self.textures:
-                text += "uniform sampler2D k_tx" + key + ",\n"
+                text += "  uniform sampler2D k_tx" + key + ",\n"
+
             if ("CartoonInk" in configuration):
             if ("CartoonInk" in configuration):
-                text += "uniform float4 k_cartoonseparation,\n"
-                text += "uniform float4 k_cartooncolor,\n"
+                text += "  uniform float4 k_cartoonseparation,\n"
+                text += "  uniform float4 k_cartooncolor,\n"
+                text += "  uniform float4 texpix_txaux,\n"
+
+            if ("BlurSharpen" in configuration):
+                text += "  uniform float4 k_blurval,\n"
+
             if ("VolumetricLighting" in configuration):
             if ("VolumetricLighting" in configuration):
-                text += "uniform float4 k_casterpos,\n"
-                text += "uniform float4 k_vlparams,\n"
-            text += "out float4 o_color : COLOR)\n"
+                text += "  uniform float4 k_casterpos,\n"
+                text += "  uniform float4 k_vlparams,\n"
+            text += "  out float4 o_color : COLOR)\n"
             text += "{\n"
             text += "{\n"
-            text += " o_color = tex2D(k_txcolor, l_texcoordC.xy);\n"
+            text += "  o_color = tex2D(k_txcolor, %s);\n" % (texcoords["color"])
             if ("CartoonInk" in configuration):
             if ("CartoonInk" in configuration):
-                text += CARTOON_BODY
+                text += CARTOON_BODY % {"texcoord" : texcoords["aux"]}
             if ("AmbientOcclusion" in configuration):
             if ("AmbientOcclusion" in configuration):
-                text += "o_color *= tex2D(k_txssao2, l_texcoordAO.xy).r;\n"
+                text += "  o_color *= tex2D(k_txssao2, %s).r;\n" % (texcoords["ssao2"])
             if ("BlurSharpen" in configuration):
             if ("BlurSharpen" in configuration):
-                text += " o_color = lerp(tex2D(k_txblur1, l_texcoordBS.xy), o_color, k_blurval.x);\n"
+                text += "  o_color = lerp(tex2D(k_txblur1, %s), o_color, k_blurval.x);\n" % (texcoords["blur1"])
             if ("Bloom" in configuration):
             if ("Bloom" in configuration):
-                text += "o_color = saturate(o_color);\n";
-                text += "float4 bloom = 0.5*tex2D(k_txbloom3, l_texcoordB.xy);\n"
-                text += "o_color = 1-((1-bloom)*(1-o_color));\n"
+                text += "  o_color = saturate(o_color);\n";
+                text += "  float4 bloom = 0.5 * tex2D(k_txbloom3, %s);\n" % (texcoords["bloom3"])
+                text += "  o_color = 1-((1-bloom)*(1-o_color));\n"
             if ("ViewGlow" in configuration):
             if ("ViewGlow" in configuration):
-                text += "o_color.r = o_color.a;\n"
+                text += "  o_color.r = o_color.a;\n"
             if ("VolumetricLighting" in configuration):
             if ("VolumetricLighting" in configuration):
-                text += "float decay = 1.0f;\n"
-                text += "float2 curcoord = l_texcoordC.xy;\n"
-                text += "float2 lightdir = curcoord - k_casterpos.xy;\n"
-                text += "lightdir *= k_vlparams.x;\n"
-                text += "half4 sample = tex2D(k_txcolor, curcoord);\n"
-                text += "float3 vlcolor = sample.rgb * sample.a;\n"
-                text += "for (int i = 0; i < %s; i++) {\n" % (int(configuration["VolumetricLighting"].numsamples))
-                text += "  curcoord -= lightdir;\n"
-                text += "  sample = tex2D(k_tx%s, curcoord);\n" % (configuration["VolumetricLighting"].source)
-                text += "  sample *= sample.a * decay;//*weight\n"
-                text += "  vlcolor += sample.rgb;\n"
-                text += "  decay *= k_vlparams.y;\n"
-                text += "}\n"
-                text += "o_color += float4(vlcolor * k_vlparams.z, 1);\n"
+                text += "  float decay = 1.0f;\n"
+                text += "  float2 curcoord = %s;\n" % (texcoords["color"])
+                text += "  float2 lightdir = curcoord - k_casterpos.xy;\n"
+                text += "  lightdir *= k_vlparams.x;\n"
+                text += "  half4 sample = tex2D(k_txcolor, curcoord);\n"
+                text += "  float3 vlcolor = sample.rgb * sample.a;\n"
+                text += "  for (int i = 0; i < %s; i++) {\n" % (int(configuration["VolumetricLighting"].numsamples))
+                text += "    curcoord -= lightdir;\n"
+                text += "    sample = tex2D(k_tx%s, curcoord);\n" % (configuration["VolumetricLighting"].source)
+                text += "    sample *= sample.a * decay;//*weight\n"
+                text += "    vlcolor += sample.rgb;\n"
+                text += "    decay *= k_vlparams.y;\n"
+                text += "  }\n"
+                text += "  o_color += float4(vlcolor * k_vlparams.z, 1);\n"
+
+            if ("GammaAdjust" in configuration):
+                gamma = configuration["GammaAdjust"]
+                if gamma == 0.5:
+                    text += "  o_color.rgb = sqrt(o_color.rgb);\n"
+                elif gamma == 2.0:
+                    text += "  o_color.rgb *= o_color.rgb;\n"
+                elif gamma != 1.0:
+                    text += "  o_color.rgb = pow(o_color.rgb, %ff);\n" % (gamma)
+
             if ("Inverted" in configuration):
             if ("Inverted" in configuration):
-                text += "o_color = float4(1, 1, 1, 1) - o_color;\n"
+                text += "  o_color = float4(1, 1, 1, 1) - o_color;\n"
             text += "}\n"
             text += "}\n"
+            print text
             
             
             self.finalQuad.setShader(Shader.make(text))
             self.finalQuad.setShader(Shader.make(text))
             for tex in self.textures:
             for tex in self.textures:
@@ -504,3 +524,17 @@ class CommonFilters:
             return self.reconfigure(True, "AmbientOcclusion")
             return self.reconfigure(True, "AmbientOcclusion")
         return True
         return True
 
 
+    def setGammaAdjust(self, gamma):
+        """ Applies additional gamma correction to the image.  1.0 = no correction. """
+        old_gamma = self.configuration.get("GammaAdjust", 1.0)
+        if old_gamma != gamma:
+            self.configuration["GammaAdjust"] = gamma
+            return self.reconfigure(True, "GammaAdjust")
+        return True
+
+    def delGammaAdjust(self):
+        if ("GammaAdjust" in self.configuration):
+            old_gamma = self.configuration["GammaAdjust"]
+            del self.configuration["GammaAdjust"]
+            return self.reconfigure((old_gamma != 1.0), "GammaAdjust")
+        return True

+ 7 - 11
direct/src/http/baseincomingset.h

@@ -4,10 +4,10 @@
 #include <list>
 #include <list>
 #include "socket_base.h"
 #include "socket_base.h"
 
 
-enum CloseState 
+enum CloseState
 {
 {
-        ConnectionDoNotClose,
-        ConnectionDoClose
+    ConnectionDoNotClose,
+    ConnectionDoClose
 };
 };
 // RHH
 // RHH
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -20,15 +20,15 @@ enum CloseState
 //
 //
 //  The general operation if get connection..
 //  The general operation if get connection..
 //          do you have a message
 //          do you have a message
-//          process message 
+//          process message
 //          go back to do you have a message or close connection
 //          go back to do you have a message or close connection
 //
 //
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template < class _INCLASS1,class _IN_LISTEN, class MESSAGE_READER_BUF, class MESSAGE_READER_UPPASS> class BaseIncomingSet : public  std::list<_INCLASS1 *>
 template < class _INCLASS1,class _IN_LISTEN, class MESSAGE_READER_BUF, class MESSAGE_READER_UPPASS> class BaseIncomingSet : public  std::list<_INCLASS1 *>
 {
 {
-        typedef std::list<_INCLASS1 *> BaseClass;
-        typedef TYPENAME BaseClass::iterator iterator;
+    typedef std::list<_INCLASS1 *> BaseClass;
+    typedef TYPENAME BaseClass::iterator iterator;
     _IN_LISTEN                  _Listener;
     _IN_LISTEN                  _Listener;
 
 
     inline void AddFromListener(void);
     inline void AddFromListener(void);
@@ -39,7 +39,7 @@ public:
 
 
 //  typedef typename BaseIncomingSet<_INCLASS1, _IN_LISTEN, MESSAGE_READER_BUF, MESSAGE_READER_UPPASS>::LinkNode LinkNode;
 //  typedef typename BaseIncomingSet<_INCLASS1, _IN_LISTEN, MESSAGE_READER_BUF, MESSAGE_READER_UPPASS>::LinkNode LinkNode;
 
 
-//  typedef SentDblLinkListNode_Gm   SentDblLinkListNode_Gm; 
+//  typedef SentDblLinkListNode_Gm   SentDblLinkListNode_Gm;
     inline BaseIncomingSet(void);
     inline BaseIncomingSet(void);
     inline BaseIncomingSet(BaseIncomingSet &in);
     inline BaseIncomingSet(BaseIncomingSet &in);
     virtual ~BaseIncomingSet();
     virtual ~BaseIncomingSet();
@@ -50,10 +50,6 @@ public:
     virtual CloseState ProcessNewConnection(SOCKET  socket);
     virtual CloseState ProcessNewConnection(SOCKET  socket);
     inline  void AddToFDSet(Socket_fdset &set);
     inline  void AddToFDSet(Socket_fdset &set);
 
 
-    
-
-
-
 //  inline  LinkNode *          GetRoot(void) {  return &this->sentenal; };
 //  inline  LinkNode *          GetRoot(void) {  return &this->sentenal; };
     BaseIncomingSet &operator=( BaseIncomingSet &inval);
     BaseIncomingSet &operator=( BaseIncomingSet &inval);
     void Reset();
     void Reset();

+ 60 - 60
direct/src/http/baseincomingset.i

@@ -1,19 +1,19 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddFromListener
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddFromListener
 // Description      : Read incoming connections off the listener
 // Description      : Read incoming connections off the listener
-//  
-// Return type      : inline void 
+//
+// Return type      : inline void
 // Argument         : void
 // Argument         : void
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddFromListener(void)
 inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddFromListener(void)
 {
 {
     Socket_Address  Addr1;
     Socket_Address  Addr1;
     SOCKET          newsck;
     SOCKET          newsck;
-    
-    
+
+
     while(_Listener.GetIncomingConnection(newsck,Addr1) == true)
     while(_Listener.GetIncomingConnection(newsck,Addr1) == true)
-    {   
+    {
         CloseState cl= ProcessNewConnection(newsck);
         CloseState cl= ProcessNewConnection(newsck);
         if(cl == ConnectionDoNotClose)
         if(cl == ConnectionDoNotClose)
         {
         {
@@ -22,52 +22,52 @@ inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READ
         }
         }
         else
         else
             DO_CLOSE(newsck);
             DO_CLOSE(newsck);
-    }       
-        
+    }
+
 }
 }
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::PumpReader
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::PumpReader
 // Description      : Tries to read a record off the incoming socket
 // Description      : Tries to read a record off the incoming socket
-//  
-// Return type      : inline void 
+//
+// Return type      : inline void
 // Argument         : Time_Clock  currentTime
 // Argument         : Time_Clock  currentTime
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline int BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::PumpReader(Time_Clock  &currentTime)
 inline int BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::PumpReader(Time_Clock  &currentTime)
-{       
+{
     MESSAGE_READER_BUF      message;
     MESSAGE_READER_BUF      message;
-    
+
     iterator lpNext, lp;
     iterator lpNext, lp;
     for (lpNext  = lp = BaseClass::begin(); lp != BaseClass::end() ; lp = lpNext)
     for (lpNext  = lp = BaseClass::begin(); lp != BaseClass::end() ; lp = lpNext)
     {
     {
-        lpNext++;   
-        
+        lpNext++;
+
         int ans = (*lp)->ReadIt(message, sizeof(message),currentTime);
         int ans = (*lp)->ReadIt(message, sizeof(message),currentTime);
         if(ans < 0)
         if(ans < 0)
         {
         {
             delete *lp;
             delete *lp;
-            erase(lp);
-        }               
+            this->erase(lp);
+        }
         if(ans > 0)
         if(ans > 0)
         {
         {
             CloseState cs = (*lp)->ProcessMessage(message,currentTime);
             CloseState cs = (*lp)->ProcessMessage(message,currentTime);
             if( cs == ConnectionDoClose)
             if( cs == ConnectionDoClose)
             {
             {
                 delete *lp;
                 delete *lp;
-                erase(lp);
+                this->erase(lp);
             }
             }
         }
         }
-    }   
-    return 0;           
+    }
+    return 0;
 }
 }
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddAConection
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddAConection
 // Description      : Adds a member to the base container
 // Description      : Adds a member to the base container
-//  
-// Return type      : inline void 
+//
+// Return type      : inline void
 // Argument         : _INCLASS1 * newt
 // Argument         : _INCLASS1 * newt
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddAConection(_INCLASS1 * newt)
 inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddAConection(_INCLASS1 * newt)
 {
 {
     push_back(newt);
     push_back(newt);
@@ -75,17 +75,17 @@ inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READ
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::BaseIncomingSet
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::BaseIncomingSet
 // Description      :  core constructor
 // Description      :  core constructor
-//  
-// Return type      : inline 
+//
+// Return type      : inline
 // Argument         : void
 // Argument         : void
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::BaseIncomingSet(void)
 inline BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::BaseIncomingSet(void)
 {
 {
-    
+
 }
 }
 
 
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::BaseIncomingSet(BaseIncomingSet &in)
 BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::BaseIncomingSet(BaseIncomingSet &in)
 {
 {
 
 
@@ -93,10 +93,10 @@ BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::~BaseIncomingSet
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::~BaseIncomingSet
 // Description      : The Destructot .. will delete all members.. ??
 // Description      : The Destructot .. will delete all members.. ??
-//  
-// Return type      : 
+//
+// Return type      :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::~BaseIncomingSet()
 BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::~BaseIncomingSet()
 {
 {
     for(iterator ii = BaseClass::begin(); ii != BaseClass::end(); ii++)
     for(iterator ii = BaseClass::begin(); ii != BaseClass::end(); ii++)
@@ -105,76 +105,76 @@ BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : & BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::GetListener
 // Function name    : & BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::GetListener
 // Description      : Retyurns a pointer to the listener in this class
 // Description      : Retyurns a pointer to the listener in this class
-//  
-// Return type      : inline _IN_LISTEN 
+//
+// Return type      : inline _IN_LISTEN
 // Argument         : void
 // Argument         : void
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
-inline _IN_LISTEN & BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::GetListener(void) 
-{ 
-    return this->Listener; 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
+inline _IN_LISTEN & BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::GetListener(void)
+{
+    return this->Listener;
 };
 };
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::init
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::init
 // Description      : the second part of the 2 phase power up.. Opends the listener
 // Description      : the second part of the 2 phase power up.. Opends the listener
-//  
-// Return type      : inline bool 
+//
+// Return type      : inline bool
 // Argument         : Socket_Address &WhereFrom
 // Argument         : Socket_Address &WhereFrom
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline bool BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::init(Socket_Address &WhereFrom)
 inline bool BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::init(Socket_Address &WhereFrom)
 {
 {
     if(_Listener.OpenForListen(WhereFrom,true) != true)
     if(_Listener.OpenForListen(WhereFrom,true) != true)
-        return false;       
+        return false;
     _Listener.SetNonBlocking();
     _Listener.SetNonBlocking();
     return true;
     return true;
 }
 }
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::PumpAll
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::PumpAll
 // Description      : THis is the polled interface to this class
 // Description      : THis is the polled interface to this class
-//  
-// Return type      : inline void 
+//
+// Return type      : inline void
 // Argument         : Time_Clock  &currentTime
 // Argument         : Time_Clock  &currentTime
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::PumpAll(Time_Clock  &currentTime)
 inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::PumpAll(Time_Clock  &currentTime)
 {
 {
     PumpReader(currentTime); // I MOVED ORDER TO FINE TUNE THE READ OPERATIONS
     PumpReader(currentTime); // I MOVED ORDER TO FINE TUNE THE READ OPERATIONS
-    AddFromListener();       
+    AddFromListener();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::ProcessNewConnection
 // Function name    : BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::ProcessNewConnection
-// Description      :  this is the vertual function call when a new connection is created 
+// Description      :  this is the vertual function call when a new connection is created
 //                      manly here for loging if needed...
 //                      manly here for loging if needed...
-//  
-// Return type      : CloseState 
+//
+// Return type      : CloseState
 // Argument         : SOCKET  socket
 // Argument         : SOCKET  socket
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 CloseState BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::ProcessNewConnection(SOCKET  socket)
 CloseState BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::ProcessNewConnection(SOCKET  socket)
 {
 {
     return ConnectionDoNotClose;
     return ConnectionDoNotClose;
 }
 }
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Function name    : void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddToFDSet
 // Function name    : void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddToFDSet
-// Description      : Add LIstener and Client to the FD set for polled reading 
-//  
-// Return type      : inline  
+// Description      : Add LIstener and Client to the FD set for polled reading
+//
+// Return type      : inline
 // Argument         : Socket_Selector &set
 // Argument         : Socket_Selector &set
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline  void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddToFDSet(Socket_fdset &set1)
 inline  void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::AddToFDSet(Socket_fdset &set1)
-{   
+{
     if(_Listener.Active())
     if(_Listener.Active())
         set1.setForSocket(_Listener);
         set1.setForSocket(_Listener);
     iterator lp;
     iterator lp;
-    
+
     for (lp = BaseClass::begin(); lp != BaseClass::end(); lp = lp++)
     for (lp = BaseClass::begin(); lp != BaseClass::end(); lp = lp++)
         set1.setForSocket((*lp)->val);
         set1.setForSocket((*lp)->val);
 }
 }
 
 
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS> &BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::operator=
 inline BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS> &BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::operator=
     (BaseIncomingSet &inval)
     (BaseIncomingSet &inval)
 {
 {
@@ -184,18 +184,18 @@ inline BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UP
 }
 }
 
 
 
 
-template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS> 
+template <class _INCLASS1,class _IN_LISTEN,typename  MESSAGE_READER_BUF, typename  MESSAGE_READER_UPPASS>
 inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::Reset()
 inline void BaseIncomingSet<_INCLASS1,_IN_LISTEN,MESSAGE_READER_BUF,MESSAGE_READER_UPPASS>::Reset()
 {
 {
     _Listener.Close();
     _Listener.Close();
     iterator lpNext, lp;
     iterator lpNext, lp;
     for (lpNext  = lp = BaseClass::begin(); lp != BaseClass::end() ; lp = lpNext)
     for (lpNext  = lp = BaseClass::begin(); lp != BaseClass::end() ; lp = lpNext)
     {
     {
-        lpNext++;   
+        lpNext++;
         (*lp)->Reset();
         (*lp)->Reset();
         delete *lp;
         delete *lp;
-        erase(lp);
-    }               
+        this->erase(lp);
+    }
 }
 }
 
 
 
 

+ 64 - 29
direct/src/p3d/p3dWrapper.c

@@ -23,12 +23,21 @@
 #include <windows.h>
 #include <windows.h>
 #include <process.h>
 #include <process.h>
 #include <assert.h>
 #include <assert.h>
+#include <malloc.h>
 
 
 #define BUFFER_SIZE 1024
 #define BUFFER_SIZE 1024
 
 
+/* It makes sense to use "App Paths\panda3d.exe".  However, Microsoft
+   decided in their infinite wisdom to disable Redirection for that
+   key from Windows 7 onward, so we can't rely on it producing a
+   result appropriate to the right architecture when both the 32-bit
+   and 64-bit versions of the runtime are installed.  Beh. */
+
+#define UNINST_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Panda3D Game Engine"
+
 int main (int argc, char* argv[]) {
 int main (int argc, char* argv[]) {
   int i;
   int i;
-  char buffer [BUFFER_SIZE];
+  char buffer[BUFFER_SIZE];
   char* p3dfile;
   char* p3dfile;
   char* runtime = NULL;
   char* runtime = NULL;
   DWORD size;
   DWORD size;
@@ -37,56 +46,82 @@ int main (int argc, char* argv[]) {
   char *cmd;
   char *cmd;
   char *newcmd;
   char *newcmd;
   HKEY hKey = 0;
   HKEY hKey = 0;
-  char buf [1024] = {0};
-  DWORD dwType = 0;
+  char buf[1024] = {0};
+  DWORD dwType = REG_SZ;
   DWORD dwBufSize = sizeof(buf);
   DWORD dwBufSize = sizeof(buf);
-  size = GetModuleFileName (NULL, buffer, BUFFER_SIZE);
+  size = GetModuleFileName(NULL, buffer, BUFFER_SIZE);
   assert (size > 0);
   assert (size > 0);
 
 
   /* Chop off the .exe and replace it by .p3d. */
   /* Chop off the .exe and replace it by .p3d. */
-  p3dfile = (char*) malloc (size + 1);
-  memcpy (p3dfile, buffer, size);
-  p3dfile [size] = 0;
-  memcpy (p3dfile + size - 3, "p3d", 3);
+  p3dfile = (char*) _alloca(size + 1);
+  memcpy(p3dfile, buffer, size);
+  p3dfile[size] = 0;
+  memcpy(p3dfile + size - 3, "p3d", 3);
 
 
-  /* Find the Panda3D applet\DefaultIcon key and extract the path to the runtime from there. */
-  if (RegOpenKey (HKEY_CLASSES_ROOT, "Panda3D applet\\DefaultIcon", &hKey) == ERROR_SUCCESS) {
-    dwType = REG_SZ;
-    if (RegQueryValueEx(hKey, 0, 0, &dwType, (BYTE*) buf, &dwBufSize) == ERROR_SUCCESS) {
-      for (i = dwBufSize - 1; i >= 0; --i) {
-        if (buf [i] == '/' || buf [i] == '\\') {
-          runtime = (char*) malloc (i + 13);
-          memcpy (runtime, buf, i);
-          runtime [i] = 0;         
-          strcat (runtime, "\\panda3d.exe");      
-          break;
+  /* Find the location of panda3d.exe using the registry path. */
+#ifdef _WIN64
+  /* If we're on 64-bit Windows, try the 64-bit registry first. */
+  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, UNINST_KEY, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS) {
+    if (RegQueryValueEx(hKey, "DisplayIcon", 0, &dwType, (BYTE*) buf, &dwBufSize) == ERROR_SUCCESS) {
+      char *slash = strrchr(buf, '\\');
+      if (slash != NULL) {
+        strcpy(slash, "\\panda3d.exe");
+        runtime = buf;
+      }
+    }
+    RegCloseKey(hKey);
+  }
+#endif
+
+  /* On 32-bit Windows, or no 64-bit Runtime installed.  Try 32-bit registry. */
+  if (runtime == NULL) {
+    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, UNINST_KEY, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) {
+      if (RegQueryValueEx(hKey, "DisplayIcon", 0, &dwType, (BYTE*) buf, &dwBufSize) == ERROR_SUCCESS) {
+        char *slash = strrchr(buf, '\\');
+        if (slash != NULL) {
+          strcpy(slash, "\\panda3d.exe");
+          runtime = buf;
         }
         }
       }
       }
+      RegCloseKey(hKey);
+    }
+  }
+
+  /* Backward compatibility: Runtime 1.0.4 and below looked for the below key, even though the
+     above keys should work fine, but let's just be certain.
+     Find the Panda3D applet\DefaultIcon key and extract the path to the runtime from there.  */
+  if (runtime == NULL) {
+    if (RegOpenKey(HKEY_CLASSES_ROOT, "Panda3D applet\\DefaultIcon", &hKey) == ERROR_SUCCESS) {
+      if (RegQueryValueEx(hKey, 0, 0, &dwType, (BYTE*) buf, &dwBufSize) == ERROR_SUCCESS) {
+        char *slash = strrchr(buf, '\\');
+        if (slash != NULL) {
+          strcpy(slash, "\\panda3d.exe");
+          runtime = buf;
+        }
+      } else {
+        fprintf(stderr, "Failed to read registry key. Try reinstalling the Panda3D Runtime.\n");
+        return 1;
+      }
+      RegCloseKey(hKey);
     } else {
     } else {
-      fprintf (stderr, "Failed to read registry key. Try reinstalling the Panda3D Runtime.\n");
+      fprintf(stderr, "The Panda3D Runtime does not appear to be installed!\n");
       return 1;
       return 1;
     }
     }
-    RegCloseKey(hKey);
-  } else {
-    fprintf (stderr, "The Panda3D Runtime does not appear to be installed!\n");
-    return 1;
   }
   }
 
 
   if (runtime == NULL) {
   if (runtime == NULL) {
-    fprintf (stderr, "Failed to find panda3d.exe in registry. Try reinstalling the Panda3D Runtime.\n");
+    fprintf(stderr, "Failed to find panda3d.exe in registry. Try reinstalling the Panda3D Runtime.\n");
     return 1;
     return 1;
   }
   }
 
 
   /* Build the command-line and run panda3d.exe. */
   /* Build the command-line and run panda3d.exe. */
   cmd = GetCommandLine();
   cmd = GetCommandLine();
-  newcmd = (char*) malloc (strlen(runtime) + strlen(p3dfile) + strlen (cmd) - strlen (argv[0]) + 7);
-  sprintf (newcmd, "\"%s\" \"%s\" %s", runtime, p3dfile, cmd + strlen (argv[0]));
+  newcmd = (char*) _alloca(strlen(runtime) + strlen(p3dfile) + strlen(cmd) - strlen (argv[0]) + 7);
+  sprintf(newcmd, "\"%s\" \"%s\" %s", runtime, p3dfile, cmd + strlen(argv[0]));
   memset(&si, 0, sizeof(si));
   memset(&si, 0, sizeof(si));
   si.cb = sizeof(STARTUPINFO);
   si.cb = sizeof(STARTUPINFO);
   if (CreateProcess(runtime, newcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
   if (CreateProcess(runtime, newcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
     WaitForSingleObject(pi.hProcess, INFINITE);
     WaitForSingleObject(pi.hProcess, INFINITE);
   }
   }
-  free (newcmd);
   return 0;
   return 0;
 }
 }
-

+ 12 - 3
direct/src/plugin_installer/make_installer.py

@@ -40,7 +40,7 @@ parser.add_option('-l', '--license', dest = 'license',
                   default = None)
                   default = None)
 parser.add_option('-w', '--website', dest = 'website',
 parser.add_option('-w', '--website', dest = 'website',
                   help = 'The product website',
                   help = 'The product website',
-                  default = 'http://www.panda3d.org')
+                  default = 'https://www.panda3d.org')
 parser.add_option('', '--start', dest = 'start',
 parser.add_option('', '--start', dest = 'start',
                   help = 'Specify this option to add a start menu',
                   help = 'Specify this option to add a start menu',
                   action = 'store_true', default = False)
                   action = 'store_true', default = False)
@@ -65,6 +65,9 @@ parser.add_option('', '--pvk', dest = 'pvk',
 parser.add_option('', '--mssdk', dest = 'mssdk',
 parser.add_option('', '--mssdk', dest = 'mssdk',
                   help = 'The path to the MS Platform SDK directory (Windows only).  mssdk/bin should contain cabarc.exe and signcode.exe.',
                   help = 'The path to the MS Platform SDK directory (Windows only).  mssdk/bin should contain cabarc.exe and signcode.exe.',
                   default = None)
                   default = None)
+parser.add_option('', '--regview', dest = 'regview',
+                  help = 'Which registry view to use, 64 or 32.',
+                  default = None)
 
 
 (options, args) = parser.parse_args()
 (options, args) = parser.parse_args()
 
 
@@ -221,7 +224,7 @@ def parseDependenciesUnix(tempFile):
         filenames.append(l.strip().split(' ', 1)[0])
         filenames.append(l.strip().split(' ', 1)[0])
     return filenames
     return filenames
 
 
-def addDependencies(path, pathname, file, pluginDependencies, dependentFiles):
+def addDependencies(path, pathname, file, pluginDependencies, dependentFiles, required=True):
     """ Checks the named file for DLL dependencies, and adds any
     """ Checks the named file for DLL dependencies, and adds any
     appropriate dependencies found into pluginDependencies and
     appropriate dependencies found into pluginDependencies and
     dependentFiles. """
     dependentFiles. """
@@ -271,7 +274,10 @@ def addDependencies(path, pathname, file, pluginDependencies, dependentFiles):
                         break
                         break
                     pathname = None
                     pathname = None
                 if not pathname:
                 if not pathname:
-                    sys.exit("Couldn't find %s." % (dfile))
+                    if required:
+                        sys.exit("Couldn't find %s." % (dfile))
+                    sys.stderr.write("Warning: couldn't find %s." % (dfile))
+                    continue
                 pathname = os.path.abspath(pathname)
                 pathname = os.path.abspath(pathname)
                 dependentFiles[dfilelower] = pathname
                 dependentFiles[dfilelower] = pathname
 
 
@@ -553,6 +559,9 @@ def makeInstaller():
         CMD += '/DPANDA3DW="' + panda3dw + '" '
         CMD += '/DPANDA3DW="' + panda3dw + '" '
         CMD += '/DPANDA3DW_PATH="' + pluginFiles[panda3dw] + '" '
         CMD += '/DPANDA3DW_PATH="' + pluginFiles[panda3dw] + '" '
 
 
+        if options.regview:
+            CMD += '/DREGVIEW=%s ' % (options.regview)
+
         dependencies = dependentFiles.items()
         dependencies = dependentFiles.items()
         for i in range(len(dependencies)):
         for i in range(len(dependencies)):
             CMD += '/DDEP%s="%s" ' % (i, dependencies[i][0])
             CMD += '/DDEP%s="%s" ' % (i, dependencies[i][0])

+ 76 - 21
direct/src/plugin_installer/p3d_installer.nsi

@@ -1,6 +1,5 @@
 !include "MUI.nsh"
 !include "MUI.nsh"
 !include LogicLib.nsh
 !include LogicLib.nsh
-!include FileAssociation.nsh
 
 
 ; Several variables are assumed to be pre-defined by the caller.  See
 ; Several variables are assumed to be pre-defined by the caller.  See
 ; make_installer.py in this directory.
 ; make_installer.py in this directory.
@@ -9,18 +8,18 @@
 !define UNINSTALL_CONFIRM "Are you sure you want to completely remove $(^Name) and all of its components?"
 !define UNINSTALL_CONFIRM "Are you sure you want to completely remove $(^Name) and all of its components?"
 !define UNINSTALL_LINK_NAME "Uninstall"
 !define UNINSTALL_LINK_NAME "Uninstall"
 !define WEBSITE_LINK_NAME "Website"
 !define WEBSITE_LINK_NAME "Website"
-!define PLID "@panda3d.org/Panda3D Runtime,version=0.0"
+!define PLID "@panda3d.org/Panda3D Runtime"
 
 
 ; HM NIS Edit Wizard helper defines
 ; HM NIS Edit Wizard helper defines
 !define APP_INTERNAL_NAME "Panda3D"
 !define APP_INTERNAL_NAME "Panda3D"
 
 
-!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\${OCX}"
+!define PRODUCT_DIR_REGKEY_PANDA3D "Software\Microsoft\Windows\CurrentVersion\App Paths\${PANDA3D}"
+!define PRODUCT_DIR_REGKEY_PANDA3DW "Software\Microsoft\Windows\CurrentVersion\App Paths\${PANDA3DW}"
+!define PRODUCT_DIR_REGKEY_OCX "Software\Microsoft\Windows\CurrentVersion\App Paths\${OCX}"
 !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
 !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
 !define PRODUCT_UNINST_ROOT_KEY "HKLM"
 !define PRODUCT_UNINST_ROOT_KEY "HKLM"
 !define PROG_GROUPNAME "${PRODUCT_NAME}"
 !define PROG_GROUPNAME "${PRODUCT_NAME}"
 
 
-!define FIREFOX_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe"
-
 SetCompressor lzma
 SetCompressor lzma
 
 
 ; MUI Settings
 ; MUI Settings
@@ -60,16 +59,32 @@ InstallDir "${INSTALL_DIR}"
   UninstallIcon "${INSTALL_ICON}"
   UninstallIcon "${INSTALL_ICON}"
 !endif
 !endif
 WindowIcon on
 WindowIcon on
-InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
+
 ShowInstDetails show
 ShowInstDetails show
 ShowUnInstDetails show
 ShowUnInstDetails show
 
 
+Function .onInit
+!ifdef REGVIEW
+  SetRegView ${REGVIEW}
+!endif
+
+  ClearErrors
+
+  ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallLocation"
+
+  IfErrors +2 0
+  StrCpy $INSTDIR $0
+
+FunctionEnd
+
 Section "MainSection" SEC01
 Section "MainSection" SEC01
   SetShellVarContext all
   SetShellVarContext all
   SetOutPath "$INSTDIR"
   SetOutPath "$INSTDIR"
   SetOverwrite ifdiff
   SetOverwrite ifdiff
 
 
+!ifdef OCX_PATH
   File "${OCX_PATH}"
   File "${OCX_PATH}"
+!endif
   File "${NPAPI_PATH}"
   File "${NPAPI_PATH}"
   File "${PANDA3D_PATH}"
   File "${PANDA3D_PATH}"
   File "${PANDA3DW_PATH}"
   File "${PANDA3DW_PATH}"
@@ -100,8 +115,6 @@ Section "MainSection" SEC01
 !ifdef DEP7P
 !ifdef DEP7P
   File "${DEP7P}"
   File "${DEP7P}"
 !endif
 !endif
-
-  ${registerExtension} "$INSTDIR\${PANDA3DW}" ".p3d" "Panda3D applet"
  
  
 !ifdef ADD_START_MENU
 !ifdef ADD_START_MENU
 ; Start->Programs links
 ; Start->Programs links
@@ -127,14 +140,41 @@ Section -AdditionalIcons
 SectionEnd
 SectionEnd
 
 
 Section -Post
 Section -Post
+!ifdef REGVIEW
+  SetRegView ${REGVIEW}
+!endif
+
   WriteUninstaller "$INSTDIR\uninst.exe"
   WriteUninstaller "$INSTDIR\uninst.exe"
-  WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\${OCX}"
+
+  WriteRegStr HKCR ".p3d" "" "Panda3D applet"
+  WriteRegStr HKCR ".p3d" "Content Type" "application/x-panda3d"
+  WriteRegStr HKCR ".p3d" "PerceivedType" "application"
+  WriteRegStr HKCR "Panda3D applet" "" "Panda3D applet"
+  WriteRegStr HKCR "Panda3D applet\DefaultIcon" "" "$INSTDIR\${PANDA3DW}"
+  WriteRegStr HKCR "Panda3D applet\shell" "" "open"
+  WriteRegStr HKCR "Panda3D applet\shell\open\command" "" '"$INSTDIR\${PANDA3DW}" "%1"'
+  WriteRegExpandStr HKCR "Panda3D applet\shell\open2" "" "Open &with Command Prompt"
+  ;WriteRegExpandStr HKCR "Panda3D applet\shell\open2" "MUIVerb" "@%SystemRoot%\System32\wshext.dll,-4511"
+  WriteRegExpandStr HKCR "Panda3D applet\shell\open2\command" "" '"$INSTDIR\${PANDA3D}" "%1"'
+
+  WriteRegStr HKLM "${PRODUCT_DIR_REGKEY_PANDA3D}" "" "$INSTDIR\${PANDA3D}"
+  WriteRegStr HKLM "${PRODUCT_DIR_REGKEY_PANDA3DW}" "" "$INSTDIR\${PANDA3DW}"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
-  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\${OCX}"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PANDA3D}"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallLocation" "$INSTDIR"
+  WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "NoModify" 1
+  WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "NoRepair" 1
+
+  SectionGetSize SEC01 $0
+  WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "EstimatedSize" $0
+
+  # Delete keys we used in older versions
+  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY_OCX}"
+  DeleteRegKey HKCR "Panda3D applet\shell\edit"
 SectionEnd
 SectionEnd
 
 
 
 
@@ -149,16 +189,23 @@ Function un.onInit
 FunctionEnd
 FunctionEnd
 
 
 Function .onInstSuccess
 Function .onInstSuccess
- # Register ActiveX
- ExecWait 'regsvr32 /s "$INSTDIR/${OCX}"'
+  # Register ActiveX
+  ExecWait 'regsvr32 /s "$INSTDIR/${OCX}"'
 
 
- # Register Mozilla Plugin
- WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Description" "Runs 3-D games and interactive applets"
- WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Path" "$INSTDIR\${NPAPI}"
- WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "ProductName" "${PRODUCT_NAME_SHORT}"
- WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Vendor" "${PRODUCT_PUBLISHER}"
- WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Version" "${PRODUCT_VERSION}"
- WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}\MimeTypes" "application/x-panda3d" ""
+!ifdef REGVIEW
+  SetRegView ${REGVIEW}
+!endif
+
+  # Register Mozilla Plugin
+  WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Description" "Runs 3-D games and interactive applets"
+  WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Path" "$INSTDIR\${NPAPI}"
+  WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "ProductName" "${PRODUCT_NAME_SHORT}"
+  WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Vendor" "${PRODUCT_PUBLISHER}"
+  WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Version" "${PRODUCT_VERSION}"
+  WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}\MimeTypes\application/x-panda3d" "Description" "Panda3D applet"
+
+  # Remove old stuff
+  DeleteRegKey HKLM "SOFTWARE\MozillaPlugins\${PLID},version=0.0"
 
 
 FunctionEnd
 FunctionEnd
 
 
@@ -196,6 +243,10 @@ Section Uninstall
   Delete "$INSTDIR\${DEP7}"
   Delete "$INSTDIR\${DEP7}"
 !endif
 !endif
 
 
+!ifdef REGVIEW
+  SetRegView ${REGVIEW}
+!endif
+
 # The following loop uninstalls the plugin where it may have been
 # The following loop uninstalls the plugin where it may have been
 # copied into one of the Mozilla Extensions dirs.  Older versions of
 # copied into one of the Mozilla Extensions dirs.  Older versions of
 # the installer would have done this, but now we just update the
 # the installer would have done this, but now we just update the
@@ -215,8 +266,10 @@ Mozilla-Uninstall-Loop:
 Mozilla-Uninstall-End:
 Mozilla-Uninstall-End:
 
 
   DeleteRegKey HKLM "SOFTWARE\MozillaPlugins\${PLID}"
   DeleteRegKey HKLM "SOFTWARE\MozillaPlugins\${PLID}"
+  DeleteRegKey HKLM "SOFTWARE\MozillaPlugins\${PLID},version=0.0"
 
 
-  ${unregisterExtension} ".p3d" "Panda3D applet"
+  DeleteRegKey HKCR ".p3d"
+  DeleteRegKey HKCR "Panda3D applet"
 
 
   # Remove the user's "Panda3D" directory, where all of the downloaded
   # Remove the user's "Panda3D" directory, where all of the downloaded
   # contents are installed.  Too bad we can't do this for every system
   # contents are installed.  Too bad we can't do this for every system
@@ -239,7 +292,9 @@ Mozilla-Uninstall-End:
   RMDir "$INSTDIR"
   RMDir "$INSTDIR"
 
 
   DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
   DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
-  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
+  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY_PANDA3D}"
+  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY_PANDA3DW}"
+  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY_OCX}"
   SetAutoClose true
   SetAutoClose true
 SectionEnd
 SectionEnd
 
 

+ 0 - 70
direct/src/showbase/PythonUtil.py

@@ -52,7 +52,6 @@ import __builtin__
 from StringIO import StringIO
 from StringIO import StringIO
 import marshal
 import marshal
 import ElementTree as ET
 import ElementTree as ET
-from HTMLParser import HTMLParser
 import BpDb
 import BpDb
 import unicodedata
 import unicodedata
 import bisect
 import bisect
@@ -4201,75 +4200,6 @@ if __debug__ and __name__ == '__main__':
     assert unescapeHtmlString('as%32df') == 'as2df'
     assert unescapeHtmlString('as%32df') == 'as2df'
     assert unescapeHtmlString('asdf%32') == 'asdf2'
     assert unescapeHtmlString('asdf%32') == 'asdf2'
 
 
-class HTMLStringToElements(HTMLParser):
-    def __init__(self, str, *a, **kw):
-        self._elements = []
-        self._elementStack = Stack()
-        HTMLParser.__init__(self, *a, **kw)
-        self.feed(str)
-        self.close()
-
-    def getElements(self):
-        return self._elements
-        
-    def _handleNewElement(self, element):
-        if len(self._elementStack):
-            self._elementStack.top().append(element)
-        else:
-            self._elements.append(element)
-        self._elementStack.push(element)
-
-    def handle_starttag(self, tag, attrs):
-        kwArgs = {}
-        for name, value in attrs:
-            kwArgs[name] = value
-        el = ET.Element(tag, **kwArgs)
-        self._handleNewElement(el)
-
-    def handle_data(self, data):
-        # this ignores text outside of a tag
-        if len(self._elementStack):
-            self._elementStack.top().text = data
-
-    def handle_endtag(self, tag):
-        top = self._elementStack.top()
-        if len(top.getchildren()) == 0:
-            # insert a comment to prevent ElementTree from using <... /> convention
-            # force it to create a tag closer a la </tag>
-            # prevents problems in certain browsers
-            if top.tag == 'script' and top.get('type') == 'text/javascript':
-                if top.text == None:
-                    top.text = '// force tag closer'
-            else:
-                self.handle_comment('force tag closer')
-                self._elementStack.pop()
-        self._elementStack.pop()
-
-    def handle_comment(self, data):
-        comment = ET.Comment(data)
-        self._handleNewElement(comment)
-
-def str2elements(str):
-    return HTMLStringToElements(str).getElements()
-
-if __debug__ and __name__ == '__main__':
-    s = ScratchPad()
-    assert len(str2elements('')) == 0
-    s.br = str2elements('<br>')
-    assert len(s.br) == 1
-    assert s.br[0].tag == 'br'
-    s.b = str2elements('<b><br></b>')
-    assert len(s.b) == 1
-    assert len(s.b[0].getchildren()) == 1
-    s.a = str2elements('<a href=\'/\'>test</a>')
-    assert len(s.a) == 1
-    assert s.a[0].get('href') == '/'
-    assert s.a[0].text == 'test'
-    s.c = str2elements('<!--testComment-->')
-    assert len(s.c) == 1
-    assert s.c[0].text == 'testComment'
-    del s
-
 def repeatableRepr(obj):
 def repeatableRepr(obj):
     if type(obj) is types.DictType:
     if type(obj) is types.DictType:
         keys = obj.keys()
         keys = obj.keys()

+ 2 - 1
direct/src/showbase/ShowBase.py

@@ -7,7 +7,8 @@ __all__ = ['ShowBase', 'WindowControls']
 # Annoying and very noisy, but sometimes useful
 # Annoying and very noisy, but sometimes useful
 #import VerboseImport
 #import VerboseImport
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 
 
 # This needs to be available early for DirectGUI imports
 # This needs to be available early for DirectGUI imports
 import __builtin__
 import __builtin__

+ 6 - 3
direct/src/showbase/VFSImporter.py

@@ -3,7 +3,6 @@ import sys
 import os
 import os
 import marshal
 import marshal
 import imp
 import imp
-import struct
 import types
 import types
 import __builtin__
 import __builtin__
 
 
@@ -286,7 +285,8 @@ class VFSLoader:
         code = None
         code = None
         data = vfile.readFile(True)
         data = vfile.readFile(True)
         if data[:4] == imp.get_magic():
         if data[:4] == imp.get_magic():
-            t = struct.unpack('<I', data[4:8])[0]
+            t = ord(data[4]) + (ord(data[5]) << 8) + \
+               (ord(data[6]) << 16) + (ord(data[7]) << 24)
             if not timestamp or t == timestamp:
             if not timestamp or t == timestamp:
                 code = marshal.loads(data[8:])
                 code = marshal.loads(data[8:])
             else:
             else:
@@ -314,7 +314,10 @@ class VFSLoader:
             pass
             pass
         else:
         else:
             f.write('\0\0\0\0')
             f.write('\0\0\0\0')
-            f.write(struct.pack('<I', self.timestamp))
+            f.write(chr(self.timestamp & 0xff) +
+                    chr((self.timestamp >> 8) & 0xff) +
+                    chr((self.timestamp >> 16) & 0xff) +
+                    chr((self.timestamp >> 24) & 0xff))
             f.write(marshal.dumps(code))
             f.write(marshal.dumps(code))
             f.flush()
             f.flush()
             f.seek(0, 0)
             f.seek(0, 0)

+ 4 - 3
direct/src/showutil/pfreeze.py

@@ -102,15 +102,16 @@ elif bl.endswith('.exe'):
     basename = os.path.splitext(basename)[0]
     basename = os.path.splitext(basename)[0]
 
 
 startfile = args[0]
 startfile = args[0]
+startmod = startfile
 if startfile.endswith('.py') or startfile.endswith('.pyw') or \
 if startfile.endswith('.py') or startfile.endswith('.pyw') or \
    startfile.endswith('.pyc') or startfile.endswith('.pyo'):
    startfile.endswith('.pyc') or startfile.endswith('.pyo'):
-    startfile = os.path.splitext(startfile)[0]
+    startmod = os.path.splitext(startfile)[0]
 
 
 compileToExe = False
 compileToExe = False
 if outputType == 'dll':
 if outputType == 'dll':
-    freezer.addModule(startfile)
+    freezer.addModule(startmod, filename = startfile)
 else:
 else:
-    freezer.addModule(startfile, newName = '__main__')
+    freezer.addModule('__main__', filename = startfile)
     compileToExe = True
     compileToExe = True
 
 
 freezer.done(compileToExe = compileToExe)
 freezer.done(compileToExe = compileToExe)

+ 0 - 8
dtool/src/dtoolbase/cmath.I

@@ -390,11 +390,7 @@ cinf(double v) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE float
 INLINE float
 make_nan(float) {
 make_nan(float) {
-#ifndef _WIN32
-  return nanf("");
-#else
   return std::numeric_limits<float>::quiet_NaN();
   return std::numeric_limits<float>::quiet_NaN();
-#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -403,11 +399,7 @@ make_nan(float) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE double
 INLINE double
 make_nan(double) {
 make_nan(double) {
-#ifndef _WIN32
-  return nan("");
-#else
   return std::numeric_limits<double>::quiet_NaN();
   return std::numeric_limits<double>::quiet_NaN();
-#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 20 - 0
dtool/src/dtoolutil/executionEnvironment.I

@@ -119,3 +119,23 @@ INLINE string ExecutionEnvironment::
 get_dtool_name() {
 get_dtool_name() {
   return get_ptr()->ns_get_dtool_name();
   return get_ptr()->ns_get_dtool_name();
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ExecutionEnvironment::set_binary_name
+//       Access: Public, Static
+//  Description: Do not use.
+////////////////////////////////////////////////////////////////////
+INLINE void ExecutionEnvironment::
+set_binary_name(const string &name) {
+  get_ptr()->_binary_name = name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ExecutionEnvironment::set_dtool_name
+//       Access: Public, Static
+//  Description: Do not use.
+////////////////////////////////////////////////////////////////////
+INLINE void ExecutionEnvironment::
+set_dtool_name(const string &name) {
+  get_ptr()->_dtool_name = name;
+}

+ 53 - 13
dtool/src/dtoolutil/executionEnvironment.cxx

@@ -31,6 +31,9 @@
 // And this is for GetModuleFileName().
 // And this is for GetModuleFileName().
 #include <windows.h>
 #include <windows.h>
 
 
+// And this is for CommandLineToArgvW.
+#include <shellapi.h>
+
 // SHGetSpecialFolderPath()
 // SHGetSpecialFolderPath()
 #include <shlobj.h>
 #include <shlobj.h>
 #endif
 #endif
@@ -74,12 +77,11 @@ extern char **environ;
 #define PREREAD_ENVIRONMENT
 #define PREREAD_ENVIRONMENT
 #endif
 #endif
 
 
-
 // We define the symbol HAVE_GLOBAL_ARGV if we have global variables
 // We define the symbol HAVE_GLOBAL_ARGV if we have global variables
 // named GLOBAL_ARGC/GLOBAL_ARGV that we can read at static init time
 // named GLOBAL_ARGC/GLOBAL_ARGV that we can read at static init time
 // to determine our command-line arguments.
 // to determine our command-line arguments.
 
 
-#if defined(HAVE_GLOBAL_ARGV) && defined(PROTOTYPE_GLOBAL_ARGV)
+#if !defined(WIN32_VC) && defined(HAVE_GLOBAL_ARGV) && defined(PROTOTYPE_GLOBAL_ARGV)
 extern char **GLOBAL_ARGV;
 extern char **GLOBAL_ARGV;
 extern int GLOBAL_ARGC;
 extern int GLOBAL_ARGC;
 #endif
 #endif
@@ -298,7 +300,7 @@ ns_get_environment_variable(const string &var) const {
 #endif
 #endif
         }
         }
       }
       }
-      
+
       PyGILState_Release(state);
       PyGILState_Release(state);
 
 
       if (main_dir.empty()) {
       if (main_dir.empty()) {
@@ -613,7 +615,7 @@ read_environment_variables() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ExecutionEnvironment::
 void ExecutionEnvironment::
 read_args() {
 read_args() {
-
+#ifndef ANDROID
   // First, we need to fill in _dtool_name.  This contains
   // First, we need to fill in _dtool_name.  This contains
   // the full path to the p3dtool library.
   // the full path to the p3dtool library.
 
 
@@ -762,7 +764,39 @@ read_args() {
   // Next we need to fill in _args, which is a vector containing
   // Next we need to fill in _args, which is a vector containing
   // the command-line arguments that the executable was invoked with.
   // the command-line arguments that the executable was invoked with.
 
 
-#if defined(IS_FREEBSD)
+#if defined(WIN32_VC)
+
+  // We cannot rely on __argv when Python is linked in Unicode mode.
+  // Instead, let's use GetCommandLine.
+
+  LPWSTR cmdline = GetCommandLineW();
+  int argc = 0;
+  LPWSTR *wargv = CommandLineToArgvW(cmdline, &argc);
+
+  if (wargv == NULL) {
+    cerr << "CommandLineToArgvW failed; command-line arguments unavailable to config.\n";
+
+  } else {
+    TextEncoder encoder;
+    encoder.set_encoding(Filename::get_filesystem_encoding());
+
+    for (int i = 0; i < argc; ++i) {
+      wstring wtext(wargv[i]);
+      encoder.set_wtext(wtext);
+
+      if (i == 0) {
+        if (_binary_name.empty()) {
+          _binary_name = encoder.get_text();
+        }
+      } else {
+        _args.push_back(encoder.get_text());
+      }
+    }
+
+    LocalFree(wargv);
+  }
+
+#elif defined(IS_FREEBSD)
   // In FreeBSD, we can use sysctl to determine the command-line arguments.
   // In FreeBSD, we can use sysctl to determine the command-line arguments.
 
 
   size_t bufsize = 4096;
   size_t bufsize = 4096;
@@ -786,13 +820,17 @@ read_args() {
 #elif defined(HAVE_GLOBAL_ARGV)
 #elif defined(HAVE_GLOBAL_ARGV)
   int argc = GLOBAL_ARGC;
   int argc = GLOBAL_ARGC;
 
 
-  if (_binary_name.empty() && argc > 0) {
-    _binary_name = GLOBAL_ARGV[0];
-    // This really needs to be resolved against PATH.
-  }
+  // On Windows, __argv can be NULL when the main entry point is
+  // compiled in Unicode mode (as is the case with Python 3)
+  if (GLOBAL_ARGV != NULL) {
+    if (_binary_name.empty() && argc > 0) {
+      _binary_name = GLOBAL_ARGV[0];
+      // This really needs to be resolved against PATH.
+    }
 
 
-  for (int i = 1; i < argc; i++) {
-    _args.push_back(GLOBAL_ARGV[i]);
+    for (int i = 1; i < argc; i++) {
+      _args.push_back(GLOBAL_ARGV[i]);
+    }
   }
   }
 
 
 #elif defined(HAVE_PROC_SELF_CMDLINE) || defined(HAVE_PROC_CURPROC_CMDLINE)
 #elif defined(HAVE_PROC_SELF_CMDLINE) || defined(HAVE_PROC_CURPROC_CMDLINE)
@@ -835,7 +873,7 @@ read_args() {
   }
   }
 #endif
 #endif
 
 
-#ifndef WIN32
+#ifndef _WIN32
   // Try to use realpath to get cleaner paths.
   // Try to use realpath to get cleaner paths.
 
 
   if (!_binary_name.empty()) {
   if (!_binary_name.empty()) {
@@ -851,7 +889,9 @@ read_args() {
       _dtool_name = newpath;
       _dtool_name = newpath;
     }
     }
   }
   }
-#endif
+#endif  // _WIN32
+
+#endif  // ANDROID
 
 
   if (_dtool_name.empty()) {
   if (_dtool_name.empty()) {
     _dtool_name = _binary_name;
     _dtool_name = _binary_name;

+ 3 - 0
dtool/src/dtoolutil/executionEnvironment.h

@@ -50,6 +50,9 @@ PUBLISHED:
   INLINE static string get_binary_name();
   INLINE static string get_binary_name();
   INLINE static string get_dtool_name();
   INLINE static string get_dtool_name();
 
 
+  INLINE static void set_binary_name(const string &name);
+  INLINE static void set_dtool_name(const string &name);
+
   static Filename get_cwd();
   static Filename get_cwd();
 
 
 private:
 private:

+ 29 - 6
dtool/src/dtoolutil/filename.cxx

@@ -61,6 +61,10 @@ TVOLATILE AtomicAdjust::Pointer Filename::_user_appdata_directory;
 TVOLATILE AtomicAdjust::Pointer Filename::_common_appdata_directory;
 TVOLATILE AtomicAdjust::Pointer Filename::_common_appdata_directory;
 TypeHandle Filename::_type_handle;
 TypeHandle Filename::_type_handle;
 
 
+#ifdef ANDROID
+string Filename::_internal_data_dir;
+#endif
+
 #ifdef WIN32
 #ifdef WIN32
 /* begin Win32-specific code */
 /* begin Win32-specific code */
 
 
@@ -463,7 +467,7 @@ Filename Filename::
 temporary(const string &dirname, const string &prefix, const string &suffix,
 temporary(const string &dirname, const string &prefix, const string &suffix,
           Type type) {
           Type type) {
   Filename fdirname = dirname;
   Filename fdirname = dirname;
-#ifdef WIN32
+#if defined(_WIN32) || defined(ANDROID)
   // The Windows tempnam() function doesn't do a good job of choosing
   // The Windows tempnam() function doesn't do a good job of choosing
   // a temporary directory.  Choose one ourselves.
   // a temporary directory.  Choose one ourselves.
   if (fdirname.empty()) {
   if (fdirname.empty()) {
@@ -527,7 +531,7 @@ get_home_directory() {
     if (home_directory.empty()) {
     if (home_directory.empty()) {
 #ifdef WIN32
 #ifdef WIN32
       wchar_t buffer[MAX_PATH];
       wchar_t buffer[MAX_PATH];
-      
+
       // On Windows, fall back to the "My Documents" folder.
       // On Windows, fall back to the "My Documents" folder.
       if (SHGetSpecialFolderPathW(NULL, buffer, CSIDL_PERSONAL, true)) {
       if (SHGetSpecialFolderPathW(NULL, buffer, CSIDL_PERSONAL, true)) {
         Filename dirname = from_os_specific_w(buffer);
         Filename dirname = from_os_specific_w(buffer);
@@ -538,15 +542,22 @@ get_home_directory() {
         }
         }
       }
       }
 
 
+#elif defined(ANDROID)
+      // Temporary hack.
+      home_directory = "/data/data/org.panda3d.sdk";
+
 #elif defined(IS_OSX)
 #elif defined(IS_OSX)
       home_directory = get_osx_home_directory();
       home_directory = get_osx_home_directory();
-      
+
+#elif defined(ANDROID)
+      home_directory = _internal_data_dir;
+
 #else
 #else
       // Posix case: check /etc/passwd?
       // Posix case: check /etc/passwd?
-      
+
 #endif  // WIN32
 #endif  // WIN32
     }
     }
-      
+
     if (home_directory.empty()) {
     if (home_directory.empty()) {
       // Fallback case.
       // Fallback case.
       home_directory = ExecutionEnvironment::get_cwd();
       home_directory = ExecutionEnvironment::get_cwd();
@@ -559,7 +570,7 @@ get_home_directory() {
       delete newdir;
       delete newdir;
     }
     }
   }
   }
-  
+
   return (*(Filename *)_home_directory);
   return (*(Filename *)_home_directory);
 }
 }
 
 
@@ -589,6 +600,10 @@ get_temp_directory() {
 #elif defined(IS_OSX)
 #elif defined(IS_OSX)
     temp_directory = get_osx_temp_directory();
     temp_directory = get_osx_temp_directory();
 
 
+#elif defined(ANDROID)
+    temp_directory.set_dirname(_internal_data_dir);
+    temp_directory.set_basename("cache");
+
 #else
 #else
     // Posix case.
     // Posix case.
     temp_directory = "/tmp";
     temp_directory = "/tmp";
@@ -638,6 +653,10 @@ get_user_appdata_directory() {
 #elif defined(IS_OSX)
 #elif defined(IS_OSX)
     user_appdata_directory = get_osx_user_appdata_directory();
     user_appdata_directory = get_osx_user_appdata_directory();
 
 
+#elif defined(ANDROID)
+    user_appdata_directory.set_dirname(_internal_data_dir);
+    user_appdata_directory.set_basename("files");
+
 #else
 #else
     // Posix case.
     // Posix case.
     user_appdata_directory = get_home_directory();
     user_appdata_directory = get_home_directory();
@@ -687,6 +706,10 @@ get_common_appdata_directory() {
 #elif defined(IS_OSX)
 #elif defined(IS_OSX)
     common_appdata_directory = get_osx_common_appdata_directory();
     common_appdata_directory = get_osx_common_appdata_directory();
 
 
+#elif defined(ANDROID)
+    common_appdata_directory.set_dirname(_internal_data_dir);
+    common_appdata_directory.set_basename("files");
+
 #else
 #else
     // Posix case.
     // Posix case.
     common_appdata_directory = "/var";
     common_appdata_directory = "/var";

+ 5 - 0
dtool/src/dtoolutil/filename.h

@@ -263,6 +263,11 @@ protected:
   static TVOLATILE AtomicAdjust::Pointer _user_appdata_directory;
   static TVOLATILE AtomicAdjust::Pointer _user_appdata_directory;
   static TVOLATILE AtomicAdjust::Pointer _common_appdata_directory;
   static TVOLATILE AtomicAdjust::Pointer _common_appdata_directory;
 
 
+#ifdef ANDROID
+public:
+  static string _internal_data_dir;
+#endif
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 34 - 2
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -2743,7 +2743,9 @@ int GetParnetDepth(CPPType *type) {
   } else if (TypeManager::is_wchar_pointer(type)) {
   } else if (TypeManager::is_wchar_pointer(type)) {
   } else if (TypeManager::is_pointer_to_PyObject(type)) {
   } else if (TypeManager::is_pointer_to_PyObject(type)) {
   } else if (TypeManager::is_pointer_to_Py_buffer(type)) {
   } else if (TypeManager::is_pointer_to_Py_buffer(type)) {
-  } else if (TypeManager::is_pointer(type) || TypeManager::is_reference(type) || TypeManager::is_struct(type)) {
+  } else if (TypeManager::is_pointer(type) ||
+             TypeManager::is_reference(type) ||
+             TypeManager::is_struct(type)) {
     ++answer;
     ++answer;
     int deepest = 0;
     int deepest = 0;
     TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(type)), false);
     TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(type)), false);
@@ -3276,6 +3278,36 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
       only_pyobjects = false;
       only_pyobjects = false;
       ++num_params;
       ++num_params;
 
 
+    } else if (TypeManager::is_pointer_to_PyStringObject(type)) {
+      if (args_type == AT_single_arg) {
+        // This is a single-arg function, so there's no need
+        // to convert anything.
+        param_name = "arg";
+        extra_param_check += " && PyString_Check(arg)";
+      } else {
+        indent(out, indent_level) << "PyStringObject *" << param_name << ";\n";
+        format_specifiers += "S";
+        parameter_list += ", &" + param_name;
+      }
+      pexpr_string = param_name;
+      expected_params += "string";
+      ++num_params;
+
+    } else if (TypeManager::is_pointer_to_PyUnicodeObject(type)) {
+      if (args_type == AT_single_arg) {
+        // This is a single-arg function, so there's no need
+        // to convert anything.
+        param_name = "arg";
+        extra_param_check += " && PyUnicode_Check(arg)";
+      } else {
+        indent(out, indent_level) << "PyUnicodeObject *" << param_name << ";\n";
+        format_specifiers += "U";
+        parameter_list += ", &" + param_name;
+      }
+      pexpr_string = param_name;
+      expected_params += "unicode";
+      ++num_params;
+
     } else if (TypeManager::is_pointer_to_PyObject(type)) {
     } else if (TypeManager::is_pointer_to_PyObject(type)) {
       if (args_type == AT_single_arg) {
       if (args_type == AT_single_arg) {
         // This is a single-arg function, so there's no need
         // This is a single-arg function, so there's no need
@@ -3605,7 +3637,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
   if (true) {
   if (true) {
     indent(out, indent_level)
     indent(out, indent_level)
       << "if (PyErr_Occurred()) {\n";
       << "if (PyErr_Occurred()) {\n";
-    delete_return_value(out, indent_level, remap, return_expr);
+    delete_return_value(out, indent_level + 2, remap, return_expr);
     indent(out, indent_level)
     indent(out, indent_level)
       << "  if (PyErr_ExceptionMatches(PyExc_TypeError)) {\n";
       << "  if (PyErr_ExceptionMatches(PyExc_TypeError)) {\n";
     indent(out, indent_level)
     indent(out, indent_level)

+ 85 - 1
dtool/src/interrogate/typeManager.cxx

@@ -1199,8 +1199,91 @@ is_PyObject(CPPType *type) {
     return is_PyObject(type->as_const_type()->_wrapped_around);
     return is_PyObject(type->as_const_type()->_wrapped_around);
 
 
   case CPPDeclaration::ST_extension:
   case CPPDeclaration::ST_extension:
+  case CPPDeclaration::ST_struct:
     return (type->get_local_name(&parser) == "PyObject" ||
     return (type->get_local_name(&parser) == "PyObject" ||
-            type->get_local_name(&parser) == "_object");
+            type->get_local_name(&parser) == "PyTypeObject" ||
+            type->get_local_name(&parser) == "PyStringObject" ||
+            type->get_local_name(&parser) == "PyUnicodeObject" ||
+            type->get_local_name(&parser) == "_object" ||
+            type->get_local_name(&parser) == "_typeobject");
+
+  default:
+    return false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_pointer_to_PyStringObject
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is PyStringObject *.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_pointer_to_PyStringObject(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_pointer_to_PyStringObject(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_pointer:
+    return is_PyStringObject(type->as_pointer_type()->_pointing_at);
+
+  default:
+    return false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_PyStringObject
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is PyStringObject.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_PyStringObject(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_PyStringObject(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_extension:
+  case CPPDeclaration::ST_struct:
+    return (type->get_local_name(&parser) == "PyStringObject");
+
+  default:
+    return false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_pointer_to_PyUnicodeObject
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is PyStringObject *.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_pointer_to_PyUnicodeObject(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_pointer_to_PyUnicodeObject(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_pointer:
+    return is_PyUnicodeObject(type->as_pointer_type()->_pointing_at);
+
+  default:
+    return false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::is_PyUnicodeObject
+//       Access: Public, Static
+//  Description: Returns true if the indicated type is PyUnicodeObject.
+////////////////////////////////////////////////////////////////////
+bool TypeManager::
+is_PyUnicodeObject(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_PyUnicodeObject(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_extension:
+  case CPPDeclaration::ST_struct:
+    return (type->get_local_name(&parser) == "PyUnicodeObject");
 
 
   default:
   default:
     return false;
     return false;
@@ -1238,6 +1321,7 @@ is_Py_buffer(CPPType *type) {
     return is_Py_buffer(type->as_const_type()->_wrapped_around);
     return is_Py_buffer(type->as_const_type()->_wrapped_around);
 
 
   case CPPDeclaration::ST_extension:
   case CPPDeclaration::ST_extension:
+  case CPPDeclaration::ST_struct:
     return (type->get_local_name(&parser) == "Py_buffer");
     return (type->get_local_name(&parser) == "Py_buffer");
 
 
   default:
   default:

+ 4 - 0
dtool/src/interrogate/typeManager.h

@@ -94,6 +94,10 @@ public:
   static bool is_const_ref_to_pointer_to_base(CPPType *type);
   static bool is_const_ref_to_pointer_to_base(CPPType *type);
   static bool is_pointer_to_PyObject(CPPType *type);
   static bool is_pointer_to_PyObject(CPPType *type);
   static bool is_PyObject(CPPType *type);
   static bool is_PyObject(CPPType *type);
+  static bool is_pointer_to_PyStringObject(CPPType *type);
+  static bool is_PyStringObject(CPPType *type);
+  static bool is_pointer_to_PyUnicodeObject(CPPType *type);
+  static bool is_PyUnicodeObject(CPPType *type);
   static bool is_pointer_to_Py_buffer(CPPType *type);
   static bool is_pointer_to_Py_buffer(CPPType *type);
   static bool is_Py_buffer(CPPType *type);
   static bool is_Py_buffer(CPPType *type);
   static bool involves_unpublished(CPPType *type);
   static bool involves_unpublished(CPPType *type);

+ 6 - 0
dtool/src/parser-inc/Python.h

@@ -23,6 +23,12 @@
 struct _object;
 struct _object;
 typedef _object PyObject;
 typedef _object PyObject;
 
 
+struct _typeobject;
+typedef _typeobject PyTypeObject;
+
+struct PyStringObject;
+struct PyUnicodeObject;
+
 class PyThreadState;
 class PyThreadState;
 typedef int Py_ssize_t;
 typedef int Py_ssize_t;
 struct Py_buffer;
 struct Py_buffer;

+ 2 - 0
dtool/src/parser-inc/android/asset_manager.h

@@ -0,0 +1,2 @@
+struct AAssetManager;
+struct AAsset;

+ 39 - 0
dtool/src/parser-inc/jni.h

@@ -0,0 +1,39 @@
+typedef unsigned char   jboolean;       /* unsigned 8 bits */
+typedef signed char     jbyte;          /* signed 8 bits */
+typedef unsigned short  jchar;          /* unsigned 16 bits */
+typedef short           jshort;         /* signed 16 bits */
+typedef int             jint;           /* signed 32 bits */
+typedef long long       jlong;          /* signed 64 bits */
+typedef float           jfloat;         /* 32-bit IEEE 754 */
+typedef double          jdouble;        /* 64-bit IEEE 754 */
+
+typedef jint jsize;
+
+typedef void*           jobject;
+typedef jobject         jclass;
+typedef jobject         jstring;
+typedef jobject         jarray;
+typedef jarray          jobjectArray;
+typedef jarray          jbooleanArray;
+typedef jarray          jbyteArray;
+typedef jarray          jcharArray;
+typedef jarray          jshortArray;
+typedef jarray          jintArray;
+typedef jarray          jlongArray;
+typedef jarray          jfloatArray;
+typedef jarray          jdoubleArray;
+typedef jobject         jthrowable;
+typedef jobject         jweak;
+
+struct _jfieldID;                       /* opaque structure */
+typedef struct _jfieldID* jfieldID;     /* field IDs */
+
+struct _jmethodID;                      /* opaque structure */
+typedef struct _jmethodID* jmethodID;   /* method IDs */
+
+struct JNIInvokeInterface;
+
+struct _JNIEnv;
+struct _JavaVM;
+typedef _JNIEnv JNIEnv;
+typedef _JavaVM JavaVM;

+ 8 - 0
dtool/src/pystub/pystub.cxx

@@ -121,6 +121,8 @@ extern "C" {
   EXPCL_PYSTUB int PyString_AsStringAndSize(...);
   EXPCL_PYSTUB int PyString_AsStringAndSize(...);
   EXPCL_PYSTUB int PyString_FromString(...);
   EXPCL_PYSTUB int PyString_FromString(...);
   EXPCL_PYSTUB int PyString_FromStringAndSize(...);
   EXPCL_PYSTUB int PyString_FromStringAndSize(...);
+  EXPCL_PYSTUB int PyString_InternFromString(...);
+  EXPCL_PYSTUB int PyString_InternInPlace(...);
   EXPCL_PYSTUB int PyString_Size(...);
   EXPCL_PYSTUB int PyString_Size(...);
   EXPCL_PYSTUB int PyString_Type(...);
   EXPCL_PYSTUB int PyString_Type(...);
   EXPCL_PYSTUB int PySys_GetObject(...);
   EXPCL_PYSTUB int PySys_GetObject(...);
@@ -152,6 +154,8 @@ extern "C" {
   EXPCL_PYSTUB int PyUnicode_FromStringAndSize(...);
   EXPCL_PYSTUB int PyUnicode_FromStringAndSize(...);
   EXPCL_PYSTUB int PyUnicode_FromWideChar(...);
   EXPCL_PYSTUB int PyUnicode_FromWideChar(...);
   EXPCL_PYSTUB int PyUnicode_GetSize(...);
   EXPCL_PYSTUB int PyUnicode_GetSize(...);
+  EXPCL_PYSTUB int PyUnicode_InternFromString(...);
+  EXPCL_PYSTUB int PyUnicode_InternInPlace(...);
   EXPCL_PYSTUB int PyUnicode_Type(...);
   EXPCL_PYSTUB int PyUnicode_Type(...);
   EXPCL_PYSTUB int Py_BuildValue(...);
   EXPCL_PYSTUB int Py_BuildValue(...);
   EXPCL_PYSTUB int Py_InitModule4(...);
   EXPCL_PYSTUB int Py_InitModule4(...);
@@ -296,6 +300,8 @@ int PyString_AsString(...) { return 0; }
 int PyString_AsStringAndSize(...) { return 0; }
 int PyString_AsStringAndSize(...) { return 0; }
 int PyString_FromString(...) { return 0; }
 int PyString_FromString(...) { return 0; }
 int PyString_FromStringAndSize(...) { return 0; }
 int PyString_FromStringAndSize(...) { return 0; }
+int PyString_InternFromString(...) { return 0; }
+int PyString_InternInPlace(...) { return 0; }
 int PyString_Size(...) { return 0; }
 int PyString_Size(...) { return 0; }
 int PyString_Type(...) { return 0; }
 int PyString_Type(...) { return 0; }
 int PySys_GetObject(...) { return 0; }
 int PySys_GetObject(...) { return 0; }
@@ -327,6 +333,8 @@ int PyUnicode_FromString(...) { return 0; }
 int PyUnicode_FromStringAndSize(...) { return 0; }
 int PyUnicode_FromStringAndSize(...) { return 0; }
 int PyUnicode_FromWideChar(...) { return 0; }
 int PyUnicode_FromWideChar(...) { return 0; }
 int PyUnicode_GetSize(...) { return 0; }
 int PyUnicode_GetSize(...) { return 0; }
+int PyUnicode_InternFromString(...) { return 0; }
+int PyUnicode_InternInPlace(...) { return 0; }
 int PyUnicode_Type(...) { return 0; }
 int PyUnicode_Type(...) { return 0; }
 int Py_BuildValue(...) { return 0; }
 int Py_BuildValue(...) { return 0; }
 int Py_InitModule4(...) { return 0; }
 int Py_InitModule4(...) { return 0; }

+ 80 - 62
makepanda/makepanda.py

@@ -30,8 +30,8 @@ import time
 import os
 import os
 import sys
 import sys
 
 
-## jGenPyCode tries to get the directory for Direct from the sys.path. This only works if you 
-## have installed the sdk using a installer. This would not work if the installer was 
+## jGenPyCode tries to get the directory for Direct from the sys.path. This only works if you
+## have installed the sdk using a installer. This would not work if the installer was
 ## never used and everything was grabbed into a virgin environment using cvs.
 ## never used and everything was grabbed into a virgin environment using cvs.
 sys.path.append(os.getcwd())
 sys.path.append(os.getcwd())
 
 
@@ -88,14 +88,14 @@ PkgListSet(["PYTHON", "DIRECT",                        # Python support
   "VRPN", "OPENSSL",                                   # Transport
   "VRPN", "OPENSSL",                                   # Transport
   "FFTW",                                              # Algorithm helpers
   "FFTW",                                              # Algorithm helpers
   "ARTOOLKIT", "OPENCV", "DIRECTCAM", "VISION",        # Augmented Reality
   "ARTOOLKIT", "OPENCV", "DIRECTCAM", "VISION",        # Augmented Reality
-  "NPAPI", "AWESOMIUM",                                # Browser embedding
-  "GTK2", "WX", "FLTK",                                # Toolkit support
-  "ROCKET",                                            # GUI libraries
+  "GTK2",                                              # GTK2 is used for PStats on Unix
+  "NPAPI", "MFC", "WX", "FLTK",                        # Used for web plug-in only
+  "ROCKET", "AWESOMIUM",                               # GUI libraries
   "CARBON", "COCOA",                                   # Mac OS X toolkits
   "CARBON", "COCOA",                                   # Mac OS X toolkits
   "X11", "XF86DGA", "XRANDR", "XCURSOR",               # Unix platform support
   "X11", "XF86DGA", "XRANDR", "XCURSOR",               # Unix platform support
   "PANDATOOL", "PVIEW", "DEPLOYTOOLS",                 # Toolchain
   "PANDATOOL", "PVIEW", "DEPLOYTOOLS",                 # Toolchain
   "SKEL",                                              # Example SKEL project
   "SKEL",                                              # Example SKEL project
-  "PANDAFX",                                           # Some distortion special lenses 
+  "PANDAFX",                                           # Some distortion special lenses
   "PANDAPARTICLESYSTEM",                               # Built in particle system
   "PANDAPARTICLESYSTEM",                               # Built in particle system
   "CONTRIB",                                           # Experimental
   "CONTRIB",                                           # Experimental
   "SSE2", "NEON",                                      # Compiler features
   "SSE2", "NEON",                                      # Compiler features
@@ -216,7 +216,7 @@ def parseopts(args):
                 if STRDXSDKVERSION == '':
                 if STRDXSDKVERSION == '':
                     print("No DirectX SDK version specified. Using 'default' DirectX SDK search")
                     print("No DirectX SDK version specified. Using 'default' DirectX SDK search")
                     STRDXSDKVERSION = 'default'
                     STRDXSDKVERSION = 'default'
-            elif (option=="--platform-sdk"): 
+            elif (option=="--platform-sdk"):
                 STRMSPLATFORMVERSION = value.strip().lower()
                 STRMSPLATFORMVERSION = value.strip().lower()
                 if STRMSPLATFORMVERSION == '':
                 if STRMSPLATFORMVERSION == '':
                     print("No MS Platform SDK version specified. Using 'default' MS Platform SDK search")
                     print("No MS Platform SDK version specified. Using 'default' MS Platform SDK search")
@@ -234,7 +234,7 @@ def parseopts(args):
             if  (option=="--everything" or option.startswith("--use-")
             if  (option=="--everything" or option.startswith("--use-")
               or option=="--nothing" or option.startswith("--no-")):
               or option=="--nothing" or option.startswith("--no-")):
               anything = 1
               anything = 1
-    except: 
+    except:
         usage(0)
         usage(0)
         print("Exception while parsing commandline:", sys.exc_info()[0])
         print("Exception while parsing commandline:", sys.exc_info()[0])
     if (anything==0): usage(0)
     if (anything==0): usage(0)
@@ -492,7 +492,7 @@ if (COMPILER == "MSVC"):
                 LibName(pkg, 'dxerr.lib')
                 LibName(pkg, 'dxerr.lib')
             else:
             else:
                 LibName(pkg, 'dxerrVNUM.lib'.replace("VNUM", vnum))
                 LibName(pkg, 'dxerrVNUM.lib'.replace("VNUM", vnum))
-            LibName(pkg, 'ddraw.lib')
+            #LibName(pkg, 'ddraw.lib')
             LibName(pkg, 'dxguid.lib')
             LibName(pkg, 'dxguid.lib')
     IncDirectory("ALWAYS", GetThirdpartyDir() + "extras/include")
     IncDirectory("ALWAYS", GetThirdpartyDir() + "extras/include")
     LibName("WINSOCK", "wsock32.lib")
     LibName("WINSOCK", "wsock32.lib")
@@ -536,7 +536,6 @@ if (COMPILER == "MSVC"):
     if (PkgSkip("FFTW")==0):     LibName("FFTW",     GetThirdpartyDir() + "fftw/lib/fftw.lib")
     if (PkgSkip("FFTW")==0):     LibName("FFTW",     GetThirdpartyDir() + "fftw/lib/fftw.lib")
     if (PkgSkip("ARTOOLKIT")==0):LibName("ARTOOLKIT",GetThirdpartyDir() + "artoolkit/lib/libAR.lib")
     if (PkgSkip("ARTOOLKIT")==0):LibName("ARTOOLKIT",GetThirdpartyDir() + "artoolkit/lib/libAR.lib")
     if (PkgSkip("FCOLLADA")==0): LibName("FCOLLADA", GetThirdpartyDir() + "fcollada/lib/FCollada.lib")
     if (PkgSkip("FCOLLADA")==0): LibName("FCOLLADA", GetThirdpartyDir() + "fcollada/lib/FCollada.lib")
-    if (PkgSkip("SQUISH")==0):   LibName("SQUISH",   GetThirdpartyDir() + "squish/lib/squish.lib")
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/cv.lib")
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/cv.lib")
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/highgui.lib")
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/highgui.lib")
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/cvaux.lib")
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/cvaux.lib")
@@ -548,6 +547,11 @@ if (COMPILER == "MSVC"):
     if (PkgSkip("FFMPEG")==0):   LibName("FFMPEG",   GetThirdpartyDir() + "ffmpeg/lib/avutil.lib")
     if (PkgSkip("FFMPEG")==0):   LibName("FFMPEG",   GetThirdpartyDir() + "ffmpeg/lib/avutil.lib")
     if (PkgSkip("SWSCALE")==0):  LibName("SWSCALE",  GetThirdpartyDir() + "ffmpeg/lib/swscale.lib")
     if (PkgSkip("SWSCALE")==0):  LibName("SWSCALE",  GetThirdpartyDir() + "ffmpeg/lib/swscale.lib")
     if (PkgSkip("SWRESAMPLE")==0):LibName("SWRESAMPLE",GetThirdpartyDir() + "ffmpeg/lib/swresample.lib")
     if (PkgSkip("SWRESAMPLE")==0):LibName("SWRESAMPLE",GetThirdpartyDir() + "ffmpeg/lib/swresample.lib")
+    if (PkgSkip("SQUISH")==0):
+        if GetOptimize() <= 2:
+            LibName("SQUISH",   GetThirdpartyDir() + "squish/lib/squishd.lib")
+        else:
+            LibName("SQUISH",   GetThirdpartyDir() + "squish/lib/squish.lib")
     if (PkgSkip("ROCKET")==0):
     if (PkgSkip("ROCKET")==0):
         LibName("ROCKET", GetThirdpartyDir() + "rocket/lib/RocketCore.lib")
         LibName("ROCKET", GetThirdpartyDir() + "rocket/lib/RocketCore.lib")
         LibName("ROCKET", GetThirdpartyDir() + "rocket/lib/RocketControls.lib")
         LibName("ROCKET", GetThirdpartyDir() + "rocket/lib/RocketControls.lib")
@@ -663,21 +667,6 @@ if (COMPILER=="GCC"):
         IncDirectory("ALWAYS", "/usr/local/include")
         IncDirectory("ALWAYS", "/usr/local/include")
         LibDirectory("ALWAYS", "/usr/local/lib")
         LibDirectory("ALWAYS", "/usr/local/lib")
 
 
-    if GetHost() != "darwin":
-        # Workaround for an issue where pkg-config does not include this path
-        if GetTargetArch() in ("x86_64", "amd64"):
-            if (os.path.isdir("/usr/lib64/glib-2.0/include")):
-                IncDirectory("GTK2", "/usr/lib64/glib-2.0/include")
-            if (os.path.isdir("/usr/lib64/gtk-2.0/include")):
-                IncDirectory("GTK2", "/usr/lib64/gtk-2.0/include")
-
-            if (os.path.isdir("/usr/X11R6/lib64")):
-                LibDirectory("ALWAYS", "/usr/X11R6/lib64")
-            else:
-                LibDirectory("ALWAYS", "/usr/X11R6/lib")
-        else:
-            LibDirectory("ALWAYS", "/usr/X11R6/lib")
-
     fcollada_libs = ("FColladaD", "FColladaSD", "FColladaS")
     fcollada_libs = ("FColladaD", "FColladaSD", "FColladaS")
     # WARNING! The order of the ffmpeg libraries matters!
     # WARNING! The order of the ffmpeg libraries matters!
     ffmpeg_libs = ("libavformat", "libavcodec", "libavutil")
     ffmpeg_libs = ("libavformat", "libavcodec", "libavutil")
@@ -752,6 +741,22 @@ if (COMPILER=="GCC"):
             SmartPkgEnable("XF86DGA", "xxf86dga", "Xxf86dga", "X11/extensions/xf86dga.h")
             SmartPkgEnable("XF86DGA", "xxf86dga", "Xxf86dga", "X11/extensions/xf86dga.h")
             SmartPkgEnable("XCURSOR", "xcursor", "Xcursor", "X11/Xcursor/Xcursor.h")
             SmartPkgEnable("XCURSOR", "xcursor", "Xcursor", "X11/Xcursor/Xcursor.h")
 
 
+    if GetHost() != "darwin":
+        # Workaround for an issue where pkg-config does not include this path
+        if GetTargetArch() in ("x86_64", "amd64"):
+            if (os.path.isdir("/usr/lib64/glib-2.0/include")):
+                IncDirectory("GTK2", "/usr/lib64/glib-2.0/include")
+            if (os.path.isdir("/usr/lib64/gtk-2.0/include")):
+                IncDirectory("GTK2", "/usr/lib64/gtk-2.0/include")
+
+            if not PkgSkip("X11"):
+                if (os.path.isdir("/usr/X11R6/lib64")):
+                    LibDirectory("ALWAYS", "/usr/X11R6/lib64")
+                else:
+                    LibDirectory("ALWAYS", "/usr/X11R6/lib")
+        elif not PkgSkip("X11"):
+            LibDirectory("ALWAYS", "/usr/X11R6/lib")
+
     if (RUNTIME):
     if (RUNTIME):
         # For the runtime, all packages are required
         # For the runtime, all packages are required
         for pkg in ["OPENSSL", "ZLIB", "NPAPI", "JPEG", "PNG"]:
         for pkg in ["OPENSSL", "ZLIB", "NPAPI", "JPEG", "PNG"]:
@@ -924,7 +929,7 @@ def CompileCxx(obj,src,opts):
                 cmd += "/DWINVER=0x601 "
                 cmd += "/DWINVER=0x601 "
             cmd += "/Fo" + obj + " /nologo /c"
             cmd += "/Fo" + obj + " /nologo /c"
             if (GetTargetArch() != 'x64' and PkgSkip("SSE2") == 0):
             if (GetTargetArch() != 'x64' and PkgSkip("SSE2") == 0):
-                cmd += " /arch:SSE2"            
+                cmd += " /arch:SSE2"
             for x in ipath: cmd += " /I" + x
             for x in ipath: cmd += " /I" + x
             for (opt,dir) in INCDIRECTORIES:
             for (opt,dir) in INCDIRECTORIES:
                 if (opt=="ALWAYS") or (opt in opts): cmd += " /I" + BracketNameWithQuotes(dir)
                 if (opt=="ALWAYS") or (opt in opts): cmd += " /I" + BracketNameWithQuotes(dir)
@@ -936,7 +941,7 @@ def CompileCxx(obj,src,opts):
             if (optlevel==1): cmd += " /MDd /Zi /RTCs /GS"
             if (optlevel==1): cmd += " /MDd /Zi /RTCs /GS"
             if (optlevel==2): cmd += " /MDd /Zi"
             if (optlevel==2): cmd += " /MDd /Zi"
             if (optlevel==3): cmd += " /MD /Zi /O2 /Ob2 /Oi /Ot /fp:fast /DFORCE_INLINING"
             if (optlevel==3): cmd += " /MD /Zi /O2 /Ob2 /Oi /Ot /fp:fast /DFORCE_INLINING"
-            if (optlevel==4): 
+            if (optlevel==4):
                cmd += " /MD /Zi /Ox /Ob2 /Oi /Ot /fp:fast /DFORCE_INLINING /DNDEBUG /GL"
                cmd += " /MD /Zi /Ox /Ob2 /Oi /Ot /fp:fast /DFORCE_INLINING /DNDEBUG /GL"
                cmd += " /Oy /Zp16"      # jean-claude add /Zp16 insures correct static alignment for SSEx
                cmd += " /Oy /Zp16"      # jean-claude add /Zp16 insures correct static alignment for SSEx
 
 
@@ -982,11 +987,11 @@ def CompileCxx(obj,src,opts):
             if (optlevel==3):
             if (optlevel==3):
                 cmd += " /MD /Zi /O2 /Oi /Ot /arch:SSE3"
                 cmd += " /MD /Zi /O2 /Oi /Ot /arch:SSE3"
                 cmd += " /Ob0"
                 cmd += " /Ob0"
-                cmd += " /Qipo-"                            # beware of IPO !!!  
+                cmd += " /Qipo-"                            # beware of IPO !!!
             ##      Lesson learned: Don't use /GL flag -> end result is MESSY
             ##      Lesson learned: Don't use /GL flag -> end result is MESSY
             ## ----------------------------------------------------------------
             ## ----------------------------------------------------------------
             if (optlevel==4):
             if (optlevel==4):
-                cmd += " /MD /Zi /O3 /Oi /Ot /Ob0 /Yc /DNDEBUG"  # /Ob0 a ete rajoute en cours de route a 47%                
+                cmd += " /MD /Zi /O3 /Oi /Ot /Ob0 /Yc /DNDEBUG"  # /Ob0 a ete rajoute en cours de route a 47%
                 cmd += " /Qipo"                              # optimization multi file
                 cmd += " /Qipo"                              # optimization multi file
 
 
             # for 3 & 4 optimization levels
             # for 3 & 4 optimization levels
@@ -998,7 +1003,7 @@ def CompileCxx(obj,src,opts):
                 cmd += " /Qopt-matmul"                        # needs /O2 or /O3
                 cmd += " /Qopt-matmul"                        # needs /O2 or /O3
                 cmd += " /Qprec-div-"
                 cmd += " /Qprec-div-"
                 cmd += " /Qsimd"
                 cmd += " /Qsimd"
-                
+
                 cmd += " /QxHost"                            # compile for target host; Compiling for distribs should probably strictly enforce /arch:..
                 cmd += " /QxHost"                            # compile for target host; Compiling for distribs should probably strictly enforce /arch:..
                 cmd += " /Quse-intel-optimized-headers"        # use intel optimized headers
                 cmd += " /Quse-intel-optimized-headers"        # use intel optimized headers
                 cmd += " /Qparallel"                        # enable parallelization
                 cmd += " /Qparallel"                        # enable parallelization
@@ -1006,7 +1011,7 @@ def CompileCxx(obj,src,opts):
 
 
             ## PCH files coexistence: the /Qpchi option causes the Intel C++ Compiler to name its
             ## PCH files coexistence: the /Qpchi option causes the Intel C++ Compiler to name its
             ## PCH files with a .pchi filename suffix and reduce build time.
             ## PCH files with a .pchi filename suffix and reduce build time.
-            ## The /Qpchi option is on by default but interferes with Microsoft libs; so use /Qpchi- to turn it off. 
+            ## The /Qpchi option is on by default but interferes with Microsoft libs; so use /Qpchi- to turn it off.
             ## I need to have a deeper look at this since the compile time is quite influenced by this setting !!!
             ## I need to have a deeper look at this since the compile time is quite influenced by this setting !!!
             cmd += " /Qpchi-"                                 # keep it this way!
             cmd += " /Qpchi-"                                 # keep it this way!
 
 
@@ -1024,7 +1029,7 @@ def CompileCxx(obj,src,opts):
             ## Use this option if you always define a class before you declare a pointer to a member of the class.
             ## Use this option if you always define a class before you declare a pointer to a member of the class.
             ## The compiler will issue an error if it encounters a pointer declaration before the class is defined.
             ## The compiler will issue an error if it encounters a pointer declaration before the class is defined.
             ## Alternate: #pragma pointers_to_members
             ## Alternate: #pragma pointers_to_members
-      
+
             cmd += " /Fd" + os.path.splitext(obj)[0] + ".pdb"
             cmd += " /Fd" + os.path.splitext(obj)[0] + ".pdb"
             building = GetValueOption(opts, "BUILDING:")
             building = GetValueOption(opts, "BUILDING:")
             if (building): cmd += " /DBUILDING_" + building
             if (building): cmd += " /DBUILDING_" + building
@@ -1032,10 +1037,10 @@ def CompileCxx(obj,src,opts):
                 cmd += " /bigobj"
                 cmd += " /bigobj"
 
 
             # level of warnings and optimization reports
             # level of warnings and optimization reports
-            if GetVerbose(): 
+            if GetVerbose():
                 cmd += " /W3 " # or /W4 or /Wall
                 cmd += " /W3 " # or /W4 or /Wall
                 cmd += " /Qopt-report:2 /Qopt-report-phase:hlo /Qopt-report-phase:hpo"    # some optimization reports
                 cmd += " /Qopt-report:2 /Qopt-report-phase:hlo /Qopt-report-phase:hpo"    # some optimization reports
-            else:            
+            else:
                 cmd += " /W1 "
                 cmd += " /W1 "
             cmd += " /EHa /Zm300 /DWIN32_VC /DWIN32"
             cmd += " /EHa /Zm300 /DWIN32_VC /DWIN32"
             if GetTargetArch() == 'x64':
             if GetTargetArch() == 'x64':
@@ -1043,10 +1048,10 @@ def CompileCxx(obj,src,opts):
             cmd += " " + BracketNameWithQuotes(src)
             cmd += " " + BracketNameWithQuotes(src)
 
 
             oscmd(cmd)
             oscmd(cmd)
-            
+
     if (COMPILER=="GCC"):
     if (COMPILER=="GCC"):
         if (src.endswith(".c")): cmd = GetCC() +' -fPIC -c -o ' + obj
         if (src.endswith(".c")): cmd = GetCC() +' -fPIC -c -o ' + obj
-        else:                    cmd = GetCXX()+' -ftemplate-depth-30 -fPIC -c -o ' + obj
+        else:                    cmd = GetCXX()+' -ftemplate-depth-50 -fPIC -c -o ' + obj
         for (opt, dir) in INCDIRECTORIES:
         for (opt, dir) in INCDIRECTORIES:
             if (opt=="ALWAYS") or (opt in opts): cmd += ' -I' + BracketNameWithQuotes(dir)
             if (opt=="ALWAYS") or (opt in opts): cmd += ' -I' + BracketNameWithQuotes(dir)
         for (opt,var,val) in DEFSYMBOLS:
         for (opt,var,val) in DEFSYMBOLS:
@@ -1070,9 +1075,12 @@ def CompileCxx(obj,src,opts):
             cmd += ' --sysroot=%s -no-canonical-prefixes' % (SDK["SYSROOT"])
             cmd += ' --sysroot=%s -no-canonical-prefixes' % (SDK["SYSROOT"])
 
 
         # Android-specific flags.
         # Android-specific flags.
+        arch = GetTargetArch()
+
         if GetTarget() == "android":
         if GetTarget() == "android":
+            cmd += ' -I%s/include' % (SDK["ANDROID_STL"])
+            cmd += ' -I%s/libs/%s/include' % (SDK["ANDROID_STL"], SDK["ANDROID_ABI"])
             cmd += ' -ffunction-sections -funwind-tables'
             cmd += ' -ffunction-sections -funwind-tables'
-            arch = GetTargetArch()
             if arch == 'armv7a':
             if arch == 'armv7a':
                 cmd += ' -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__'
                 cmd += ' -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__'
                 cmd += ' -fstack-protector -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16'
                 cmd += ' -fstack-protector -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16'
@@ -1111,9 +1119,9 @@ def CompileCxx(obj,src,opts):
         else:
         else:
             cmd += " -pthread"
             cmd += " -pthread"
 
 
-        if PkgSkip("SSE2") == 0:
+        if PkgSkip("SSE2") == 0 and not arch.startswith("arm"):
             cmd += " -msse2"
             cmd += " -msse2"
-        
+
         if (optlevel==1): cmd += " -ggdb -D_DEBUG"
         if (optlevel==1): cmd += " -ggdb -D_DEBUG"
         if (optlevel==2): cmd += " -O1 -D_DEBUG"
         if (optlevel==2): cmd += " -O1 -D_DEBUG"
         if (optlevel==3): cmd += " -O2"
         if (optlevel==3): cmd += " -O2"
@@ -1217,7 +1225,7 @@ def CompileIgate(woutd,wsrc,opts):
         # NOTE: this 1600 value is the version number for VC2010.
         # NOTE: this 1600 value is the version number for VC2010.
         cmd += ' -D_MSC_VER=1600 -D"_declspec(param)=" -D_near -D_far -D__near -D__far -D__stdcall'
         cmd += ' -D_MSC_VER=1600 -D"_declspec(param)=" -D_near -D_far -D__near -D__far -D__stdcall'
     if (COMPILER=="GCC"):
     if (COMPILER=="GCC"):
-        cmd += ' -DCPPPARSER -D__STDC__=1 -D__cplusplus -D__inline -D__const=const'
+        cmd += ' -DCPPPARSER -D__STDC__=1 -D__cplusplus -D__inline -D__const=const -D__attribute__\(x\)='
         if GetTargetArch() in ("x86_64", "amd64"):
         if GetTargetArch() in ("x86_64", "amd64"):
             cmd += ' -D_LP64'
             cmd += ' -D_LP64'
         else:
         else:
@@ -1339,7 +1347,7 @@ def CompileLink(dll, obj, opts):
             if ("MFC" not in opts):
             if ("MFC" not in opts):
                 cmd += " /NOD:MFC90.LIB /NOD:MFC80.LIB /NOD:LIBCMT"
                 cmd += " /NOD:MFC90.LIB /NOD:MFC80.LIB /NOD:LIBCMT"
             cmd += " /NOD:LIBCI.LIB /DEBUG"
             cmd += " /NOD:LIBCI.LIB /DEBUG"
-            cmd += " /nod:libc /nod:libcmtd /nod:atlthunk /nod:atls"
+            cmd += " /nod:libc /nod:libcmtd /nod:atlthunk /nod:atls /nod:atlsd"
             if (GetOrigExt(dll) != ".exe"): cmd += " /DLL"
             if (GetOrigExt(dll) != ".exe"): cmd += " /DLL"
             optlevel = GetOptimizeOption(opts)
             optlevel = GetOptimizeOption(opts)
             if (optlevel==1): cmd += " /MAP /MAPINFO:EXPORTS /NOD:MSVCRT.LIB /NOD:MSVCPRT.LIB /NOD:MSVCIRT.LIB"
             if (optlevel==1): cmd += " /MAP /MAPINFO:EXPORTS /NOD:MSVCRT.LIB /NOD:MSVCPRT.LIB /NOD:MSVCIRT.LIB"
@@ -1390,7 +1398,7 @@ def CompileLink(dll, obj, opts):
             oscmd(cmd)
             oscmd(cmd)
         else:
         else:
             cmd = "xilink"
             cmd = "xilink"
-            if GetVerbose(): cmd += " /verbose:lib"            
+            if GetVerbose(): cmd += " /verbose:lib"
             if HasTargetArch():
             if HasTargetArch():
                 cmd += " /MACHINE:" + GetTargetArch().upper()
                 cmd += " /MACHINE:" + GetTargetArch().upper()
             if ("MFC" not in opts):
             if ("MFC" not in opts):
@@ -1495,7 +1503,7 @@ def CompileLink(dll, obj, opts):
 
 
         # Android-specific flags.
         # Android-specific flags.
         if GetTarget() == 'android':
         if GetTarget() == 'android':
-            cmd += " -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now"
+            cmd += " -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now"
             if GetTargetArch() == 'armv7a':
             if GetTargetArch() == 'armv7a':
                 cmd += " -march=armv7-a -Wl,--fix-cortex-a8"
                 cmd += " -march=armv7-a -Wl,--fix-cortex-a8"
             cmd += ' -lc -lm'
             cmd += ' -lc -lm'
@@ -2130,7 +2138,7 @@ def WriteConfigSettings():
 
 
     if (PkgSkip("TOUCHINPUT") == 0 and GetTarget() == "windows"):
     if (PkgSkip("TOUCHINPUT") == 0 and GetTarget() == "windows"):
         dtool_config["HAVE_WIN_TOUCHINPUT"] = '1'
         dtool_config["HAVE_WIN_TOUCHINPUT"] = '1'
-    
+
     if (GetOptimize() <= 3):
     if (GetOptimize() <= 3):
         dtool_config["HAVE_ROCKET_DEBUGGER"] = '1'
         dtool_config["HAVE_ROCKET_DEBUGGER"] = '1'
 
 
@@ -3168,6 +3176,7 @@ if (not RUNTIME):
   TargetAdd('libp3gobj.in', opts=['IMOD:panda3d.core', 'ILIB:libp3gobj', 'SRCDIR:panda/src/gobj'])
   TargetAdd('libp3gobj.in', opts=['IMOD:panda3d.core', 'ILIB:libp3gobj', 'SRCDIR:panda/src/gobj'])
   TargetAdd('libp3gobj_igate.obj', input='libp3gobj.in', opts=["DEPENDENCYONLY"])
   TargetAdd('libp3gobj_igate.obj', input='libp3gobj.in', opts=["DEPENDENCYONLY"])
   TargetAdd('p3gobj_geomVertexArrayData_ext.obj', opts=OPTS, input='geomVertexArrayData_ext.cxx')
   TargetAdd('p3gobj_geomVertexArrayData_ext.obj', opts=OPTS, input='geomVertexArrayData_ext.cxx')
+  TargetAdd('p3gobj_internalName_ext.obj', opts=OPTS, input='internalName_ext.cxx')
 
 
 #
 #
 # DIRECTORY: panda/src/pgraphnodes/
 # DIRECTORY: panda/src/pgraphnodes/
@@ -3539,6 +3548,7 @@ if (not RUNTIME):
   TargetAdd('libpanda.dll', input='p3putil_typedWritable_ext.obj')
   TargetAdd('libpanda.dll', input='p3putil_typedWritable_ext.obj')
   TargetAdd('libpanda.dll', input='p3pnmimage_pfmFile_ext.obj')
   TargetAdd('libpanda.dll', input='p3pnmimage_pfmFile_ext.obj')
   TargetAdd('libpanda.dll', input='p3gobj_geomVertexArrayData_ext.obj')
   TargetAdd('libpanda.dll', input='p3gobj_geomVertexArrayData_ext.obj')
+  TargetAdd('libpanda.dll', input='p3gobj_internalName_ext.obj')
   TargetAdd('libpanda.dll', input='p3pgraph_ext_composite.obj')
   TargetAdd('libpanda.dll', input='p3pgraph_ext_composite.obj')
   TargetAdd('libpanda.dll', input='p3display_graphicsStateGuardian_ext.obj')
   TargetAdd('libpanda.dll', input='p3display_graphicsStateGuardian_ext.obj')
 
 
@@ -3825,16 +3835,15 @@ if (PkgSkip("OPENSSL")==0 and not RTDIST and not RUNTIME and PkgSkip("DEPLOYTOOL
   TargetAdd('build_patch.exe', input=COMMON_PANDA_LIBS_PYSTUB)
   TargetAdd('build_patch.exe', input=COMMON_PANDA_LIBS_PYSTUB)
   TargetAdd('build_patch.exe', opts=OPTS)
   TargetAdd('build_patch.exe', opts=OPTS)
 
 
-  if not PkgSkip("ZLIB"):
-    TargetAdd('check_adler_check_adler.obj', opts=OPTS, input='check_adler.cxx')
-    TargetAdd('check_adler.exe', input=['check_adler_check_adler.obj'])
-    TargetAdd('check_adler.exe', input=COMMON_PANDA_LIBS_PYSTUB)
-    TargetAdd('check_adler.exe', opts=OPTS)
+  TargetAdd('check_adler_check_adler.obj', opts=OPTS, input='check_adler.cxx')
+  TargetAdd('check_adler.exe', input=['check_adler_check_adler.obj'])
+  TargetAdd('check_adler.exe', input=COMMON_PANDA_LIBS_PYSTUB)
+  TargetAdd('check_adler.exe', opts=OPTS)
 
 
-    TargetAdd('check_crc_check_crc.obj', opts=OPTS, input='check_crc.cxx')
-    TargetAdd('check_crc.exe', input=['check_crc_check_crc.obj'])
-    TargetAdd('check_crc.exe', input=COMMON_PANDA_LIBS_PYSTUB)
-    TargetAdd('check_crc.exe', opts=OPTS)
+  TargetAdd('check_crc_check_crc.obj', opts=OPTS, input='check_crc.cxx')
+  TargetAdd('check_crc.exe', input=['check_crc_check_crc.obj'])
+  TargetAdd('check_crc.exe', input=COMMON_PANDA_LIBS_PYSTUB)
+  TargetAdd('check_crc.exe', opts=OPTS)
 
 
   TargetAdd('check_md5_check_md5.obj', opts=OPTS, input='check_md5.cxx')
   TargetAdd('check_md5_check_md5.obj', opts=OPTS, input='check_md5.cxx')
   TargetAdd('check_md5.exe', input=['check_md5_check_md5.obj'])
   TargetAdd('check_md5.exe', input=['check_md5_check_md5.obj'])
@@ -4470,7 +4479,7 @@ if (PkgSkip("DIRECT")==0):
     TargetAdd('packpanda.obj', opts=OPTS+['BUILDING:PACKPANDA'], input='ppython.cxx')
     TargetAdd('packpanda.obj', opts=OPTS+['BUILDING:PACKPANDA'], input='ppython.cxx')
     TargetAdd('packpanda.exe', input='packpanda.obj')
     TargetAdd('packpanda.exe', input='packpanda.obj')
     TargetAdd('packpanda.exe', opts=['PYTHON'])
     TargetAdd('packpanda.exe', opts=['PYTHON'])
-  
+
     DefSymbol("BUILDING:EGGCACHER", "IMPORT_MODULE", "direct.directscripts.eggcacher")
     DefSymbol("BUILDING:EGGCACHER", "IMPORT_MODULE", "direct.directscripts.eggcacher")
     TargetAdd('eggcacher.obj', opts=OPTS+['BUILDING:EGGCACHER'], input='ppython.cxx')
     TargetAdd('eggcacher.obj', opts=OPTS+['BUILDING:EGGCACHER'], input='ppython.cxx')
     TargetAdd('eggcacher.exe', input='eggcacher.obj')
     TargetAdd('eggcacher.exe', input='eggcacher.obj')
@@ -4738,7 +4747,7 @@ if (RUNTIME and PkgSkip("NPAPI")==0):
 # DIRECTORY: direct/src/plugin_activex/
 # DIRECTORY: direct/src/plugin_activex/
 #
 #
 
 
-if (RUNTIME and GetTarget() == 'windows'):
+if (RUNTIME and GetTarget() == 'windows' and PkgSkip("MFC")==0):
   OPTS=['DIR:direct/src/plugin_activex', 'RUNTIME', 'ACTIVEX', 'MFC']
   OPTS=['DIR:direct/src/plugin_activex', 'RUNTIME', 'ACTIVEX', 'MFC']
   DefSymbol('ACTIVEX', '_USRDLL', '')
   DefSymbol('ACTIVEX', '_USRDLL', '')
   DefSymbol('ACTIVEX', '_WINDLL', '')
   DefSymbol('ACTIVEX', '_WINDLL', '')
@@ -5805,7 +5814,7 @@ if (PkgSkip("PYTHON")==0 and not RUNTIME):
     TargetAdd('PandaModules.py', input='fx.pyd')
     TargetAdd('PandaModules.py', input='fx.pyd')
   if (PkgSkip("DIRECT")==0):
   if (PkgSkip("DIRECT")==0):
     TargetAdd('PandaModules.py', input='direct.pyd')
     TargetAdd('PandaModules.py', input='direct.pyd')
-  if (PkgSkip("VISION")==0):  
+  if (PkgSkip("VISION")==0):
     TargetAdd('PandaModules.py', input='vision.pyd')
     TargetAdd('PandaModules.py', input='vision.pyd')
   if (PkgSkip("SKEL")==0):
   if (PkgSkip("SKEL")==0):
     TargetAdd('PandaModules.py', input='skel.pyd')
     TargetAdd('PandaModules.py', input='skel.pyd')
@@ -6042,11 +6051,25 @@ def MakeInstallerNSIS(file, fullname, smdirectory, installdir):
     elif (os.path.isdir(file)):
     elif (os.path.isdir(file)):
         shutil.rmtree(file)
         shutil.rmtree(file)
 
 
+    if GetTargetArch() == 'x64':
+        regview = '64'
+    else:
+        regview = '32'
+
     if (RUNTIME):
     if (RUNTIME):
         # Invoke the make_installer script.
         # Invoke the make_installer script.
         AddToPathEnv("PATH", GetOutputDir() + "\\bin")
         AddToPathEnv("PATH", GetOutputDir() + "\\bin")
         AddToPathEnv("PATH", GetOutputDir() + "\\plugins")
         AddToPathEnv("PATH", GetOutputDir() + "\\plugins")
-        oscmd(sys.executable + " -B direct\\src\\plugin_installer\\make_installer.py --version %s" % VERSION)
+
+        cmd = sys.executable + " -B -u direct\\src\\plugin_installer\\make_installer.py"
+        cmd += " --version %s --regview %s" % (VERSION, regview)
+
+        if GetTargetArch() == 'x64':
+            cmd += " --install \"$PROGRAMFILES64\\Panda3D\" "
+        else:
+            cmd += " --install \"$PROGRAMFILES32\\Panda3D\" "
+
+        oscmd(cmd)
         shutil.move("direct\\src\\plugin_installer\\p3d-setup.exe", file)
         shutil.move("direct\\src\\plugin_installer\\p3d-setup.exe", file)
         return
         return
 
 
@@ -6059,11 +6082,6 @@ def MakeInstallerNSIS(file, fullname, smdirectory, installdir):
     psource = os.path.abspath(".")
     psource = os.path.abspath(".")
     panda = os.path.abspath(GetOutputDir())
     panda = os.path.abspath(GetOutputDir())
 
 
-    if GetTargetArch() == 'x64':
-        regview = '64'
-    else:
-        regview = '32'
-
     nsis_defs = {
     nsis_defs = {
         'COMPRESSOR'  : COMPRESSOR,
         'COMPRESSOR'  : COMPRESSOR,
         'NAME'        : fullname,
         'NAME'        : fullname,

+ 124 - 71
makepanda/makepandacore.py

@@ -37,6 +37,7 @@ HAS_TARGET_ARCH = False
 TOOLCHAIN_PREFIX = ""
 TOOLCHAIN_PREFIX = ""
 ANDROID_ABI = None
 ANDROID_ABI = None
 SYS_LIB_DIRS = []
 SYS_LIB_DIRS = []
+DEBUG_DEPENDENCIES = False
 
 
 # Is the current Python a 32-bit or 64-bit build?  There doesn't
 # Is the current Python a 32-bit or 64-bit build?  There doesn't
 # appear to be a universal test for this.
 # appear to be a universal test for this.
@@ -220,7 +221,7 @@ def ProgressOutput(progress, msg, target = None):
             prefix = "%s[%s %d%%%s] " % (GetColor("yellow"), GetColor("cyan"), progress, GetColor("yellow"))
             prefix = "%s[%s %d%%%s] " % (GetColor("yellow"), GetColor("cyan"), progress, GetColor("yellow"))
     else:
     else:
         global THREADS
         global THREADS
-        
+
         ident = thread.get_ident()
         ident = thread.get_ident()
         if (ident not in THREADS):
         if (ident not in THREADS):
             THREADS[ident] = len(THREADS) + 1
             THREADS[ident] = len(THREADS) + 1
@@ -468,7 +469,7 @@ def LocateBinary(binary):
         p = os.environ["PATH"]
         p = os.environ["PATH"]
 
 
     pathList = p.split(os.pathsep)
     pathList = p.split(os.pathsep)
-    
+
     if GetHost() == 'windows':
     if GetHost() == 'windows':
         if not binary.endswith('.exe'):
         if not binary.endswith('.exe'):
             # Append .exe if necessary
             # Append .exe if necessary
@@ -652,7 +653,10 @@ def NeedsBuild(files, others):
     for file in files:
     for file in files:
         dates[file] = GetTimestamp(file)
         dates[file] = GetTimestamp(file)
         if not os.path.exists(file):
         if not os.path.exists(file):
+            if DEBUG_DEPENDENCIES:
+                print("rebuilding %s because it does not exist" % (file))
             return True
             return True
+
     for file in others:
     for file in others:
         dates[file] = GetTimestamp(file)
         dates[file] = GetTimestamp(file)
 
 
@@ -661,6 +665,16 @@ def NeedsBuild(files, others):
         cached = BUILTFROMCACHE[key]
         cached = BUILTFROMCACHE[key]
         if cached == dates:
         if cached == dates:
             return False
             return False
+        elif DEBUG_DEPENDENCIES:
+            print("rebuilding %s because:" % (key))
+            for key in frozenset(cached.keys()) | frozenset(dates.keys()):
+                if key not in cached:
+                    print("    new dependency: %s" % (key))
+                elif key not in dates:
+                    print("    removed dependency: %s" % (key))
+                elif cached[key] != dates[key]:
+                    print("    dependency changed: %s" % (key))
+
         if VERBOSE and frozenset(cached) != frozenset(dates):
         if VERBOSE and frozenset(cached) != frozenset(dates):
             print("%sWARNING:%s file dependencies changed: %s%s%s" % (GetColor("red"), GetColor(), GetColor("green"), files, GetColor()))
             print("%sWARNING:%s file dependencies changed: %s%s%s" % (GetColor("red"), GetColor(), GetColor("green"), files, GetColor()))
 
 
@@ -857,7 +871,7 @@ def CxxCalcDependencies(srcfile, ipath, ignore):
 ########################################################################
 ########################################################################
 
 
 if sys.platform == "win32":
 if sys.platform == "win32":
-    # Note: not supported on cygwin. 
+    # Note: not supported on cygwin.
     if sys.version_info >= (3, 0):
     if sys.version_info >= (3, 0):
         import winreg
         import winreg
     else:
     else:
@@ -1118,7 +1132,7 @@ def GetThirdpartyBase():
     THIRDPARTYBASE = "thirdparty"
     THIRDPARTYBASE = "thirdparty"
     if "MAKEPANDA_THIRDPARTY" in os.environ:
     if "MAKEPANDA_THIRDPARTY" in os.environ:
         THIRDPARTYBASE = os.environ["MAKEPANDA_THIRDPARTY"]
         THIRDPARTYBASE = os.environ["MAKEPANDA_THIRDPARTY"]
-    
+
     return THIRDPARTYBASE
     return THIRDPARTYBASE
 
 
 def GetThirdpartyDir():
 def GetThirdpartyDir():
@@ -1181,40 +1195,44 @@ def GetThirdpartyDir():
 ########################################################################
 ########################################################################
 
 
 def GetOutputDir():
 def GetOutputDir():
-  return OUTPUTDIR
+    return OUTPUTDIR
 
 
 def IsCustomOutputDir():
 def IsCustomOutputDir():
-  return CUSTOM_OUTPUTDIR
+    return CUSTOM_OUTPUTDIR
 
 
 def SetOutputDir(outputdir):
 def SetOutputDir(outputdir):
-  global OUTPUTDIR, CUSTOM_OUTPUTDIR
-  OUTPUTDIR=outputdir
-  CUSTOM_OUTPUTDIR=True
+    global OUTPUTDIR, CUSTOM_OUTPUTDIR
+    OUTPUTDIR = outputdir
+    CUSTOM_OUTPUTDIR = True
 
 
 def GetOptimize():
 def GetOptimize():
-  return int(OPTIMIZE)
+    return int(OPTIMIZE)
 
 
 def SetOptimize(optimize):
 def SetOptimize(optimize):
-  global OPTIMIZE
-  OPTIMIZE=optimize
+    global OPTIMIZE
+    OPTIMIZE = optimize
 
 
 def GetVerbose():
 def GetVerbose():
-  return VERBOSE
+    return VERBOSE
 
 
 def SetVerbose(verbose):
 def SetVerbose(verbose):
-  global VERBOSE
-  VERBOSE=verbose
+    global VERBOSE
+    VERBOSE = verbose
+
+def SetDebugDependencies(dd = True):
+    global DEBUG_DEPENDENCIES
+    DEBUG_DEPENDENCIES = dd
 
 
 def GetLinkAllStatic():
 def GetLinkAllStatic():
-  return LINK_ALL_STATIC
+    return LINK_ALL_STATIC
 
 
 def SetLinkAllStatic(val = True):
 def SetLinkAllStatic(val = True):
-  global LINK_ALL_STATIC
-  LINK_ALL_STATIC = val
+    global LINK_ALL_STATIC
+    LINK_ALL_STATIC = val
 
 
 def UnsetLinkAllStatic():
 def UnsetLinkAllStatic():
-  global LINK_ALL_STATIC
-  LINK_ALL_STATIC = False
+    global LINK_ALL_STATIC
+    LINK_ALL_STATIC = False
 
 
 ########################################################################
 ########################################################################
 ##
 ##
@@ -1292,7 +1310,7 @@ def OverrideValue(parameter, value):
 def PkgConfigHavePkg(pkgname, tool = "pkg-config"):
 def PkgConfigHavePkg(pkgname, tool = "pkg-config"):
     """Returns a bool whether the pkg-config package is installed."""
     """Returns a bool whether the pkg-config package is installed."""
 
 
-    if (sys.platform == "win32" or not LocateBinary(tool)):
+    if (sys.platform == "win32" or CrossCompiling() or not LocateBinary(tool)):
         return False
         return False
     if (tool == "pkg-config"):
     if (tool == "pkg-config"):
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --modversion " + pkgname)
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --modversion " + pkgname)
@@ -1307,7 +1325,7 @@ def PkgConfigHavePkg(pkgname, tool = "pkg-config"):
 def PkgConfigGetLibs(pkgname, tool = "pkg-config"):
 def PkgConfigGetLibs(pkgname, tool = "pkg-config"):
     """Returns a list of libs for the package, prefixed by -l."""
     """Returns a list of libs for the package, prefixed by -l."""
 
 
-    if (sys.platform == "win32" or not LocateBinary(tool)):
+    if (sys.platform == "win32" or CrossCompiling() or not LocateBinary(tool)):
         return []
         return []
     if (tool == "pkg-config"):
     if (tool == "pkg-config"):
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --libs-only-l " + pkgname)
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --libs-only-l " + pkgname)
@@ -1338,7 +1356,7 @@ def PkgConfigGetLibs(pkgname, tool = "pkg-config"):
 def PkgConfigGetIncDirs(pkgname, tool = "pkg-config"):
 def PkgConfigGetIncDirs(pkgname, tool = "pkg-config"):
     """Returns a list of includes for the package, NOT prefixed by -I."""
     """Returns a list of includes for the package, NOT prefixed by -I."""
 
 
-    if (sys.platform == "win32" or not LocateBinary(tool)):
+    if (sys.platform == "win32" or CrossCompiling() or not LocateBinary(tool)):
         return []
         return []
     if (tool == "pkg-config"):
     if (tool == "pkg-config"):
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --cflags-only-I " + pkgname)
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --cflags-only-I " + pkgname)
@@ -1359,7 +1377,7 @@ def PkgConfigGetIncDirs(pkgname, tool = "pkg-config"):
 def PkgConfigGetLibDirs(pkgname, tool = "pkg-config"):
 def PkgConfigGetLibDirs(pkgname, tool = "pkg-config"):
     """Returns a list of library paths for the package, NOT prefixed by -L."""
     """Returns a list of library paths for the package, NOT prefixed by -L."""
 
 
-    if (sys.platform == "win32" or not LocateBinary(tool)):
+    if (sys.platform == "win32" or CrossCompiling() or not LocateBinary(tool)):
         return []
         return []
     if (tool == "pkg-config"):
     if (tool == "pkg-config"):
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --libs-only-L " + pkgname)
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --libs-only-L " + pkgname)
@@ -1379,7 +1397,7 @@ def PkgConfigGetLibDirs(pkgname, tool = "pkg-config"):
 def PkgConfigGetDefSymbols(pkgname, tool = "pkg-config"):
 def PkgConfigGetDefSymbols(pkgname, tool = "pkg-config"):
     """Returns a dictionary of preprocessor definitions."""
     """Returns a dictionary of preprocessor definitions."""
 
 
-    if (sys.platform == "win32" or not LocateBinary(tool)):
+    if (sys.platform == "win32" or CrossCompiling() or not LocateBinary(tool)):
         return []
         return []
     if (tool == "pkg-config"):
     if (tool == "pkg-config"):
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --cflags " + pkgname)
         handle = os.popen(LocateBinary("pkg-config") + " --silence-errors --cflags " + pkgname)
@@ -1411,7 +1429,6 @@ def PkgConfigEnable(opt, pkgname, tool = "pkg-config"):
 
 
 def LibraryExists(lib, lpath=[]):
 def LibraryExists(lib, lpath=[]):
     """ Returns True if this library was found in the given search path, False otherwise. """
     """ Returns True if this library was found in the given search path, False otherwise. """
-
     target = GetTarget()
     target = GetTarget()
 
 
     for dir in lpath:
     for dir in lpath:
@@ -1517,6 +1534,7 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
         for d, v in defs.values():
         for d, v in defs.values():
             DefSymbol(target_pkg, d, v)
             DefSymbol(target_pkg, d, v)
         return
         return
+
     elif (GetHost() == "darwin" and framework != None):
     elif (GetHost() == "darwin" and framework != None):
         if (os.path.isdir("/Library/Frameworks/%s.framework" % framework) or
         if (os.path.isdir("/Library/Frameworks/%s.framework" % framework) or
             os.path.isdir("/System/Library/Frameworks/%s.framework" % framework) or
             os.path.isdir("/System/Library/Frameworks/%s.framework" % framework) or
@@ -1532,6 +1550,7 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
             print("%sERROR:%s Could not locate framework %s, aborting build" % (GetColor("red"), GetColor(), framework))
             print("%sERROR:%s Could not locate framework %s, aborting build" % (GetColor("red"), GetColor(), framework))
             exit()
             exit()
         return
         return
+
     elif (LocateBinary(tool) != None and (tool != "pkg-config" or pkgconfig != None)):
     elif (LocateBinary(tool) != None and (tool != "pkg-config" or pkgconfig != None)):
         if (isinstance(pkgconfig, str) or tool != "pkg-config"):
         if (isinstance(pkgconfig, str) or tool != "pkg-config"):
             if (PkgConfigHavePkg(pkgconfig, tool)):
             if (PkgConfigHavePkg(pkgconfig, tool)):
@@ -1553,6 +1572,7 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
         else:
         else:
             print("%sERROR:%s Could not locate pkg-config package %s, aborting build" % (GetColor("red"), GetColor(), pkgconfig))
             print("%sERROR:%s Could not locate pkg-config package %s, aborting build" % (GetColor("red"), GetColor(), pkgconfig))
             exit()
             exit()
+
     else:
     else:
         # Okay, our pkg-config attempts failed. Let's try locating the libs by ourselves.
         # Okay, our pkg-config attempts failed. Let's try locating the libs by ourselves.
         have_pkg = True
         have_pkg = True
@@ -1825,56 +1845,84 @@ def SdkLocateMax():
                             SDK[version+"CS"] = top + subdir
                             SDK[version+"CS"] = top + subdir
 
 
 def SdkLocatePython(force_use_sys_executable = False):
 def SdkLocatePython(force_use_sys_executable = False):
-    if (PkgSkip("PYTHON")==0):
-        if GetTarget() != GetHost():
-            exit('Use --no-python when cross-compiling until support has been added')
-
-        if (GetTarget() == 'windows' and not force_use_sys_executable):
-            SDK["PYTHON"] = GetThirdpartyBase()+"/win-python"
-            if (GetOptimize() <= 2):
-                SDK["PYTHON"] += "-dbg"
-            if (GetTargetArch() == 'x64' and os.path.isdir(SDK["PYTHON"] + "-x64")):
-                SDK["PYTHON"] += "-x64"
-
-            SDK["PYTHONEXEC"] = SDK["PYTHON"].replace('/', '\\') + "\\python"
-            if (GetOptimize() <= 2):
-                SDK["PYTHONEXEC"] += "_d.exe"
-            else:
-                SDK["PYTHONEXEC"] += ".exe"
+    if PkgSkip("PYTHON"):
+        SDK["PYTHONEXEC"] = os.path.realpath(sys.executable)
+        return
+
+    if CrossCompiling():
+        force_use_sys_executable = False
+
+    if (GetTarget() == 'windows' and not force_use_sys_executable):
+        SDK["PYTHON"] = GetThirdpartyBase() + "/win-python"
+        if (GetOptimize() <= 2):
+            SDK["PYTHON"] += "-dbg"
+        if (GetTargetArch() == 'x64' and os.path.isdir(SDK["PYTHON"] + "-x64")):
+            SDK["PYTHON"] += "-x64"
+
+        SDK["PYTHONEXEC"] = SDK["PYTHON"].replace('/', '\\') + "\\python"
+        if (GetOptimize() <= 2):
+            SDK["PYTHONEXEC"] += "_d.exe"
+        else:
+            SDK["PYTHONEXEC"] += ".exe"
 
 
-            if (not os.path.isfile(SDK["PYTHONEXEC"])):
-                exit("Could not find %s!" % SDK["PYTHONEXEC"])
+        if (not os.path.isfile(SDK["PYTHONEXEC"])):
+            exit("Could not find %s!" % SDK["PYTHONEXEC"])
 
 
-            # Determine which version it is by checking which dll is in the directory.
-            if (GetOptimize() <= 2):
-                py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9]_d.dll")
-            else:
-                py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9].dll")
+        # Determine which version it is by checking which dll is in the directory.
+        if (GetOptimize() <= 2):
+            py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9]_d.dll")
+        else:
+            py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9].dll")
 
 
-            if len(py_dlls) == 0:
-                exit("Could not find the Python dll in %s." % (SDK["PYTHON"]))
-            elif len(py_dlls) > 1:
-                exit("Found multiple Python dlls in %s." % (SDK["PYTHON"]))
+        if len(py_dlls) == 0:
+            exit("Could not find the Python dll in %s." % (SDK["PYTHON"]))
+        elif len(py_dlls) > 1:
+            exit("Found multiple Python dlls in %s." % (SDK["PYTHON"]))
 
 
-            py_dll = os.path.basename(py_dlls[0])
-            SDK["PYTHONVERSION"] = "python" + py_dll[6] + "." + py_dll[7]
+        py_dll = os.path.basename(py_dlls[0])
+        SDK["PYTHONVERSION"] = "python" + py_dll[6] + "." + py_dll[7]
 
 
-        elif (GetTarget() == 'windows'):
-            SDK["PYTHON"] = os.path.dirname(sysconfig.get_python_inc())
-            SDK["PYTHONVERSION"] = "python" + sysconfig.get_python_version()
-            SDK["PYTHONEXEC"] = sys.executable
+        os.environ["PYTHONHOME"] = SDK["PYTHON"]
 
 
+    elif CrossCompiling():
+        tp_python = os.path.join(GetThirdpartyDir(), "python")
+        SDK["PYTHON"] = tp_python + "/include"
+
+        if GetTarget() == 'darwin':
+            py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].dylib")
         else:
         else:
-            SDK["PYTHON"] = sysconfig.get_python_inc()
-            SDK["PYTHONVERSION"] = "python" + sysconfig.get_python_version()
-            SDK["PYTHONEXEC"] = os.path.realpath(sys.executable)
+            py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].so")
+
+        if len(py_libs) == 0:
+            py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].a")
+
+        if len(py_libs) == 0:
+            exit("Could not find the Python library in %s." % (tp_python))
+        elif len(py_libs) > 1:
+            exit("Found multiple Python libraries in %s." % (tp_python))
 
 
-        if GetVerbose():
-            print("Using Python %s build located at %s" % (SDK["PYTHONVERSION"][6:9], SDK["PYTHON"]))
+        py_lib = os.path.basename(py_libs[0])
+        SDK["PYTHONVERSION"] = "python" + py_lib[9] + "." + py_lib[11]
+
+    elif (GetTarget() == 'windows'):
+        SDK["PYTHON"] = os.path.dirname(sysconfig.get_python_inc())
+        SDK["PYTHONVERSION"] = "python" + sysconfig.get_python_version()
+        SDK["PYTHONEXEC"] = sys.executable
 
 
     else:
     else:
+        SDK["PYTHON"] = sysconfig.get_python_inc()
+        SDK["PYTHONVERSION"] = "python" + sysconfig.get_python_version()
         SDK["PYTHONEXEC"] = os.path.realpath(sys.executable)
         SDK["PYTHONEXEC"] = os.path.realpath(sys.executable)
 
 
+    if CrossCompiling():
+        SDK["PYTHONEXEC"] = sys.executable
+        host_version = "python" + sysconfig.get_python_version()
+        if SDK["PYTHONVERSION"] != host_version:
+            exit("Host Python version (%s) must be the same as target Python version (%s)!" % (host_version, SDK["PYTHONVERSION"]))
+
+    if GetVerbose():
+        print("Using Python %s build located at %s" % (SDK["PYTHONVERSION"][6:9], SDK["PYTHON"]))
+
 def SdkLocateVisualStudio():
 def SdkLocateVisualStudio():
     if (GetHost() != "windows"): return
     if (GetHost() != "windows"): return
     vcdir = GetRegistryKey("SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7", "10.0")
     vcdir = GetRegistryKey("SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7", "10.0")
@@ -2025,9 +2073,9 @@ def SdkLocateAndroid():
     SDK["ANDROID_NDK"] = ndk_root
     SDK["ANDROID_NDK"] = ndk_root
 
 
     # Determine the toolchain location.
     # Determine the toolchain location.
-    gcc_ver = '4.7'
+    gcc_ver = '4.8'
     arch = GetTargetArch()
     arch = GetTargetArch()
-    if arch == 'armv7' or arch == 'arm':
+    if arch == 'armv7a' or arch == 'arm':
         arch = 'arm'
         arch = 'arm'
         toolchain = 'arm-linux-androideabi-' + gcc_ver
         toolchain = 'arm-linux-androideabi-' + gcc_ver
     elif arch == 'x86':
     elif arch == 'x86':
@@ -2045,8 +2093,10 @@ def SdkLocateAndroid():
     #IncDirectory("ALWAYS", os.path.join(SDK["SYSROOT"], 'usr', 'include'))
     #IncDirectory("ALWAYS", os.path.join(SDK["SYSROOT"], 'usr', 'include'))
 
 
     stdlibc = os.path.join(ndk_root, 'sources', 'cxx-stl', 'gnu-libstdc++', gcc_ver)
     stdlibc = os.path.join(ndk_root, 'sources', 'cxx-stl', 'gnu-libstdc++', gcc_ver)
-    IncDirectory("ALWAYS", os.path.join(stdlibc, 'include'))
-    IncDirectory("ALWAYS", os.path.join(stdlibc, 'libs', abi, 'include'))
+    SDK["ANDROID_STL"] = stdlibc
+
+    #IncDirectory("ALWAYS", os.path.join(stdlibc, 'include'))
+    #IncDirectory("ALWAYS", os.path.join(stdlibc, 'libs', abi, 'include'))
 
 
     stl_lib = os.path.join(stdlibc, 'libs', abi, 'libgnustl_shared.so')
     stl_lib = os.path.join(stdlibc, 'libs', abi, 'libgnustl_shared.so')
     LibName("ALWAYS", stl_lib)
     LibName("ALWAYS", stl_lib)
@@ -2231,7 +2281,9 @@ def SetupBuildEnvironment(compiler):
         global SYS_LIB_DIRS
         global SYS_LIB_DIRS
 
 
         # gcc doesn't add this one, but we do want it:
         # gcc doesn't add this one, but we do want it:
-        SYS_LIB_DIRS.append('/usr/local/lib')
+        local_lib = SDK.get("SYSROOT", "") + "/usr/local/lib"
+        if os.path.isdir(local_lib):
+            SYS_LIB_DIRS.append(local_lib)
 
 
         cmd = GetCXX() + " -print-search-dirs"
         cmd = GetCXX() + " -print-search-dirs"
 
 
@@ -2253,7 +2305,8 @@ def SetupBuildEnvironment(compiler):
         returnval = handle.close()
         returnval = handle.close()
         if returnval != None and returnval != 0:
         if returnval != None and returnval != 0:
             print("%sWARNING:%s %s failed" % (GetColor("red"), GetColor(), cmd))
             print("%sWARNING:%s %s failed" % (GetColor("red"), GetColor(), cmd))
-            SYS_LIB_DIRS += ['/usr/lib']
+            SYS_LIB_DIRS += [SDK.get("SYSROOT", "") + "/usr/lib"]
+
         elif GetVerbose():
         elif GetVerbose():
             print("System library search path: %s" % ':'.join(SYS_LIB_DIRS))
             print("System library search path: %s" % ':'.join(SYS_LIB_DIRS))
 
 
@@ -2753,4 +2806,4 @@ def TargetAdd(target, dummy=0, opts=0, input=0, dep=0, ipath=0, winrc=0):
         t.deps[FindLocation("dtool_have_python.dat", [])] = 1
         t.deps[FindLocation("dtool_have_python.dat", [])] = 1
 
 
     if target.endswith(".pz") and not CrossCompiling():
     if target.endswith(".pz") and not CrossCompiling():
-        t.deps[FindLocation("pzip.exe", [])] = 1     
+        t.deps[FindLocation("pzip.exe", [])] = 1

+ 30 - 2
panda/src/android/android_main.cxx

@@ -16,6 +16,7 @@
 #include "config_util.h"
 #include "config_util.h"
 #include "virtualFileMountAndroidAsset.h"
 #include "virtualFileMountAndroidAsset.h"
 #include "virtualFileSystem.h"
 #include "virtualFileSystem.h"
+#include "filename.h"
 
 
 #include "config_display.h"
 #include "config_display.h"
 //#define OPENGLES_1
 //#define OPENGLES_1
@@ -45,9 +46,36 @@ void android_main(struct android_app* app) {
     return;
     return;
   }
   }
 
 
+  // Fetch the data directory.
+  jclass activity_class = env->GetObjectClass(activity->clazz);
+  jmethodID get_appinfo = env->GetMethodID(activity_class, "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;");
+
+  jobject appinfo = env->CallObjectMethod(activity->clazz, get_appinfo);
+  jclass appinfo_class = env->GetObjectClass(appinfo);
+
+  // Fetch the path to the data directory.
+  jfieldID datadir_field = env->GetFieldID(appinfo_class, "dataDir", "Ljava/lang/String;");
+  jstring datadir = (jstring) env->GetObjectField(appinfo, datadir_field);
+  const char *data_path = env->GetStringUTFChars(datadir, NULL);
+
+  Filename::_internal_data_dir = data_path;
+  android_cat.info() << "Path to data: " << data_path << "\n";
+
+  env->ReleaseStringUTFChars(datadir, data_path);
+
+  // Fetch the path to the library directory.
+  jfieldID libdir_field = env->GetFieldID(appinfo_class, "nativeLibraryDir", "Ljava/lang/String;");
+  jstring libdir = (jstring) env->GetObjectField(appinfo, libdir_field);
+  const char *lib_path = env->GetStringUTFChars(libdir, NULL);
+
+  string dtool_name = string(lib_path) + "/libp3dtool.so";
+  ExecutionEnvironment::set_dtool_name(dtool_name);
+  android_cat.info() << "Path to dtool: " << dtool_name << "\n";
+
+  env->ReleaseStringUTFChars(libdir, lib_path);
+
   // Get the path to the APK.
   // Get the path to the APK.
-  jclass clazz = env->GetObjectClass(activity->clazz);
-  jmethodID methodID = env->GetMethodID(clazz, "getPackageCodePath", "()Ljava/lang/String;");
+  jmethodID methodID = env->GetMethodID(activity_class, "getPackageCodePath", "()Ljava/lang/String;");
   jstring code_path = (jstring) env->CallObjectMethod(activity->clazz, methodID);
   jstring code_path = (jstring) env->CallObjectMethod(activity->clazz, methodID);
 
 
   const char* apk_path;
   const char* apk_path;

+ 11 - 2
panda/src/androiddisplay/androidGraphicsWindow.cxx

@@ -326,7 +326,7 @@ open_window() {
     return false;
     return false;
   }
   }
 
 
-  //_fb_properties = androidgsg->get_fb_properties();
+  _fb_properties = androidgsg->get_fb_properties();
 
 
   androiddisplay_cat.error() << "open_window done\n";
   androiddisplay_cat.error() << "open_window done\n";
 
 
@@ -434,7 +434,7 @@ handle_command(struct android_app *app, int32_t command) {
 void AndroidGraphicsWindow::
 void AndroidGraphicsWindow::
 ns_handle_command(int32_t command) {
 ns_handle_command(int32_t command) {
   WindowProperties properties;
   WindowProperties properties;
-  
+
   switch (command) {
   switch (command) {
     case APP_CMD_SAVE_STATE:
     case APP_CMD_SAVE_STATE:
       // The system has asked us to save our current state.  Do so.
       // The system has asked us to save our current state.  Do so.
@@ -446,16 +446,25 @@ ns_handle_command(int32_t command) {
       // The window is being shown, get it ready.
       // The window is being shown, get it ready.
       if (_app->window != NULL) {
       if (_app->window != NULL) {
         create_surface();
         create_surface();
+        properties.set_size(ANativeWindow_getWidth(_app->window),
+                            ANativeWindow_getHeight(_app->window));
         properties.set_minimized(false);
         properties.set_minimized(false);
         system_changed_properties(properties);
         system_changed_properties(properties);
       }
       }
       break;
       break;
+    case APP_CMD_CONFIG_CHANGED:
+      properties.set_size(ANativeWindow_getWidth(_app->window),
+                          ANativeWindow_getHeight(_app->window));
+      system_changed_properties(properties);
+      break;
     case APP_CMD_TERM_WINDOW:
     case APP_CMD_TERM_WINDOW:
       destroy_surface();
       destroy_surface();
       properties.set_minimized(true);
       properties.set_minimized(true);
       system_changed_properties(properties);
       system_changed_properties(properties);
       break;
       break;
     case APP_CMD_WINDOW_RESIZED:
     case APP_CMD_WINDOW_RESIZED:
+      properties.set_size(ANativeWindow_getWidth(_app->window),
+                          ANativeWindow_getHeight(_app->window));
       break;
       break;
     case APP_CMD_WINDOW_REDRAW_NEEDED:
     case APP_CMD_WINDOW_REDRAW_NEEDED:
       break;
       break;

+ 2 - 0
panda/src/display/Sources.pp

@@ -38,6 +38,7 @@
     lru.h \
     lru.h \
     nativeWindowHandle.I nativeWindowHandle.h \
     nativeWindowHandle.I nativeWindowHandle.h \
     parasiteBuffer.I parasiteBuffer.h \
     parasiteBuffer.I parasiteBuffer.h \
+    pStatGPUTimer.I pStatGPUTimer.h \
     windowHandle.I windowHandle.h \
     windowHandle.I windowHandle.h \
     windowProperties.I windowProperties.h \
     windowProperties.I windowProperties.h \
     renderBuffer.h \
     renderBuffer.h \
@@ -112,6 +113,7 @@
     lru.h \
     lru.h \
     nativeWindowHandle.I nativeWindowHandle.h \
     nativeWindowHandle.I nativeWindowHandle.h \
     parasiteBuffer.I parasiteBuffer.h \
     parasiteBuffer.I parasiteBuffer.h \
+    pStatGPUTimer.I pStatGPUTimer.h \
     windowHandle.I windowHandle.h \
     windowHandle.I windowHandle.h \
     windowProperties.I windowProperties.h \
     windowProperties.I windowProperties.h \
     renderBuffer.h \
     renderBuffer.h \

+ 4 - 4
panda/src/display/displayRegion.I

@@ -580,9 +580,9 @@ get_region_pixels_i(int i, int &xo, int &yo, int &w, int &h) const {
   CDReader cdata(_cycler);
   CDReader cdata(_cycler);
   const Region &region = cdata->_regions[i];
   const Region &region = cdata->_regions[i];
   xo = region._pixels_i[0];
   xo = region._pixels_i[0];
-  yo = region._pixels_i[2];
+  yo = region._pixels_i[3];
   w = region._pixels_i[1] - xo;
   w = region._pixels_i[1] - xo;
-  h = region._pixels_i[3] - yo;
+  h = region._pixels_i[2] - yo;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1068,9 +1068,9 @@ INLINE void DisplayRegionPipelineReader::
 get_region_pixels_i(int i, int &xo, int &yo, int &w, int &h) const {
 get_region_pixels_i(int i, int &xo, int &yo, int &w, int &h) const {
   const DisplayRegion::Region &region = _cdata->_regions[i];
   const DisplayRegion::Region &region = _cdata->_regions[i];
   xo = region._pixels_i[0];
   xo = region._pixels_i[0];
-  yo = region._pixels_i[2];
+  yo = region._pixels_i[3];
   w = region._pixels_i[1] - xo;
   w = region._pixels_i[1] - xo;
-  h = region._pixels_i[3] - yo;
+  h = region._pixels_i[2] - yo;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 130 - 113
panda/src/display/graphicsEngine.cxx

@@ -24,6 +24,7 @@
 #include "cullTraverser.h"
 #include "cullTraverser.h"
 #include "clockObject.h"
 #include "clockObject.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
+#include "pStatGPUTimer.h"
 #include "pStatClient.h"
 #include "pStatClient.h"
 #include "pStatCollector.h"
 #include "pStatCollector.h"
 #include "mutexHolder.h"
 #include "mutexHolder.h"
@@ -52,7 +53,7 @@
   #define WINDOWS_LEAN_AND_MEAN
   #define WINDOWS_LEAN_AND_MEAN
   #include <WinSock2.h>
   #include <WinSock2.h>
   #include <wtypes.h>
   #include <wtypes.h>
-  #undef WINDOWS_LEAN_AND_MEAN  
+  #undef WINDOWS_LEAN_AND_MEAN
 #else
 #else
   #include <sys/time.h>
   #include <sys/time.h>
 #endif
 #endif
@@ -140,7 +141,7 @@ GraphicsEngine(Pipeline *pipeline) :
   _windows_sorted = true;
   _windows_sorted = true;
   _window_sort_index = 0;
   _window_sort_index = 0;
   _needs_open_windows = false;
   _needs_open_windows = false;
-  
+
   set_threading_model(GraphicsThreadingModel(threading_model));
   set_threading_model(GraphicsThreadingModel(threading_model));
   if (!_threading_model.is_default()) {
   if (!_threading_model.is_default()) {
     display_cat.info()
     display_cat.info()
@@ -188,7 +189,7 @@ set_threading_model(const GraphicsThreadingModel &threading_model) {
       return;
       return;
     }
     }
   }
   }
-    
+
 #ifndef THREADED_PIPELINE
 #ifndef THREADED_PIPELINE
   if (!threading_model.is_single_threaded()) {
   if (!threading_model.is_single_threaded()) {
     display_cat.warning()
     display_cat.warning()
@@ -238,7 +239,7 @@ get_threading_model() const {
 //
 //
 //               If a null pointer is supplied for the gsg, then this
 //               If a null pointer is supplied for the gsg, then this
 //               routine will create a new gsg.
 //               routine will create a new gsg.
-//               
+//
 //               This routine is only called from the app thread.
 //               This routine is only called from the app thread.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
@@ -283,7 +284,7 @@ make_output(GraphicsPipe *pipe,
   //  already-initialized gsg.
   //  already-initialized gsg.
 
 
   // Simplify the input parameters.
   // Simplify the input parameters.
-  
+
   int x_size = 0, y_size = 0;
   int x_size = 0, y_size = 0;
   if (win_prop.has_size()) {
   if (win_prop.has_size()) {
     x_size = win_prop.get_x_size();
     x_size = win_prop.get_x_size();
@@ -359,7 +360,7 @@ make_output(GraphicsPipe *pipe,
     // an unencumbered GSG.
     // an unencumbered GSG.
     return NULL;
     return NULL;
   }
   }
-  
+
   // Determine if a parasite buffer meets the user's specs.
   // Determine if a parasite buffer meets the user's specs.
 
 
   bool can_use_parasite = false;
   bool can_use_parasite = false;
@@ -381,7 +382,7 @@ make_output(GraphicsPipe *pipe,
   // Even if prefer-parasite-buffer is set, parasites are not preferred
   // Even if prefer-parasite-buffer is set, parasites are not preferred
   // if the host window is too small, or if the host window does not
   // if the host window is too small, or if the host window does not
   // have the requested properties.
   // have the requested properties.
-  
+
   if ((prefer_parasite_buffer) &&
   if ((prefer_parasite_buffer) &&
       (can_use_parasite) &&
       (can_use_parasite) &&
       (x_size <= host->get_x_size())&&
       (x_size <= host->get_x_size())&&
@@ -408,10 +409,10 @@ make_output(GraphicsPipe *pipe,
   }
   }
 
 
   // Ask the pipe to create a window.
   // Ask the pipe to create a window.
-  
+
   for (int retry=0; retry<10; retry++) {
   for (int retry=0; retry<10; retry++) {
     bool precertify = false;
     bool precertify = false;
-    PT(GraphicsOutput) window = 
+    PT(GraphicsOutput) window =
       pipe->make_output(name, fb_prop, win_prop, flags, this, gsg, host, retry, precertify);
       pipe->make_output(name, fb_prop, win_prop, flags, this, gsg, host, retry, precertify);
     if (window != (GraphicsOutput *)NULL) {
     if (window != (GraphicsOutput *)NULL) {
       window->_sort = sort;
       window->_sort = sort;
@@ -455,11 +456,11 @@ make_output(GraphicsPipe *pipe,
       nassertr(removed, NULL);
       nassertr(removed, NULL);
     }
     }
   }
   }
-  
+
   // Parasite buffers were not preferred, but the pipe could not
   // Parasite buffers were not preferred, but the pipe could not
   // create a window to the user's specs.  Try a parasite as a
   // create a window to the user's specs.  Try a parasite as a
   // last hope.
   // last hope.
-  
+
   if (can_use_parasite) {
   if (can_use_parasite) {
     ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
     ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
     buffer->_sort = sort;
     buffer->_sort = sort;
@@ -613,7 +614,7 @@ remove_all_windows() {
 //       Access: Published
 //       Access: Published
 //  Description: Resets the framebuffer of the current window.  This
 //  Description: Resets the framebuffer of the current window.  This
 //               is currently used by DirectX 8 only. It calls a
 //               is currently used by DirectX 8 only. It calls a
-//               reset_window function on each active window to 
+//               reset_window function on each active window to
 //               release/create old/new framebuffer
 //               release/create old/new framebuffer
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::
 void GraphicsEngine::
@@ -712,11 +713,11 @@ render_frame() {
     if (!_windows_sorted) {
     if (!_windows_sorted) {
       do_resort_windows();
       do_resort_windows();
     }
     }
-    
+
     if (sync_flip && _flip_state != FS_flip) {
     if (sync_flip && _flip_state != FS_flip) {
       do_flip_frame(current_thread);
       do_flip_frame(current_thread);
     }
     }
-    
+
     // Are any of the windows ready to be deleted?
     // Are any of the windows ready to be deleted?
     Windows new_windows;
     Windows new_windows;
     new_windows.reserve(_windows.size());
     new_windows.reserve(_windows.size());
@@ -726,10 +727,10 @@ render_frame() {
       nassertv(win != NULL);
       nassertv(win != NULL);
       if (win->get_delete_flag()) {
       if (win->get_delete_flag()) {
         do_remove_window(win, current_thread);
         do_remove_window(win, current_thread);
-        
+
       } else {
       } else {
         new_windows.push_back(win);
         new_windows.push_back(win);
-        
+
         // Let's calculate each scene's bounding volume here in App,
         // Let's calculate each scene's bounding volume here in App,
         // before we cycle the pipeline.  The cull traversal will
         // before we cycle the pipeline.  The cull traversal will
         // calculate it anyway, but if we calculate it in App first
         // calculate it anyway, but if we calculate it in App first
@@ -770,11 +771,11 @@ render_frame() {
       }
       }
       _loaded_textures.clear();
       _loaded_textures.clear();
     }
     }
-    
+
     // Now it's time to do any drawing from the main frame--after all of
     // Now it's time to do any drawing from the main frame--after all of
     // the App code has executed, but before we begin the next frame.
     // the App code has executed, but before we begin the next frame.
     _app.do_frame(this, current_thread);
     _app.do_frame(this, current_thread);
-    
+
     // Grab each thread's mutex again after all windows have flipped,
     // Grab each thread's mutex again after all windows have flipped,
     // and wait for the thread to finish.
     // and wait for the thread to finish.
     {
     {
@@ -783,32 +784,32 @@ render_frame() {
       for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
       for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
         RenderThread *thread = (*ti).second;
         RenderThread *thread = (*ti).second;
         thread->_cv_mutex.acquire();
         thread->_cv_mutex.acquire();
-        
+
         while (thread->_thread_state != TS_wait) {
         while (thread->_thread_state != TS_wait) {
           thread->_cv_done.wait();
           thread->_cv_done.wait();
         }
         }
       }
       }
     }
     }
-    
+
 #if defined(THREADED_PIPELINE) && defined(DO_PSTATS)
 #if defined(THREADED_PIPELINE) && defined(DO_PSTATS)
     _cyclers_pcollector.set_level(_pipeline->get_num_cyclers());
     _cyclers_pcollector.set_level(_pipeline->get_num_cyclers());
     _dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers());
     _dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers());
-    
+
 #ifdef DEBUG_THREADS
 #ifdef DEBUG_THREADS
     if (PStatClient::is_connected()) {
     if (PStatClient::is_connected()) {
       _pipeline->iterate_all_cycler_types(pstats_count_cycler_type, this);
       _pipeline->iterate_all_cycler_types(pstats_count_cycler_type, this);
       _pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type, this);
       _pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type, this);
     }
     }
 #endif  // DEBUG_THREADS
 #endif  // DEBUG_THREADS
-    
+
 #endif  // THREADED_PIPELINE && DO_PSTATS
 #endif  // THREADED_PIPELINE && DO_PSTATS
-    
+
     GeomCacheManager::flush_level();
     GeomCacheManager::flush_level();
     CullTraverser::flush_level();
     CullTraverser::flush_level();
     RenderState::flush_level();
     RenderState::flush_level();
     TransformState::flush_level();
     TransformState::flush_level();
     CullableObject::flush_level();
     CullableObject::flush_level();
-    
+
     // Now cycle the pipeline and officially begin the next frame.
     // Now cycle the pipeline and officially begin the next frame.
 #ifdef THREADED_PIPELINE
 #ifdef THREADED_PIPELINE
     {
     {
@@ -816,15 +817,15 @@ render_frame() {
       _pipeline->cycle();
       _pipeline->cycle();
     }
     }
 #endif  // THREADED_PIPELINE
 #endif  // THREADED_PIPELINE
-    
+
     global_clock->tick(current_thread);
     global_clock->tick(current_thread);
     if (global_clock->check_errors(current_thread)) {
     if (global_clock->check_errors(current_thread)) {
       throw_event("clock_error");
       throw_event("clock_error");
     }
     }
-    
+
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
     PStatClient::main_tick();
     PStatClient::main_tick();
-    
+
     // Reset our pcollectors that track data across the frame.
     // Reset our pcollectors that track data across the frame.
     CullTraverser::_nodes_pcollector.clear_level();
     CullTraverser::_nodes_pcollector.clear_level();
     CullTraverser::_geom_nodes_pcollector.clear_level();
     CullTraverser::_geom_nodes_pcollector.clear_level();
@@ -833,18 +834,18 @@ render_frame() {
     GeomCacheManager::_geom_cache_record_pcollector.clear_level();
     GeomCacheManager::_geom_cache_record_pcollector.clear_level();
     GeomCacheManager::_geom_cache_erase_pcollector.clear_level();
     GeomCacheManager::_geom_cache_erase_pcollector.clear_level();
     GeomCacheManager::_geom_cache_evict_pcollector.clear_level();
     GeomCacheManager::_geom_cache_evict_pcollector.clear_level();
-    
+
     GraphicsStateGuardian::init_frame_pstats();
     GraphicsStateGuardian::init_frame_pstats();
-    
+
     _transform_states_pcollector.set_level(TransformState::get_num_states());
     _transform_states_pcollector.set_level(TransformState::get_num_states());
     _render_states_pcollector.set_level(RenderState::get_num_states());
     _render_states_pcollector.set_level(RenderState::get_num_states());
     if (pstats_unused_states) {
     if (pstats_unused_states) {
       _transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states());
       _transform_states_unused_pcollector.set_level(TransformState::get_num_unused_states());
       _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states());
       _render_states_unused_pcollector.set_level(RenderState::get_num_unused_states());
     }
     }
-    
+
     _sw_sprites_pcollector.clear_level();
     _sw_sprites_pcollector.clear_level();
-    
+
     _cnode_volume_pcollector.clear_level();
     _cnode_volume_pcollector.clear_level();
     _gnode_volume_pcollector.clear_level();
     _gnode_volume_pcollector.clear_level();
     _geom_volume_pcollector.clear_level();
     _geom_volume_pcollector.clear_level();
@@ -869,18 +870,18 @@ render_frame() {
     _occlusion_passed_pcollector.clear_level();
     _occlusion_passed_pcollector.clear_level();
     _occlusion_failed_pcollector.clear_level();
     _occlusion_failed_pcollector.clear_level();
     _occlusion_tests_pcollector.clear_level();
     _occlusion_tests_pcollector.clear_level();
-    
+
     if (PStatClient::is_connected()) {
     if (PStatClient::is_connected()) {
       size_t small_buf = GeomVertexArrayData::get_small_lru()->get_total_size();
       size_t small_buf = GeomVertexArrayData::get_small_lru()->get_total_size();
       size_t independent = GeomVertexArrayData::get_independent_lru()->get_total_size();
       size_t independent = GeomVertexArrayData::get_independent_lru()->get_total_size();
       size_t resident = VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->get_total_size();
       size_t resident = VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->get_total_size();
       size_t compressed = VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->get_total_size();
       size_t compressed = VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->get_total_size();
       size_t pending = VertexDataPage::get_pending_lru()->get_total_size();
       size_t pending = VertexDataPage::get_pending_lru()->get_total_size();
-      
+
       VertexDataSaveFile *save_file = VertexDataPage::get_save_file();
       VertexDataSaveFile *save_file = VertexDataPage::get_save_file();
       size_t total_disk = save_file->get_total_file_size();
       size_t total_disk = save_file->get_total_file_size();
       size_t used_disk = save_file->get_used_file_size();
       size_t used_disk = save_file->get_used_file_size();
-      
+
       _vertex_data_small_pcollector.set_level(small_buf);
       _vertex_data_small_pcollector.set_level(small_buf);
       _vertex_data_independent_pcollector.set_level(independent);
       _vertex_data_independent_pcollector.set_level(independent);
       _vertex_data_pending_pcollector.set_level(pending);
       _vertex_data_pending_pcollector.set_level(pending);
@@ -889,11 +890,11 @@ render_frame() {
       _vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk);
       _vertex_data_unused_disk_pcollector.set_level(total_disk - used_disk);
       _vertex_data_used_disk_pcollector.set_level(used_disk);
       _vertex_data_used_disk_pcollector.set_level(used_disk);
     }
     }
-    
+
 #endif  // DO_PSTATS
 #endif  // DO_PSTATS
-    
+
     GeomVertexArrayData::lru_epoch();
     GeomVertexArrayData::lru_epoch();
-    
+
     // Now signal all of our threads to begin their next frame.
     // Now signal all of our threads to begin their next frame.
     Threads::const_iterator ti;
     Threads::const_iterator ti;
     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
@@ -904,24 +905,24 @@ render_frame() {
       }
       }
       thread->_cv_mutex.release();
       thread->_cv_mutex.release();
     }
     }
-    
+
     // Some threads may still be drawing, so indicate that we have to
     // Some threads may still be drawing, so indicate that we have to
     // wait for those threads before we can flip.
     // wait for those threads before we can flip.
     _flip_state = _auto_flip ? FS_flip : FS_draw;
     _flip_state = _auto_flip ? FS_flip : FS_draw;
   }
   }
 
 
   // Now the lock is released.
   // Now the lock is released.
-  
+
   if (yield_timeslice) {
   if (yield_timeslice) {
     // Nap for a moment to yield the timeslice, to be polite to other
     // Nap for a moment to yield the timeslice, to be polite to other
     // running applications.
     // running applications.
     PStatTimer timer(_yield_pcollector, current_thread);
     PStatTimer timer(_yield_pcollector, current_thread);
     Thread::force_yield();
     Thread::force_yield();
-  } else if (!Thread::is_true_threads()) { 
+  } else if (!Thread::is_true_threads()) {
     PStatTimer timer(_yield_pcollector, current_thread);
     PStatTimer timer(_yield_pcollector, current_thread);
     Thread::consider_yield();
     Thread::consider_yield();
   }
   }
-  
+
   // Anything that happens outside of GraphicsEngine::render_frame()
   // Anything that happens outside of GraphicsEngine::render_frame()
   // is deemed to be App.
   // is deemed to be App.
   _app_pcollector.start();
   _app_pcollector.start();
@@ -961,11 +962,11 @@ open_windows() {
     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
     for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
       RenderThread *thread = (*ti).second;
       RenderThread *thread = (*ti).second;
       thread->_cv_mutex.acquire();
       thread->_cv_mutex.acquire();
-      
+
       while (thread->_thread_state != TS_wait) {
       while (thread->_thread_state != TS_wait) {
         thread->_cv_done.wait();
         thread->_cv_done.wait();
       }
       }
-      
+
       thread->_thread_state = TS_do_windows;
       thread->_thread_state = TS_do_windows;
       thread->_cv_start.notify();
       thread->_cv_start.notify();
       thread->_cv_mutex.release();
       thread->_cv_mutex.release();
@@ -1004,7 +1005,7 @@ sync_frame() {
 //               we seems to return once all draw calls have been submitted.
 //               we seems to return once all draw calls have been submitted.
 //               Calling 'flip_frame' after this function should immediately
 //               Calling 'flip_frame' after this function should immediately
 //               cause a buffer flip.  This function will only work in
 //               cause a buffer flip.  This function will only work in
-//               opengl right now, for all other graphics pipelines it will 
+//               opengl right now, for all other graphics pipelines it will
 //               simply return immediately.  In opengl it's a bit of a hack:
 //               simply return immediately.  In opengl it's a bit of a hack:
 //               it will attempt to read a single pixel from the frame buffer to
 //               it will attempt to read a single pixel from the frame buffer to
 //               force the graphics card to finish drawing before it returns
 //               force the graphics card to finish drawing before it returns
@@ -1082,7 +1083,7 @@ extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg) {
     WindowRenderer *wr = get_window_renderer(draw_name, 0);
     WindowRenderer *wr = get_window_renderer(draw_name, 0);
     RenderThread *thread = (RenderThread *)wr;
     RenderThread *thread = (RenderThread *)wr;
     MutexHolder holder2(thread->_cv_mutex);
     MutexHolder holder2(thread->_cv_mutex);
-      
+
     while (thread->_thread_state != TS_wait) {
     while (thread->_thread_state != TS_wait) {
       thread->_cv_done.wait();
       thread->_cv_done.wait();
     }
     }
@@ -1131,7 +1132,7 @@ dispatch_compute(const LVecBase3i &work_groups, const ShaderAttrib *sattr, Graph
     WindowRenderer *wr = get_window_renderer(draw_name, 0);
     WindowRenderer *wr = get_window_renderer(draw_name, 0);
     RenderThread *thread = (RenderThread *)wr;
     RenderThread *thread = (RenderThread *)wr;
     MutexHolder holder2(thread->_cv_mutex);
     MutexHolder holder2(thread->_cv_mutex);
-      
+
     while (thread->_thread_state != TS_wait) {
     while (thread->_thread_state != TS_wait) {
       thread->_cv_done.wait();
       thread->_cv_done.wait();
     }
     }
@@ -1149,7 +1150,7 @@ dispatch_compute(const LVecBase3i &work_groups, const ShaderAttrib *sattr, Graph
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::get_global_ptr
 //     Function: GraphicsEngine::get_global_ptr
 //       Access: Published, Static
 //       Access: Published, Static
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GraphicsEngine *GraphicsEngine::
 GraphicsEngine *GraphicsEngine::
 get_global_ptr() {
 get_global_ptr() {
@@ -1217,7 +1218,7 @@ do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
       local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy());
       local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy());
 
 
       NodePath scene_parent = scene_setup->get_scene_root().get_parent(current_thread);
       NodePath scene_parent = scene_setup->get_scene_root().get_parent(current_thread);
-      CPT(TransformState) cull_center_transform = 
+      CPT(TransformState) cull_center_transform =
         scene_setup->get_cull_center().get_transform(scene_parent, current_thread);
         scene_setup->get_cull_center().get_transform(scene_parent, current_thread);
       local_frustum->xform(cull_center_transform->get_mat());
       local_frustum->xform(cull_center_transform->get_mat());
 
 
@@ -1338,7 +1339,7 @@ cull_and_draw_together(const GraphicsEngine::Windows &wlist,
 
 
       if (win->begin_frame(GraphicsOutput::FM_render, current_thread)) {
       if (win->begin_frame(GraphicsOutput::FM_render, current_thread)) {
         win->clear(current_thread);
         win->clear(current_thread);
-      
+
         int num_display_regions = win->get_num_active_display_regions();
         int num_display_regions = win->get_num_active_display_regions();
         for (int i = 0; i < num_display_regions; i++) {
         for (int i = 0; i < num_display_regions; i++) {
           DisplayRegion *dr = win->get_active_display_region(i);
           DisplayRegion *dr = win->get_active_display_region(i);
@@ -1377,7 +1378,7 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
   GraphicsStateGuardian *gsg = win->get_gsg();
   GraphicsStateGuardian *gsg = win->get_gsg();
   nassertv(gsg != (GraphicsStateGuardian *)NULL);
   nassertv(gsg != (GraphicsStateGuardian *)NULL);
 
 
-  DisplayRegionPipelineReader *dr_reader = 
+  DisplayRegionPipelineReader *dr_reader =
     new DisplayRegionPipelineReader(dr, current_thread);
     new DisplayRegionPipelineReader(dr, current_thread);
 
 
   win->change_scenes(dr_reader);
   win->change_scenes(dr_reader);
@@ -1410,9 +1411,9 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
         // Issue the cull callback on this DisplayRegion.
         // Issue the cull callback on this DisplayRegion.
         DisplayRegionCullCallbackData cbdata(&cull_handler, scene_setup);
         DisplayRegionCullCallbackData cbdata(&cull_handler, scene_setup);
         cbobj->do_callback(&cbdata);
         cbobj->do_callback(&cbdata);
-        
+
         // The callback has taken care of the culling.
         // The callback has taken care of the culling.
-        
+
       } else {
       } else {
         // Perform the cull normally.
         // Perform the cull normally.
         dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
         dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
@@ -1456,7 +1457,7 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
       for (int i = 0; i < num_display_regions; ++i) {
       for (int i = 0; i < num_display_regions; ++i) {
         DisplayRegion *dr = win->get_active_display_region(i);
         DisplayRegion *dr = win->get_active_display_region(i);
         if (dr != (DisplayRegion *)NULL) {
         if (dr != (DisplayRegion *)NULL) {
-          DisplayRegionPipelineReader *dr_reader = 
+          DisplayRegionPipelineReader *dr_reader =
             new DisplayRegionPipelineReader(dr, current_thread);
             new DisplayRegionPipelineReader(dr, current_thread);
           NodePath camera = dr_reader->get_camera();
           NodePath camera = dr_reader->get_camera();
           AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(camera, (DisplayRegion *)NULL)).first;
           AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(camera, (DisplayRegion *)NULL)).first;
@@ -1467,7 +1468,7 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
             dr_reader = NULL;
             dr_reader = NULL;
             (*aci).second = dr;
             (*aci).second = dr;
             cull_to_bins(win, dr, current_thread);
             cull_to_bins(win, dr, current_thread);
-            
+
           } else {
           } else {
             // We have already culled a scene using this camera in
             // We have already culled a scene using this camera in
             // this thread, and now we're being asked to cull another
             // this thread, and now we're being asked to cull another
@@ -1481,7 +1482,7 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
                                 setup_scene(win->get_gsg(), dr_reader),
                                 setup_scene(win->get_gsg(), dr_reader),
                                 current_thread);
                                 current_thread);
           }
           }
-        
+
           if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
           if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
             delete dr_reader;
             delete dr_reader;
           }
           }
@@ -1539,7 +1540,7 @@ cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
     PStatTimer timer(_cull_sort_pcollector, current_thread);
     PStatTimer timer(_cull_sort_pcollector, current_thread);
     cull_result->finish_cull(scene_setup, current_thread);
     cull_result->finish_cull(scene_setup, current_thread);
   }
   }
-  
+
   // Save the results for next frame.
   // Save the results for next frame.
   dr->set_cull_result(cull_result, scene_setup, current_thread);
   dr->set_cull_result(cull_result, scene_setup, current_thread);
 }
 }
@@ -1560,53 +1561,73 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
   size_t wlist_size = wlist.size();
   size_t wlist_size = wlist.size();
   for (size_t wi = 0; wi < wlist_size; ++wi) {
   for (size_t wi = 0; wi < wlist_size; ++wi) {
     GraphicsOutput *win = wlist[wi];
     GraphicsOutput *win = wlist[wi];
+
     if (win->is_active()) {
     if (win->is_active()) {
-      if (win->flip_ready()) {
+      GraphicsStateGuardian *gsg = win->get_gsg();
+
+      GraphicsOutput *host = win->get_host();
+      if (host->flip_ready()) {
         {
         {
+          // We can't use a PStatGPUTimer before begin_frame, so when using GPU
+          // timing, it is advisable to set auto-flip to #t.
           PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
           PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
-          win->begin_flip();
+          host->begin_flip();
         }
         }
         {
         {
           PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
           PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
-          win->end_flip();
+          host->end_flip();
         }
         }
       }
       }
 
 
-      PStatTimer timer(win->get_draw_window_pcollector(), current_thread);
       if (win->begin_frame(GraphicsOutput::FM_render, current_thread)) {
       if (win->begin_frame(GraphicsOutput::FM_render, current_thread)) {
-        win->clear(current_thread);
+        // We have to place this collector inside begin_frame, because
+        // we need a current context for PStatGPUTimer to work.
+        {
+          PStatGPUTimer timer(win->get_gsg(), win->get_draw_window_pcollector(), current_thread);
+          win->clear(current_thread);
 
 
-        if (display_cat.is_spam()) {
-          display_cat.spam()
-            << "Drawing window " << win->get_name() << "\n";
-        }
-        int num_display_regions = win->get_num_active_display_regions();
-        for (int i = 0; i < num_display_regions; ++i) {
-          DisplayRegion *dr = win->get_active_display_region(i);
-          if (dr != (DisplayRegion *)NULL) {
-            draw_bins(win, dr, current_thread);
+          if (display_cat.is_spam()) {
+            display_cat.spam()
+              << "Drawing window " << win->get_name() << "\n";
+          }
+          int num_display_regions = win->get_num_active_display_regions();
+          for (int i = 0; i < num_display_regions; ++i) {
+            DisplayRegion *dr = win->get_active_display_region(i);
+            if (dr != (DisplayRegion *)NULL) {
+              draw_bins(win, dr, current_thread);
+            }
           }
           }
         }
         }
         win->end_frame(GraphicsOutput::FM_render, current_thread);
         win->end_frame(GraphicsOutput::FM_render, current_thread);
 
 
         if (_auto_flip) {
         if (_auto_flip) {
+#ifdef DO_PSTATS
+          // This is a good time to perform a latency query.
+          if (win->get_gsg()->get_timer_queries_active()) {
+            win->get_gsg()->issue_timer_query(GraphicsStateGuardian::_command_latency_pcollector.get_index());
+          }
+#endif
+
           if (win->flip_ready()) {
           if (win->flip_ready()) {
             {
             {
+              // begin_flip doesn't do anything interesting, let's not waste two timer queries on that.
               PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
               PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
               win->begin_flip();
               win->begin_flip();
             }
             }
             {
             {
-              PStatTimer timer(GraphicsEngine::_flip_end_pcollector, current_thread);
+              PStatGPUTimer timer(win->get_gsg(), GraphicsEngine::_flip_end_pcollector, current_thread);
               win->end_flip();
               win->end_flip();
             }
             }
           }
           }
         }
         }
+
       } else {
       } else {
         if (display_cat.is_spam()) {
         if (display_cat.is_spam()) {
           display_cat.spam()
           display_cat.spam()
             << "Not drawing window " << win->get_name() << "\n";
             << "Not drawing window " << win->get_name() << "\n";
         }
         }
       }
       }
+
     } else {
     } else {
       if (display_cat.is_spam()) {
       if (display_cat.is_spam()) {
         display_cat.spam()
         display_cat.spam()
@@ -1723,8 +1744,6 @@ ready_flip_windows(const GraphicsEngine::Windows &wlist, Thread *current_thread)
   }
   }
 }
 }
 
 
-
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::do_sync_frame
 //     Function: GraphicsEngine::do_sync_frame
 //       Access: Private
 //       Access: Private
@@ -1752,7 +1771,6 @@ do_sync_frame(Thread *current_thread) {
   _flip_state = FS_sync;
   _flip_state = FS_sync;
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::do_ready_flip
 //     Function: GraphicsEngine::do_ready_flip
 //       Access: Private
 //       Access: Private
@@ -1778,8 +1796,6 @@ do_ready_flip(Thread *current_thread) {
   }
   }
   _app.do_ready_flip(this,current_thread);
   _app.do_ready_flip(this,current_thread);
   _flip_state = FS_sync;
   _flip_state = FS_sync;
-  
-
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1812,7 +1828,7 @@ do_flip_frame(Thread *current_thread) {
       }
       }
     }
     }
   }
   }
-  
+
   // Now signal all of our threads to flip the windows.
   // Now signal all of our threads to flip the windows.
   _app.do_flip(this, current_thread);
   _app.do_flip(this, current_thread);
 
 
@@ -1896,7 +1912,7 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
     // There must be a singular transform over the scene.
     // There must be a singular transform over the scene.
     if (!_singular_warning_last_frame) {
     if (!_singular_warning_last_frame) {
       display_cat.warning()
       display_cat.warning()
-        << "Scene " << scene_root << " has net scale (" 
+        << "Scene " << scene_root << " has net scale ("
         << scene_root.get_scale(NodePath()) << "); cannot render.\n";
         << scene_root.get_scale(NodePath()) << "); cannot render.\n";
       _singular_warning_this_frame = true;
       _singular_warning_this_frame = true;
     }
     }
@@ -1907,7 +1923,7 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
     // There must be a singular transform over the camera.
     // There must be a singular transform over the camera.
     if (!_singular_warning_last_frame) {
     if (!_singular_warning_last_frame) {
       display_cat.warning()
       display_cat.warning()
-        << "Camera " << camera << " has net scale (" 
+        << "Camera " << camera << " has net scale ("
         << camera.get_scale(NodePath()) << "); cannot render.\n";
         << camera.get_scale(NodePath()) << "); cannot render.\n";
     }
     }
     _singular_warning_this_frame = true;
     _singular_warning_this_frame = true;
@@ -1951,11 +1967,12 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
 void GraphicsEngine::
 void GraphicsEngine::
 do_draw(CullResult *cull_result, SceneSetup *scene_setup,
 do_draw(CullResult *cull_result, SceneSetup *scene_setup,
         GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
         GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
-  // Statistics
-  PStatTimer timer(dr->get_draw_region_pcollector(), current_thread);
 
 
-  GraphicsStateGuardian *gsg = win->get_gsg();
   CallbackObject *cbobj;
   CallbackObject *cbobj;
+  GraphicsStateGuardian *gsg = win->get_gsg();
+
+  // Statistics
+  PStatGPUTimer timer(gsg, dr->get_draw_region_pcollector(), current_thread);
 
 
   {
   {
     DisplayRegionPipelineReader dr_reader(dr, current_thread);
     DisplayRegionPipelineReader dr_reader(dr, current_thread);
@@ -2034,20 +2051,20 @@ do_add_window(GraphicsOutput *window,
   _windows_sorted = false;
   _windows_sorted = false;
   _windows.push_back(window);
   _windows.push_back(window);
 
 
-  WindowRenderer *cull = 
+  WindowRenderer *cull =
     get_window_renderer(threading_model.get_cull_name(),
     get_window_renderer(threading_model.get_cull_name(),
                         threading_model.get_cull_stage());
                         threading_model.get_cull_stage());
-  WindowRenderer *draw = 
+  WindowRenderer *draw =
     get_window_renderer(threading_model.get_draw_name(),
     get_window_renderer(threading_model.get_draw_name(),
                         threading_model.get_draw_stage());
                         threading_model.get_draw_stage());
-  
+
   if (threading_model.get_cull_sorting()) {
   if (threading_model.get_cull_sorting()) {
     cull->add_window(cull->_cull, window);
     cull->add_window(cull->_cull, window);
     draw->add_window(draw->_draw, window);
     draw->add_window(draw->_draw, window);
   } else {
   } else {
     cull->add_window(cull->_cdraw, window);
     cull->add_window(cull->_cdraw, window);
   }
   }
-  
+
   // Ask the pipe which thread it prefers to run its windowing
   // Ask the pipe which thread it prefers to run its windowing
   // commands in (the "window thread").  This is the thread that
   // commands in (the "window thread").  This is the thread that
   // handles the commands to open, resize, etc. the window.  X
   // handles the commands to open, resize, etc. the window.  X
@@ -2057,7 +2074,7 @@ do_add_window(GraphicsOutput *window,
   // has been bound in a given thread, it cannot subsequently be bound
   // has been bound in a given thread, it cannot subsequently be bound
   // in any other thread, and we have to bind a context in
   // in any other thread, and we have to bind a context in
   // open_window()).
   // open_window()).
-  
+
   switch (window->get_pipe()->get_preferred_window_thread()) {
   switch (window->get_pipe()->get_preferred_window_thread()) {
   case GraphicsPipe::PWT_app:
   case GraphicsPipe::PWT_app:
     _app.add_window(_app._window, window);
     _app.add_window(_app._window, window);
@@ -2096,8 +2113,8 @@ do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
   }
   }
 
 
   auto_adjust_capabilities(gsg);
   auto_adjust_capabilities(gsg);
-  
-  WindowRenderer *draw = 
+
+  WindowRenderer *draw =
     get_window_renderer(threading_model.get_draw_name(),
     get_window_renderer(threading_model.get_draw_name(),
                         threading_model.get_draw_stage());
                         threading_model.get_draw_stage());
 
 
@@ -2228,7 +2245,7 @@ auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
       << "textures_power_2 to 'up' or 'down'.\n";
       << "textures_power_2 to 'up' or 'down'.\n";
     textures_power_2 = ATS_down; // Not a fix.  Just suppresses further error messages.
     textures_power_2 = ATS_down; // Not a fix.  Just suppresses further error messages.
   }
   }
-  
+
   if (textures_auto_power_2 && !Texture::has_textures_power_2()) {
   if (textures_auto_power_2 && !Texture::has_textures_power_2()) {
     if (gsg->get_supports_tex_non_pow2()) {
     if (gsg->get_supports_tex_non_pow2()) {
       Texture::set_textures_power_2(ATS_none);
       Texture::set_textures_power_2(ATS_none);
@@ -2236,13 +2253,13 @@ auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
       Texture::set_textures_power_2(textures_power_2);
       Texture::set_textures_power_2(textures_power_2);
     }
     }
   }
   }
-  
-  if ((Texture::get_textures_power_2() == ATS_none) && 
+
+  if ((Texture::get_textures_power_2() == ATS_none) &&
       (!gsg->get_supports_tex_non_pow2())) {
       (!gsg->get_supports_tex_non_pow2())) {
-    
+
     // Overaggressive configuration detected
     // Overaggressive configuration detected
-    
-    display_cat.error() 
+
+    display_cat.error()
       << "The 'textures_power_2' configuration is set to 'none', meaning \n"
       << "The 'textures_power_2' configuration is set to 'none', meaning \n"
       << "that non-power-of-two texture support is required, but the video \n"
       << "that non-power-of-two texture support is required, but the video \n"
       << "driver I'm trying to use does not support non-power-of-two textures.\n";
       << "driver I'm trying to use does not support non-power-of-two textures.\n";
@@ -2251,7 +2268,7 @@ auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
       display_cat.error()
       display_cat.error()
         << "The 'none' did not come from the config file.  In other words,\n"
         << "The 'none' did not come from the config file.  In other words,\n"
         << "the variable 'textures_power_2' was altered procedurally.\n";
         << "the variable 'textures_power_2' was altered procedurally.\n";
-    
+
       if (textures_auto_power_2) {
       if (textures_auto_power_2) {
         display_cat.error()
         display_cat.error()
           << "It is possible that it was set by panda's automatic mechanisms,\n"
           << "It is possible that it was set by panda's automatic mechanisms,\n"
@@ -2264,7 +2281,7 @@ auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
       }
       }
     }
     }
   }
   }
-  
+
   if (shader_auto_utilization && (shader_utilization != SUT_none)) {
   if (shader_auto_utilization && (shader_utilization != SUT_none)) {
     display_cat.error()
     display_cat.error()
       << "Invalid panda config file: if you set the config-variable\n"
       << "Invalid panda config file: if you set the config-variable\n"
@@ -2272,7 +2289,7 @@ auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
       << "shader_utilization to 'none'.\n";
       << "shader_utilization to 'none'.\n";
     shader_utilization = SUT_none; // Not a fix.  Just suppresses further error messages.
     shader_utilization = SUT_none; // Not a fix.  Just suppresses further error messages.
   }
   }
-  
+
   if (shader_auto_utilization && !Shader::have_shader_utilization()) {
   if (shader_auto_utilization && !Shader::have_shader_utilization()) {
     if (gsg->get_supports_basic_shaders()) {
     if (gsg->get_supports_basic_shaders()) {
       Shader::set_shader_utilization(SUT_basic);
       Shader::set_shader_utilization(SUT_basic);
@@ -2280,13 +2297,13 @@ auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
       Shader::set_shader_utilization(SUT_none);
       Shader::set_shader_utilization(SUT_none);
     }
     }
   }
   }
-  
-  if ((Shader::get_shader_utilization() != SUT_none) && 
+
+  if ((Shader::get_shader_utilization() != SUT_none) &&
       (!gsg->get_supports_basic_shaders())) {
       (!gsg->get_supports_basic_shaders())) {
-    
+
     // Overaggressive configuration detected
     // Overaggressive configuration detected
-    
-    display_cat.error() 
+
+    display_cat.error()
       << "The 'shader_utilization' config variable is set, meaning\n"
       << "The 'shader_utilization' config variable is set, meaning\n"
       << "that panda may try to generate shaders.  However, the video \n"
       << "that panda may try to generate shaders.  However, the video \n"
       << "driver I'm trying to use does not support shaders.\n";
       << "driver I'm trying to use does not support shaders.\n";
@@ -2295,7 +2312,7 @@ auto_adjust_capabilities(GraphicsStateGuardian *gsg) {
       display_cat.error()
       display_cat.error()
         << "The 'shader_utilization' setting did not come from the config\n"
         << "The 'shader_utilization' setting did not come from the config\n"
         << "file.  In other words, it was altered procedurally.\n";
         << "file.  In other words, it was altered procedurally.\n";
-    
+
       if (shader_auto_utilization) {
       if (shader_auto_utilization) {
         display_cat.error()
         display_cat.error()
           << "It is possible that it was set by panda's automatic mechanisms,\n"
           << "It is possible that it was set by panda's automatic mechanisms,\n"
@@ -2323,7 +2340,7 @@ terminate_threads(Thread *current_thread) {
   // We spend almost our entire time in this method just waiting for
   // We spend almost our entire time in this method just waiting for
   // threads.  Time it appropriately.
   // threads.  Time it appropriately.
   PStatTimer timer(_wait_pcollector, current_thread);
   PStatTimer timer(_wait_pcollector, current_thread);
-  
+
   // First, wait for all the threads to finish their current frame.
   // First, wait for all the threads to finish their current frame.
   // Grabbing the mutex should achieve that.
   // Grabbing the mutex should achieve that.
   Threads::const_iterator ti;
   Threads::const_iterator ti;
@@ -2331,7 +2348,7 @@ terminate_threads(Thread *current_thread) {
     RenderThread *thread = (*ti).second;
     RenderThread *thread = (*ti).second;
     thread->_cv_mutex.acquire();
     thread->_cv_mutex.acquire();
   }
   }
-  
+
   // Now tell them to close their windows and terminate.
   // Now tell them to close their windows and terminate.
   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
   for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
     RenderThread *thread = (*ti).second;
     RenderThread *thread = (*ti).second;
@@ -2345,7 +2362,7 @@ terminate_threads(Thread *current_thread) {
     RenderThread *thread = (*ti).second;
     RenderThread *thread = (*ti).second;
     thread->join();
     thread->join();
   }
   }
-  
+
   _threads.clear();
   _threads.clear();
 }
 }
 
 
@@ -2451,7 +2468,7 @@ get_window_renderer(const string &name, int pipeline_stage) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::WindowRenderer::Constructor
 //     Function: GraphicsEngine::WindowRenderer::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GraphicsEngine::WindowRenderer::
 GraphicsEngine::WindowRenderer::
 WindowRenderer(const string &name) :
 WindowRenderer(const string &name) :
@@ -2589,7 +2606,7 @@ do_frame(GraphicsEngine *engine, Thread *current_thread) {
         // This one has no outstanding pointers; clean it up.
         // This one has no outstanding pointers; clean it up.
         GraphicsPipe *pipe = gsg->get_pipe();
         GraphicsPipe *pipe = gsg->get_pipe();
         engine->close_gsg(pipe, gsg);
         engine->close_gsg(pipe, gsg);
-      } else { 
+      } else {
         // This one is ok; preserve it.
         // This one is ok; preserve it.
         new_gsgs.insert(gsg);
         new_gsgs.insert(gsg);
       }
       }
@@ -2668,12 +2685,12 @@ do_close(GraphicsEngine *engine, Thread *current_thread) {
       // This one has no outstanding pointers; clean it up.
       // This one has no outstanding pointers; clean it up.
       GraphicsPipe *pipe = gsg->get_pipe();
       GraphicsPipe *pipe = gsg->get_pipe();
       engine->close_gsg(pipe, gsg);
       engine->close_gsg(pipe, gsg);
-    } else { 
+    } else {
       // This one is ok; preserve it.
       // This one is ok; preserve it.
       new_gsgs.insert(gsg);
       new_gsgs.insert(gsg);
     }
     }
   }
   }
-  
+
   _gsgs.swap(new_gsgs);
   _gsgs.swap(new_gsgs);
 }
 }
 
 
@@ -2729,10 +2746,10 @@ any_done_gsgs() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::RenderThread::Constructor
 //     Function: GraphicsEngine::RenderThread::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GraphicsEngine::RenderThread::
 GraphicsEngine::RenderThread::
-RenderThread(const string &name, GraphicsEngine *engine) : 
+RenderThread(const string &name, GraphicsEngine *engine) :
   Thread(name, "Main"),
   Thread(name, "Main"),
   WindowRenderer(name),
   WindowRenderer(name),
   _engine(engine),
   _engine(engine),

+ 52 - 3
panda/src/display/graphicsStateGuardian.I

@@ -1,6 +1,6 @@
 // Filename: graphicsStateGuardian.I
 // Filename: graphicsStateGuardian.I
 // Created by:  drose (24Sep99)
 // Created by:  drose (24Sep99)
-// Updated by: fperazzi, PandaSE (29Apr10) (added 
+// Updated by: fperazzi, PandaSE (29Apr10) (added
 // get_max_2d_texture_array_layers and related)
 // get_max_2d_texture_array_layers and related)
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -334,10 +334,10 @@ get_max_3d_texture_dimension() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_max_2d_texture_array_layers
 //     Function: GraphicsStateGuardian::get_max_2d_texture_array_layers
 //       Access: Published
 //       Access: Published
-//  Description: Returns the largest possible number of pages, or -1 
+//  Description: Returns the largest possible number of pages, or -1
 //               if there is no particular limit. Returns 0 if 2-d
 //               if there is no particular limit. Returns 0 if 2-d
 //               texture arrays not supported.
 //               texture arrays not supported.
-//               
+//
 //               The value returned may not be meaningful until after
 //               The value returned may not be meaningful until after
 //               the graphics context has been fully created (e.g. the
 //               the graphics context has been fully created (e.g. the
 //               window has been opened).
 //               window has been opened).
@@ -447,6 +447,16 @@ get_supports_tex_non_pow2() const {
   return _supports_tex_non_pow2;
   return _supports_tex_non_pow2;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_supports_texture_srgb
+//       Access: Published
+//  Description: Returns true if this GSG can handle sRGB textures.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_supports_texture_srgb() const {
+  return _supports_texture_srgb;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_supports_compressed_texture
 //     Function: GraphicsStateGuardian::get_supports_compressed_texture
 //       Access: Published
 //       Access: Published
@@ -713,6 +723,45 @@ get_supports_geometry_instancing() const {
   return _supports_geometry_instancing;
   return _supports_geometry_instancing;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_supports_occlusion_query
+//       Access: Published
+//  Description: Returns true if this GSG supports an occlusion query.
+//               If this is true, then begin_occlusion_query() and
+//               end_occlusion_query() may be called to bracket a
+//               sequence of draw_triangles() (or whatever) calls to
+//               measure pixels that pass the depth test.
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+get_supports_occlusion_query() const {
+  return _supports_occlusion_query;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_supports_timer_query
+//       Access: Published
+//  Description: Returns true if this GSG supports a timer query.
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+get_supports_timer_query() const {
+  return _supports_timer_query;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_timer_queries_active
+//       Access: Published
+//  Description: Returns true if timer queries are currently
+//               enabled on this GSG.
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+get_timer_queries_active() const {
+#ifdef DO_PSTATS
+  return _timer_queries_active;
+#else
+  return false;
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_max_color_targets
 //     Function: GraphicsStateGuardian::get_max_color_targets
 //       Access: Published
 //       Access: Published

+ 213 - 39
panda/src/display/graphicsStateGuardian.cxx

@@ -28,6 +28,7 @@
 #include "throw_event.h"
 #include "throw_event.h"
 #include "clockObject.h"
 #include "clockObject.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
+#include "pStatGPUTimer.h"
 #include "geomTristrips.h"
 #include "geomTristrips.h"
 #include "geomTrifans.h"
 #include "geomTrifans.h"
 #include "geomLinestrips.h"
 #include "geomLinestrips.h"
@@ -55,6 +56,7 @@
 #include "colorScaleAttrib.h"
 #include "colorScaleAttrib.h"
 #include "clipPlaneAttrib.h"
 #include "clipPlaneAttrib.h"
 #include "fogAttrib.h"
 #include "fogAttrib.h"
+#include "config_pstats.h"
 
 
 #include <algorithm>
 #include <algorithm>
 #include <limits.h>
 #include <limits.h>
@@ -87,9 +89,19 @@ PStatCollector GraphicsStateGuardian::_draw_primitive_pcollector("Draw:Primitive
 PStatCollector GraphicsStateGuardian::_draw_set_state_pcollector("Draw:Set State");
 PStatCollector GraphicsStateGuardian::_draw_set_state_pcollector("Draw:Set State");
 PStatCollector GraphicsStateGuardian::_clear_pcollector("Draw:Clear");
 PStatCollector GraphicsStateGuardian::_clear_pcollector("Draw:Clear");
 PStatCollector GraphicsStateGuardian::_flush_pcollector("Draw:Flush");
 PStatCollector GraphicsStateGuardian::_flush_pcollector("Draw:Flush");
+PStatCollector GraphicsStateGuardian::_compute_dispatch_pcollector("Draw:Compute dispatch");
 
 
 PStatCollector GraphicsStateGuardian::_wait_occlusion_pcollector("Wait:Occlusion");
 PStatCollector GraphicsStateGuardian::_wait_occlusion_pcollector("Wait:Occlusion");
+PStatCollector GraphicsStateGuardian::_wait_timer_pcollector("Wait:Timer Queries");
+PStatCollector GraphicsStateGuardian::_timer_queries_pcollector("Timer queries");
+PStatCollector GraphicsStateGuardian::_command_latency_pcollector("Command latency");
 
 
+PStatCollector GraphicsStateGuardian::_prepare_pcollector("Draw:Prepare");
+PStatCollector GraphicsStateGuardian::_prepare_texture_pcollector("Draw:Prepare:Texture");
+PStatCollector GraphicsStateGuardian::_prepare_geom_pcollector("Draw:Prepare:Geom");
+PStatCollector GraphicsStateGuardian::_prepare_shader_pcollector("Draw:Prepare:Shader");
+PStatCollector GraphicsStateGuardian::_prepare_vertex_buffer_pcollector("Draw:Prepare:Vertex buffer");
+PStatCollector GraphicsStateGuardian::_prepare_index_buffer_pcollector("Draw:Prepare:Index buffer");
 
 
 PStatCollector GraphicsStateGuardian::_draw_set_state_transform_pcollector("Draw:Set State:Transform");
 PStatCollector GraphicsStateGuardian::_draw_set_state_transform_pcollector("Draw:Set State:Transform");
 PStatCollector GraphicsStateGuardian::_draw_set_state_alpha_test_pcollector("Draw:Set State:Alpha test");
 PStatCollector GraphicsStateGuardian::_draw_set_state_alpha_test_pcollector("Draw:Set State:Alpha test");
@@ -115,7 +127,6 @@ PStatCollector GraphicsStateGuardian::_draw_set_state_stencil_pcollector("Draw:S
 PStatCollector GraphicsStateGuardian::_draw_set_state_fog_pcollector("Draw:Set State:Fog");
 PStatCollector GraphicsStateGuardian::_draw_set_state_fog_pcollector("Draw:Set State:Fog");
 PStatCollector GraphicsStateGuardian::_draw_set_state_scissor_pcollector("Draw:Set State:Scissor");
 PStatCollector GraphicsStateGuardian::_draw_set_state_scissor_pcollector("Draw:Set State:Scissor");
 
 
-
 PT(TextureStage) GraphicsStateGuardian::_alpha_scale_texture_stage = NULL;
 PT(TextureStage) GraphicsStateGuardian::_alpha_scale_texture_stage = NULL;
 
 
 TypeHandle GraphicsStateGuardian::_type_handle;
 TypeHandle GraphicsStateGuardian::_type_handle;
@@ -184,6 +195,7 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _supports_2d_texture_array = false;
   _supports_2d_texture_array = false;
   _supports_cube_map = false;
   _supports_cube_map = false;
   _supports_tex_non_pow2 = false;
   _supports_tex_non_pow2 = false;
+  _supports_texture_srgb = false;
   _supports_compressed_texture = false;
   _supports_compressed_texture = false;
   _compressed_texture_formats.clear();
   _compressed_texture_formats.clear();
   _compressed_texture_formats.set_bit(Texture::CM_off);
   _compressed_texture_formats.set_bit(Texture::CM_off);
@@ -197,6 +209,16 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _max_vertex_transform_indices = 0;
   _max_vertex_transform_indices = 0;
 
 
   _supports_occlusion_query = false;
   _supports_occlusion_query = false;
+  _supports_timer_query = false;
+
+#ifdef DO_PSTATS
+  _timer_queries_active = false;
+  _last_query_frame = 0;
+  _last_num_queried = 0;
+  //_timer_delta = 0.0;
+
+  _pstats_gpu_thread = -1;
+#endif
 
 
   // Initially, we set this to false; a GSG that knows it has this
   // Initially, we set this to false; a GSG that knows it has this
   // property should set it to true.
   // property should set it to true.
@@ -261,7 +283,7 @@ GraphicsStateGuardian::
     delete _stencil_render_states;
     delete _stencil_render_states;
     _stencil_render_states = 0;
     _stencil_render_states = 0;
   }
   }
-  
+
   if (_shader_generator) {
   if (_shader_generator) {
     delete _shader_generator;
     delete _shader_generator;
     _shader_generator = 0;
     _shader_generator = 0;
@@ -322,7 +344,7 @@ get_supported_geom_rendering() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_supports_cg_profile
 //     Function: GraphicsStateGuardian::get_supports_cg_profile
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: Returns true if this particular GSG supports the 
+//  Description: Returns true if this particular GSG supports the
 //               specified Cg Shader Profile.
 //               specified Cg Shader Profile.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
 bool GraphicsStateGuardian::
@@ -405,7 +427,7 @@ get_prepared_objects() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
 bool GraphicsStateGuardian::
 set_gamma(PN_stdfloat gamma) {
 set_gamma(PN_stdfloat gamma) {
-  _gamma = gamma;  
+  _gamma = gamma;
 
 
   return false;
   return false;
 }
 }
@@ -437,7 +459,7 @@ restore_gamma() {
 //               function returns false.
 //               function returns false.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
-traverse_prepared_textures(GraphicsStateGuardian::TextureCallback *func, 
+traverse_prepared_textures(GraphicsStateGuardian::TextureCallback *func,
                            void *callback_arg) {
                            void *callback_arg) {
   ReMutexHolder holder(_prepared_objects->_lock);
   ReMutexHolder holder(_prepared_objects->_lock);
   PreparedGraphicsObjects::Textures::const_iterator ti;
   PreparedGraphicsObjects::Textures::const_iterator ti;
@@ -702,20 +724,6 @@ void GraphicsStateGuardian::
 release_index_buffer(IndexBufferContext *) {
 release_index_buffer(IndexBufferContext *) {
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::get_supports_occlusion_query
-//       Access: Public, Virtual
-//  Description: Returns true if this GSG supports an occlusion query.
-//               If this is true, then begin_occlusion_query() and
-//               end_occlusion_query() may be called to bracket a
-//               sequence of draw_triangles() (or whatever) calls to
-//               measure pixels that pass the depth test.
-////////////////////////////////////////////////////////////////////
-bool GraphicsStateGuardian::
-get_supports_occlusion_query() const {
-  return _supports_occlusion_query;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::begin_occlusion_query
 //     Function: GraphicsStateGuardian::begin_occlusion_query
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -754,6 +762,17 @@ end_occlusion_query() {
   return result;
   return result;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::issue_timer_query
+//       Access: Public, Virtual
+//  Description: Adds a timer query to the command stream, associated
+//               with the given PStats collector index.
+////////////////////////////////////////////////////////////////////
+PT(TimerQueryContext) GraphicsStateGuardian::
+issue_timer_query(int pstats_index) {
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::dispatch_compute
 //     Function: GraphicsStateGuardian::dispatch_compute
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -888,7 +907,7 @@ compute_distance_to(const LPoint3 &point) const {
 //               the need for a separate routine to fetch these values.
 //               the need for a separate routine to fetch these values.
 //
 //
 //               The "altered" bits indicate what parts of the
 //               The "altered" bits indicate what parts of the
-//               state_and_transform have changed since the last 
+//               state_and_transform have changed since the last
 //               time this particular ShaderMatSpec was evaluated.
 //               time this particular ShaderMatSpec was evaluated.
 //               This may allow data to be cached and not reevaluated.
 //               This may allow data to be cached and not reevaluated.
 //
 //
@@ -896,7 +915,7 @@ compute_distance_to(const LPoint3 &point) const {
 const LMatrix4 *GraphicsStateGuardian::
 const LMatrix4 *GraphicsStateGuardian::
 fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) {
 fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) {
   LVecBase3 v;
   LVecBase3 v;
-  
+
   if (altered & spec._dep[0]) {
   if (altered & spec._dep[0]) {
     const LMatrix4 *t = fetch_specified_part(spec._part[0], spec._arg[0], spec._cache[0]);
     const LMatrix4 *t = fetch_specified_part(spec._part[0], spec._arg[0], spec._cache[0]);
     if (t != &spec._cache[0]) {
     if (t != &spec._cache[0]) {
@@ -909,7 +928,7 @@ fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) {
       spec._cache[1] = *t;
       spec._cache[1] = *t;
     }
     }
   }
   }
-  
+
   switch(spec._func) {
   switch(spec._func) {
   case Shader::SMF_compose:
   case Shader::SMF_compose:
     spec._value.multiply(spec._cache[0], spec._cache[1]);
     spec._value.multiply(spec._cache[0], spec._cache[1]);
@@ -1470,6 +1489,29 @@ begin_frame(Thread *current_thread) {
   _state_rs = RenderState::make_empty();
   _state_rs = RenderState::make_empty();
   _state_mask.clear();
   _state_mask.clear();
 
 
+#ifdef DO_PSTATS
+  // We have to do this here instead of in GraphicsEngine because
+  // we need a current context to issue timer queries.
+  int frame = ClockObject::get_global_clock()->get_frame_count();
+  if (_last_query_frame < frame) {
+    _last_query_frame = frame;
+    _timer_queries_pcollector.clear_level();
+
+    // Now is a good time to flush previous frame's queries.  We
+    // may not actually have all of the previous frame's results
+    // in yet, but that's okay; the GPU data is allowed to lag a
+    // few frames behind.
+    flush_timer_queries();
+
+    if (_timer_queries_active) {
+      // Issue a stop and start event for collector 0, marking the
+      // beginning of the new frame.
+      issue_timer_query(0x8000);
+      issue_timer_query(0x0000);
+    }
+  }
+#endif
+
   return !_needs_reset;
   return !_needs_reset;
 }
 }
 
 
@@ -1566,6 +1608,138 @@ end_frame(Thread *current_thread) {
   _prepared_objects->_graphics_memory_lru.begin_epoch();
   _prepared_objects->_graphics_memory_lru.begin_epoch();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::flush_timer_queries
+//       Access: Public
+//  Description: Called by the graphics engine on the draw thread
+//               to check the status of the running timer queries
+//               and submit their results to the PStats server.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+flush_timer_queries() {
+#ifdef DO_PSTATS
+  // This uses the lower-level PStats interfaces for now because
+  // of all the unnecessary overhead that would otherwise be incurred
+  // when adding such a large amount of data at once.
+
+  PStatClient *client = PStatClient::get_global_pstats();
+
+  if (!client->client_is_connected()) {
+    _timer_queries_active = false;
+    return;
+  }
+
+  if (!_timer_queries_active) {
+    if (pstats_gpu_timing && _supports_timer_query) {
+      // Check if timer queries should be enabled.
+      _timer_queries_active = true;
+    } else {
+      return;
+    }
+  }
+
+  // Currently, we use one thread per GSG, for convenience.  In the
+  // future, we may want to try and use one thread per graphics card.
+  if (_pstats_gpu_thread == -1) {
+    _pstats_gpu_thread = client->make_gpu_thread(get_driver_renderer()).get_index();
+  }
+  PStatThread gpu_thread(client, _pstats_gpu_thread);
+
+  // Get the results of all the timer queries.
+  int first = 0;
+  if (!_pending_timer_queries.empty()) {
+    int count = _pending_timer_queries.size();
+    if (count == 0) {
+      return;
+    }
+
+    PStatGPUTimer timer(this, _wait_timer_pcollector);
+
+    if (_last_num_queried > 0) {
+      // We know how many queries were available last frame, and this
+      // usually stays fairly constant, so use this as a starting point.
+      int i = min(_last_num_queried, count) - 1;
+
+      if (_pending_timer_queries[i]->is_answer_ready()) {
+        first = count;
+        while (i < count) {
+          if (!_pending_timer_queries[++i]->is_answer_ready()) {
+            first = i;
+            break;
+          }
+        }
+      } else {
+        first = 0;
+        while (i > 0) {
+          if (_pending_timer_queries[--i]->is_answer_ready()) {
+            first = i + 1;
+            break;
+          }
+        }
+      }
+    } else {
+      // We figure out which tasks the GPU has already finished by doing
+      // a binary search for the first query that does not have an answer
+      // ready.  We know then that everything before that must be ready.
+      while (count > 0) {
+        int step = count / 2;
+        int i = first + step;
+        if (_pending_timer_queries[i]->is_answer_ready()) {
+          first += step + 1;
+          count -= step + 1;
+        } else {
+          count = step;
+        }
+      }
+    }
+
+    if (first <= 0) {
+      return;
+    }
+
+    _last_num_queried = first;
+
+    int frame_index = ClockObject::get_global_clock()->get_frame_count();
+
+    for (int i = 0; i < first; ++i) {
+      CPT(TimerQueryContext) query = _pending_timer_queries[i];
+
+      double time_data = query->get_timestamp(); //  + _timer_delta;
+
+      if (query->_pstats_index == _command_latency_pcollector.get_index()) {
+        // Special case for the latency pcollector.
+        PStatCollectorDef *cdef;
+        cdef = client->get_collector_ptr(query->_pstats_index)->get_def(client, query->_pstats_index);
+        _pstats_gpu_data.add_level(query->_pstats_index, time_data * cdef->_factor);
+
+      } else if (query->_pstats_index & 0x8000) {
+        _pstats_gpu_data.add_stop(query->_pstats_index & 0x7fff, time_data);
+
+      } else {
+        _pstats_gpu_data.add_start(query->_pstats_index & 0x7fff, time_data);
+      }
+
+      // We found an end-frame marker (a stop event for collector 0).
+      // This means that the GPU actually caught up with that frame,
+      // and we can flush the GPU thread's frame data to the pstats server.
+      if (query->_pstats_index == 0x8000) {
+        gpu_thread.add_frame(_pstats_gpu_data);
+        _pstats_gpu_data.clear();
+      }
+    }
+  }
+
+  if (first > 0) {
+    // Do this out of the scope of _wait_timer_pcollector.
+    _pending_timer_queries.erase(
+      _pending_timer_queries.begin(),
+      _pending_timer_queries.begin() + first
+    );
+    _timer_queries_pcollector.add_level_now(first);
+  }
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::depth_offset_decals
 //     Function: GraphicsStateGuardian::depth_offset_decals
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -1819,7 +1993,7 @@ reset() {
     delete _stencil_render_states;
     delete _stencil_render_states;
     _stencil_render_states = 0;
     _stencil_render_states = 0;
   }
   }
-  _stencil_render_states = new StencilRenderStates (this);
+  _stencil_render_states = new StencilRenderStates(this);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1935,12 +2109,12 @@ do_issue_clip_plane() {
           enable_clip_planes(true);
           enable_clip_planes(true);
           _clip_planes_enabled = true;
           _clip_planes_enabled = true;
         }
         }
-        
+
         enable_clip_plane(num_enabled, true);
         enable_clip_plane(num_enabled, true);
         if (num_enabled == 0) {
         if (num_enabled == 0) {
           begin_bind_clip_planes();
           begin_bind_clip_planes();
         }
         }
-        
+
         bind_clip_plane(plane, num_enabled);
         bind_clip_plane(plane, num_enabled);
         num_enabled++;
         num_enabled++;
       }
       }
@@ -2123,7 +2297,7 @@ do_issue_light() {
           if (num_enabled == 0) {
           if (num_enabled == 0) {
             begin_bind_lights();
             begin_bind_lights();
           }
           }
-          
+
           light_obj->bind(this, light, num_enabled);
           light_obj->bind(this, light, num_enabled);
           num_enabled++;
           num_enabled++;
         }
         }
@@ -2278,24 +2452,24 @@ create_gamma_table (PN_stdfloat gamma, unsigned short *red_table, unsigned short
     // avoid divide by zero and negative exponents
     // avoid divide by zero and negative exponents
     gamma = 1.0;
     gamma = 1.0;
   }
   }
-  
+
   for (i = 0; i < 256; i++) {
   for (i = 0; i < 256; i++) {
     double g;
     double g;
     double x;
     double x;
     PN_stdfloat gamma_correction;
     PN_stdfloat gamma_correction;
-    
+
     x = ((double) i / 255.0);
     x = ((double) i / 255.0);
-    gamma_correction = 1.0 / gamma;    
+    gamma_correction = 1.0 / gamma;
     x = pow (x, (double) gamma_correction);
     x = pow (x, (double) gamma_correction);
     if (x > 1.00) {
     if (x > 1.00) {
       x = 1.0;
       x = 1.0;
     }
     }
 
 
-    g = x * 65535.0;    
+    g = x * 65535.0;
     red_table [i] = (int)g;
     red_table [i] = (int)g;
     green_table [i] = (int)g;
     green_table [i] = (int)g;
     blue_table [i] = (int)g;
     blue_table [i] = (int)g;
-  }    
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -2638,7 +2812,7 @@ async_reload_texture(TextureContext *tc) {
 
 
   string task_name = string("reload:") + tc->get_texture()->get_name();
   string task_name = string("reload:") + tc->get_texture()->get_name();
   PT(AsyncTaskManager) task_mgr = _loader->get_task_manager();
   PT(AsyncTaskManager) task_mgr = _loader->get_task_manager();
-  
+
   // See if we are already loading this task.
   // See if we are already loading this task.
   AsyncTaskCollection orig_tasks = task_mgr->find_tasks(task_name);
   AsyncTaskCollection orig_tasks = task_mgr->find_tasks(task_name);
   int num_tasks = orig_tasks.get_num_tasks();
   int num_tasks = orig_tasks.get_num_tasks();
@@ -2655,7 +2829,7 @@ async_reload_texture(TextureContext *tc) {
 
 
   // This texture has not yet been queued to be reloaded.  Queue it up
   // This texture has not yet been queued to be reloaded.  Queue it up
   // now.
   // now.
-  PT(AsyncTask) request = 
+  PT(AsyncTask) request =
     new TextureReloadRequest(task_name,
     new TextureReloadRequest(task_name,
                              _prepared_objects, tc->get_texture(),
                              _prepared_objects, tc->get_texture(),
                              _supports_compressed_texture);
                              _supports_compressed_texture);
@@ -2762,20 +2936,20 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_driver_vendor
 //     Function: GraphicsStateGuardian::get_driver_vendor
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: Returns the vendor of the video card driver 
+//  Description: Returns the vendor of the video card driver
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 string GraphicsStateGuardian::
 string GraphicsStateGuardian::
 get_driver_vendor() {
 get_driver_vendor() {
-  return string("0");
+  return string();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::get_driver_vendor
+//     Function: GraphicsStateGuardian::get_driver_renderer
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description: Returns GL_Renderer
 //  Description: Returns GL_Renderer
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 string GraphicsStateGuardian::get_driver_renderer() {
 string GraphicsStateGuardian::get_driver_renderer() {
-  return string("0");
+  return string();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -2783,12 +2957,12 @@ string GraphicsStateGuardian::get_driver_renderer() {
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description: Returns driver version
 //  Description: Returns driver version
 //               This has an implementation-defined meaning, and may
 //               This has an implementation-defined meaning, and may
-//               be "0" if the particular graphics implementation
+//               be "" if the particular graphics implementation
 //               does not provide a way to query this information.
 //               does not provide a way to query this information.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 string GraphicsStateGuardian::
 string GraphicsStateGuardian::
 get_driver_version() {
 get_driver_version() {
-  return string("0");
+  return string();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 41 - 7
panda/src/display/graphicsStateGuardian.h

@@ -44,6 +44,7 @@
 #include "bitMask.h"
 #include "bitMask.h"
 #include "texture.h"
 #include "texture.h"
 #include "occlusionQueryContext.h"
 #include "occlusionQueryContext.h"
+#include "timerQueryContext.h"
 #include "stencilRenderStates.h"
 #include "stencilRenderStates.h"
 #include "loader.h"
 #include "loader.h"
 #include "shaderAttrib.h"
 #include "shaderAttrib.h"
@@ -126,6 +127,7 @@ PUBLISHED:
   INLINE bool get_supports_2d_texture_array() const;
   INLINE bool get_supports_2d_texture_array() const;
   INLINE bool get_supports_cube_map() const;
   INLINE bool get_supports_cube_map() const;
   INLINE bool get_supports_tex_non_pow2() const;
   INLINE bool get_supports_tex_non_pow2() const;
+  INLINE bool get_supports_texture_srgb() const;
 
 
   INLINE bool get_supports_compressed_texture() const;
   INLINE bool get_supports_compressed_texture() const;
   virtual INLINE bool get_supports_compressed_texture_format(int compression_mode) const;
   virtual INLINE bool get_supports_compressed_texture_format(int compression_mode) const;
@@ -151,6 +153,10 @@ PUBLISHED:
   INLINE bool get_supports_two_sided_stencil() const;
   INLINE bool get_supports_two_sided_stencil() const;
   INLINE bool get_supports_geometry_instancing() const;
   INLINE bool get_supports_geometry_instancing() const;
 
 
+  INLINE bool get_supports_occlusion_query() const;
+  INLINE bool get_supports_timer_query() const;
+  INLINE bool get_timer_queries_active() const;
+
   INLINE int get_max_color_targets() const;
   INLINE int get_max_color_targets() const;
   INLINE int get_maximum_simultaneous_render_targets() const;
   INLINE int get_maximum_simultaneous_render_targets() const;
 
 
@@ -200,7 +206,7 @@ PUBLISHED:
   virtual int get_driver_version_minor();
   virtual int get_driver_version_minor();
   virtual int get_driver_shader_version_major();
   virtual int get_driver_shader_version_major();
   virtual int get_driver_shader_version_minor();
   virtual int get_driver_shader_version_minor();
-  
+
   bool set_scene(SceneSetup *scene_setup);
   bool set_scene(SceneSetup *scene_setup);
   virtual SceneSetup *get_scene() const;
   virtual SceneSetup *get_scene() const;
 
 
@@ -222,10 +228,11 @@ public:
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data);
   virtual void release_index_buffer(IndexBufferContext *ibc);
   virtual void release_index_buffer(IndexBufferContext *ibc);
 
 
-  virtual bool get_supports_occlusion_query() const;
   virtual void begin_occlusion_query();
   virtual void begin_occlusion_query();
   virtual PT(OcclusionQueryContext) end_occlusion_query();
   virtual PT(OcclusionQueryContext) end_occlusion_query();
 
 
+  virtual PT(TimerQueryContext) issue_timer_query(int pstats_index);
+
   virtual void dispatch_compute(int size_x, int size_y, int size_z);
   virtual void dispatch_compute(int size_x, int size_y, int size_z);
 
 
   virtual PT(GeomMunger) get_geom_munger(const RenderState *state,
   virtual PT(GeomMunger) get_geom_munger(const RenderState *state,
@@ -239,7 +246,7 @@ public:
   virtual PN_stdfloat compute_distance_to(const LPoint3 &point) const;
   virtual PN_stdfloat compute_distance_to(const LPoint3 &point) const;
 
 
   virtual void clear(DrawableRegion *clearable);
   virtual void clear(DrawableRegion *clearable);
-  
+
   const LMatrix4 *fetch_specified_value(Shader::ShaderMatSpec &spec, int altered);
   const LMatrix4 *fetch_specified_value(Shader::ShaderMatSpec &spec, int altered);
   const LMatrix4 *fetch_specified_part(Shader::ShaderMatInput input, InternalName *name, LMatrix4 &t);
   const LMatrix4 *fetch_specified_part(Shader::ShaderMatInput input, InternalName *name, LMatrix4 &t);
   const Shader::ShaderPtrData *fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec);
   const Shader::ShaderPtrData *fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec);
@@ -260,6 +267,8 @@ PUBLISHED:
 public:
 public:
   virtual void end_frame(Thread *current_thread);
   virtual void end_frame(Thread *current_thread);
 
 
+  void flush_timer_queries();
+
   void set_current_properties(const FrameBufferProperties *properties);
   void set_current_properties(const FrameBufferProperties *properties);
 
 
   virtual bool depth_offset_decals();
   virtual bool depth_offset_decals();
@@ -375,7 +384,7 @@ protected:
   // This bitmask contains a 1 bit everywhere that _state_rs has a
   // This bitmask contains a 1 bit everywhere that _state_rs has a
   // known value.  If a bit is 0, the corresponding state must be
   // known value.  If a bit is 0, the corresponding state must be
   // re-sent.
   // re-sent.
-  // 
+  //
   // Derived GSGs should initialize _inv_state_mask in reset() as a mask of
   // Derived GSGs should initialize _inv_state_mask in reset() as a mask of
   // 1's where they don't care, and 0's where they do care, about the state.
   // 1's where they don't care, and 0's where they do care, about the state.
   RenderState::SlotMask _state_mask;
   RenderState::SlotMask _state_mask;
@@ -406,7 +415,7 @@ protected:
 
 
   unsigned int _color_write_mask;
   unsigned int _color_write_mask;
 
 
-  CPT(DisplayRegion) _current_display_region;
+  PT(DisplayRegion) _current_display_region;
   Lens::StereoChannel _current_stereo_channel;
   Lens::StereoChannel _current_stereo_channel;
   int _current_tex_view_offset;
   int _current_tex_view_offset;
   CPT(Lens) _current_lens;
   CPT(Lens) _current_lens;
@@ -468,6 +477,7 @@ protected:
   bool _supports_2d_texture_array;
   bool _supports_2d_texture_array;
   bool _supports_cube_map;
   bool _supports_cube_map;
   bool _supports_tex_non_pow2;
   bool _supports_tex_non_pow2;
+  bool _supports_texture_srgb;
 
 
   bool _supports_compressed_texture;
   bool _supports_compressed_texture;
   BitMask32 _compressed_texture_formats;
   BitMask32 _compressed_texture_formats;
@@ -481,6 +491,19 @@ protected:
   bool _supports_occlusion_query;
   bool _supports_occlusion_query;
   PT(OcclusionQueryContext) _current_occlusion_query;
   PT(OcclusionQueryContext) _current_occlusion_query;
 
 
+  bool _supports_timer_query;
+#ifdef DO_PSTATS
+  int _pstats_gpu_thread;
+  bool _timer_queries_active;
+  PStatFrameData _pstats_gpu_data;
+
+  int _last_query_frame;
+  int _last_num_queried;
+  //double _timer_delta;
+  typedef pdeque<PT(TimerQueryContext)> TimerQueryQueue;
+  TimerQueryQueue _pending_timer_queries;
+#endif
+
   bool _copy_texture_inverted;
   bool _copy_texture_inverted;
   bool _supports_multisample;
   bool _supports_multisample;
   bool _supports_generate_mipmap;
   bool _supports_generate_mipmap;
@@ -520,13 +543,13 @@ protected:
 
 
   PN_stdfloat _gamma;
   PN_stdfloat _gamma;
   Texture::QualityLevel _texture_quality_override;
   Texture::QualityLevel _texture_quality_override;
-  
+
   ShaderGenerator* _shader_generator;
   ShaderGenerator* _shader_generator;
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
   PT(Texture) _flash_texture;
   PT(Texture) _flash_texture;
 #endif
 #endif
-  
+
 public:
 public:
   // Statistics
   // Statistics
   static PStatCollector _vertex_buffer_switch_pcollector;
   static PStatCollector _vertex_buffer_switch_pcollector;
@@ -558,7 +581,18 @@ public:
   static PStatCollector _draw_set_state_pcollector;
   static PStatCollector _draw_set_state_pcollector;
   static PStatCollector _clear_pcollector;
   static PStatCollector _clear_pcollector;
   static PStatCollector _flush_pcollector;
   static PStatCollector _flush_pcollector;
+  static PStatCollector _compute_dispatch_pcollector;
   static PStatCollector _wait_occlusion_pcollector;
   static PStatCollector _wait_occlusion_pcollector;
+  static PStatCollector _wait_timer_pcollector;
+  static PStatCollector _timer_queries_pcollector;
+  static PStatCollector _command_latency_pcollector;
+
+  static PStatCollector _prepare_pcollector;
+  static PStatCollector _prepare_texture_pcollector;
+  static PStatCollector _prepare_geom_pcollector;
+  static PStatCollector _prepare_shader_pcollector;
+  static PStatCollector _prepare_vertex_buffer_pcollector;
+  static PStatCollector _prepare_index_buffer_pcollector;
 
 
   // A whole slew of collectors to measure the cost of individual
   // A whole slew of collectors to measure the cost of individual
   // state changes.  These are disabled by default.
   // state changes.  These are disabled by default.

+ 61 - 0
panda/src/display/pStatGPUTimer.I

@@ -0,0 +1,61 @@
+// Filename: pStatGPUTimer.I
+// Created by:  rdb (21Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+#ifdef DO_PSTATS
+
+////////////////////////////////////////////////////////////////////
+//     Function: PStatGPUTimer::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PStatGPUTimer::
+PStatGPUTimer(GraphicsStateGuardian *gsg, PStatCollector &collector) :
+  PStatTimer(collector),
+  _gsg(gsg)
+{
+  if (gsg->get_timer_queries_active()) {
+    gsg->issue_timer_query(collector.get_index());
+    //cerr << "issuing " << collector << " active " << collector.is_active() << "\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PStatGPUTimer::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PStatGPUTimer::
+PStatGPUTimer(GraphicsStateGuardian *gsg, PStatCollector &collector, Thread *current_thread) :
+  PStatTimer(collector, current_thread),
+  _gsg(gsg)
+{
+  if (gsg->get_timer_queries_active()) {
+    gsg->issue_timer_query(collector.get_index());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PStatGPUTimer::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PStatGPUTimer::
+~PStatGPUTimer() {
+  if (_gsg->get_timer_queries_active()) {
+    _gsg->issue_timer_query(_collector.get_index() | 0x8000);
+  }
+}
+
+#endif

+ 67 - 0
panda/src/display/pStatGPUTimer.h

@@ -0,0 +1,67 @@
+// Filename: pStatGPUTimer.h
+// Created by:  rdb (21Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PSTATGPUTIMER_H
+#define PSTATGPUTIMER_H
+
+#include "pandabase.h"
+#include "pStatTimer.h"
+#include "pStatCollector.h"
+#include "config_pstats.h"
+#include "timerQueryContext.h"
+
+class Thread;
+class GraphicsStateGuardian;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PStatGPUTimer
+// Description : This is a special type of PStatTimer that also
+//               uses a timer query on the GSG to measure how long
+//               a task actually takes to execute on the GPU, rather
+//               than how long it took for the API commands to be
+//               queued up.
+//
+//               This class may only be used on the draw thread.
+//
+//               At present, it tracks both the CPU time (like a
+//               regular PStatTimer does) and the GPU time, which
+//               is recorded using a special PStatThread.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_DISPLAY PStatGPUTimer : public PStatTimer {
+public:
+#ifdef DO_PSTATS
+  INLINE PStatGPUTimer(GraphicsStateGuardian *gsg,
+                       PStatCollector &collector);
+  INLINE PStatGPUTimer(GraphicsStateGuardian *gsg,
+                       PStatCollector &collector,
+                       Thread *current_thread);
+  INLINE ~PStatGPUTimer();
+
+  GraphicsStateGuardian *_gsg;
+
+private:
+#else // DO_PSTATS
+
+  INLINE PStatGPUTimer(GraphicsStateGuardian *, PStatCollector &col)
+    : PStatTimer(col) { }
+  INLINE PStatGPUTimer(GraphicsStateGuardian *, PStatCollector &col, Thread *)
+    : PStatTimer(col) { }
+  INLINE ~PStatGPUTimer() { }
+
+#endif  // DO_PSTATS
+};
+
+#include "pStatGPUTimer.I"
+
+#endif

+ 8 - 2
panda/src/display/standardMunger.cxx

@@ -178,7 +178,10 @@ munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
     // Even beyond munging the vertex format, we have to convert the
     // Even beyond munging the vertex format, we have to convert the
     // Geom itself into a new primitive type the GSG can render
     // Geom itself into a new primitive type the GSG can render
     // directly.
     // directly.
-    if ((unsupported_bits & Geom::GR_composite_bits) != 0) {
+    // If we don't support a strip cut index, it might be faster to
+    // just decompose it rather than draw them one by one.
+    if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
+        (unsupported_bits & Geom::GR_strip_cut_index) != 0) {
       // This decomposes everything in the primitive, so that if (for
       // This decomposes everything in the primitive, so that if (for
       // instance) the primitive contained both strips and fans, but
       // instance) the primitive contained both strips and fans, but
       // the GSG didn't support fans, it would decompose the strips
       // the GSG didn't support fans, it would decompose the strips
@@ -224,7 +227,10 @@ premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
     // Even beyond munging the vertex format, we have to convert the
     // Even beyond munging the vertex format, we have to convert the
     // Geom itself into a new primitive type the GSG can render
     // Geom itself into a new primitive type the GSG can render
     // directly.
     // directly.
-    if ((unsupported_bits & Geom::GR_composite_bits) != 0) {
+    // If we don't support a strip cut index, it might be faster to
+    // just decompose it rather than draw them one by one.
+    if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
+        (unsupported_bits & Geom::GR_strip_cut_index) != 0) {
       // This decomposes everything in the primitive, so that if (for
       // This decomposes everything in the primitive, so that if (for
       // instance) the primitive contained both strips and fans, but
       // instance) the primitive contained both strips and fans, but
       // the GSG didn't support fans, it would decompose the strips
       // the GSG didn't support fans, it would decompose the strips

+ 1 - 1
panda/src/dxgsg8/Sources.pp

@@ -22,7 +22,7 @@
     wdxGraphicsPipe8.I wdxGraphicsPipe8.h \
     wdxGraphicsPipe8.I wdxGraphicsPipe8.h \
     wdxGraphicsWindow8.I wdxGraphicsWindow8.h \
     wdxGraphicsWindow8.I wdxGraphicsWindow8.h \
     dxgsg8base.h config_dxgsg8.h dxGraphicsStateGuardian8.I dxGraphicsStateGuardian8.h \
     dxgsg8base.h config_dxgsg8.h dxGraphicsStateGuardian8.I dxGraphicsStateGuardian8.h \
-    dxVertexBufferContext8.h dxVertexbufferContext8.I \
+    dxVertexBufferContext8.h dxVertexBufferContext8.I \
     dxIndexBufferContext8.h dxIndexBufferContext8.I \
     dxIndexBufferContext8.h dxIndexBufferContext8.I \
     dxTextureContext8.h dxTextureContext8.I \
     dxTextureContext8.h dxTextureContext8.I \
     dxGeomMunger8.h dxGeomMunger8.I \
     dxGeomMunger8.h dxGeomMunger8.I \

+ 2 - 2
panda/src/dxgsg8/wdxGraphicsWindow8.cxx

@@ -413,7 +413,7 @@ handle_reshape() {
   GdiFlush();
   GdiFlush();
   WinGraphicsWindow::handle_reshape();
   WinGraphicsWindow::handle_reshape();
 
 
-  if (_dxgsg != NULL) {
+  if (_dxgsg != NULL && _dxgsg->_d3d_device != NULL) {
     // create the new resized rendertargets
     // create the new resized rendertargets
     WindowProperties props = get_properties();
     WindowProperties props = get_properties();
     int x_size = props.get_x_size();
     int x_size = props.get_x_size();
@@ -422,7 +422,7 @@ handle_reshape() {
     if (_wcontext._presentation_params.BackBufferWidth != x_size ||
     if (_wcontext._presentation_params.BackBufferWidth != x_size ||
         _wcontext._presentation_params.BackBufferHeight != y_size) {
         _wcontext._presentation_params.BackBufferHeight != y_size) {
       bool resize_succeeded = reset_device_resize_window(x_size, y_size);
       bool resize_succeeded = reset_device_resize_window(x_size, y_size);
-      
+
       if (wdxdisplay8_cat.is_debug()) {
       if (wdxdisplay8_cat.is_debug()) {
         if (!resize_succeeded) {
         if (!resize_succeeded) {
           wdxdisplay8_cat.debug()
           wdxdisplay8_cat.debug()

+ 1 - 1
panda/src/dxgsg9/Sources.pp

@@ -22,7 +22,7 @@
     wdxGraphicsPipe9.I wdxGraphicsPipe9.h \
     wdxGraphicsPipe9.I wdxGraphicsPipe9.h \
     wdxGraphicsWindow9.I wdxGraphicsWindow9.h \
     wdxGraphicsWindow9.I wdxGraphicsWindow9.h \
     dxgsg9base.h config_dxgsg9.h dxGraphicsStateGuardian9.I dxGraphicsStateGuardian9.h \
     dxgsg9base.h config_dxgsg9.h dxGraphicsStateGuardian9.I dxGraphicsStateGuardian9.h \
-    dxVertexBufferContext9.h dxVertexbufferContext9.I \
+    dxVertexBufferContext9.h dxVertexBufferContext9.I \
     dxIndexBufferContext9.h dxIndexBufferContext9.I \
     dxIndexBufferContext9.h dxIndexBufferContext9.I \
     dxTextureContext9.h dxTextureContext9.I \
     dxTextureContext9.h dxTextureContext9.I \
     dxGeomMunger9.h dxGeomMunger9.I \
     dxGeomMunger9.h dxGeomMunger9.I \

+ 77 - 57
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -224,6 +224,13 @@ apply_texture(int i, TextureContext *tc) {
   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
   Texture *tex = tc->get_texture();
   Texture *tex = tc->get_texture();
 
 
+  //if (tex->get_color_space() == CS_srgb) {
+  if (Texture::is_srgb(tex->get_format())) {
+    set_sampler_state(i, D3DSAMP_SRGBTEXTURE, TRUE);
+  } else {
+    set_sampler_state(i, D3DSAMP_SRGBTEXTURE, FALSE);
+  }
+
   Texture::WrapMode wrap_u, wrap_v, wrap_w;
   Texture::WrapMode wrap_u, wrap_v, wrap_w;
 
 
   DWORD address_u;
   DWORD address_u;
@@ -256,7 +263,7 @@ apply_texture(int i, TextureContext *tc) {
 
 
   int supports_anisotropic_mag_filter;
   int supports_anisotropic_mag_filter;
   D3DTEXTUREFILTERTYPE new_mag_filter;
   D3DTEXTUREFILTERTYPE new_mag_filter;
-  
+
   supports_anisotropic_mag_filter = (_screen -> _d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
   supports_anisotropic_mag_filter = (_screen -> _d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
   if (aniso_degree <= 1 || supports_anisotropic_mag_filter == 0) {
   if (aniso_degree <= 1 || supports_anisotropic_mag_filter == 0) {
     new_mag_filter = ((ft != Texture::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT);
     new_mag_filter = ((ft != Texture::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT);
@@ -268,8 +275,8 @@ apply_texture(int i, TextureContext *tc) {
   hr = set_sampler_state(i, D3DSAMP_MAGFILTER, new_mag_filter);
   hr = set_sampler_state(i, D3DSAMP_MAGFILTER, new_mag_filter);
   if (hr != D3D_OK) {
   if (hr != D3D_OK) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
-      << "ERROR: set_sampler_state (D3DSAMP_MAGFILTER, " 
-      << new_mag_filter << ") failed for texture:" << tex -> get_name() << endl;    
+      << "ERROR: set_sampler_state (D3DSAMP_MAGFILTER, "
+      << new_mag_filter << ") failed for texture:" << tex -> get_name() << endl;
   }
   }
 
 
   // map Panda composite min+mip filter types to d3d's separate min & mip filter types
   // map Panda composite min+mip filter types to d3d's separate min & mip filter types
@@ -353,7 +360,7 @@ upload_texture(DXTextureContext9 *dtc, bool force) {
   dtc->delete_texture();
   dtc->delete_texture();
   dtc->update_data_size_bytes(0);
   dtc->update_data_size_bytes(0);
   dtc->mark_unloaded();
   dtc->mark_unloaded();
-  
+
   if (_effective_incomplete_render && !force) {
   if (_effective_incomplete_render && !force) {
     bool has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
     bool has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
     if (!has_image && tex->might_have_ram_image() &&
     if (!has_image && tex->might_have_ram_image() &&
@@ -371,7 +378,7 @@ upload_texture(DXTextureContext9 *dtc, bool force) {
       }
       }
     }
     }
   }
   }
-  
+
   return dtc->create_texture(*_screen);
   return dtc->create_texture(*_screen);
 }
 }
 
 
@@ -746,7 +753,7 @@ begin_occlusion_query() {
       << "Occlusion query failed.\n";
       << "Occlusion query failed.\n";
     return;
     return;
   }
   }
-  
+
   PT(DXOcclusionQueryContext9) queryobj = new DXOcclusionQueryContext9(query);
   PT(DXOcclusionQueryContext9) queryobj = new DXOcclusionQueryContext9(query);
 
 
   if (dxgsg9_cat.is_debug()) {
   if (dxgsg9_cat.is_debug()) {
@@ -776,7 +783,7 @@ end_occlusion_query() {
   PT(OcclusionQueryContext) result = _current_occlusion_query;
   PT(OcclusionQueryContext) result = _current_occlusion_query;
 
 
   IDirect3DQuery9 *query = DCAST(DXOcclusionQueryContext9, result)->_query;
   IDirect3DQuery9 *query = DCAST(DXOcclusionQueryContext9, result)->_query;
-    
+
   if (dxgsg9_cat.is_debug()) {
   if (dxgsg9_cat.is_debug()) {
     dxgsg9_cat.debug()
     dxgsg9_cat.debug()
       << "ending occlusion query " << query << "\n";
       << "ending occlusion query " << query << "\n";
@@ -857,7 +864,7 @@ clear(DrawableRegion *clearable) {
           aux_flags |=  D3DCLEAR_ZBUFFER;
           aux_flags |=  D3DCLEAR_ZBUFFER;
           HRESULT hr2 = _d3d_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color_clear_value,
           HRESULT hr2 = _d3d_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color_clear_value,
                                            depth_clear_value, stencil_clear_value);
                                            depth_clear_value, stencil_clear_value);
-          if (FAILED(hr2)) {          
+          if (FAILED(hr2)) {
             dxgsg9_cat.error()
             dxgsg9_cat.error()
               << "Unable to clear depth buffer; removing.\n";
               << "Unable to clear depth buffer; removing.\n";
             // This is really hacky code.
             // This is really hacky code.
@@ -1040,6 +1047,12 @@ begin_frame(Thread *current_thread) {
     return false;
     return false;
   }
   }
 
 
+  if (_current_properties->get_srgb_color()) {
+    set_render_state(D3DRS_SRGBWRITEENABLE, TRUE);
+  } else {
+    set_render_state(D3DRS_SRGBWRITEENABLE, FALSE);
+  }
+
   return true;
   return true;
 }
 }
 
 
@@ -1343,14 +1356,14 @@ update_standard_vertex_arrays(bool force) {
       dxgsg9_cat.error() << "Unable to get reader for array " << array_index << "\n";
       dxgsg9_cat.error() << "Unable to get reader for array " << array_index << "\n";
       return false;
       return false;
     }
     }
-  
+
     // Get the vertex buffer for this array.
     // Get the vertex buffer for this array.
     CLP(VertexBufferContext)* dvbc;
     CLP(VertexBufferContext)* dvbc;
     if (!setup_array_data(dvbc, array_reader, force)) {
     if (!setup_array_data(dvbc, array_reader, force)) {
       dxgsg9_cat.error() << "Unable to setup vertex buffer for array " << array_index << "\n";
       dxgsg9_cat.error() << "Unable to setup vertex buffer for array " << array_index << "\n";
       return false;
       return false;
     }
     }
-  
+
     // Bind this array as the data source for the corresponding stream.
     // Bind this array as the data source for the corresponding stream.
     const GeomVertexArrayFormat* array_format = array_reader->get_array_format();
     const GeomVertexArrayFormat* array_format = array_reader->get_array_format();
     hr = _d3d_device->SetStreamSource( array_index, dvbc->_vbuffer, 0, array_format->get_stride() );
     hr = _d3d_device->SetStreamSource( array_index, dvbc->_vbuffer, 0, array_format->get_stride() );
@@ -2315,7 +2328,7 @@ reset() {
   // want gsg to pass all state settings down so any non-matching defaults we set here get overwritten
   // want gsg to pass all state settings down so any non-matching defaults we set here get overwritten
 
 
   nassertv(_screen->_d3d9 != NULL);
   nassertv(_screen->_d3d9 != NULL);
-  
+
   if (_d3d_device == NULL) {
   if (_d3d_device == NULL) {
     return;
     return;
   }
   }
@@ -2379,27 +2392,27 @@ reset() {
     _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_2_0;
     _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_2_0;
 */
 */
   }
   }
-  
+
   if (dxgsg9_cat.is_debug()) {
   if (dxgsg9_cat.is_debug()) {
-    
+
     CGprofile vertex_profile;
     CGprofile vertex_profile;
     CGprofile pixel_profile;
     CGprofile pixel_profile;
-    
+
     vertex_profile = cgD3D9GetLatestVertexProfile();
     vertex_profile = cgD3D9GetLatestVertexProfile();
     pixel_profile = cgD3D9GetLatestPixelProfile();
     pixel_profile = cgD3D9GetLatestPixelProfile();
-    
+
     const char *vertex_profile_str =
     const char *vertex_profile_str =
       cgGetProfileString(vertex_profile);
       cgGetProfileString(vertex_profile);
     const char *pixel_profile_str =
     const char *pixel_profile_str =
       cgGetProfileString(pixel_profile);
       cgGetProfileString(pixel_profile);
-    
+
     if (vertex_profile_str == NULL) {
     if (vertex_profile_str == NULL) {
       vertex_profile_str = "(null)";
       vertex_profile_str = "(null)";
     }
     }
     if (pixel_profile_str == NULL) {
     if (pixel_profile_str == NULL) {
       pixel_profile_str = "(null)";
       pixel_profile_str = "(null)";
     }
     }
-    
+
     dxgsg9_cat.debug()
     dxgsg9_cat.debug()
       << "\nCg vertex profile = " << vertex_profile_str << "  id = " << vertex_profile
       << "\nCg vertex profile = " << vertex_profile_str << "  id = " << vertex_profile
       << "\nCg pixel profile = " << pixel_profile_str << "  id = " << pixel_profile
       << "\nCg pixel profile = " << pixel_profile_str << "  id = " << pixel_profile
@@ -2495,7 +2508,7 @@ reset() {
       << "\nDirectX SDK version " DIRECTX_SDK_VERSION
       << "\nDirectX SDK version " DIRECTX_SDK_VERSION
       << "\n";
       << "\n";
   }
   }
-  
+
   // OVERRIDE SUPPORT SINCE IT DOES NOT WORK WELL
   // OVERRIDE SUPPORT SINCE IT DOES NOT WORK WELL
   _screen->_supports_automatic_mipmap_generation = false;
   _screen->_supports_automatic_mipmap_generation = false;
 
 
@@ -2618,12 +2631,19 @@ reset() {
 
 
   _last_testcooplevel_result = D3D_OK;
   _last_testcooplevel_result = D3D_OK;
 
 
+  if (dxgsg9_cat.is_debug()) {
+    dxgsg9_cat.debug() << "Supported texture formats:\n";
+  }
+
   for(int i = 0; i < MAX_POSSIBLE_TEXFMTS; i++) {
   for(int i = 0; i < MAX_POSSIBLE_TEXFMTS; i++) {
     // look for all possible DX9 texture fmts
     // look for all possible DX9 texture fmts
     D3DFORMAT_FLAG fmtflag = D3DFORMAT_FLAG(1 << i);
     D3DFORMAT_FLAG fmtflag = D3DFORMAT_FLAG(1 << i);
     hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format,
     hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format,
                                           0x0, D3DRTYPE_TEXTURE, g_D3DFORMATmap[fmtflag]);
                                           0x0, D3DRTYPE_TEXTURE, g_D3DFORMATmap[fmtflag]);
-    if (SUCCEEDED(hr)){
+    if (SUCCEEDED(hr)) {
+      if (dxgsg9_cat.is_debug()) {
+        dxgsg9_cat.debug() << "  " << D3DFormatStr(g_D3DFORMATmap[fmtflag]) << "\n";
+      }
       _screen->_supported_tex_formats_mask |= fmtflag;
       _screen->_supported_tex_formats_mask |= fmtflag;
     }
     }
   }
   }
@@ -2632,7 +2652,7 @@ reset() {
   #define CHECK_FOR_DXTVERSION(num) \
   #define CHECK_FOR_DXTVERSION(num) \
   if (_screen->_supported_tex_formats_mask & DXT##num##_FLAG) {\
   if (_screen->_supported_tex_formats_mask & DXT##num##_FLAG) {\
     if (dxgsg9_cat.is_debug()) {\
     if (dxgsg9_cat.is_debug()) {\
-      dxgsg9_cat.debug() << "Compressed texture format DXT" << #num << " supported \n";\
+      dxgsg9_cat.debug() << "Compressed texture format DXT" << #num << " supported\n";\
     }\
     }\
     _supports_compressed_texture = true;\
     _supports_compressed_texture = true;\
     _compressed_texture_formats.set_bit(Texture::CM_dxt##num);\
     _compressed_texture_formats.set_bit(Texture::CM_dxt##num);\
@@ -2641,9 +2661,9 @@ reset() {
   if (_screen->_intel_compressed_texture_bug) {
   if (_screen->_intel_compressed_texture_bug) {
     dxgsg9_cat.info()
     dxgsg9_cat.info()
       << "Buggy Intel driver detected; disabling compressed textures.\n";
       << "Buggy Intel driver detected; disabling compressed textures.\n";
-    _screen->_supported_tex_formats_mask &= 
+    _screen->_supported_tex_formats_mask &=
       ~(DXT1_FLAG | DXT2_FLAG | DXT3_FLAG | DXT4_FLAG | DXT5_FLAG);
       ~(DXT1_FLAG | DXT2_FLAG | DXT3_FLAG | DXT4_FLAG | DXT5_FLAG);
-                                              
+
   } else {
   } else {
     // Check for available compressed formats normally.
     // Check for available compressed formats normally.
     CHECK_FOR_DXTVERSION(1);
     CHECK_FOR_DXTVERSION(1);
@@ -2652,7 +2672,7 @@ reset() {
     CHECK_FOR_DXTVERSION(4);
     CHECK_FOR_DXTVERSION(4);
     CHECK_FOR_DXTVERSION(5);
     CHECK_FOR_DXTVERSION(5);
   }
   }
-      
+
   #undef CHECK_FOR_DXTVERSION
   #undef CHECK_FOR_DXTVERSION
 
 
   _screen->_supports_rgba16f_texture_format = false;
   _screen->_supports_rgba16f_texture_format = false;
@@ -3292,7 +3312,7 @@ set_state_and_transform(const RenderState *target,
       !_state_mask.get_bit(transparency_slot) ||
       !_state_mask.get_bit(transparency_slot) ||
       !_state_mask.get_bit(color_write_slot) ||
       !_state_mask.get_bit(color_write_slot) ||
       !_state_mask.get_bit(color_blend_slot) ||
       !_state_mask.get_bit(color_blend_slot) ||
-      (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write) != 
+      (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write) !=
        _state_shader->get_flag(ShaderAttrib::F_disable_alpha_write))) {
        _state_shader->get_flag(ShaderAttrib::F_disable_alpha_write))) {
     //PStatTimer timer(_draw_set_state_blending_pcollector);
     //PStatTimer timer(_draw_set_state_blending_pcollector);
     do_issue_blending();
     do_issue_blending();
@@ -3353,7 +3373,7 @@ set_state_and_transform(const RenderState *target,
     do_issue_stencil();
     do_issue_stencil();
     _state_mask.set_bit(stencil_slot);
     _state_mask.set_bit(stencil_slot);
   }
   }
-     
+
   int fog_slot = FogAttrib::get_class_slot();
   int fog_slot = FogAttrib::get_class_slot();
   if (_target_rs->get_attrib(fog_slot) != _state_rs->get_attrib(fog_slot) ||
   if (_target_rs->get_attrib(fog_slot) != _state_rs->get_attrib(fog_slot) ||
       !_state_mask.get_bit(fog_slot)) {
       !_state_mask.get_bit(fog_slot)) {
@@ -3446,22 +3466,22 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
     const LMatrix4 &light_mat = transform->get_mat();
     const LMatrix4 &light_mat = transform->get_mat();
     LMatrix4 rel_mat = light_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
     LMatrix4 rel_mat = light_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
     LVector3f dir = LCAST(float, light_obj->get_direction() * rel_mat);
     LVector3f dir = LCAST(float, light_obj->get_direction() * rel_mat);
-    
+
     D3DCOLORVALUE black;
     D3DCOLORVALUE black;
     black.r = black.g = black.b = black.a = 0.0f;
     black.r = black.g = black.b = black.a = 0.0f;
-    
+
     ZeroMemory(&fdata, sizeof(D3DLIGHT9));
     ZeroMemory(&fdata, sizeof(D3DLIGHT9));
-    
+
     fdata.Type =  D3DLIGHT_DIRECTIONAL;
     fdata.Type =  D3DLIGHT_DIRECTIONAL;
     fdata.Ambient  =  black ;
     fdata.Ambient  =  black ;
     LColorf color = LCAST(float, light_obj->get_specular_color());
     LColorf color = LCAST(float, light_obj->get_specular_color());
     fdata.Specular = *(D3DCOLORVALUE *)(color.get_data());
     fdata.Specular = *(D3DCOLORVALUE *)(color.get_data());
-    
+
     fdata.Direction = *(D3DVECTOR *)dir.get_data();
     fdata.Direction = *(D3DVECTOR *)dir.get_data();
-    
+
     fdata.Range =  __D3DLIGHT_RANGE_MAX;
     fdata.Range =  __D3DLIGHT_RANGE_MAX;
     fdata.Falloff =  1.0f;
     fdata.Falloff =  1.0f;
-    
+
     fdata.Attenuation0 = 1.0f;       // constant
     fdata.Attenuation0 = 1.0f;       // constant
     fdata.Attenuation1 = 0.0f;       // linear
     fdata.Attenuation1 = 0.0f;       // linear
     fdata.Attenuation2 = 0.0f;       // quadratic
     fdata.Attenuation2 = 0.0f;       // quadratic
@@ -4125,7 +4145,7 @@ close_gsg() {
 
 
   if (dxgsg9_cat.is_debug()) {
   if (dxgsg9_cat.is_debug()) {
     dxgsg9_cat.debug()
     dxgsg9_cat.debug()
-      << "Closing GSG, prepared_objects count = " 
+      << "Closing GSG, prepared_objects count = "
       << _prepared_objects->get_ref_count() << "\n";
       << _prepared_objects->get_ref_count() << "\n";
   }
   }
 
 
@@ -4210,9 +4230,9 @@ set_read_buffer(const RenderBuffer &rb) {
   if (rb._buffer_type & RenderBuffer::T_front) {
   if (rb._buffer_type & RenderBuffer::T_front) {
     _cur_read_pixel_buffer = RenderBuffer::T_front;
     _cur_read_pixel_buffer = RenderBuffer::T_front;
   } else  if (rb._buffer_type & RenderBuffer::T_back) {
   } else  if (rb._buffer_type & RenderBuffer::T_back) {
-    _cur_read_pixel_buffer = RenderBuffer::T_back;      
+    _cur_read_pixel_buffer = RenderBuffer::T_back;
   } else  if (rb._buffer_type & RenderBuffer::T_aux_rgba_ALL) {
   } else  if (rb._buffer_type & RenderBuffer::T_aux_rgba_ALL) {
-    _cur_read_pixel_buffer = RenderBuffer::T_back;      
+    _cur_read_pixel_buffer = RenderBuffer::T_back;
   } else {
   } else {
     dxgsg9_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n";
     dxgsg9_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n";
   }
   }
@@ -4816,7 +4836,7 @@ check_cooperative_level() {
   case D3DERR_DEVICELOST:
   case D3DERR_DEVICELOST:
     // sleep while the device is lost to free up the CPU
     // sleep while the device is lost to free up the CPU
     Sleep (10);
     Sleep (10);
-    
+
     if (SUCCEEDED(_last_testcooplevel_result)) {
     if (SUCCEEDED(_last_testcooplevel_result)) {
       if (_dx_is_ready) {
       if (_dx_is_ready) {
         _dx_is_ready = false;
         _dx_is_ready = false;
@@ -4847,7 +4867,7 @@ show_frame() {
   if (_swap_chain) {
   if (_swap_chain) {
     DWORD flags;
     DWORD flags;
     flags = 0;
     flags = 0;
-    
+
     hr = _swap_chain->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL, flags);
     hr = _swap_chain->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL, flags);
   } else {
   } else {
     hr = _d3d_device->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL);
     hr = _d3d_device->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL);
@@ -5220,7 +5240,7 @@ check_dx_allocation (HRESULT result, int allocation_size, int attempts)
         // increase the page out size as the number of attempts increases
         // increase the page out size as the number of attempts increases
         {
         {
           size_t current_size = _prepared_objects->_graphics_memory_lru.get_total_size();
           size_t current_size = _prepared_objects->_graphics_memory_lru.get_total_size();
-          size_t target_size = max(current_size - allocation_size * attempts, 0);
+          size_t target_size = max(current_size - allocation_size * attempts, (size_t) 0);
           _prepared_objects->_graphics_memory_lru.evict_to(target_size);
           _prepared_objects->_graphics_memory_lru.evict_to(target_size);
           dxgsg9_cat.info()
           dxgsg9_cat.info()
             << "Evicted " << current_size - _prepared_objects->_graphics_memory_lru.get_total_size() << " bytes of texture memory to make room for more.\n";
             << "Evicted " << current_size - _prepared_objects->_graphics_memory_lru.get_total_size() << " bytes of texture memory to make room for more.\n";
@@ -5435,7 +5455,7 @@ do_issue_stencil() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: dxGraphicsStateGuardian9::do_issue_scissor
 //     Function: dxGraphicsStateGuardian9::do_issue_scissor
 //       Access: Protected
 //       Access: Protected
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian9::
 void DXGraphicsStateGuardian9::
 do_issue_scissor() {
 do_issue_scissor() {
@@ -5522,8 +5542,8 @@ void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table,
     // avoid divide by zero and negative exponents
     // avoid divide by zero and negative exponents
     gamma = 1.0;
     gamma = 1.0;
   }
   }
-  gamma_correction = 1.0 / (double) gamma;    
-  
+  gamma_correction = 1.0 / (double) gamma;
+
   for (i = 0; i < 256; i++) {
   for (i = 0; i < 256; i++) {
     double r;
     double r;
     double g;
     double g;
@@ -5534,11 +5554,11 @@ void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table,
       g = (double) original_green_table [i] / GAMMA_1;
       g = (double) original_green_table [i] / GAMMA_1;
       b = (double) original_blue_table [i] / GAMMA_1;
       b = (double) original_blue_table [i] / GAMMA_1;
     }
     }
-    else {    
+    else {
       r = ((double) i / 255.0);
       r = ((double) i / 255.0);
       g = r;
       g = r;
       b = r;
       b = r;
-    }    
+    }
 
 
     r = pow (r, gamma_correction);
     r = pow (r, gamma_correction);
     g = pow (g, gamma_correction);
     g = pow (g, gamma_correction);
@@ -5554,14 +5574,14 @@ void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table,
       b = 1.0;
       b = 1.0;
     }
     }
 
 
-    r = r * GAMMA_1;    
-    g = g * GAMMA_1;    
-    b = b * GAMMA_1;    
+    r = r * GAMMA_1;
+    g = g * GAMMA_1;
+    b = b * GAMMA_1;
 
 
     red_table [i] = r;
     red_table [i] = r;
     green_table [i] = g;
     green_table [i] = g;
     blue_table [i] = b;
     blue_table [i] = b;
-  }    
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -5571,13 +5591,13 @@ void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian9::
 bool DXGraphicsStateGuardian9::
 get_gamma_table(void) {
 get_gamma_table(void) {
-  bool get;  
+  bool get;
 
 
   get = false;
   get = false;
   if (_gamma_table_initialized == false) {
   if (_gamma_table_initialized == false) {
     HDC hdc = GetDC(NULL);
     HDC hdc = GetDC(NULL);
 
 
-    if (hdc) {   
+    if (hdc) {
       if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) {
       if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) {
         _gamma_table_initialized = true;
         _gamma_table_initialized = true;
         get = true;
         get = true;
@@ -5586,26 +5606,26 @@ get_gamma_table(void) {
       ReleaseDC (NULL, hdc);
       ReleaseDC (NULL, hdc);
     }
     }
   }
   }
-  
+
   return get;
   return get;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian9::static_set_gamma
 //     Function: DXGraphicsStateGuardian9::static_set_gamma
 //       Access: Public, Static
 //       Access: Public, Static
-//  Description: Static function for setting gamma which is needed 
+//  Description: Static function for setting gamma which is needed
 //               for atexit.
 //               for atexit.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian9::
 bool DXGraphicsStateGuardian9::
 static_set_gamma(bool restore, PN_stdfloat gamma) {
 static_set_gamma(bool restore, PN_stdfloat gamma) {
-  bool set;  
+  bool set;
   HDC hdc = GetDC(NULL);
   HDC hdc = GetDC(NULL);
 
 
   set = false;
   set = false;
-  if (hdc) {   
+  if (hdc) {
     unsigned short ramp [256 * 3];
     unsigned short ramp [256 * 3];
 
 
-    if (restore && _gamma_table_initialized) {    
+    if (restore && _gamma_table_initialized) {
       _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
       _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
     }
     }
     else {
     else {
@@ -5615,7 +5635,7 @@ static_set_gamma(bool restore, PN_stdfloat gamma) {
     if (SetDeviceGammaRamp (hdc, ramp)) {
     if (SetDeviceGammaRamp (hdc, ramp)) {
       set = true;
       set = true;
     }
     }
-    
+
     ReleaseDC (NULL, hdc);
     ReleaseDC (NULL, hdc);
   }
   }
 
 
@@ -5634,7 +5654,7 @@ set_gamma(PN_stdfloat gamma) {
 
 
   set = static_set_gamma(false, gamma);
   set = static_set_gamma(false, gamma);
   if (set) {
   if (set) {
-    _gamma = gamma;  
+    _gamma = gamma;
   }
   }
 
 
   return set;
   return set;
@@ -5664,7 +5684,7 @@ atexit_function(void) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian9::get_supports_cg_profile
 //     Function: DXGraphicsStateGuardian9::get_supports_cg_profile
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: Returns true if this particular GSG supports the 
+//  Description: Returns true if this particular GSG supports the
 //               specified Cg Shader Profile.
 //               specified Cg Shader Profile.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool DXGraphicsStateGuardian9::
 bool DXGraphicsStateGuardian9::
@@ -5673,7 +5693,7 @@ get_supports_cg_profile(const string &name) const {
   return false;
   return false;
 #else
 #else
   CGprofile profile = cgGetProfile(name.c_str());
   CGprofile profile = cgGetProfile(name.c_str());
-  
+
   if (profile == CG_PROFILE_UNKNOWN) {
   if (profile == CG_PROFILE_UNKNOWN) {
     dxgsg9_cat.error() << name <<", unknown Cg-profile\n";
     dxgsg9_cat.error() << name <<", unknown Cg-profile\n";
     return false;
     return false;

+ 5 - 5
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -36,9 +36,7 @@
 #include "vertexElementArray.h"
 #include "vertexElementArray.h"
 #include "dxShaderContext9.h"
 #include "dxShaderContext9.h"
 
 
-
-enum GsgPageType
-{
+enum GsgPageType {
   GPT_Texture,
   GPT_Texture,
   GPT_VertexBuffer,
   GPT_VertexBuffer,
   GPT_IndexBuffer,
   GPT_IndexBuffer,
@@ -52,6 +50,8 @@ class DXTextureContext9;
 class DXVertexBufferContext9;
 class DXVertexBufferContext9;
 class DXIndexBufferContext9;
 class DXIndexBufferContext9;
 
 
+class wdxGraphicsBuffer9;
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : DXGraphicsStateGuardian9
 //       Class : DXGraphicsStateGuardian9
 // Description : A GraphicsStateGuardian for rendering into DirectX9
 // Description : A GraphicsStateGuardian for rendering into DirectX9
@@ -265,7 +265,7 @@ protected:
 
 
 public:
 public:
   DXScreenData *_screen;
   DXScreenData *_screen;
-  
+
 protected:
 protected:
   LPDIRECT3DDEVICE9 _d3d_device;  // same as _screen->_d3d_device, cached for spd
   LPDIRECT3DDEVICE9 _d3d_device;  // same as _screen->_d3d_device, cached for spd
   IDirect3DSwapChain9 *_swap_chain;
   IDirect3DSwapChain9 *_swap_chain;
@@ -374,7 +374,7 @@ protected:
 
 
   list <wdxGraphicsBuffer9 **> _graphics_buffer_list;
   list <wdxGraphicsBuffer9 **> _graphics_buffer_list;
 
 
-  int _supports_gamma_calibration;  
+  int _supports_gamma_calibration;
 
 
   static LPDIRECT3DDEVICE9 _cg_device;
   static LPDIRECT3DDEVICE9 _cg_device;
 
 

+ 87 - 58
panda/src/dxgsg9/dxTextureContext9.cxx

@@ -135,13 +135,13 @@ create_texture(DXScreenData &scrn) {
   bool texture_wants_compressed = false;
   bool texture_wants_compressed = false;
   Texture::CompressionMode compression_mode = tex->get_ram_image_compression();
   Texture::CompressionMode compression_mode = tex->get_ram_image_compression();
   bool texture_stored_compressed = compression_mode != Texture::CM_off;
   bool texture_stored_compressed = compression_mode != Texture::CM_off;
-  
+
   if (texture_stored_compressed) {
   if (texture_stored_compressed) {
-    texture_wants_compressed = true;  
+    texture_wants_compressed = true;
   } else {
   } else {
     if (tex->get_compression() == Texture::CM_off) {
     if (tex->get_compression() == Texture::CM_off) {
       // no compression
       // no compression
-    } else {    
+    } else {
       if (tex->get_compression() == Texture::CM_default) {
       if (tex->get_compression() == Texture::CM_default) {
         // default = use "compressed-textures" config setting
         // default = use "compressed-textures" config setting
         if (compressed_textures) {
         if (compressed_textures) {
@@ -150,9 +150,9 @@ create_texture(DXScreenData &scrn) {
       } else {
       } else {
         texture_wants_compressed = true;
         texture_wants_compressed = true;
       }
       }
-    }  
+    }
   }
   }
-    
+
   switch (tex->get_texture_type()) {
   switch (tex->get_texture_type()) {
     case Texture::TT_1d_texture:
     case Texture::TT_1d_texture:
     case Texture::TT_2d_texture:
     case Texture::TT_2d_texture:
@@ -197,7 +197,9 @@ create_texture(DXScreenData &scrn) {
 
 
   if ((tex->get_format() == Texture::F_luminance_alpha)||
   if ((tex->get_format() == Texture::F_luminance_alpha)||
       (tex->get_format() == Texture::F_luminance_alphamask) ||
       (tex->get_format() == Texture::F_luminance_alphamask) ||
-      (tex->get_format() == Texture::F_luminance)) {
+      (tex->get_format() == Texture::F_luminance) ||
+      (tex->get_format() == Texture::F_sluminance_alpha) ||
+      (tex->get_format() == Texture::F_sluminance)) {
     needs_luminance = true;
     needs_luminance = true;
   }
   }
 
 
@@ -232,7 +234,7 @@ create_texture(DXScreenData &scrn) {
     _d3d_format = D3DFMT_A8R8G8B8;
     _d3d_format = D3DFMT_A8R8G8B8;
     break;
     break;
   }
   }
-  
+
   // make sure we handled all the possible cases
   // make sure we handled all the possible cases
   nassertr(_d3d_format != D3DFMT_UNKNOWN, false);
   nassertr(_d3d_format != D3DFMT_UNKNOWN, false);
 
 
@@ -398,9 +400,9 @@ create_texture(DXScreenData &scrn) {
 
 
   if (compress_texture) {
   if (compress_texture) {
     if (num_alpha_bits <= 1) {
     if (num_alpha_bits <= 1) {
-      CHECK_FOR_FMT(DXT1);    
+      CHECK_FOR_FMT(DXT1);
     } else if (num_alpha_bits <= 4) {
     } else if (num_alpha_bits <= 4) {
-      CHECK_FOR_FMT(DXT3);    
+      CHECK_FOR_FMT(DXT3);
     } else {
     } else {
       CHECK_FOR_FMT(DXT5);
       CHECK_FOR_FMT(DXT5);
     }
     }
@@ -425,7 +427,7 @@ create_texture(DXScreenData &scrn) {
     // array (the texture array contains num_color_channels*8bits)
     // array (the texture array contains num_color_channels*8bits)
 
 
   case 128:
   case 128:
-    // check if format is supported    
+    // check if format is supported
     if (scrn._supports_rgba32_texture_format) {
     if (scrn._supports_rgba32_texture_format) {
       target_pixel_format = D3DFMT_A32B32G32R32F;
       target_pixel_format = D3DFMT_A32B32G32R32F;
     }
     }
@@ -435,7 +437,7 @@ create_texture(DXScreenData &scrn) {
     goto found_matching_format;
     goto found_matching_format;
 
 
   case 64:
   case 64:
-    // check if format is supported 
+    // check if format is supported
     if (scrn._supports_rgba16f_texture_format) {
     if (scrn._supports_rgba16f_texture_format) {
       target_pixel_format = D3DFMT_A16B16G16R16F;
       target_pixel_format = D3DFMT_A16B16G16R16F;
     }
     }
@@ -443,7 +445,7 @@ create_texture(DXScreenData &scrn) {
       target_pixel_format = scrn._render_to_texture_d3d_format;
       target_pixel_format = scrn._render_to_texture_d3d_format;
     }
     }
     goto found_matching_format;
     goto found_matching_format;
-    
+
   case 32:
   case 32:
     if (!((num_color_channels == 3) || (num_color_channels == 4)))
     if (!((num_color_channels == 3) || (num_color_channels == 4)))
       break; //bail
       break; //bail
@@ -502,7 +504,7 @@ create_texture(DXScreenData &scrn) {
 
 
     CHECK_FOR_FMT(X8R8G8B8);
     CHECK_FOR_FMT(X8R8G8B8);
     CHECK_FOR_FMT(A8R8G8B8);
     CHECK_FOR_FMT(A8R8G8B8);
-    
+
     // no 24-bit or 32 fmt.  look for 16 bit fmt (higher res 565 1st)
     // no 24-bit or 32 fmt.  look for 16 bit fmt (higher res 565 1st)
     CHECK_FOR_FMT(R5G6B5);
     CHECK_FOR_FMT(R5G6B5);
     CHECK_FOR_FMT(X1R5G5B5);
     CHECK_FOR_FMT(X1R5G5B5);
@@ -782,13 +784,13 @@ create_texture(DXScreenData &scrn) {
     // REQUIRED PARAMETERS
     // REQUIRED PARAMETERS
     _managed = false;
     _managed = false;
     _is_render_target = true;
     _is_render_target = true;
-    
+
     pool = D3DPOOL_DEFAULT;
     pool = D3DPOOL_DEFAULT;
     usage = D3DUSAGE_RENDERTARGET;
     usage = D3DUSAGE_RENDERTARGET;
     if (target_bpp <= 32 ) {
     if (target_bpp <= 32 ) {
       target_pixel_format = scrn._render_to_texture_d3d_format;
       target_pixel_format = scrn._render_to_texture_d3d_format;
     }
     }
-    
+
     dxgsg9_cat.debug ()
     dxgsg9_cat.debug ()
       << "*** RENDER TO TEXTURE ***: format "
       << "*** RENDER TO TEXTURE ***: format "
       << D3DFormatStr(target_pixel_format)
       << D3DFormatStr(target_pixel_format)
@@ -848,7 +850,7 @@ create_texture(DXScreenData &scrn) {
     data_size *= 6;
     data_size *= 6;
   }
   }
   update_data_size_bytes(data_size);
   update_data_size_bytes(data_size);
-  
+
   int attempts;
   int attempts;
 
 
   if (dxgsg9_cat.is_debug()) {
   if (dxgsg9_cat.is_debug()) {
@@ -882,7 +884,7 @@ create_texture(DXScreenData &scrn) {
       hr = scrn._d3d_device->CreateTexture
       hr = scrn._d3d_device->CreateTexture
         (target_width, target_height, mip_level_count, usage,
         (target_width, target_height, mip_level_count, usage,
          target_pixel_format, pool, &_d3d_2d_texture, NULL);
          target_pixel_format, pool, &_d3d_2d_texture, NULL);
-      _d3d_texture = _d3d_2d_texture;      
+      _d3d_texture = _d3d_2d_texture;
       break;
       break;
 
 
     case Texture::TT_3d_texture:
     case Texture::TT_3d_texture:
@@ -952,7 +954,7 @@ create_texture(DXScreenData &scrn) {
     scrn._dxgsg9->get_engine()->texture_uploaded(tex);
     scrn._dxgsg9->get_engine()->texture_uploaded(tex);
   }
   }
   mark_loaded();
   mark_loaded();
-  
+
   return true;
   return true;
 
 
  error_exit:
  error_exit:
@@ -967,7 +969,7 @@ create_texture(DXScreenData &scrn) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXTextureContext9::create_simple_texture
 //     Function: DXTextureContext9::create_simple_texture
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool DXTextureContext9::
 bool DXTextureContext9::
 create_simple_texture(DXScreenData &scrn) {
 create_simple_texture(DXScreenData &scrn) {
@@ -993,7 +995,7 @@ create_simple_texture(DXScreenData &scrn) {
   hr = scrn._d3d_device->CreateTexture
   hr = scrn._d3d_device->CreateTexture
     (target_width, target_height, mip_level_count, usage,
     (target_width, target_height, mip_level_count, usage,
      target_pixel_format, pool, &_d3d_2d_texture, NULL);
      target_pixel_format, pool, &_d3d_2d_texture, NULL);
-  _d3d_texture = _d3d_2d_texture;      
+  _d3d_texture = _d3d_2d_texture;
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
       << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr);
       << "D3D create_simple_texture failed!" << D3DERRORSTRING(hr);
@@ -1032,13 +1034,13 @@ create_simple_texture(DXScreenData &scrn) {
 
 
     RELEASE(surface, dxgsg9, "create_simple_texture Surface", RELEASE_ONCE);
     RELEASE(surface, dxgsg9, "create_simple_texture Surface", RELEASE_ONCE);
   }
   }
-    
+
   if (FAILED(hr)) {
   if (FAILED(hr)) {
     dxgsg9_cat.debug ()
     dxgsg9_cat.debug ()
       << "*** fill_d3d_texture_pixels failed ***: format "
       << "*** fill_d3d_texture_pixels failed ***: format "
       << target_pixel_format
       << target_pixel_format
       << "\n";
       << "\n";
-    
+
     goto error_exit;
     goto error_exit;
   }
   }
 
 
@@ -1084,7 +1086,7 @@ bool DXTextureContext9::
 extract_texture_data(DXScreenData &screen) {
 extract_texture_data(DXScreenData &screen) {
   bool state;
   bool state;
   HRESULT hr;
   HRESULT hr;
-  
+
   state = false;
   state = false;
   Texture *tex = get_texture();
   Texture *tex = get_texture();
   if (tex->get_texture_type() != Texture::TT_2d_texture) {
   if (tex->get_texture_type() != Texture::TT_2d_texture) {
@@ -1147,7 +1149,7 @@ extract_texture_data(DXScreenData &screen) {
 
 
   default:
   default:
     dxgsg9_cat.error()
     dxgsg9_cat.error()
-      << "Cannot extract texture data: unhandled surface format " 
+      << "Cannot extract texture data: unhandled surface format "
       << desc.Format << "\n";
       << desc.Format << "\n";
     return state;
     return state;
   }
   }
@@ -1164,13 +1166,13 @@ extract_texture_data(DXScreenData &screen) {
   if (_is_render_target) {
   if (_is_render_target) {
     IDirect3DSurface9* source_surface;
     IDirect3DSurface9* source_surface;
     IDirect3DSurface9* destination_surface;
     IDirect3DSurface9* destination_surface;
-  
+
     source_surface = 0;
     source_surface = 0;
     destination_surface = 0;
     destination_surface = 0;
-    
+
     hr = _d3d_2d_texture -> GetSurfaceLevel (0, &source_surface);
     hr = _d3d_2d_texture -> GetSurfaceLevel (0, &source_surface);
-    if (hr == D3D_OK) {    
-       
+    if (hr == D3D_OK) {
+
       D3DPOOL pool;
       D3DPOOL pool;
       D3DSURFACE_DESC surface_description;
       D3DSURFACE_DESC surface_description;
 
 
@@ -1186,7 +1188,7 @@ extract_texture_data(DXScreenData &screen) {
         NULL);
         NULL);
       if (hr == D3D_OK) {
       if (hr == D3D_OK) {
         if (source_surface && destination_surface) {
         if (source_surface && destination_surface) {
-          hr = screen._d3d_device -> GetRenderTargetData (source_surface, destination_surface);          
+          hr = screen._d3d_device -> GetRenderTargetData (source_surface, destination_surface);
           if (hr == D3D_OK) {
           if (hr == D3D_OK) {
 
 
             D3DLOCKED_RECT rect;
             D3DLOCKED_RECT rect;
@@ -1200,13 +1202,13 @@ extract_texture_data(DXScreenData &screen) {
 
 
               int surface_bytes_per_line;
               int surface_bytes_per_line;
               unsigned char *surface_pointer;
               unsigned char *surface_pointer;
-              
+
               bytes_per_line = surface_description.Width * this -> d3d_format_to_bytes_per_pixel (surface_description.Format);
               bytes_per_line = surface_description.Width * this -> d3d_format_to_bytes_per_pixel (surface_description.Format);
               size = bytes_per_line * surface_description.Height;
               size = bytes_per_line * surface_description.Height;
 
 
               surface_bytes_per_line = rect.Pitch;
               surface_bytes_per_line = rect.Pitch;
               surface_pointer = (unsigned char *) rect.pBits;
               surface_pointer = (unsigned char *) rect.pBits;
-              
+
               PTA_uchar image = PTA_uchar::empty_array(size);
               PTA_uchar image = PTA_uchar::empty_array(size);
 
 
               int offset;
               int offset;
@@ -1217,29 +1219,29 @@ extract_texture_data(DXScreenData &screen) {
                 memcpy (&image [offset], surface_pointer, bytes_per_line);
                 memcpy (&image [offset], surface_pointer, bytes_per_line);
 
 
                 offset += bytes_per_line;
                 offset += bytes_per_line;
-                surface_pointer += surface_bytes_per_line;  
+                surface_pointer += surface_bytes_per_line;
               }
               }
 
 
               tex->set_ram_image(image, Texture::CM_off);
               tex->set_ram_image(image, Texture::CM_off);
 
 
               state = true;
               state = true;
-              
+
               destination_surface -> UnlockRect();
               destination_surface -> UnlockRect();
             }
             }
           }
           }
-        }    
-        
+        }
+
         destination_surface -> Release ( );
         destination_surface -> Release ( );
       }
       }
       else {
       else {
         dxgsg9_cat.error()
         dxgsg9_cat.error()
           << "CreateImageSurface failed in extract_texture_data()"
           << "CreateImageSurface failed in extract_texture_data()"
-          << D3DERRORSTRING(hr);      
-      }      
+          << D3DERRORSTRING(hr);
+      }
       source_surface -> Release ( );
       source_surface -> Release ( );
     }
     }
   }
   }
-  else {  
+  else {
     for (int n = 0; n < num_levels; ++n) {
     for (int n = 0; n < num_levels; ++n) {
       D3DLOCKED_RECT rect;
       D3DLOCKED_RECT rect;
       hr = _d3d_2d_texture->LockRect(n, &rect, NULL, D3DLOCK_READONLY);
       hr = _d3d_2d_texture->LockRect(n, &rect, NULL, D3DLOCK_READONLY);
@@ -1248,11 +1250,11 @@ extract_texture_data(DXScreenData &screen) {
           << "Texture::LockRect() failed!  level = " << n << " " << D3DERRORSTRING(hr);
           << "Texture::LockRect() failed!  level = " << n << " " << D3DERRORSTRING(hr);
         return state;
         return state;
       }
       }
-    
+
       int x_size = tex->get_expected_mipmap_x_size(n);
       int x_size = tex->get_expected_mipmap_x_size(n);
       int y_size = tex->get_expected_mipmap_y_size(n);
       int y_size = tex->get_expected_mipmap_y_size(n);
       PTA_uchar image;
       PTA_uchar image;
-      
+
       if (compression == Texture::CM_off) {
       if (compression == Texture::CM_off) {
         // Uncompressed, but we have to respect the pitch.
         // Uncompressed, but we have to respect the pitch.
         int pitch = x_size * tex->get_num_components() * tex->get_component_width();
         int pitch = x_size * tex->get_num_components() * tex->get_component_width();
@@ -1273,7 +1275,7 @@ extract_texture_data(DXScreenData &screen) {
             source += rect.Pitch;
             source += rect.Pitch;
           }
           }
         }
         }
-        
+
       } else {
       } else {
         // Compressed; just copy the data verbatim.
         // Compressed; just copy the data verbatim.
         int size = rect.Pitch * (y_size / div);
         int size = rect.Pitch * (y_size / div);
@@ -1288,10 +1290,10 @@ extract_texture_data(DXScreenData &screen) {
         tex->set_ram_mipmap_image(n, image);
         tex->set_ram_mipmap_image(n, image);
       }
       }
     }
     }
-    
+
     state = true;
     state = true;
   }
   }
-  
+
   return state;
   return state;
 }
 }
 
 
@@ -1560,7 +1562,7 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: calculate_row_byte_length
 //     Function: calculate_row_byte_length
 //       Access: Private, hidden
 //       Access: Private, hidden
-//  Description: local helper function, which calculates the 
+//  Description: local helper function, which calculates the
 //               'row_byte_length' or 'pitch' needed for calling
 //               'row_byte_length' or 'pitch' needed for calling
 //               D3DXLoadSurfaceFromMemory.
 //               D3DXLoadSurfaceFromMemory.
 //               Takes compressed formats (DXTn) into account.
 //               Takes compressed formats (DXTn) into account.
@@ -1596,12 +1598,12 @@ static UINT calculate_row_byte_length (int width, int num_color_channels, D3DFOR
 //       Access: Private
 //       Access: Private
 //  Description: Called from fill_d3d_texture_pixels, this function
 //  Description: Called from fill_d3d_texture_pixels, this function
 //               fills a single mipmap with texture data.
 //               fills a single mipmap with texture data.
-//               Takes care of all necessery conversions and error
+//               Takes care of all necessary conversions and error
 //               handling.
 //               handling.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format)
 HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_format)
 {
 {
-  // This whole function was refactored out of fill_d3d_texture_pixels to make the code 
+  // This whole function was refactored out of fill_d3d_texture_pixels to make the code
   // more readable and to avoid code duplication.
   // more readable and to avoid code duplication.
   IDirect3DSurface9 *mip_surface = NULL;
   IDirect3DSurface9 *mip_surface = NULL;
   bool using_temp_buffer = false;
   bool using_temp_buffer = false;
@@ -1617,7 +1619,7 @@ HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
   pixels += view_size * get_view();
   pixels += view_size * get_view();
   size_t page_size = get_texture()->get_expected_ram_mipmap_page_size(mip_level);
   size_t page_size = get_texture()->get_expected_ram_mipmap_page_size(mip_level);
   pixels += page_size * depth_index;
   pixels += page_size * depth_index;
-  
+
   if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
   if (get_texture()->get_texture_type() == Texture::TT_cube_map) {
     nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
     nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
     hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface);
     hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)depth_index, mip_level, &mip_surface);
@@ -1645,6 +1647,10 @@ HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
   // dithering)??)
   // dithering)??)
   mip_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
   mip_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
 
 
+  if (Texture::is_srgb(get_texture()->get_format())) {
+    mip_filter |= D3DX_FILTER_SRGB;
+  }
+
   // D3DXLoadSurfaceFromMemory will load black luminance and we want
   // D3DXLoadSurfaceFromMemory will load black luminance and we want
   // full white, so convert to explicit luminance-alpha format
   // full white, so convert to explicit luminance-alpha format
   if (_d3d_format == D3DFMT_A8) {
   if (_d3d_format == D3DFMT_A8) {
@@ -1671,7 +1677,7 @@ HRESULT DXTextureContext9::fill_d3d_texture_mipmap_pixels(int mip_level, int dep
     source_format = D3DFMT_A8L8;
     source_format = D3DFMT_A8L8;
     source_row_byte_length = width * sizeof(USHORT);
     source_row_byte_length = width * sizeof(USHORT);
     pixels = (BYTE*)temp_buffer;
     pixels = (BYTE*)temp_buffer;
-  } 
+  }
   else if (component_width != 1) {
   else if (component_width != 1) {
     // Convert from 16-bit per channel (or larger) format down to
     // Convert from 16-bit per channel (or larger) format down to
     // 8-bit per channel.  This throws away precision in the
     // 8-bit per channel.  This throws away precision in the
@@ -1756,7 +1762,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
     // The texture doesn't have an image to load.  That's ok; it
     // The texture doesn't have an image to load.  That's ok; it
     // might be a texture we've rendered to by frame buffer
     // might be a texture we've rendered to by frame buffer
     // operations or something.
     // operations or something.
-    if (tex->get_render_to_texture()) {   
+    if (tex->get_render_to_texture()) {
       HRESULT result;
       HRESULT result;
 
 
       if (_d3d_2d_texture) {
       if (_d3d_2d_texture) {
@@ -1777,7 +1783,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
               depth_stencil_surface = 0;
               depth_stencil_surface = 0;
               if (device -> GetDepthStencilSurface (&depth_stencil_surface) == D3D_OK) {
               if (device -> GetDepthStencilSurface (&depth_stencil_surface) == D3D_OK) {
                 if (device -> SetDepthStencilSurface (NULL) == D3D_OK) {
                 if (device -> SetDepthStencilSurface (NULL) == D3D_OK) {
-      
+
                 }
                 }
               }
               }
 
 
@@ -1791,7 +1797,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
                 }
                 }
               }
               }
 
 
-              // restore depth stencil 
+              // restore depth stencil
               if (depth_stencil_surface) {
               if (depth_stencil_surface) {
                 device -> SetDepthStencilSurface (depth_stencil_surface);
                 device -> SetDepthStencilSurface (depth_stencil_surface);
                 depth_stencil_surface -> Release();
                 depth_stencil_surface -> Release();
@@ -1806,7 +1812,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
           surface -> Release();
           surface -> Release();
         }
         }
       }
       }
-      
+
       return S_OK;
       return S_OK;
     }
     }
     return E_FAIL;
     return E_FAIL;
@@ -1842,7 +1848,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
   }
   }
 
 
   for (unsigned int di = 0; di < orig_depth; di++) {
   for (unsigned int di = 0; di < orig_depth; di++) {
-    
+
     // fill top level mipmap
     // fill top level mipmap
     hr = fill_d3d_texture_mipmap_pixels(0, di, source_format);
     hr = fill_d3d_texture_mipmap_pixels(0, di, source_format);
     if (FAILED(hr)) {
     if (FAILED(hr)) {
@@ -1861,8 +1867,8 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
           if (FAILED(hr)) {
           if (FAILED(hr)) {
             return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
             return hr; // error message was already output in fill_d3d_texture_mipmap_pixels
           }
           }
-        }        
-      } 
+        }
+      }
       else {
       else {
         // mipmaps need to be generated, either use autogen or d3dx functions
         // mipmaps need to be generated, either use autogen or d3dx functions
 
 
@@ -1888,6 +1894,10 @@ fill_d3d_texture_pixels(DXScreenData &scrn, bool compress_texture) {
             mip_filter_flags = D3DX_FILTER_TRIANGLE;
             mip_filter_flags = D3DX_FILTER_TRIANGLE;
           }
           }
 
 
+          if (Texture::is_srgb(tex->get_format())) {
+            mip_filter_flags |= D3DX_FILTER_SRGB;
+          }
+
           // mip_filter_flags |= D3DX_FILTER_DITHER;
           // mip_filter_flags |= D3DX_FILTER_DITHER;
           hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0,
           hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0,
                                 mip_filter_flags);
                                 mip_filter_flags);
@@ -1934,7 +1944,7 @@ fill_d3d_volume_texture_pixels(DXScreenData &scrn) {
   if (!scrn._dxgsg9->get_supports_compressed_texture_format(image_compression)) {
   if (!scrn._dxgsg9->get_supports_compressed_texture_format(image_compression)) {
     image = tex->get_uncompressed_ram_image();
     image = tex->get_uncompressed_ram_image();
     image_compression = Texture::CM_off;
     image_compression = Texture::CM_off;
-  }    
+  }
 
 
   if (image.is_null()) {
   if (image.is_null()) {
     // The texture doesn't have an image to load.  That's ok; it
     // The texture doesn't have an image to load.  That's ok; it
@@ -1991,6 +2001,10 @@ fill_d3d_volume_texture_pixels(DXScreenData &scrn) {
   // dithering)??)
   // dithering)??)
   level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
   level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
 
 
+  if (Texture::is_srgb(tex->get_format())) {
+    level_0_filter |= D3DX_FILTER_SRGB;
+  }
+
   // D3DXLoadSurfaceFromMemory will load black luminance and we want
   // D3DXLoadSurfaceFromMemory will load black luminance and we want
   // full white, so convert to explicit luminance-alpha format
   // full white, so convert to explicit luminance-alpha format
   if (_d3d_format == D3DFMT_A8) {
   if (_d3d_format == D3DFMT_A8) {
@@ -2070,6 +2084,10 @@ fill_d3d_volume_texture_pixels(DXScreenData &scrn) {
       mip_filter_flags = D3DX_FILTER_TRIANGLE;
       mip_filter_flags = D3DX_FILTER_TRIANGLE;
     }
     }
 
 
+    if (Texture::is_srgb(tex->get_format())) {
+      mip_filter_flags |= D3DX_FILTER_SRGB;
+    }
+
     //    mip_filter_flags| = D3DX_FILTER_DITHER;
     //    mip_filter_flags| = D3DX_FILTER_DITHER;
 
 
     hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0,
     hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0,
@@ -2167,6 +2185,17 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) {
   case Texture::F_rgba32:
   case Texture::F_rgba32:
     *alphbits = 32;
     *alphbits = 32;
     return 128;
     return 128;
+
+  case Texture::F_srgb:
+    return 24;
+  case Texture::F_srgb_alpha:
+    *alphbits = 8;
+    return 32;
+  case Texture::F_sluminance:
+    return 8;
+  case Texture::F_sluminance_alpha:
+    *alphbits = 8;
+    return 16;
   }
   }
   return 8;
   return 8;
 }
 }
@@ -2180,7 +2209,7 @@ PN_stdfloat DXTextureContext9::
 d3d_format_to_bytes_per_pixel (D3DFORMAT format)
 d3d_format_to_bytes_per_pixel (D3DFORMAT format)
 {
 {
   PN_stdfloat bytes_per_pixel;
   PN_stdfloat bytes_per_pixel;
-  
+
   bytes_per_pixel = 0.0f;
   bytes_per_pixel = 0.0f;
   switch (format)
   switch (format)
   {
   {
@@ -2246,6 +2275,6 @@ d3d_format_to_bytes_per_pixel (D3DFORMAT format)
       bytes_per_pixel = 1.0f;
       bytes_per_pixel = 1.0f;
       break;
       break;
   }
   }
-  
+
   return bytes_per_pixel;
   return bytes_per_pixel;
 }
 }

+ 4 - 4
panda/src/dxgsg9/wdxGraphicsPipe9.cxx

@@ -139,7 +139,7 @@ make_output(const string &name,
     // Early failure - if we are sure that this buffer WONT
     // Early failure - if we are sure that this buffer WONT
     // meet specs, we can bail out early.
     // meet specs, we can bail out early.
     if ((flags & BF_fb_props_optional) == 0) {
     if ((flags & BF_fb_props_optional) == 0) {
-      if ((fb_prop.get_indexed_color() > 0)||
+      if (fb_prop.get_indexed_color() ||
           (fb_prop.get_back_buffers() > 0)||
           (fb_prop.get_back_buffers() > 0)||
           (fb_prop.get_accum_bits() > 0)||
           (fb_prop.get_accum_bits() > 0)||
           (fb_prop.get_multisamples() > 0)) {
           (fb_prop.get_multisamples() > 0)) {
@@ -649,7 +649,7 @@ search_for_valid_displaymode(DXScreenData &scrn,
         continue;
         continue;
       }
       }
 
 
-      // disable refresh rate checking since SLI video cards may use 
+      // disable refresh rate checking since SLI video cards may use
       // refresh rates less than 60
       // refresh rates less than 60
       if (0) {
       if (0) {
         if ((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) {
         if ((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) {
@@ -663,7 +663,7 @@ search_for_valid_displaymode(DXScreenData &scrn,
           continue;
           continue;
         }
         }
       }
       }
-      
+
       // Note no attempt is made to verify if format will work at
       // Note no attempt is made to verify if format will work at
       // requested size, so even if this call succeeds, could still get
       // requested size, so even if this call succeeds, could still get
       // an out-of-video-mem error
       // an out-of-video-mem error
@@ -956,7 +956,7 @@ const char *D3DFormatStr(D3DFORMAT fmt) {
     CASESTR(D3DFMT_D24X4S4);
     CASESTR(D3DFMT_D24X4S4);
     CASESTR(D3DFMT_VERTEXDATA);
     CASESTR(D3DFMT_VERTEXDATA);
     CASESTR(D3DFMT_INDEX16);
     CASESTR(D3DFMT_INDEX16);
-    CASESTR(D3DFMT_INDEX32);    
+    CASESTR(D3DFMT_INDEX32);
     CASESTR(D3DFMT_A16B16G16R16F);
     CASESTR(D3DFMT_A16B16G16R16F);
     CASESTR(D3DFMT_A32B32G32R32F);
     CASESTR(D3DFMT_A32B32G32R32F);
   }
   }

+ 14 - 14
panda/src/dxgsg9/wdxGraphicsWindow9.cxx

@@ -252,7 +252,7 @@ verify_window_sizes(int numsizes, int *dimen) {
 void wdxGraphicsWindow9::
 void wdxGraphicsWindow9::
 close_window() {
 close_window() {
   if (wdxdisplay9_cat.is_debug()) {
   if (wdxdisplay9_cat.is_debug()) {
-    wdxdisplay9_cat.debug() 
+    wdxdisplay9_cat.debug()
       << "wdxGraphicsWindow9::close_window() " << this << "\n";
       << "wdxGraphicsWindow9::close_window() " << this << "\n";
   }
   }
 
 
@@ -300,7 +300,7 @@ open_window() {
   // window.
   // window.
   {
   {
     WindowProperties resized_props;
     WindowProperties resized_props;
-    resized_props.set_size(_wcontext._display_mode.Width, 
+    resized_props.set_size(_wcontext._display_mode.Width,
                            _wcontext._display_mode.Height);
                            _wcontext._display_mode.Height);
     _properties.add_properties(resized_props);
     _properties.add_properties(resized_props);
   }
   }
@@ -420,17 +420,17 @@ void wdxGraphicsWindow9::
 handle_reshape() {
 handle_reshape() {
   GdiFlush();
   GdiFlush();
   WinGraphicsWindow::handle_reshape();
   WinGraphicsWindow::handle_reshape();
-  
-  if (_dxgsg != NULL) {
+
+  if (_dxgsg != NULL && _dxgsg->_d3d_device != NULL) {
     // create the new resized rendertargets
     // create the new resized rendertargets
     WindowProperties props = get_properties();
     WindowProperties props = get_properties();
     int x_size = props.get_x_size();
     int x_size = props.get_x_size();
     int y_size = props.get_y_size();
     int y_size = props.get_y_size();
-    
+
     if (_wcontext._presentation_params.BackBufferWidth != x_size ||
     if (_wcontext._presentation_params.BackBufferWidth != x_size ||
         _wcontext._presentation_params.BackBufferHeight != y_size) {
         _wcontext._presentation_params.BackBufferHeight != y_size) {
       bool resize_succeeded = reset_device_resize_window(x_size, y_size);
       bool resize_succeeded = reset_device_resize_window(x_size, y_size);
-      
+
       if (wdxdisplay9_cat.is_debug()) {
       if (wdxdisplay9_cat.is_debug()) {
         if (!resize_succeeded) {
         if (!resize_succeeded) {
           wdxdisplay9_cat.debug()
           wdxdisplay9_cat.debug()
@@ -708,7 +708,7 @@ create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer
   if (dx_disable_driver_management_ex) {
   if (dx_disable_driver_management_ex) {
     dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX;
     dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX;
   }
   }
-  
+
   if (is_fullscreen()) {
   if (is_fullscreen()) {
     // CREATE FULLSCREEN BUFFERS
     // CREATE FULLSCREEN BUFFERS
 
 
@@ -751,11 +751,11 @@ create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer
     }
     }
 
 
     //From d3d8caps.h
     //From d3d8caps.h
-    //D3DPRESENT_INTERVAL_DEFAULT  = 0x00000000L 
+    //D3DPRESENT_INTERVAL_DEFAULT  = 0x00000000L
     //#define D3DPRESENT_INTERVAL_ONE         0x00000001L
     //#define D3DPRESENT_INTERVAL_ONE         0x00000001L
     //Next line is really sloppy, should either be D3DPRESENT_INTERVAL_DEFAULT or D3DPRESENT_INTERVAL_ONE
     //Next line is really sloppy, should either be D3DPRESENT_INTERVAL_DEFAULT or D3DPRESENT_INTERVAL_ONE
     //not a direct number! but I'm not going to touch it because it's working as is. Zhao 12/15/2011
     //not a direct number! but I'm not going to touch it because it's working as is. Zhao 12/15/2011
-    presentation_params->PresentationInterval = 0;    
+    presentation_params->PresentationInterval = 0;
 
 
     //ATI 5450 doesn't like D3DSWAPEFFECT_FLIP
     //ATI 5450 doesn't like D3DSWAPEFFECT_FLIP
     presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
     presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
@@ -803,7 +803,7 @@ create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer
 
 
   PRINT_REFCNT(wdxdisplay9, _wcontext._d3d_device);
   PRINT_REFCNT(wdxdisplay9, _wcontext._d3d_device);
 
 
-  if (presentation_params->EnableAutoDepthStencil) {    
+  if (presentation_params->EnableAutoDepthStencil) {
     int depth_bits;
     int depth_bits;
     int stencil_bits;
     int stencil_bits;
 
 
@@ -846,7 +846,7 @@ create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer
         wdxdisplay9_cat.error() << "unknown depth stencil format  " << presentation_params->AutoDepthStencilFormat;
         wdxdisplay9_cat.error() << "unknown depth stencil format  " << presentation_params->AutoDepthStencilFormat;
         break;
         break;
     }
     }
-      
+
     _fb_properties.set_stencil_bits(stencil_bits);
     _fb_properties.set_stencil_bits(stencil_bits);
     _fb_properties.set_depth_bits(depth_bits);
     _fb_properties.set_depth_bits(depth_bits);
   } else {
   } else {
@@ -1118,16 +1118,16 @@ consider_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) {
 
 
   if (is_fullscreen()) {
   if (is_fullscreen()) {
     bool bCouldntFindValidZBuf;
     bool bCouldntFindValidZBuf;
-    
+
     dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight,
     dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight,
                                          bNeedZBuffer, bWantStencil,
                                          bNeedZBuffer, bWantStencil,
                                          &_wcontext._supported_screen_depths_mask,
                                          &_wcontext._supported_screen_depths_mask,
                                          &bCouldntFindValidZBuf,
                                          &bCouldntFindValidZBuf,
                                          &pixFmt, dx_force_16bpp_zbuffer, true);
                                          &pixFmt, dx_force_16bpp_zbuffer, true);
-    
+
     // note I'm not saving refresh rate, will just use adapter
     // note I'm not saving refresh rate, will just use adapter
     // default at given res for now
     // default at given res for now
-    
+
     if (pixFmt == D3DFMT_UNKNOWN) {
     if (pixFmt == D3DFMT_UNKNOWN) {
       wdxdisplay9_cat.error()
       wdxdisplay9_cat.error()
         << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
         << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")

+ 1 - 1
panda/src/express/virtualFileMountAndroidAsset.I

@@ -31,5 +31,5 @@ VirtualFileMountAndroidAsset(AAssetManager *mgr, const string &apk_path) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE VirtualFileMountAndroidAsset::AssetStream::
 INLINE VirtualFileMountAndroidAsset::AssetStream::
 AssetStream(AAsset *asset) :
 AssetStream(AAsset *asset) :
-  istream(new AssetStreamBuf(asset)) {
+  istream(new VirtualFileMountAndroidAsset::AssetStreamBuf(asset)) {
 }
 }

+ 1 - 1
panda/src/express/virtualFileMountAndroidAsset.cxx

@@ -57,7 +57,7 @@ get_fd(const Filename &file, off_t *start, off_t *length) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool VirtualFileMountAndroidAsset::
 bool VirtualFileMountAndroidAsset::
 has_file(const Filename &file) const {
 has_file(const Filename &file) const {
-  return (file.empty() || is_directory(file) || is_regular_file(file));
+  return (file.empty() || /*is_directory(file) ||*/ is_regular_file(file));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
panda/src/glesgsg/glesgsg.h

@@ -90,6 +90,7 @@
 #define GL_DEPTH_STENCIL_EXT GL_DEPTH_STENCIL_OES
 #define GL_DEPTH_STENCIL_EXT GL_DEPTH_STENCIL_OES
 #define GL_UNSIGNED_INT_24_8_EXT GL_UNSIGNED_INT_24_8_OES
 #define GL_UNSIGNED_INT_24_8_EXT GL_UNSIGNED_INT_24_8_OES
 #define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8_OES
 #define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8_OES
+#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
 #define GL_DEPTH_COMPONENT16 GL_DEPTH_COMPONENT16_OES
 #define GL_DEPTH_COMPONENT16 GL_DEPTH_COMPONENT16_OES
 #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
 #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
 #define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES
 #define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES

+ 12 - 12
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -18,7 +18,7 @@
 
 
 #include "Cg/cgGL.h"
 #include "Cg/cgGL.h"
 
 
-#include "pStatTimer.h"
+#include "pStatGPUTimer.h"
 
 
 TypeHandle CLP(CgShaderContext)::_type_handle;
 TypeHandle CLP(CgShaderContext)::_type_handle;
 
 
@@ -50,7 +50,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
 
 
   nassertv(s->get_language() == Shader::SL_Cg);
   nassertv(s->get_language() == Shader::SL_Cg);
 
 
-  // Ask the shader to compile itself for us and 
+  // Ask the shader to compile itself for us and
   // to give us the resulting Cg program objects.
   // to give us the resulting Cg program objects.
   if (!s->cg_compile_for(_glgsg->_shader_caps,
   if (!s->cg_compile_for(_glgsg->_shader_caps,
                          _cg_context,
                          _cg_context,
@@ -223,7 +223,7 @@ unbind() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(CgShaderContext)::
 void CLP(CgShaderContext)::
 issue_parameters(int altered) {
 issue_parameters(int altered) {
-  PStatTimer timer(_glgsg->_draw_set_state_shader_parameters_pcollector);
+  //PStatGPUTimer timer(_glgsg, _glgsg->_draw_set_state_shader_parameters_pcollector);
 
 
   if (!valid()) {
   if (!valid()) {
     return;
     return;
@@ -233,9 +233,9 @@ issue_parameters(int altered) {
   for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
   for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
     if (altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])) {
     if (altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])) {
       const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i];
       const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i];
-      Shader::ShaderPtrData* ptr_data = 
+      Shader::ShaderPtrData* ptr_data =
         const_cast< Shader::ShaderPtrData*>(_glgsg->fetch_ptr_parameter(_ptr));
         const_cast< Shader::ShaderPtrData*>(_glgsg->fetch_ptr_parameter(_ptr));
-      
+
       if (ptr_data == NULL){ //the input is not contained in ShaderPtrData
       if (ptr_data == NULL){ //the input is not contained in ShaderPtrData
         release_resources();
         release_resources();
         return;
         return;
@@ -249,14 +249,14 @@ issue_parameters(int altered) {
       int input_size = _ptr._dim[0] * _ptr._dim[1] * _ptr._dim[2];
       int input_size = _ptr._dim[0] * _ptr._dim[1] * _ptr._dim[2];
 
 
       // dimension is negative only if the parameter had the (deprecated)k_ prefix.
       // dimension is negative only if the parameter had the (deprecated)k_ prefix.
-      if ((input_size > ptr_data->_size) && (_ptr._dim[0] > 0)) { 
-        GLCAT.error() << _ptr._id._name << ": incorrect number of elements, expected " 
+      if ((input_size > ptr_data->_size) && (_ptr._dim[0] > 0)) {
+        GLCAT.error() << _ptr._id._name << ": incorrect number of elements, expected "
                       <<  input_size <<" got " <<  ptr_data->_size << "\n";
                       <<  input_size <<" got " <<  ptr_data->_size << "\n";
         release_resources();
         release_resources();
         return;
         return;
       }
       }
       CGparameter p = _cg_parameter_map[_ptr._id._seqno];
       CGparameter p = _cg_parameter_map[_ptr._id._seqno];
-      
+
       switch (ptr_data->_type) {
       switch (ptr_data->_type) {
       case Shader::SPT_float:
       case Shader::SPT_float:
         switch(_ptr._info._class) {
         switch(_ptr._info._class) {
@@ -271,7 +271,7 @@ issue_parameters(int altered) {
         case Shader::SAC_matrix: cgGLSetMatrixParameterfc(p,(float*)ptr_data->_ptr); continue;
         case Shader::SAC_matrix: cgGLSetMatrixParameterfc(p,(float*)ptr_data->_ptr); continue;
         case Shader::SAC_array: {
         case Shader::SAC_array: {
           switch(_ptr._info._subclass) {
           switch(_ptr._info._subclass) {
-          case Shader::SAC_scalar: 
+          case Shader::SAC_scalar:
             cgGLSetParameterArray1f(p,0,_ptr._dim[0],(float*)ptr_data->_ptr); continue;
             cgGLSetParameterArray1f(p,0,_ptr._dim[0],(float*)ptr_data->_ptr); continue;
           case Shader::SAC_vector:
           case Shader::SAC_vector:
             switch(_ptr._dim[2]) {
             switch(_ptr._dim[2]) {
@@ -298,7 +298,7 @@ issue_parameters(int altered) {
         case Shader::SAC_matrix: cgGLSetMatrixParameterdc(p,(double*)ptr_data->_ptr); continue;
         case Shader::SAC_matrix: cgGLSetMatrixParameterdc(p,(double*)ptr_data->_ptr); continue;
         case Shader::SAC_array: {
         case Shader::SAC_array: {
           switch(_ptr._info._subclass) {
           switch(_ptr._info._subclass) {
-          case Shader::SAC_scalar: 
+          case Shader::SAC_scalar:
             cgGLSetParameterArray1d(p,0,_ptr._dim[0],(double*)ptr_data->_ptr); continue;
             cgGLSetParameterArray1d(p,0,_ptr._dim[0],(double*)ptr_data->_ptr); continue;
           case Shader::SAC_vector:
           case Shader::SAC_vector:
             switch(_ptr._dim[2]) {
             switch(_ptr._dim[2]) {
@@ -323,8 +323,8 @@ issue_parameters(int altered) {
           case Shader::SAT_vec4: cgSetParameter4iv(p,(int*)ptr_data->_ptr); continue;
           case Shader::SAT_vec4: cgSetParameter4iv(p,(int*)ptr_data->_ptr); continue;
           }
           }
         }
         }
-      default: GLCAT.error() << _ptr._id._name << ":" << "unrecognized parameter type\n"; 
-        release_resources(); 
+      default: GLCAT.error() << _ptr._id._name << ":" << "unrecognized parameter type\n";
+        release_resources();
         return;
         return;
       }
       }
     }
     }

+ 34 - 7
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -27,7 +27,10 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
                     int flags,
                     int flags,
                     GraphicsStateGuardian *gsg,
                     GraphicsStateGuardian *gsg,
                     GraphicsOutput *host) :
                     GraphicsOutput *host) :
-  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
+  GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host),
+  _bind_texture_pcollector(_draw_window_pcollector, "Bind textures"),
+  _generate_mipmap_pcollector(_draw_window_pcollector, "Generate mipmaps"),
+  _resolve_multisample_pcollector(_draw_window_pcollector, "Resolve multisamples")
 {
 {
   CLP(GraphicsStateGuardian) *glgsg;
   CLP(GraphicsStateGuardian) *glgsg;
 
 
@@ -171,11 +174,12 @@ begin_frame(FrameMode mode, Thread *current_thread) {
 
 
     // In case of multisample rendering, we don't need to issue
     // In case of multisample rendering, we don't need to issue
     // the barrier until we call glBlitFramebuffer.
     // the barrier until we call glBlitFramebuffer.
+#ifndef OPENGLES
     if (gl_enable_memory_barriers && _fbo_multisample == 0) {
     if (gl_enable_memory_barriers && _fbo_multisample == 0) {
       CLP(GraphicsStateGuardian) *glgsg;
       CLP(GraphicsStateGuardian) *glgsg;
       DCAST_INTO_R(glgsg, _gsg, false);
       DCAST_INTO_R(glgsg, _gsg, false);
 
 
-      pvector<CLP(TextureContext)*>::iterator it;
+      TextureContexts::iterator it;
       for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
       for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
         CLP(TextureContext) *gtc = *it;
         CLP(TextureContext) *gtc = *it;
 
 
@@ -186,6 +190,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
         }
         }
       }
       }
     }
     }
+#endif
   }
   }
 
 
   _gsg->set_current_properties(&get_fb_properties());
   _gsg->set_current_properties(&get_fb_properties());
@@ -274,6 +279,8 @@ rebuild_bitplanes() {
     return;
     return;
   }
   }
 
 
+  PStatGPUTimer timer(glgsg, _bind_texture_pcollector);
+
   // Calculate bitplane size.  This can be larger than the buffer.
   // Calculate bitplane size.  This can be larger than the buffer.
   if (_creation_flags & GraphicsPipe::BF_size_track_host) {
   if (_creation_flags & GraphicsPipe::BF_size_track_host) {
     if (_host->get_size() != _size) {
     if (_host->get_size() != _size) {
@@ -437,6 +444,19 @@ rebuild_bitplanes() {
     // Bind the FBO
     // Bind the FBO
     if (_fbo[layer] == 0) {
     if (_fbo[layer] == 0) {
       glgsg->_glGenFramebuffers(1, &_fbo[layer]);
       glgsg->_glGenFramebuffers(1, &_fbo[layer]);
+
+#ifndef OPENGLES
+      if (glgsg->_use_object_labels) {
+        if (num_fbos > 1) {
+          GLchar name[128];
+          GLsizei len = snprintf(name, 128, "%s[%d]", _name.c_str(), layer);
+          glgsg->_glObjectLabel(GL_FRAMEBUFFER, _fbo[layer], len, name);
+        } else {
+          glgsg->_glObjectLabel(GL_FRAMEBUFFER, _fbo[layer], _name.size(), _name.data());
+        }
+      }
+#endif
+
       if (_fbo[layer] == 0) {
       if (_fbo[layer] == 0) {
         report_my_gl_errors();
         report_my_gl_errors();
         return;
         return;
@@ -469,7 +489,7 @@ rebuild_bitplanes() {
       _have_any_color = true;
       _have_any_color = true;
     }
     }
 
 
-#ifndef OPENGLES
+#ifndef OPENGLES_1
     for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
     for (int i=0; i<_fb_properties.get_aux_rgba(); i++) {
       bind_slot(layer, rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i), next++);
       bind_slot(layer, rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i), next++);
       _have_any_color = true;
       _have_any_color = true;
@@ -1131,6 +1151,8 @@ generate_mipmaps() {
   CLP(GraphicsStateGuardian) *glgsg;
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
   DCAST_INTO_V(glgsg, _gsg);
 
 
+  //PStatGPUTimer timer(glgsg, _generate_mipmap_pcollector);
+
   pvector<CLP(TextureContext)*>::iterator it;
   pvector<CLP(TextureContext)*>::iterator it;
   for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
   for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
     CLP(TextureContext) *gtc = *it;
     CLP(TextureContext) *gtc = *it;
@@ -1168,7 +1190,8 @@ end_frame(FrameMode mode, Thread *current_thread) {
     copy_to_textures();
     copy_to_textures();
   }
   }
 
 
-  // Unbind the FBO
+  // Unbind the FBO.  TODO: calling bind_fbo is slow, so we should
+  // probably move this to begin_frame to prevent unnecessary calls.
   CLP(GraphicsStateGuardian) *glgsg;
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
   DCAST_INTO_V(glgsg, _gsg);
   glgsg->bind_fbo(0);
   glgsg->bind_fbo(0);
@@ -1604,11 +1627,14 @@ check_host_valid() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsBuffer)::
 void CLP(GraphicsBuffer)::
 resolve_multisamples() {
 resolve_multisamples() {
+  nassertv(_fbo.size() > 0);
+
   CLP(GraphicsStateGuardian) *glgsg;
   CLP(GraphicsStateGuardian) *glgsg;
   DCAST_INTO_V(glgsg, _gsg);
   DCAST_INTO_V(glgsg, _gsg);
 
 
-  nassertv(_fbo.size() > 0);
+  PStatGPUTimer timer(glgsg, _resolve_multisample_pcollector);
 
 
+#ifndef OPENGLES
   if (gl_enable_memory_barriers) {
   if (gl_enable_memory_barriers) {
     // Issue memory barriers as necessary to make sure that the
     // Issue memory barriers as necessary to make sure that the
     // texture memory is synchronized before we blit to it.
     // texture memory is synchronized before we blit to it.
@@ -1623,6 +1649,7 @@ resolve_multisamples() {
       }
       }
     }
     }
   }
   }
+#endif
 
 
   glgsg->report_my_gl_errors();
   glgsg->report_my_gl_errors();
   GLuint fbo = _fbo[0];
   GLuint fbo = _fbo[0];
@@ -1631,7 +1658,7 @@ resolve_multisamples() {
   }
   }
   glgsg->_glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo);
   glgsg->_glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo);
   glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample);
   glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample);
-  
+
   // If the depth buffer is shared, resolve it only on the last to render FBO.
   // If the depth buffer is shared, resolve it only on the last to render FBO.
   bool do_depth_blit = false;
   bool do_depth_blit = false;
   if (_rbm[RTP_depth_stencil] != 0 || _rbm[RTP_depth] != 0) {
   if (_rbm[RTP_depth_stencil] != 0 || _rbm[RTP_depth] != 0) {
@@ -1671,6 +1698,7 @@ resolve_multisamples() {
                               GL_NEAREST);
                               GL_NEAREST);
   }
   }
   // Now handle the other color buffers.
   // Now handle the other color buffers.
+#ifndef OPENGLES_1
   int next = GL_COLOR_ATTACHMENT1_EXT;
   int next = GL_COLOR_ATTACHMENT1_EXT;
   if (_fb_properties.is_stereo()) {
   if (_fb_properties.is_stereo()) {
     glReadBuffer(next);
     glReadBuffer(next);
@@ -1679,7 +1707,6 @@ resolve_multisamples() {
                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
     next += 1;
     next += 1;
   }
   }
-#ifndef OPENGLES
   for (int i = 0; i < _fb_properties.get_aux_rgba(); ++i) {
   for (int i = 0; i < _fb_properties.get_aux_rgba(); ++i) {
     glReadBuffer(next);
     glReadBuffer(next);
     glDrawBuffer(next);
     glDrawBuffer(next);

+ 14 - 9
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -34,7 +34,7 @@
 //               * Can render onto a texture without clearing it first.
 //               * Can render onto a texture without clearing it first.
 //               * Supports multisample antialiased rendering.
 //               * Supports multisample antialiased rendering.
 //
 //
-//               Some of these deserve a little explanation. 
+//               Some of these deserve a little explanation.
 //               Auxiliary bitplanes are additional bitplanes above
 //               Auxiliary bitplanes are additional bitplanes above
 //               and beyond the normal depth,stencil,color.  One can
 //               and beyond the normal depth,stencil,color.  One can
 //               use them to render out multiple textures in a single
 //               use them to render out multiple textures in a single
@@ -43,14 +43,14 @@
 //               buffer will be equal to the texture's previous
 //               buffer will be equal to the texture's previous
 //               contents.  This alo means you can meaningfully
 //               contents.  This alo means you can meaningfully
 //               share a bitplane between two buffers by binding
 //               share a bitplane between two buffers by binding
-//               the same texture to both buffers. 
+//               the same texture to both buffers.
 //
 //
 //               If either of the necessary OpenGL extensions is not
 //               If either of the necessary OpenGL extensions is not
 //               available, then the glGraphicsBuffer will not be
 //               available, then the glGraphicsBuffer will not be
 //               available (although it may still be possible to
 //               available (although it may still be possible to
 //               create a wglGraphicsBuffer or glxGraphicsBuffer).
 //               create a wglGraphicsBuffer or glxGraphicsBuffer).
 //
 //
-//               This class now also uses the extensions 
+//               This class now also uses the extensions
 //               EXT_framebuffer_multisample and EXT_framebuffer_blit
 //               EXT_framebuffer_multisample and EXT_framebuffer_blit
 //               to allow for multisample antialiasing these offscreen
 //               to allow for multisample antialiasing these offscreen
 //               render targets.  If these extensions are unavailable
 //               render targets.  If these extensions are unavailable
@@ -87,13 +87,13 @@ public:
 protected:
 protected:
   virtual void close_buffer();
   virtual void close_buffer();
   virtual bool open_buffer();
   virtual bool open_buffer();
-  
+
   void check_host_valid();
   void check_host_valid();
-  
+
   void report_my_errors(int line, const char *file);
   void report_my_errors(int line, const char *file);
 
 
 private:
 private:
-  
+
   void bind_slot(int layer, bool rb_resize, Texture **attach,
   void bind_slot(int layer, bool rb_resize, Texture **attach,
                  RenderTexturePlane plane, GLenum attachpoint);
                  RenderTexturePlane plane, GLenum attachpoint);
   void bind_slot_multisample(bool rb_resize, Texture **attach,
   void bind_slot_multisample(bool rb_resize, Texture **attach,
@@ -127,7 +127,8 @@ private:
 
 
   // List of textures for which we might have to generate mipmaps
   // List of textures for which we might have to generate mipmaps
   // after rendering one frame.
   // after rendering one frame.
-  pvector<CLP(TextureContext)*> _texture_contexts;
+  typedef pvector<CLP(TextureContext)*> TextureContexts;
+  TextureContexts _texture_contexts;
 
 
   // The cube map face we are currently drawing to or have just
   // The cube map face we are currently drawing to or have just
   // finished drawing to, or -1 if we are not drawing to a cube map.
   // finished drawing to, or -1 if we are not drawing to a cube map.
@@ -136,10 +137,14 @@ private:
   bool _initial_clear;
   bool _initial_clear;
   bool _needs_rebuild;
   bool _needs_rebuild;
   UpdateSeq _last_textures_seq;
   UpdateSeq _last_textures_seq;
-  
+
   CLP(GraphicsBuffer) *_shared_depth_buffer;
   CLP(GraphicsBuffer) *_shared_depth_buffer;
   list <CLP(GraphicsBuffer) *> _shared_depth_buffer_list;
   list <CLP(GraphicsBuffer) *> _shared_depth_buffer_list;
-  
+
+  PStatCollector _bind_texture_pcollector;
+  PStatCollector _generate_mipmap_pcollector;
+  PStatCollector _resolve_multisample_pcollector;
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 9 - 5
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -27,6 +27,7 @@
 INLINE bool CLP(GraphicsStateGuardian)::
 INLINE bool CLP(GraphicsStateGuardian)::
 report_errors(int line, const char *source_file) {
 report_errors(int line, const char *source_file) {
 #ifndef NDEBUG
 #ifndef NDEBUG
+  PStatTimer timer(_check_error_pcollector);
   GLenum error_code = glGetError();
   GLenum error_code = glGetError();
   if (error_code != GL_NO_ERROR) {
   if (error_code != GL_NO_ERROR) {
     int error_count = 0;
     int error_count = 0;
@@ -46,6 +47,7 @@ INLINE void CLP(GraphicsStateGuardian)::
 report_my_errors(int line, const char *source_file) {
 report_my_errors(int line, const char *source_file) {
 #ifndef NDEBUG
 #ifndef NDEBUG
   if (_check_errors) {
   if (_check_errors) {
+    PStatTimer timer(_check_error_pcollector);
     GLenum error_code = glGetError();
     GLenum error_code = glGetError();
     if (error_code != GL_NO_ERROR) {
     if (error_code != GL_NO_ERROR) {
       if (!report_errors_loop(line, source_file, error_code, _error_count)) {
       if (!report_errors_loop(line, source_file, error_code, _error_count)) {
@@ -69,6 +71,7 @@ report_my_errors(int line, const char *source_file) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(GraphicsStateGuardian)::
 INLINE bool CLP(GraphicsStateGuardian)::
 clear_errors(int line, const char *source_file) {
 clear_errors(int line, const char *source_file) {
+  PStatTimer timer(_check_error_pcollector);
   GLenum error_code = glGetError();
   GLenum error_code = glGetError();
   if (error_code != GL_NO_ERROR) {
   if (error_code != GL_NO_ERROR) {
     int error_count = 0;
     int error_count = 0;
@@ -92,6 +95,7 @@ clear_errors(int line, const char *source_file) {
 INLINE void CLP(GraphicsStateGuardian)::
 INLINE void CLP(GraphicsStateGuardian)::
 clear_my_errors(int line, const char *source_file) {
 clear_my_errors(int line, const char *source_file) {
   if (_check_errors) {
   if (_check_errors) {
+    PStatTimer timer(_check_error_pcollector);
     GLenum error_code = glGetError();
     GLenum error_code = glGetError();
     if (error_code != GL_NO_ERROR) {
     if (error_code != GL_NO_ERROR) {
       int error_count = 0;
       int error_count = 0;
@@ -743,7 +747,7 @@ get_clip_plane_id(int index) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_multisample
 //     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_multisample
 //       Access: Public
 //       Access: Public
-//  Description: Returns if this glGsg supports multisample 
+//  Description: Returns if this glGsg supports multisample
 //               antialiasing for framebuffer objects.
 //               antialiasing for framebuffer objects.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(GraphicsStateGuardian)::
 INLINE bool CLP(GraphicsStateGuardian)::
@@ -754,7 +758,7 @@ get_supports_framebuffer_multisample() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_multisample
 //     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_multisample
 //       Access: Public
 //       Access: Public
-//  Description: Returns if this glGsg supports multisample 
+//  Description: Returns if this glGsg supports multisample
 //               antialiasing for framebuffer objects.
 //               antialiasing for framebuffer objects.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(GraphicsStateGuardian)::
 INLINE bool CLP(GraphicsStateGuardian)::
@@ -766,7 +770,7 @@ get_supports_framebuffer_multisample_coverage_nv() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_blit
 //     Function: CLP(GraphicsStateGuardian)::get_supports_framebuffer_blit
 //       Access: Public
 //       Access: Public
-//  Description: Returns if this glGsg supports multisample 
+//  Description: Returns if this glGsg supports multisample
 //               antialiasing for framebuffer objects.
 //               antialiasing for framebuffer objects.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(GraphicsStateGuardian)::
 INLINE bool CLP(GraphicsStateGuardian)::
@@ -778,7 +782,7 @@ get_supports_framebuffer_blit() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::UsageTextureKey::Constructor
 //     Function: GLGraphicsStateGuardian::UsageTextureKey::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(GraphicsStateGuardian)::UsageTextureKey::
 INLINE CLP(GraphicsStateGuardian)::UsageTextureKey::
 UsageTextureKey(int x_size, int y_size) :
 UsageTextureKey(int x_size, int y_size) :
@@ -792,7 +796,7 @@ UsageTextureKey(int x_size, int y_size) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::UsageTextureKey::operator <
 //     Function: GLGraphicsStateGuardian::UsageTextureKey::operator <
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool CLP(GraphicsStateGuardian)::UsageTextureKey::
 INLINE bool CLP(GraphicsStateGuardian)::UsageTextureKey::
 operator < (const CLP(GraphicsStateGuardian)::UsageTextureKey &other) const {
 operator < (const CLP(GraphicsStateGuardian)::UsageTextureKey &other) const {

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 361 - 107
panda/src/glstuff/glGraphicsStateGuardian_src.cxx


+ 58 - 33
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -1,6 +1,6 @@
 // Filename: glGraphicsStateGuardian_src.h
 // Filename: glGraphicsStateGuardian_src.h
 // Created by:  drose (02Feb99)
 // Created by:  drose (02Feb99)
-// Updated by: fperazzi, PandaSE (05May10) (added 
+// Updated by: fperazzi, PandaSE (05May10) (added
 //   get_supports_cg_profile)
 //   get_supports_cg_profile)
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -37,6 +37,7 @@
 #include "pmap.h"
 #include "pmap.h"
 #include "geomVertexArrayData.h"
 #include "geomVertexArrayData.h"
 #include "lightMutex.h"
 #include "lightMutex.h"
+#include "pStatGPUTimer.h"
 
 
 class PlaneNode;
 class PlaneNode;
 class Light;
 class Light;
@@ -58,6 +59,7 @@ typedef double GLdouble;
 typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
 typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
 typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
 typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
 typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
 typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
 typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
 typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
 typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
 typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
 typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
 typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
@@ -65,6 +67,8 @@ typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);
 typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
 typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
 typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
 typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
 typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
 typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params);
+typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *params);
 typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
 typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
 typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
 typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
 // There is some trivial disagreement between different gl.h headers about this one, so we use our own typename.
 // There is some trivial disagreement between different gl.h headers about this one, so we use our own typename.
@@ -98,32 +102,32 @@ typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
 typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
 typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
-typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); 
-typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); 
-typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); 
-typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); 
-typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); 
-typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); 
-typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); 
-typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); 
-typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); 
-typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); 
-typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); 
-typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); 
-typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); 
-typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); 
-typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); 
-typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); 
-typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); 
+typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
+typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
 #ifdef OPENGLES_2
 #ifdef OPENGLES_2
 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
 #else
 #else
-typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); 
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
 #endif
 #endif
 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
-typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); 
-typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); 
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
 typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
 typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
 typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
 typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
 typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
 typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
@@ -189,7 +193,7 @@ typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count
 typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
 typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
 typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
 typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
 typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufsize, GLsizei *length, GLenum *binaryFormat, void *binary);
 typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufsize, GLsizei *length, GLenum *binaryFormat, void *binary);
-typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); 
+typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
 typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEPROC) (GLuint texture);
 typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEPROC) (GLuint texture);
 typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEPROC) (GLuint texture, GLuint sampler);
 typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEPROC) (GLuint texture, GLuint sampler);
 typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTPROC) (GLuint64 handle);
 typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTPROC) (GLuint64 handle);
@@ -228,7 +232,7 @@ public:
   virtual int get_driver_version_minor();
   virtual int get_driver_version_minor();
   virtual int get_driver_shader_version_major();
   virtual int get_driver_shader_version_major();
   virtual int get_driver_shader_version_minor();
   virtual int get_driver_shader_version_minor();
-  
+
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
   static void debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam);
   static void debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam);
 #endif
 #endif
@@ -302,13 +306,15 @@ public:
   virtual void begin_occlusion_query();
   virtual void begin_occlusion_query();
   virtual PT(OcclusionQueryContext) end_occlusion_query();
   virtual PT(OcclusionQueryContext) end_occlusion_query();
 
 
+  virtual PT(TimerQueryContext) issue_timer_query(int pstats_index);
+
   virtual void dispatch_compute(int size_x, int size_y, int size_z);
   virtual void dispatch_compute(int size_x, int size_y, int size_z);
 
 
   virtual PT(GeomMunger) make_geom_munger(const RenderState *state,
   virtual PT(GeomMunger) make_geom_munger(const RenderState *state,
                                           Thread *current_thread);
                                           Thread *current_thread);
 
 
   virtual void clear(DrawableRegion *region);
   virtual void clear(DrawableRegion *region);
-  
+
   virtual bool framebuffer_copy_to_texture
   virtual bool framebuffer_copy_to_texture
     (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
     (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb);
   virtual bool framebuffer_copy_to_ram
   virtual bool framebuffer_copy_to_ram
@@ -332,9 +338,9 @@ public:
   void draw_immediate_composite_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode);
   void draw_immediate_composite_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode);
 #endif  // SUPPORT_IMMEDIATE_MODE
 #endif  // SUPPORT_IMMEDIATE_MODE
 
 
-  INLINE static bool report_errors(int line, const char *source_file);
+  INLINE bool report_errors(int line, const char *source_file);
   INLINE void report_my_errors(int line, const char *source_file);
   INLINE void report_my_errors(int line, const char *source_file);
-  INLINE static bool clear_errors(int line, const char *source_file);
+  INLINE bool clear_errors(int line, const char *source_file);
   INLINE void clear_my_errors(int line, const char *source_file);
   INLINE void clear_my_errors(int line, const char *source_file);
 
 
   INLINE const string &get_gl_vendor() const;
   INLINE const string &get_gl_vendor() const;
@@ -475,8 +481,8 @@ protected:
   bool upload_texture(CLP(TextureContext) *gtc, bool force);
   bool upload_texture(CLP(TextureContext) *gtc, bool force);
   bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
   bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
                             bool uses_mipmaps, int mipmap_bias,
                             bool uses_mipmaps, int mipmap_bias,
-                            GLenum texture_target, GLenum page_target, 
-                            GLint internal_format, GLint external_format, 
+                            GLenum texture_target, GLenum page_target,
+                            GLint internal_format, GLint external_format,
                             GLenum component_type,
                             GLenum component_type,
                             bool one_page_only, int z,
                             bool one_page_only, int z,
                             Texture::CompressionMode image_compression);
                             Texture::CompressionMode image_compression);
@@ -590,9 +596,12 @@ protected:
 public:
 public:
   bool _supports_point_parameters;
   bool _supports_point_parameters;
   PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;
   PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;
-
   bool _supports_point_sprite;
   bool _supports_point_sprite;
 
 
+#ifndef OPENGLES
+  PFNGLPRIMITIVERESTARTINDEXPROC _glPrimitiveRestartIndex;
+#endif
+
   bool _supports_vertex_blend;
   bool _supports_vertex_blend;
   PFNGLWEIGHTPOINTERARBPROC _glWeightPointer;
   PFNGLWEIGHTPOINTERARBPROC _glWeightPointer;
   PFNGLVERTEXBLENDARBPROC _glVertexBlend;
   PFNGLVERTEXBLENDARBPROC _glVertexBlend;
@@ -703,6 +712,14 @@ public:
   PFNGLGETQUERYIVPROC _glGetQueryiv;
   PFNGLGETQUERYIVPROC _glGetQueryiv;
   PFNGLGETQUERYOBJECTUIVPROC _glGetQueryObjectuiv;
   PFNGLGETQUERYOBJECTUIVPROC _glGetQueryObjectuiv;
 
 
+#ifndef OPENGLES
+  PFNGLQUERYCOUNTERPROC _glQueryCounter;
+  PFNGLGETQUERYOBJECTI64VPROC _glGetQueryObjecti64v;
+  PFNGLGETQUERYOBJECTUI64VPROC _glGetQueryObjectui64v;
+
+  PFNGLGETINTEGER64VPROC _glGetInteger64v;
+#endif
+
   PFNGLACTIVESTENCILFACEEXTPROC _glActiveStencilFaceEXT;
   PFNGLACTIVESTENCILFACEEXTPROC _glActiveStencilFaceEXT;
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
@@ -778,9 +795,9 @@ public:
 #endif
 #endif
 
 
   LightMutex _lock;
   LightMutex _lock;
-  typedef pvector<GLuint> DeletedDisplayLists;
-  DeletedDisplayLists _deleted_display_lists;
-  DeletedDisplayLists _deleted_queries;
+  typedef pvector<GLuint> DeletedNames;
+  DeletedNames _deleted_display_lists;
+  DeletedNames _deleted_queries;
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
   // Stores textures for which memory bariers should be issued.
   // Stores textures for which memory bariers should be issued.
@@ -797,6 +814,9 @@ public:
   bool _force_flush;
   bool _force_flush;
   bool _supports_debug;
   bool _supports_debug;
 
 
+  bool _use_object_labels;
+  PFNGLOBJECTLABELPROC _glObjectLabel;
+
 #ifndef NDEBUG
 #ifndef NDEBUG
   bool _show_texture_usage;
   bool _show_texture_usage;
   int _show_texture_usage_max_size;
   int _show_texture_usage_max_size;
@@ -818,7 +838,11 @@ public:
   static PStatCollector _primitive_batches_display_list_pcollector;
   static PStatCollector _primitive_batches_display_list_pcollector;
   static PStatCollector _vertices_display_list_pcollector;
   static PStatCollector _vertices_display_list_pcollector;
   static PStatCollector _vertices_immediate_pcollector;
   static PStatCollector _vertices_immediate_pcollector;
-  static PStatCollector _compute_dispatch_pcollector;
+  static PStatCollector _memory_barrier_pcollector;
+  static PStatCollector _vertex_array_update_pcollector;
+  static PStatCollector _texture_update_pcollector;
+  static PStatCollector _fbo_bind_pcollector;
+  static PStatCollector _check_error_pcollector;
 
 
 public:
 public:
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {
@@ -846,6 +870,7 @@ private:
   friend class CLP(CgShaderContext);
   friend class CLP(CgShaderContext);
   friend class CLP(GraphicsBuffer);
   friend class CLP(GraphicsBuffer);
   friend class CLP(OcclusionQueryContext);
   friend class CLP(OcclusionQueryContext);
+  friend class CLP(TimerQueryContext);
 };
 };
 
 
 #include "glGraphicsStateGuardian_src.I"
 #include "glGraphicsStateGuardian_src.I"

+ 14 - 0
panda/src/glstuff/glLatencyQueryContext_src.I

@@ -0,0 +1,14 @@
+// Filename: glLatencyQueryContext_src.I
+// Created by:  rdb (24Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+

+ 54 - 0
panda/src/glstuff/glLatencyQueryContext_src.cxx

@@ -0,0 +1,54 @@
+// Filename: glLatencyQueryContext_src.cxx
+// Created by:  rdb (24Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef OPENGLES  // Timer queries not supported by OpenGL ES.
+
+TypeHandle CLP(LatencyQueryContext)::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(LatencyQueryContext)::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CLP(LatencyQueryContext)::
+CLP(LatencyQueryContext)(CLP(GraphicsStateGuardian) *glgsg,
+                         int pstats_index) :
+  CLP(TimerQueryContext)(glgsg, pstats_index),
+  _timestamp(0)
+{
+  glgsg->_glGetInteger64v(GL_TIMESTAMP, &_timestamp);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LatencyQueryContext::get_timestamp
+//       Access: Public, Virtual
+//  Description: Returns the timestamp that is the result of this
+//               timer query.  There's no guarantee about which
+//               clock this uses, the only guarantee is that
+//               subtracting a start time from an end time should
+//               yield a time in seconds.
+//               If is_answer_ready() did not return true, this
+//               function may block before it returns.
+//
+//               It is only valid to call this from the draw thread.
+////////////////////////////////////////////////////////////////////
+double CLP(LatencyQueryContext)::
+get_timestamp() const {
+  GLint64 time_ns;
+  _glgsg->_glGetQueryObjecti64v(_index, GL_QUERY_RESULT, &time_ns);
+
+  return (time_ns - _timestamp) * 0.000000001;
+}
+
+#endif  // OPENGLES

+ 57 - 0
panda/src/glstuff/glLatencyQueryContext_src.h

@@ -0,0 +1,57 @@
+// Filename: glLatencyQueryContext_src.h
+// Created by:  rdb (24Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+class GraphicsStateGuardian;
+
+#ifndef OPENGLES  // Timer queries not supported by OpenGL ES.
+
+////////////////////////////////////////////////////////////////////
+//       Class : GLLatencyQueryContext
+// Description : This is a special variant of GLTimerQueryContext
+//               that measures the command latency, ie. the time
+//               it takes for the GPU to actually get to the commands
+//               we are issuing right now.
+////////////////////////////////////////////////////////////////////
+class EXPCL_GL CLP(LatencyQueryContext) : public CLP(TimerQueryContext) {
+public:
+  CLP(LatencyQueryContext)(CLP(GraphicsStateGuardian) *glgsg, int pstats_index);
+
+  ALLOC_DELETED_CHAIN(CLP(LatencyQueryContext));
+
+  virtual double get_timestamp() const;
+
+  GLint64 _timestamp;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    CLP(TimerQueryContext)::init_type();
+    register_type(_type_handle, CLASSPREFIX_QUOTED "LatencyQueryContext",
+                  CLP(TimerQueryContext)::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "glLatencyQueryContext_src.I"
+
+#endif  // OPENGLES
+

+ 28 - 19
panda/src/glstuff/glShaderContext_src.cxx

@@ -16,7 +16,7 @@
 
 
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
 
 
-#include "pStatTimer.h"
+#include "pStatGPUTimer.h"
 
 
 TypeHandle CLP(ShaderContext)::_type_handle;
 TypeHandle CLP(ShaderContext)::_type_handle;
 
 
@@ -35,19 +35,19 @@ TypeHandle CLP(ShaderContext)::_type_handle;
 //       Access: Public
 //       Access: Public
 //  Description: The Panda CG shader syntax defines a useful set of shorthand notations for setting nodepath
 //  Description: The Panda CG shader syntax defines a useful set of shorthand notations for setting nodepath
 //               properties as shaderinputs. For example, float4 mspos_XXX refers to nodepath XXX's position
 //               properties as shaderinputs. For example, float4 mspos_XXX refers to nodepath XXX's position
-//               in model space. This function is a rough attempt to reimplement some of the shorthand 
+//               in model space. This function is a rough attempt to reimplement some of the shorthand
 //               notations for GLSL. The code is ~99% composed of excerpts dealing with matrix shaderinputs
 //               notations for GLSL. The code is ~99% composed of excerpts dealing with matrix shaderinputs
-//               from Shader::compile_parameter.  
-//               
-//               Given a uniform variable name queried from the compiled shader passed in via arg_id, 
+//               from Shader::compile_parameter.
+//
+//               Given a uniform variable name queried from the compiled shader passed in via arg_id,
 //                  1) parse the name
 //                  1) parse the name
 //                  2a) if the name refers to a Panda shorthand notation
 //                  2a) if the name refers to a Panda shorthand notation
 //                        push the appropriate matrix into shader._mat_spec
 //                        push the appropriate matrix into shader._mat_spec
 //                        returns True
 //                        returns True
 //                  2b) If the name doesn't refer to a Panda shorthand notation
 //                  2b) If the name doesn't refer to a Panda shorthand notation
 //                        returns False
 //                        returns False
-//               
-//               The boolean return is used to notify down-river processing whether the shader var/parm was 
+//
+//               The boolean return is used to notify down-river processing whether the shader var/parm was
 //               actually picked up and the appropriate ShaderMatSpec pushed onto _mat_spec.
 //               actually picked up and the appropriate ShaderMatSpec pushed onto _mat_spec.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CLP(ShaderContext)::
 bool CLP(ShaderContext)::
@@ -700,7 +700,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
         }
         }
       }
       }
     }
     }
-    
+
     // Now we've processed the uniforms, we'll process the attribs.
     // Now we've processed the uniforms, we'll process the attribs.
     _glgsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_ATTRIBUTES, &param_count);
     _glgsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_ATTRIBUTES, &param_count);
     _glgsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &param_maxlength);
     _glgsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &param_maxlength);
@@ -836,7 +836,7 @@ release_resources() {
   }
   }
 
 
   _glsl_shaders.clear();
   _glsl_shaders.clear();
-  
+
   _glgsg->report_my_gl_errors();
   _glgsg->report_my_gl_errors();
 }
 }
 
 
@@ -890,7 +890,7 @@ unbind() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(ShaderContext)::
 void CLP(ShaderContext)::
 issue_parameters(int altered) {
 issue_parameters(int altered) {
-  PStatTimer timer(_glgsg->_draw_set_state_shader_parameters_pcollector);
+  //PStatGPUTimer timer(_glgsg, _glgsg->_draw_set_state_shader_parameters_pcollector);
 
 
   if (!valid()) {
   if (!valid()) {
     return;
     return;
@@ -1374,12 +1374,11 @@ glsl_report_shader_errors(GLuint shader) {
   _glgsg->_glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
   _glgsg->_glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
 
 
   if (length > 1) {
   if (length > 1) {
-    info_log = (char *) malloc(length);
+    info_log = (char *) alloca(length);
     _glgsg->_glGetShaderInfoLog(shader, length, &num_chars, info_log);
     _glgsg->_glGetShaderInfoLog(shader, length, &num_chars, info_log);
     if (strcmp(info_log, "Success.\n") != 0 && strcmp(info_log, "No errors.\n") != 0) {
     if (strcmp(info_log, "Success.\n") != 0 && strcmp(info_log, "No errors.\n") != 0) {
       GLCAT.error(false) << info_log << "\n";
       GLCAT.error(false) << info_log << "\n";
     }
     }
-    free(info_log);
   }
   }
 }
 }
 
 
@@ -1397,19 +1396,18 @@ glsl_report_program_errors(GLuint program) {
   _glgsg->_glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
   _glgsg->_glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
 
 
   if (length > 1) {
   if (length > 1) {
-    info_log = (char *) malloc(length);
+    info_log = (char *) alloca(length);
     _glgsg->_glGetProgramInfoLog(program, length, &num_chars, info_log);
     _glgsg->_glGetProgramInfoLog(program, length, &num_chars, info_log);
     if (strcmp(info_log, "Success.\n") != 0 && strcmp(info_log, "No errors.\n") != 0) {
     if (strcmp(info_log, "Success.\n") != 0 && strcmp(info_log, "No errors.\n") != 0) {
       GLCAT.error(false) << info_log << "\n";
       GLCAT.error(false) << info_log << "\n";
     }
     }
-    free(info_log);
   }
   }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::glsl_compile_shader
 //     Function: Shader::glsl_compile_shader
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool CLP(ShaderContext)::
 bool CLP(ShaderContext)::
 glsl_compile_shader(Shader::ShaderType type) {
 glsl_compile_shader(Shader::ShaderType type) {
@@ -1451,16 +1449,21 @@ glsl_compile_shader(Shader::ShaderType type) {
     return false;
     return false;
   }
   }
 
 
+  if (_glgsg->_use_object_labels) {
+    string name = _shader->get_filename(type);
+    _glgsg->_glObjectLabel(GL_SHADER, handle, name.size(), name.data());
+  }
+
   string text_str = _shader->get_text(type);
   string text_str = _shader->get_text(type);
   const char* text = text_str.c_str();
   const char* text = text_str.c_str();
   _glgsg->_glShaderSource(handle, 1, &text, NULL);
   _glgsg->_glShaderSource(handle, 1, &text, NULL);
   _glgsg->_glCompileShader(handle);
   _glgsg->_glCompileShader(handle);
   GLint status;
   GLint status;
   _glgsg->_glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
   _glgsg->_glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
-  
+
   if (status != GL_TRUE) {
   if (status != GL_TRUE) {
-    GLCAT.error() 
-      << "An error occurred while compiling shader " 
+    GLCAT.error()
+      << "An error occurred while compiling shader "
       << _shader->get_filename(type) << "\n";
       << _shader->get_filename(type) << "\n";
     glsl_report_shader_errors(handle);
     glsl_report_shader_errors(handle);
     _glgsg->_glDeleteShader(handle);
     _glgsg->_glDeleteShader(handle);
@@ -1485,6 +1488,12 @@ glsl_compile_and_link() {
   if (!_glsl_program) {
   if (!_glsl_program) {
     return false;
     return false;
   }
   }
+
+  if (_glgsg->_use_object_labels) {
+    string name = _shader->get_filename();
+    _glgsg->_glObjectLabel(GL_PROGRAM, _glsl_program, name.size(), name.data());
+  }
+
   bool valid = true;
   bool valid = true;
 
 
   if (!_shader->get_text(Shader::ST_vertex).empty()) {
   if (!_shader->get_text(Shader::ST_vertex).empty()) {
@@ -1507,7 +1516,7 @@ glsl_compile_and_link() {
     nassertr(_glgsg->_glProgramParameteri != NULL, false);
     nassertr(_glgsg->_glProgramParameteri != NULL, false);
     GLint max_vertices;
     GLint max_vertices;
     glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &max_vertices);
     glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &max_vertices);
-    _glgsg->_glProgramParameteri(_glsl_program, GL_GEOMETRY_VERTICES_OUT_ARB, max_vertices); 
+    _glgsg->_glProgramParameteri(_glsl_program, GL_GEOMETRY_VERTICES_OUT_ARB, max_vertices);
   }
   }
 #endif
 #endif
 
 

+ 10 - 1
panda/src/glstuff/glTextureContext_src.cxx

@@ -23,12 +23,14 @@ TypeHandle CLP(TextureContext)::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CLP(TextureContext)::
 CLP(TextureContext)::
 ~CLP(TextureContext)() {
 ~CLP(TextureContext)() {
+#ifndef OPENGLES
   if (gl_enable_memory_barriers) {
   if (gl_enable_memory_barriers) {
     _glgsg->_textures_needing_fetch_barrier.erase(this);
     _glgsg->_textures_needing_fetch_barrier.erase(this);
     _glgsg->_textures_needing_image_access_barrier.erase(this);
     _glgsg->_textures_needing_image_access_barrier.erase(this);
     _glgsg->_textures_needing_update_barrier.erase(this);
     _glgsg->_textures_needing_update_barrier.erase(this);
     _glgsg->_textures_needing_framebuffer_barrier.erase(this);
     _glgsg->_textures_needing_framebuffer_barrier.erase(this);
   }
   }
+#endif
 
 
   glDeleteTextures(1, &_index);
   glDeleteTextures(1, &_index);
   _index = 0;
   _index = 0;
@@ -53,12 +55,15 @@ void CLP(TextureContext)::
 evict_lru() {
 evict_lru() {
   dequeue_lru();
   dequeue_lru();
 
 
+#ifndef OPENGLES
   if (_handle != 0) {
   if (_handle != 0) {
     if (_handle_resident) {
     if (_handle_resident) {
       _glgsg->_glMakeTextureHandleNonResident(_handle);
       _glgsg->_glMakeTextureHandleNonResident(_handle);
     }
     }
     _handle_resident = false;
     _handle_resident = false;
-  } else {
+  } else
+#endif
+  {
     reset_data();
     reset_data();
   }
   }
 
 
@@ -74,9 +79,11 @@ evict_lru() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(TextureContext)::
 void CLP(TextureContext)::
 reset_data() {
 reset_data() {
+#ifndef OPENGLES
   if (_handle != 0 && _handle_resident) {
   if (_handle != 0 && _handle_resident) {
     _glgsg->_glMakeTextureHandleNonResident(_handle);
     _glgsg->_glMakeTextureHandleNonResident(_handle);
   }
   }
+#endif
 
 
   // Free the texture resources.
   // Free the texture resources.
   glDeleteTextures(1, &_index);
   glDeleteTextures(1, &_index);
@@ -108,6 +115,7 @@ reset_data() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(TextureContext)::
 void CLP(TextureContext)::
 make_handle_resident() {
 make_handle_resident() {
+#ifndef OPENGLES
   if (_handle != 0) {
   if (_handle != 0) {
     if (!_handle_resident) {
     if (!_handle_resident) {
       _glgsg->_glMakeTextureHandleResident(_handle);
       _glgsg->_glMakeTextureHandleResident(_handle);
@@ -115,6 +123,7 @@ make_handle_resident() {
     }
     }
     set_resident(true);
     set_resident(true);
   }
   }
+#endif
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 28 - 0
panda/src/glstuff/glTimerQueryContext_src.I

@@ -0,0 +1,28 @@
+// Filename: glTimerQueryContext_src.I
+// Created by:  rdb (22Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(TimerQueryContext)::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE CLP(TimerQueryContext)::
+CLP(TimerQueryContext)(CLP(GraphicsStateGuardian) *glgsg,
+                       int pstats_index) :
+  TimerQueryContext(pstats_index),
+  _glgsg(glgsg),
+  _index(0)
+{
+}

+ 104 - 0
panda/src/glstuff/glTimerQueryContext_src.cxx

@@ -0,0 +1,104 @@
+// Filename: glTimerQueryContext_src.cxx
+// Created by:  rdb (22Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pnotify.h"
+#include "dcast.h"
+#include "lightMutexHolder.h"
+#include "pStatTimer.h"
+
+#ifndef OPENGLES  // Timer queries not supported by OpenGL ES.
+
+TypeHandle CLP(TimerQueryContext)::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLTimerQueryContext::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CLP(TimerQueryContext)::
+~CLP(TimerQueryContext)() {
+  if (_index != 0) {
+    // Tell the GSG to recycle this index when it gets around to it.
+    LightMutexHolder holder(_glgsg->_lock);
+    _glgsg->_deleted_queries.push_back(_index);
+    _index = 0;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLTimerQueryContext::is_answer_ready
+//       Access: Public, Virtual
+//  Description: Returns true if the query's answer is ready, false
+//               otherwise.  If this returns false, the application
+//               must continue to poll until it returns true.
+//
+//               It is only valid to call this from the draw thread.
+////////////////////////////////////////////////////////////////////
+bool CLP(TimerQueryContext)::
+is_answer_ready() const {
+  GLuint result;
+  _glgsg->_glGetQueryObjectuiv(_index, GL_QUERY_RESULT_AVAILABLE, &result);
+
+  return (result != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GLTimerQueryContext::waiting_for_answer
+//       Access: Public, Virtual
+//  Description: Requests the graphics engine to expedite the pending
+//               answer--the application is now waiting until the
+//               answer is ready.
+//
+//               It is only valid to call this from the draw thread.
+////////////////////////////////////////////////////////////////////
+void CLP(TimerQueryContext)::
+waiting_for_answer() {
+  PStatTimer timer(GraphicsStateGuardian::_wait_timer_pcollector);
+  glFlush();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TimerQueryContext::get_timestamp
+//       Access: Public, Virtual
+//  Description: Returns the timestamp that is the result of this
+//               timer query.  There's no guarantee about which
+//               clock this uses, the only guarantee is that
+//               subtracting a start time from an end time should
+//               yield a time in seconds.
+//               If is_answer_ready() did not return true, this
+//               function may block before it returns.
+//
+//               It is only valid to call this from the draw thread.
+////////////////////////////////////////////////////////////////////
+double CLP(TimerQueryContext)::
+get_timestamp() const {
+  GLuint64 time_ns;
+
+  /*GLuint available;
+  _glgsg->_glGetQueryObjectuiv(_index[1], GL_QUERY_RESULT_AVAILABLE, &available);
+  if (available) {
+    // The answer is ready now.
+    do_get_timestamps(begin_ns, end_ns);
+  } else {
+    // The answer is not ready; this call will block.
+    PStatTimer timer(GraphicsStateGuardian::_wait_timer_pcollector);
+    do_get_timestamps(begin_ns, end_ns);
+  }*/
+
+  _glgsg->_glGetQueryObjectui64v(_index, GL_QUERY_RESULT, &time_ns);
+
+  return time_ns * 0.000000001;
+}
+
+#endif  // OPENGLES

+ 68 - 0
panda/src/glstuff/glTimerQueryContext_src.h

@@ -0,0 +1,68 @@
+// Filename: glTimerQueryContext_src.h
+// Created by:  rdb (22Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandabase.h"
+#include "timerQueryContext.h"
+#include "deletedChain.h"
+#include "clockObject.h"
+
+class GraphicsStateGuardian;
+
+#ifndef OPENGLES  // Timer queries not supported by OpenGL ES.
+
+////////////////////////////////////////////////////////////////////
+//       Class : GLTimerQueryContext
+// Description : This class manages a timer query that can be used
+//               by a PStatGPUTimer to measure the time a task takes
+//               to execute on the GPU.
+//               This records the current timestamp; a pair of these
+//               is usually used to get the elapsed time.
+////////////////////////////////////////////////////////////////////
+class EXPCL_GL CLP(TimerQueryContext) : public TimerQueryContext {
+public:
+  INLINE CLP(TimerQueryContext)(CLP(GraphicsStateGuardian) *glgsg,
+                                int pstats_index);
+  virtual ~CLP(TimerQueryContext)();
+
+  ALLOC_DELETED_CHAIN(CLP(TimerQueryContext));
+
+  virtual bool is_answer_ready() const;
+  virtual void waiting_for_answer();
+  virtual double get_timestamp() const;
+
+  GLuint _index;
+  CLP(GraphicsStateGuardian) *_glgsg;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TimerQueryContext::init_type();
+    register_type(_type_handle, CLASSPREFIX_QUOTED "TimerQueryContext",
+                  TimerQueryContext::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "glTimerQueryContext_src.I"
+
+#endif  // OPENGLES
+

+ 11 - 1
panda/src/glstuff/glmisc_src.cxx

@@ -151,6 +151,13 @@ ConfigVariableEnum<NotifySeverity> gl_debug_abort_level
             "that triggered the error message.  "
             "that triggered the error message.  "
             "This feature is not available when NDEBUG has been defined."));
             "This feature is not available when NDEBUG has been defined."));
 
 
+ConfigVariableBool gl_debug_object_labels
+  ("gl-debug-object-labels", true,
+   PRC_DESC("When gl-debug is set to true, this will tell OpenGL the "
+            "name of textures, shaders, and other objects, so that OpenGL "
+            "can display those in error messages.  There's usually no "
+            "reason to disable this."));
+
 ConfigVariableBool gl_debug_buffers
 ConfigVariableBool gl_debug_buffers
   ("gl-debug-buffers", false,
   ("gl-debug-buffers", false,
    PRC_DESC("Set this true, in addition to enabling debug notify for "
    PRC_DESC("Set this true, in addition to enabling debug notify for "
@@ -162,7 +169,8 @@ ConfigVariableBool gl_finish
    PRC_DESC("Set this true to force a call to glFinish() after every major "
    PRC_DESC("Set this true to force a call to glFinish() after every major "
             "graphics operation.  This is likely to slow down rendering "
             "graphics operation.  This is likely to slow down rendering "
             "performance substantially, but it will make PStats graphs "
             "performance substantially, but it will make PStats graphs "
-            "more accurately reflect where the graphics bottlenecks are.  "
+            "more accurately reflect where the graphics bottlenecks are, "
+            "although it is better to use timer queries when available. "
             "This variable is enabled only if PStats is compiled in."));
             "This variable is enabled only if PStats is compiled in."));
 
 
 ConfigVariableBool gl_force_depth_stencil
 ConfigVariableBool gl_force_depth_stencil
@@ -252,6 +260,8 @@ void CLP(init_classes)() {
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
   CLP(OcclusionQueryContext)::init_type();
   CLP(OcclusionQueryContext)::init_type();
+  CLP(TimerQueryContext)::init_type();
+  CLP(LatencyQueryContext)::init_type();
 #endif
 #endif
 
 
   PandaSystem *ps = PandaSystem::get_global_ptr();
   PandaSystem *ps = PandaSystem::get_global_ptr();

+ 1 - 0
panda/src/glstuff/glmisc_src.h

@@ -58,6 +58,7 @@ extern ConfigVariableEnum<GeomEnums::UsageHint> gl_min_buffer_usage_hint;
 extern ConfigVariableBool gl_debug;
 extern ConfigVariableBool gl_debug;
 extern ConfigVariableBool gl_debug_synchronous;
 extern ConfigVariableBool gl_debug_synchronous;
 extern ConfigVariableEnum<NotifySeverity> gl_debug_abort_level;
 extern ConfigVariableEnum<NotifySeverity> gl_debug_abort_level;
+extern ConfigVariableBool gl_debug_object_labels;
 extern ConfigVariableBool gl_debug_buffers;
 extern ConfigVariableBool gl_debug_buffers;
 extern ConfigVariableBool gl_finish;
 extern ConfigVariableBool gl_finish;
 extern ConfigVariableBool gl_force_depth_stencil;
 extern ConfigVariableBool gl_force_depth_stencil;

+ 2 - 0
panda/src/glstuff/glstuff_src.cxx

@@ -22,6 +22,8 @@
 #include "glVertexBufferContext_src.cxx"
 #include "glVertexBufferContext_src.cxx"
 #include "glIndexBufferContext_src.cxx"
 #include "glIndexBufferContext_src.cxx"
 #include "glOcclusionQueryContext_src.cxx"
 #include "glOcclusionQueryContext_src.cxx"
+#include "glTimerQueryContext_src.cxx"
+#include "glLatencyQueryContext_src.cxx"
 #include "glGeomContext_src.cxx"
 #include "glGeomContext_src.cxx"
 #include "glGeomMunger_src.cxx"
 #include "glGeomMunger_src.cxx"
 #include "glShaderContext_src.cxx"
 #include "glShaderContext_src.cxx"

+ 2 - 0
panda/src/glstuff/glstuff_src.h

@@ -36,6 +36,8 @@
 #include "glVertexBufferContext_src.h"
 #include "glVertexBufferContext_src.h"
 #include "glIndexBufferContext_src.h"
 #include "glIndexBufferContext_src.h"
 #include "glOcclusionQueryContext_src.h"
 #include "glOcclusionQueryContext_src.h"
+#include "glTimerQueryContext_src.h"
+#include "glLatencyQueryContext_src.h"
 #include "glGeomContext_src.h"
 #include "glGeomContext_src.h"
 #include "glGeomMunger_src.h"
 #include "glGeomMunger_src.h"
 #include "glShaderContext_src.h"
 #include "glShaderContext_src.h"

+ 8 - 3
panda/src/glstuff/panda_glext.h

@@ -6,7 +6,7 @@ extern "C" {
 
 
 /*
 /*
 ** Copyright (c) 2007-2012 The Khronos Group Inc.
 ** Copyright (c) 2007-2012 The Khronos Group Inc.
-** 
+**
 ** Permission is hereby granted, free of charge, to any person obtaining a
 ** Permission is hereby granted, free of charge, to any person obtaining a
 ** copy of this software and/or associated documentation files (the
 ** copy of this software and/or associated documentation files (the
 ** "Materials"), to deal in the Materials without restriction, including
 ** "Materials"), to deal in the Materials without restriction, including
@@ -14,10 +14,10 @@ extern "C" {
 ** distribute, sublicense, and/or sell copies of the Materials, and to
 ** distribute, sublicense, and/or sell copies of the Materials, and to
 ** permit persons to whom the Materials are furnished to do so, subject to
 ** permit persons to whom the Materials are furnished to do so, subject to
 ** the following conditions:
 ** the following conditions:
-** 
+**
 ** The above copyright notice and this permission notice shall be included
 ** The above copyright notice and this permission notice shall be included
 ** in all copies or substantial portions of the Materials.
 ** in all copies or substantial portions of the Materials.
-** 
+**
 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -1163,6 +1163,11 @@ extern "C" {
 /* reuse GL_TEXTURE_IMMUTABLE_FORMAT */
 /* reuse GL_TEXTURE_IMMUTABLE_FORMAT */
 #endif
 #endif
 
 
+#ifndef GL_VERSION_4_3
+#define GL_VERSION_4_3 1
+#define GL_PRIMITIVE_RESTART_FIXED_INDEX  0x8D69
+#endif
+
 #ifndef GL_ARB_multitexture
 #ifndef GL_ARB_multitexture
 #define GL_TEXTURE0_ARB                   0x84C0
 #define GL_TEXTURE0_ARB                   0x84C0
 #define GL_TEXTURE1_ARB                   0x84C1
 #define GL_TEXTURE1_ARB                   0x84C1

+ 4 - 0
panda/src/gobj/Sources.pp

@@ -43,6 +43,7 @@
     geomVertexWriter.h geomVertexWriter.I \
     geomVertexWriter.h geomVertexWriter.I \
     indexBufferContext.I indexBufferContext.h \
     indexBufferContext.I indexBufferContext.h \
     internalName.I internalName.h \
     internalName.I internalName.h \
+    internalName_ext.h internalName_ext.cxx \
     lens.h lens.I \
     lens.h lens.I \
     material.I material.h materialPool.I materialPool.h  \
     material.I material.h materialPool.I materialPool.h  \
     matrixLens.I matrixLens.h \
     matrixLens.I matrixLens.h \
@@ -66,6 +67,7 @@
     textureReloadRequest.I textureReloadRequest.h \
     textureReloadRequest.I textureReloadRequest.h \
     textureStage.I textureStage.h \
     textureStage.I textureStage.h \
     textureStagePool.I textureStagePool.h \
     textureStagePool.I textureStagePool.h \
+    timerQueryContext.I timerQueryContext.h \
     transformBlend.I transformBlend.h \
     transformBlend.I transformBlend.h \
     transformBlendTable.I transformBlendTable.h \
     transformBlendTable.I transformBlendTable.h \
     transformTable.I transformTable.h \
     transformTable.I transformTable.h \
@@ -136,6 +138,7 @@
     textureReloadRequest.cxx \
     textureReloadRequest.cxx \
     textureStage.cxx \
     textureStage.cxx \
     textureStagePool.cxx \
     textureStagePool.cxx \
+    timerQueryContext.cxx \
     transformBlend.cxx \
     transformBlend.cxx \
     transformBlendTable.cxx \
     transformBlendTable.cxx \
     transformTable.cxx \
     transformTable.cxx \
@@ -208,6 +211,7 @@
     textureReloadRequest.I textureReloadRequest.h \
     textureReloadRequest.I textureReloadRequest.h \
     textureStage.I textureStage.h \
     textureStage.I textureStage.h \
     textureStagePool.I textureStagePool.h \
     textureStagePool.I textureStagePool.h \
+    timerQueryContext.I timerQueryContext.h \
     transformBlend.I transformBlend.h \
     transformBlend.I transformBlend.h \
     transformBlendTable.I transformBlendTable.h \
     transformBlendTable.I transformBlendTable.h \
     transformTable.I transformTable.h \
     transformTable.I transformTable.h \

+ 5 - 3
panda/src/gobj/config_gobj.cxx

@@ -44,6 +44,7 @@
 #include "textureReloadRequest.h"
 #include "textureReloadRequest.h"
 #include "textureStage.h"
 #include "textureStage.h"
 #include "textureContext.h"
 #include "textureContext.h"
+#include "timerQueryContext.h"
 #include "shader.h"
 #include "shader.h"
 #include "shaderContext.h"
 #include "shaderContext.h"
 #include "transformBlend.h"
 #include "transformBlend.h"
@@ -92,7 +93,7 @@ ConfigVariableInt texture_scale_limit
           "to both X and Y."));
           "to both X and Y."));
 
 
 ConfigVariableList exclude_texture_scale
 ConfigVariableList exclude_texture_scale
-("exclude-texture-scale", 
+("exclude-texture-scale",
  PRC_DESC("This is a list of glob patterns for texture filenames "
  PRC_DESC("This is a list of glob patterns for texture filenames "
           "(excluding the directory part of the filename, but including "
           "(excluding the directory part of the filename, but including "
           "the extension); for instance, 'digits_*.png'.  Any texture "
           "the extension); for instance, 'digits_*.png'.  Any texture "
@@ -287,7 +288,7 @@ ConfigVariableInt vertex_column_alignment
           "this alignment for the vertex animation columns only."));
           "this alignment for the vertex animation columns only."));
 
 
 ConfigVariableBool vertex_animation_align_16
 ConfigVariableBool vertex_animation_align_16
-("vertex-animation-align-16", 
+("vertex-animation-align-16",
 #ifdef LINMATH_ALIGN
 #ifdef LINMATH_ALIGN
  true,
  true,
 #else
 #else
@@ -343,7 +344,7 @@ ConfigVariableInt simple_image_size
 
 
 ConfigVariableDouble simple_image_threshold
 ConfigVariableDouble simple_image_threshold
 ("simple-image-threshold", 0.1,
 ("simple-image-threshold", 0.1,
- PRC_DESC("This is a value that indicates how closely a texture's " 
+ PRC_DESC("This is a value that indicates how closely a texture's "
           "generated simple "
           "generated simple "
           "image should approximate the original image.  The smaller the "
           "image should approximate the original image.  The smaller the "
           "number, the closer the match; small numbers will result in "
           "number, the closer the match; small numbers will result in "
@@ -568,6 +569,7 @@ ConfigureFn(config_gobj) {
   TexturePoolFilter::init_type();
   TexturePoolFilter::init_type();
   TextureReloadRequest::init_type();
   TextureReloadRequest::init_type();
   TextureStage::init_type();
   TextureStage::init_type();
+  TimerQueryContext::init_type();
   TransformBlend::init_type();
   TransformBlend::init_type();
   TransformBlendTable::init_type();
   TransformBlendTable::init_type();
   TransformTable::init_type();
   TransformTable::init_type();

+ 3 - 1
panda/src/gobj/geomEnums.h

@@ -125,6 +125,9 @@ PUBLISHED:
     // The union of all of the above composite types.
     // The union of all of the above composite types.
     GR_composite_bits       = 0x01c00,
     GR_composite_bits       = 0x01c00,
 
 
+    // If strip-cut indices are used to restart a composite primitive.
+    GR_strip_cut_index      = 0x20000,
+
     // If the shade model requires a particular vertex for flat shading.
     // If the shade model requires a particular vertex for flat shading.
     GR_flat_first_vertex    = 0x02000,
     GR_flat_first_vertex    = 0x02000,
     GR_flat_last_vertex     = 0x04000,
     GR_flat_last_vertex     = 0x04000,
@@ -216,4 +219,3 @@ EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::NumericType nume
 EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::Contents contents);
 EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::Contents contents);
 
 
 #endif
 #endif
-

+ 51 - 2
panda/src/gobj/geomLinestrips.cxx

@@ -89,7 +89,11 @@ get_primitive_type() const {
 int GeomLinestrips::
 int GeomLinestrips::
 get_geom_rendering() const {
 get_geom_rendering() const {
   if (is_indexed()) {
   if (is_indexed()) {
-    return GR_line_strip | GR_indexed_other;
+    if (get_num_primitives() > 1) {
+      return GR_line_strip | GR_indexed_other | GR_strip_cut_index; 
+    } else {
+      return GR_line_strip | GR_indexed_other;
+    }
   } else {
   } else {
     return GR_line_strip;
     return GR_line_strip;
   }
   }
@@ -106,6 +110,20 @@ get_min_num_vertices_per_primitive() const {
   return 2;
   return 2;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomLinestrips::get_num_unused_vertices_per_primitive
+//       Access: Public, Virtual
+//  Description: Returns the number of vertices that are added between
+//               primitives that aren't, strictly speaking, part of
+//               the primitives themselves.  This is used, for
+//               instance, to define degenerate triangles to connect
+//               otherwise disconnected triangle strips.
+////////////////////////////////////////////////////////////////////
+int GeomLinestrips::
+get_num_unused_vertices_per_primitive() const {
+  return 1;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomLinestrips::draw
 //     Function: GeomLinestrips::draw
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -138,9 +156,13 @@ decompose_impl() const {
   lines->set_shade_model(get_shade_model());
   lines->set_shade_model(get_shade_model());
   CPTA_int ends = get_ends();
   CPTA_int ends = get_ends();
 
 
-  int vi = 0;
+  int num_unused = get_num_unused_vertices_per_primitive();
+
+  int vi = -num_unused;
   int li = 0;
   int li = 0;
   while (li < (int)ends.size()) {
   while (li < (int)ends.size()) {
+    // Skip unused vertices between tristrips.
+    vi += num_unused;
     int end = ends[li];
     int end = ends[li];
     nassertr(vi + 1 <= end, lines.p());
     nassertr(vi + 1 <= end, lines.p());
     int v0 = get_vertex(vi);
     int v0 = get_vertex(vi);
@@ -210,6 +232,33 @@ rotate_impl() const {
   return new_vertices;
   return new_vertices;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomLinestrips::requires_unused_vertices
+//       Access: Protected, Virtual
+//  Description: Should be redefined to return true in any primitive
+//               that implements append_unused_vertices().
+////////////////////////////////////////////////////////////////////
+bool GeomLinestrips::
+requires_unused_vertices() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomLinestrips::append_unused_vertices
+//       Access: Protected, Virtual
+//  Description: Called when a new primitive is begun (other than the
+//               first primitive), this should add some degenerate
+//               vertices between primitives, if the primitive type
+//               requires that.  The second parameter is the first
+//               vertex that begins the new primitive.
+////////////////////////////////////////////////////////////////////
+void GeomLinestrips::
+append_unused_vertices(GeomVertexArrayData *vertices, int vertex) {
+  GeomVertexWriter to(vertices, 0);
+  to.set_row_unsafe(vertices->get_num_rows());
+  to.add_data1i(get_strip_cut_index());
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomLinestrips::register_with_read_factory
 //     Function: GeomLinestrips::register_with_read_factory
 //       Access: Public, Static
 //       Access: Public, Static

+ 4 - 0
panda/src/gobj/geomLinestrips.h

@@ -34,6 +34,7 @@ public:
   virtual PrimitiveType get_primitive_type() const;
   virtual PrimitiveType get_primitive_type() const;
   virtual int get_geom_rendering() const;
   virtual int get_geom_rendering() const;
   virtual int get_min_num_vertices_per_primitive() const;
   virtual int get_min_num_vertices_per_primitive() const;
+  virtual int get_num_unused_vertices_per_primitive() const;
 
 
 public:
 public:
   virtual bool draw(GraphicsStateGuardianBase *gsg,
   virtual bool draw(GraphicsStateGuardianBase *gsg,
@@ -43,6 +44,9 @@ public:
 protected:
 protected:
   virtual CPT(GeomPrimitive) decompose_impl() const;
   virtual CPT(GeomPrimitive) decompose_impl() const;
   virtual CPT(GeomVertexArrayData) rotate_impl() const;
   virtual CPT(GeomVertexArrayData) rotate_impl() const;
+  virtual bool requires_unused_vertices() const;
+  virtual void append_unused_vertices(GeomVertexArrayData *vertices, 
+                                      int vertex);
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

+ 52 - 1
panda/src/gobj/geomPrimitive.I

@@ -129,7 +129,7 @@ get_first_vertex() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::get_num_vertices
 //     Function: GeomPrimitive::get_num_vertices
 //       Access: Published
 //       Access: Published
-//  Description: Returns the number of vertices used by all the
+//  Description: Returns the number of indices used by all the
 //               primitives in this object.
 //               primitives in this object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int GeomPrimitive::
 INLINE int GeomPrimitive::
@@ -310,6 +310,20 @@ get_index_stride() const {
   return reader.get_index_stride();
   return reader.get_index_stride();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitive::get_strip_cut_index
+//       Access: Published
+//  Description: If relevant, returns the index value that may be
+//               used in some cases to signify the end of a
+//               primitive.  This is typically the highest value
+//               that the numeric type can store.
+////////////////////////////////////////////////////////////////////
+INLINE int GeomPrimitive::
+get_strip_cut_index() const {
+  CDReader cdata(_cycler);
+  return get_strip_cut_index(cdata->_index_type);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::get_ends
 //     Function: GeomPrimitive::get_ends
 //       Access: Published
 //       Access: Published
@@ -415,6 +429,17 @@ add_vertices(int v1, int v2, int v3, int v4) {
   add_vertex(v4);
   add_vertex(v4);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitive::get_index_format
+//       Access: Public
+//  Description: Returns a registered format appropriate for using to
+//               store the index table.
+////////////////////////////////////////////////////////////////////
+INLINE const GeomVertexArrayFormat *GeomPrimitive::
+get_index_format() const {
+  return get_index_format(get_index_type());
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::make_index_data
 //     Function: GeomPrimitive::make_index_data
 //       Access: Public
 //       Access: Public
@@ -425,6 +450,22 @@ make_index_data() const {
   return new GeomVertexArrayData(get_index_format(), get_usage_hint());
   return new GeomVertexArrayData(get_index_format(), get_usage_hint());
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitive::make_index_format
+//       Access: Private, Static
+//  Description: Returns a registered format appropriate for using to
+//               store the index table.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(GeomVertexArrayFormat) GeomPrimitive::
+make_index_format(NumericType index_type) {
+  PT(GeomVertexArrayFormat) format = new GeomVertexArrayFormat;
+  // It's important that the index format *not* respect the global
+  // setting of vertex-column-alignment.  It needs to be tightly
+  // packed, so we specify an explict column_alignment of 1.
+  format->add_column(InternalName::get_index(), 1, index_type, C_index, 0, 1);
+  return GeomVertexArrayFormat::register_format(format);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::CData::Constructor
 //     Function: GeomPrimitive::CData::Constructor
 //       Access: Public
 //       Access: Public
@@ -679,6 +720,16 @@ get_read_pointer(bool force) const {
   return _vertices_reader->get_read_pointer(force);
   return _vertices_reader->get_read_pointer(force);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitivePipelineReader::get_strip_cut_index
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE int GeomPrimitivePipelineReader::
+get_strip_cut_index() const {
+  return GeomPrimitive::get_strip_cut_index(_cdata->_index_type);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitivePipelineReader::get_ends
 //     Function: GeomPrimitivePipelineReader::get_ends
 //       Access: Public
 //       Access: Public

+ 209 - 75
panda/src/gobj/geomPrimitive.cxx

@@ -62,18 +62,18 @@ make_cow_copy() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::Constructor
 //     Function: GeomPrimitive::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomPrimitive::
 GeomPrimitive::
 GeomPrimitive(GeomPrimitive::UsageHint usage_hint) {
 GeomPrimitive(GeomPrimitive::UsageHint usage_hint) {
   CDWriter cdata(_cycler, true);
   CDWriter cdata(_cycler, true);
   cdata->_usage_hint = usage_hint;
   cdata->_usage_hint = usage_hint;
 }
 }
- 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::Copy Constructor
 //     Function: GeomPrimitive::Copy Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomPrimitive::
 GeomPrimitive::
 GeomPrimitive(const GeomPrimitive &copy) :
 GeomPrimitive(const GeomPrimitive &copy) :
@@ -81,7 +81,7 @@ GeomPrimitive(const GeomPrimitive &copy) :
   _cycler(copy._cycler)
   _cycler(copy._cycler)
 {
 {
 }
 }
-  
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::Copy Assignment Operator
 //     Function: GeomPrimitive::Copy Assignment Operator
 //       Access: Published
 //       Access: Published
@@ -99,7 +99,7 @@ operator = (const GeomPrimitive &copy) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::Destructor
 //     Function: GeomPrimitive::Destructor
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomPrimitive::
 GeomPrimitive::
 ~GeomPrimitive() {
 ~GeomPrimitive() {
@@ -198,7 +198,7 @@ add_vertex(int vertex) {
 
 
   int num_primitives = get_num_primitives();
   int num_primitives = get_num_primitives();
   if (num_primitives > 0 &&
   if (num_primitives > 0 &&
-      requires_unused_vertices() && 
+      requires_unused_vertices() &&
       get_num_vertices() == get_primitive_end(num_primitives - 1)) {
       get_num_vertices() == get_primitive_end(num_primitives - 1)) {
     // If we are beginning a new primitive, give the derived class a
     // If we are beginning a new primitive, give the derived class a
     // chance to insert some degenerate vertices.
     // chance to insert some degenerate vertices.
@@ -225,7 +225,7 @@ add_vertex(int vertex) {
       cdata->_got_minmax = false;
       cdata->_got_minmax = false;
       return;
       return;
     }
     }
-    
+
     // Otherwise, we need to suddenly become an indexed primitive.
     // Otherwise, we need to suddenly become an indexed primitive.
     do_make_indexed(cdata);
     do_make_indexed(cdata);
   }
   }
@@ -289,7 +289,7 @@ add_consecutive_vertices(int start, int num_vertices) {
       cdata->_got_minmax = false;
       cdata->_got_minmax = false;
       return;
       return;
     }
     }
-    
+
     // Otherwise, we need to suddenly become an indexed primitive.
     // Otherwise, we need to suddenly become an indexed primitive.
     do_make_indexed(cdata);
     do_make_indexed(cdata);
   }
   }
@@ -469,12 +469,18 @@ offset_vertices(int offset) {
       recompute_minmax(cdata);
       recompute_minmax(cdata);
       nassertv(cdata->_got_minmax);
       nassertv(cdata->_got_minmax);
     }
     }
-    
+
     consider_elevate_index_type(cdata, cdata->_max_vertex + offset);
     consider_elevate_index_type(cdata, cdata->_max_vertex + offset);
 
 
+    int strip_cut_index = get_strip_cut_index(cdata->_index_type);
+
     GeomVertexRewriter index(do_modify_vertices(cdata), 0);
     GeomVertexRewriter index(do_modify_vertices(cdata), 0);
     while (!index.is_at_end()) {
     while (!index.is_at_end()) {
-      index.set_data1i(index.get_data1i() + offset);
+      int vertex = index.get_data1i();
+
+      if (vertex != strip_cut_index) {
+        index.set_data1i(vertex + offset);
+      }
     }
     }
 
 
   } else {
   } else {
@@ -484,7 +490,7 @@ offset_vertices(int offset) {
     cdata->_modified = Geom::get_next_modified();
     cdata->_modified = Geom::get_next_modified();
     cdata->_got_minmax = false;
     cdata->_got_minmax = false;
 
 
-    consider_elevate_index_type(cdata, 
+    consider_elevate_index_type(cdata,
                                 cdata->_first_vertex + cdata->_num_vertices - 1);
                                 cdata->_first_vertex + cdata->_num_vertices - 1);
   }
   }
 }
 }
@@ -517,14 +523,19 @@ offset_vertices(int offset, int begin_row, int end_row) {
 
 
   if (is_indexed()) {
   if (is_indexed()) {
     CDWriter cdata(_cycler, true);
     CDWriter cdata(_cycler, true);
-    
+
+    int strip_cut_index = get_strip_cut_index(cdata->_index_type);
+
     // Calculate the maximum vertex over our range.
     // Calculate the maximum vertex over our range.
     int max_vertex = 0;
     int max_vertex = 0;
     {
     {
       GeomVertexReader index_r(cdata->_vertices.get_read_pointer(), 0);
       GeomVertexReader index_r(cdata->_vertices.get_read_pointer(), 0);
       index_r.set_row_unsafe(begin_row);
       index_r.set_row_unsafe(begin_row);
       for (int j = begin_row; j < end_row; ++j) {
       for (int j = begin_row; j < end_row; ++j) {
-        max_vertex = max(max_vertex, index_r.get_data1i());
+        int vertex = index_r.get_data1i();
+        if (vertex != strip_cut_index) {
+          max_vertex = max(max_vertex, vertex);
+        }
       }
       }
     }
     }
 
 
@@ -533,7 +544,10 @@ offset_vertices(int offset, int begin_row, int end_row) {
     GeomVertexRewriter index(do_modify_vertices(cdata), 0);
     GeomVertexRewriter index(do_modify_vertices(cdata), 0);
     index.set_row_unsafe(begin_row);
     index.set_row_unsafe(begin_row);
     for (int j = begin_row; j < end_row; ++j) {
     for (int j = begin_row; j < end_row; ++j) {
-      index.set_data1i(index.get_data1i() + offset);
+      int vertex = index.get_data1i();
+      if (vertex != strip_cut_index) {
+        index.set_data1i(vertex + offset);
+      }
     }
     }
 
 
   } else {
   } else {
@@ -545,7 +559,7 @@ offset_vertices(int offset, int begin_row, int end_row) {
     cdata->_modified = Geom::get_next_modified();
     cdata->_modified = Geom::get_next_modified();
     cdata->_got_minmax = false;
     cdata->_got_minmax = false;
 
 
-    consider_elevate_index_type(cdata, 
+    consider_elevate_index_type(cdata,
                                 cdata->_first_vertex + cdata->_num_vertices - 1);
                                 cdata->_first_vertex + cdata->_num_vertices - 1);
   }
   }
 }
 }
@@ -555,17 +569,20 @@ offset_vertices(int offset, int begin_row, int end_row) {
 //       Access: Published
 //       Access: Published
 //  Description: Converts the primitive from indexed to nonindexed by
 //  Description: Converts the primitive from indexed to nonindexed by
 //               duplicating vertices as necessary into the indicated
 //               duplicating vertices as necessary into the indicated
-//               dest GeomVertexData.
+//               dest GeomVertexData.  Note: does not support
+//               primitives with strip cut indices.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 void GeomPrimitive::
 make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
 make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
   Thread *current_thread = Thread::get_current_thread();
   Thread *current_thread = Thread::get_current_thread();
   int num_vertices = get_num_vertices();
   int num_vertices = get_num_vertices();
   int dest_start = dest->get_num_rows();
   int dest_start = dest->get_num_rows();
+  int strip_cut_index = get_strip_cut_index();
 
 
   dest->set_num_rows(dest_start + num_vertices);
   dest->set_num_rows(dest_start + num_vertices);
   for (int i = 0; i < num_vertices; ++i) {
   for (int i = 0; i < num_vertices; ++i) {
     int v = get_vertex(i);
     int v = get_vertex(i);
+    nassertd(v != strip_cut_index) continue;
     dest->copy_row_from(dest_start + i, source, v, current_thread);
     dest->copy_row_from(dest_start + i, source, v, current_thread);
   }
   }
 
 
@@ -597,14 +614,18 @@ pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
 
 
     int num_vertices = get_num_vertices();
     int num_vertices = get_num_vertices();
     int dest_start = dest->get_num_rows();
     int dest_start = dest->get_num_rows();
+    int strip_cut_index = get_strip_cut_index();
 
 
     for (int i = 0; i < num_vertices; ++i) {
     for (int i = 0; i < num_vertices; ++i) {
       int v = get_vertex(i);
       int v = get_vertex(i);
+      if (v == strip_cut_index) {
+        continue;
+      }
 
 
       // Try to add the relation { v : size() }.  If that succeeds,
       // Try to add the relation { v : size() }.  If that succeeds,
       // great; if it doesn't, look up whatever we previously added
       // great; if it doesn't, look up whatever we previously added
       // for v.
       // for v.
-      pair<CopiedIndices::iterator, bool> result = 
+      pair<CopiedIndices::iterator, bool> result =
         copied_indices.insert(CopiedIndices::value_type(v, (int)copied_indices.size()));
         copied_indices.insert(CopiedIndices::value_type(v, (int)copied_indices.size()));
       int v2 = (*result.first).second + dest_start;
       int v2 = (*result.first).second + dest_start;
       index.add_data1i(v2);
       index.add_data1i(v2);
@@ -614,7 +635,7 @@ pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
         dest->copy_row_from(v2, source, v, current_thread);
         dest->copy_row_from(v2, source, v, current_thread);
       }
       }
     }
     }
-    
+
     set_vertices(new_vertices);
     set_vertices(new_vertices);
   }
   }
 }
 }
@@ -644,7 +665,7 @@ make_indexed() {
 //     Function: GeomPrimitive::get_primitive_start
 //     Function: GeomPrimitive::get_primitive_start
 //       Access: Published
 //       Access: Published
 //  Description: Returns the element within the _vertices list at which
 //  Description: Returns the element within the _vertices list at which
-//               the nth primitive starts.  
+//               the nth primitive starts.
 //
 //
 //               If i is one more than the highest valid primitive
 //               If i is one more than the highest valid primitive
 //               vertex, the return value will be one more than the
 //               vertex, the return value will be one more than the
@@ -724,7 +745,7 @@ get_primitive_num_vertices(int n) const {
     } else {
     } else {
       int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
       int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
       return cdata->_ends[n] - cdata->_ends[n - 1] - num_unused_vertices_per_primitive;
       return cdata->_ends[n] - cdata->_ends[n - 1] - num_unused_vertices_per_primitive;
-    }      
+    }
 
 
   } else {
   } else {
     // This is a simple primitive type like a triangle: each primitive
     // This is a simple primitive type like a triangle: each primitive
@@ -733,6 +754,28 @@ get_primitive_num_vertices(int n) const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitive::get_num_used_vertices
+//       Access: Published
+//  Description: Returns the number of vertices used by all of the
+//               primitives.  This is the same as summing
+//               get_primitive_num_vertices(n) for n in
+//               get_num_primitives().  It is like get_num_vertices
+//               except that it excludes all of the degenerate
+//               vertices and strip-cut indices.
+////////////////////////////////////////////////////////////////////
+int GeomPrimitive::
+get_num_used_vertices() const {
+  int num_primitives = get_num_primitives();
+
+  if (num_primitives > 0) {
+    return get_num_vertices() - ((num_primitives - 1) *
+           get_num_unused_vertices_per_primitive());
+  } else {
+    return 0;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::get_primitive_min_vertex
 //     Function: GeomPrimitive::get_primitive_min_vertex
 //       Access: Published
 //       Access: Published
@@ -960,10 +1003,14 @@ make_points() const {
   int num_vertices = get_num_vertices();
   int num_vertices = get_num_vertices();
   if (is_indexed()) {
   if (is_indexed()) {
     CPT(GeomVertexArrayData) vertices = get_vertices();
     CPT(GeomVertexArrayData) vertices = get_vertices();
+    int strip_cut_index = get_strip_cut_index();
     GeomVertexReader index(vertices, 0);
     GeomVertexReader index(vertices, 0);
     for (int vi = 0; vi < num_vertices; ++vi) {
     for (int vi = 0; vi < num_vertices; ++vi) {
       nassertr(!index.is_at_end(), NULL);
       nassertr(!index.is_at_end(), NULL);
-      bits.set_bit(index.get_data1i());
+      int vertex = index.get_data1i();
+      if (vertex != strip_cut_index) {
+        bits.set_bit(vertex);
+      }
     }
     }
   } else {
   } else {
     int first_vertex = get_first_vertex();
     int first_vertex = get_first_vertex();
@@ -997,14 +1044,13 @@ make_points() const {
 //       Access: Published
 //       Access: Published
 //  Description: Decomposes a complex primitive type into a simpler
 //  Description: Decomposes a complex primitive type into a simpler
 //               primitive type, for instance triangle strips to
 //               primitive type, for instance triangle strips to
-//               triangles, puts these in a new GeomPatches objectand returns a pointer to the new primitive
+//               triangles, puts these in a new GeomPatches object
+//               and returns a pointer to the new primitive
 //               definition.  If the decomposition cannot be
 //               definition.  If the decomposition cannot be
 //               performed, this might return the original object.
 //               performed, this might return the original object.
 //
 //
 //               This method is useful for application code that wants
 //               This method is useful for application code that wants
-//               to iterate through the set of triangles on the
-//               primitive without having to write handlers for each
-//               possible kind of primitive type.
+//               to use tesselation shaders on arbitrary geometry.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 CPT(GeomPrimitive) GeomPrimitive::
 CPT(GeomPrimitive) GeomPrimitive::
 make_patches() const {
 make_patches() const {
@@ -1080,7 +1126,7 @@ request_resident() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::output
 //     Function: GeomPrimitive::output
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 void GeomPrimitive::
 output(ostream &out) const {
 output(ostream &out) const {
@@ -1091,7 +1137,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::write
 //     Function: GeomPrimitive::write
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 void GeomPrimitive::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
@@ -1188,6 +1234,11 @@ set_vertices(const GeomVertexArrayData *vertices, int num_vertices) {
   cdata->_vertices = (GeomVertexArrayData *)vertices;
   cdata->_vertices = (GeomVertexArrayData *)vertices;
   cdata->_num_vertices = num_vertices;
   cdata->_num_vertices = num_vertices;
 
 
+  // Validate the format and make sure to copy its numeric type.
+  const GeomVertexArrayFormat *format = vertices->get_array_format();
+  nassertv(format->get_num_columns() == 1);
+  cdata->_index_type = format->get_column(0)->get_numeric_type();
+
   cdata->_modified = Geom::get_next_modified();
   cdata->_modified = Geom::get_next_modified();
   cdata->_got_minmax = false;
   cdata->_got_minmax = false;
 }
 }
@@ -1449,7 +1500,7 @@ is_prepared(PreparedGraphicsObjects *prepared_objects) const {
 //               rendered.
 //               rendered.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 IndexBufferContext *GeomPrimitive::
 IndexBufferContext *GeomPrimitive::
-prepare_now(PreparedGraphicsObjects *prepared_objects, 
+prepare_now(PreparedGraphicsObjects *prepared_objects,
             GraphicsStateGuardianBase *gsg) {
             GraphicsStateGuardianBase *gsg) {
   nassertr(is_indexed(), NULL);
   nassertr(is_indexed(), NULL);
 
 
@@ -1519,18 +1570,41 @@ release_all() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::get_index_format
 //     Function: GeomPrimitive::get_index_format
-//       Access: Public
-//  Description: Returns a registered format appropriate for using to
-//               store the index table.
+//       Access: Public, Static
+//  Description: Returns a registered GeomVertexArrayFormat of the
+//               indicated unsigned integer numeric type for storing
+//               index values.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-CPT(GeomVertexArrayFormat) GeomPrimitive::
-get_index_format() const {
-  PT(GeomVertexArrayFormat) format = new GeomVertexArrayFormat;
-  // It's important that the index format *not* respect the global
-  // setting of vertex-column-alignment.  It needs to be tightly
-  // packed, so we specify an explict column_alignment of 1.
-  format->add_column(InternalName::get_index(), 1, get_index_type(), C_index, 0, 1);
-  return GeomVertexArrayFormat::register_format(format);
+const GeomVertexArrayFormat *GeomPrimitive::
+get_index_format(NumericType index_type) {
+  switch (index_type) {
+  case NT_uint8:
+    {
+      static CPT(GeomVertexArrayFormat) cformat = NULL;
+      if (cformat == NULL) {
+        cformat = make_index_format(NT_uint8);
+      }
+      return cformat;
+    }
+  case NT_uint16:
+    {
+      static CPT(GeomVertexArrayFormat) cformat = NULL;
+      if (cformat == NULL) {
+        cformat = make_index_format(NT_uint16);
+      }
+      return cformat;
+    }
+  case NT_uint32:
+    {
+      static CPT(GeomVertexArrayFormat) cformat = NULL;
+      if (cformat == NULL) {
+        cformat = make_index_format(NT_uint32);
+      }
+      return cformat;
+    }
+  }
+
+  return NULL;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -1559,28 +1633,57 @@ clear_prepared(PreparedGraphicsObjects *prepared_objects) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::get_highest_index_value
 //     Function: GeomPrimitive::get_highest_index_value
 //       Access: Private, Static
 //       Access: Private, Static
-//  Description: Returns the largest index value that can be stored in
-//               an index of the indicated type.
+//  Description: Returns the largest index value that can be stored
+//               in an index of the indicated type, minus one (to
+//               leave room for a potential strip cut index)
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GeomPrimitive::
 int GeomPrimitive::
 get_highest_index_value(NumericType index_type) {
 get_highest_index_value(NumericType index_type) {
+  // Reserve the highest possible index because implementations use
+  // this as a strip-cut index.
   switch (index_type) {
   switch (index_type) {
   case NT_uint8:
   case NT_uint8:
-    return 0xff;
+    return 0xff - 1;
 
 
   case NT_uint16:
   case NT_uint16:
-    return 0xffff;
+    return 0xffff - 1;
 
 
   case NT_uint32:
   case NT_uint32:
     // We don't actually allow use of the sign bit, since all of our
     // We don't actually allow use of the sign bit, since all of our
     // functions receive an "int" instead of an "unsigned int".
     // functions receive an "int" instead of an "unsigned int".
-    return 0x7fffffff;
+    return 0x7fffffff - 1;
 
 
   default:
   default:
     return 0;
     return 0;
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitive::get_strip_cut_index
+//       Access: Private, Static
+//  Description: Returns the index of the indicated type that is
+//               reserved for use as a strip cut index, if enabled
+//               for the primitive.  When the renderer encounters
+//               this index, it will restart the primitive.  This
+//               is guaranteed not to point to an actual vertex.
+////////////////////////////////////////////////////////////////////
+int GeomPrimitive::
+get_strip_cut_index(NumericType index_type) {
+  // Reserve the highest possible index because implementations use
+  // this as a strip-cut index.
+  switch (index_type) {
+  case NT_uint8:
+    return 0xff;
+
+  case NT_uint16:
+    return 0xffff;
+
+  case NT_uint32:
+  default:
+    return -1;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::calc_tight_bounds
 //     Function: GeomPrimitive::calc_tight_bounds
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -1594,7 +1697,7 @@ get_highest_index_value(NumericType index_type) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 void GeomPrimitive::
 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
-                  bool &found_any, 
+                  bool &found_any,
                   const GeomVertexData *vertex_data,
                   const GeomVertexData *vertex_data,
                   bool got_mat, const LMatrix4 &mat,
                   bool got_mat, const LMatrix4 &mat,
                   const InternalName *column_name,
                   const InternalName *column_name,
@@ -1614,7 +1717,7 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
       for (int i = 0; i < cdata->_num_vertices; i++) {
       for (int i = 0; i < cdata->_num_vertices; i++) {
         reader.set_row_unsafe(cdata->_first_vertex + i);
         reader.set_row_unsafe(cdata->_first_vertex + i);
         LPoint3 vertex = mat.xform_point(reader.get_data3());
         LPoint3 vertex = mat.xform_point(reader.get_data3());
-        
+
         if (found_any) {
         if (found_any) {
           min_point.set(min(min_point[0], vertex[0]),
           min_point.set(min(min_point[0], vertex[0]),
                         min(min_point[1], vertex[1]),
                         min(min_point[1], vertex[1]),
@@ -1632,7 +1735,7 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
       for (int i = 0; i < cdata->_num_vertices; i++) {
       for (int i = 0; i < cdata->_num_vertices; i++) {
         reader.set_row_unsafe(cdata->_first_vertex + i);
         reader.set_row_unsafe(cdata->_first_vertex + i);
         const LVecBase3 &vertex = reader.get_data3();
         const LVecBase3 &vertex = reader.get_data3();
-        
+
         if (found_any) {
         if (found_any) {
           min_point.set(min(min_point[0], vertex[0]),
           min_point.set(min(min_point[0], vertex[0]),
                         min(min_point[1], vertex[1]),
                         min(min_point[1], vertex[1]),
@@ -1651,13 +1754,17 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
   } else {
   } else {
     // Indexed case.
     // Indexed case.
     GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
     GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
+    int strip_cut_index = get_strip_cut_index(cdata->_index_type);
 
 
     if (got_mat) {
     if (got_mat) {
       while (!index.is_at_end()) {
       while (!index.is_at_end()) {
         int ii = index.get_data1i();
         int ii = index.get_data1i();
+        if (ii == strip_cut_index) {
+          continue;
+        }
         reader.set_row_unsafe(ii);
         reader.set_row_unsafe(ii);
         LPoint3 vertex = mat.xform_point(reader.get_data3());
         LPoint3 vertex = mat.xform_point(reader.get_data3());
-        
+
         if (found_any) {
         if (found_any) {
           min_point.set(min(min_point[0], vertex[0]),
           min_point.set(min(min_point[0], vertex[0]),
                         min(min_point[1], vertex[1]),
                         min(min_point[1], vertex[1]),
@@ -1674,9 +1781,12 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
     } else {
     } else {
       while (!index.is_at_end()) {
       while (!index.is_at_end()) {
         int ii = index.get_data1i();
         int ii = index.get_data1i();
+        if (ii == strip_cut_index) {
+          continue;
+        }
         reader.set_row_unsafe(ii);
         reader.set_row_unsafe(ii);
         const LVecBase3 &vertex = reader.get_data3();
         const LVecBase3 &vertex = reader.get_data3();
-        
+
         if (found_any) {
         if (found_any) {
           min_point.set(min(min_point[0], vertex[0]),
           min_point.set(min(min_point[0], vertex[0]),
                         min(min_point[1], vertex[1]),
                         min(min_point[1], vertex[1]),
@@ -1798,63 +1908,77 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
       cdata->_max_vertex = 0;
       cdata->_max_vertex = 0;
       cdata->_mins.clear();
       cdata->_mins.clear();
       cdata->_maxs.clear();
       cdata->_maxs.clear();
-      
+
     } else if (get_num_vertices_per_primitive() == 0) {
     } else if (get_num_vertices_per_primitive() == 0) {
       // This is a complex primitive type like a triangle strip; compute
       // This is a complex primitive type like a triangle strip; compute
       // the minmax of each primitive (as well as the overall minmax).
       // the minmax of each primitive (as well as the overall minmax).
       GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
       GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
-      
+
       cdata->_mins = make_index_data();
       cdata->_mins = make_index_data();
       cdata->_maxs = make_index_data();
       cdata->_maxs = make_index_data();
-      
+
       GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0);
       GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0);
       mins.reserve_num_rows(cdata->_ends.size());
       mins.reserve_num_rows(cdata->_ends.size());
       GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0);
       GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0);
       maxs.reserve_num_rows(cdata->_ends.size());
       maxs.reserve_num_rows(cdata->_ends.size());
-      
+
       int pi = 0;
       int pi = 0;
-      
+
       unsigned int vertex = index.get_data1i();
       unsigned int vertex = index.get_data1i();
       cdata->_min_vertex = vertex;
       cdata->_min_vertex = vertex;
       cdata->_max_vertex = vertex;
       cdata->_max_vertex = vertex;
       unsigned int min_prim = vertex;
       unsigned int min_prim = vertex;
       unsigned int max_prim = vertex;
       unsigned int max_prim = vertex;
-      
+
+      int num_unused_vertices = get_num_unused_vertices_per_primitive();
+
       for (int vi = 1; vi < num_vertices; ++vi) {
       for (int vi = 1; vi < num_vertices; ++vi) {
         nassertv(!index.is_at_end());
         nassertv(!index.is_at_end());
-        unsigned int vertex = index.get_data1i();
-        cdata->_min_vertex = min(cdata->_min_vertex, vertex);
-        cdata->_max_vertex = max(cdata->_max_vertex, vertex);
-
         nassertv(pi < (int)cdata->_ends.size());
         nassertv(pi < (int)cdata->_ends.size());
+
+        unsigned int vertex;
+
         if (vi == cdata->_ends[pi]) {
         if (vi == cdata->_ends[pi]) {
+          // Skip unused vertices, since they won't be very relevant and
+          // may contain a strip-cut index, which would distort the result.
+          if (num_unused_vertices > 0) {
+            vi += num_unused_vertices;
+            index.set_row_unsafe(vi);
+          }
+          vertex = index.get_data1i();
+
           mins.add_data1i(min_prim);
           mins.add_data1i(min_prim);
           maxs.add_data1i(max_prim);
           maxs.add_data1i(max_prim);
           min_prim = vertex;
           min_prim = vertex;
           max_prim = vertex;
           max_prim = vertex;
           ++pi;
           ++pi;
-          
+
         } else {
         } else {
+          vertex = index.get_data1i();
           min_prim = min(min_prim, vertex);
           min_prim = min(min_prim, vertex);
           max_prim = max(max_prim, vertex);
           max_prim = max(max_prim, vertex);
         }
         }
+
+        cdata->_min_vertex = min(cdata->_min_vertex, vertex);
+        cdata->_max_vertex = max(cdata->_max_vertex, vertex);
       }
       }
+
       mins.add_data1i(min_prim);
       mins.add_data1i(min_prim);
       maxs.add_data1i(max_prim);
       maxs.add_data1i(max_prim);
       nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
       nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
-      
+
     } else {
     } else {
       // This is a simple primitive type like a triangle; just compute
       // This is a simple primitive type like a triangle; just compute
       // the overall minmax.
       // the overall minmax.
       GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
       GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
-      
+
       cdata->_mins.clear();
       cdata->_mins.clear();
       cdata->_maxs.clear();
       cdata->_maxs.clear();
-      
+
       unsigned int vertex = index.get_data1i();
       unsigned int vertex = index.get_data1i();
       cdata->_min_vertex = vertex;
       cdata->_min_vertex = vertex;
       cdata->_max_vertex = vertex;
       cdata->_max_vertex = vertex;
-      
+
       for (int vi = 1; vi < num_vertices; ++vi) {
       for (int vi = 1; vi < num_vertices; ++vi) {
         nassertv(!index.is_at_end());
         nassertv(!index.is_at_end());
         unsigned int vertex = index.get_data1i();
         unsigned int vertex = index.get_data1i();
@@ -1863,7 +1987,7 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
       }
       }
     }
     }
   }
   }
-    
+
   cdata->_got_minmax = true;
   cdata->_got_minmax = true;
 }
 }
 
 
@@ -1900,22 +2024,25 @@ do_make_indexed(CData *cdata) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 void GeomPrimitive::
 consider_elevate_index_type(CData *cdata, int vertex) {
 consider_elevate_index_type(CData *cdata, int vertex) {
+  // Note that we reserve the highest possible index of a particular
+  // index type (ie. -1) because this is commonly used as a strip-cut
+  // (also known as primitive restart) index.
   switch (cdata->_index_type) {
   switch (cdata->_index_type) {
   case NT_uint8:
   case NT_uint8:
-    if (vertex > 0xff) {
+    if (vertex >= 0xff) {
       do_set_index_type(cdata, NT_uint16);
       do_set_index_type(cdata, NT_uint16);
     }
     }
     break;
     break;
 
 
   case NT_uint16:
   case NT_uint16:
-    if (vertex > 0xffff) {
+    if (vertex >= 0xffff) {
       do_set_index_type(cdata, NT_uint32);
       do_set_index_type(cdata, NT_uint32);
     }
     }
     break;
     break;
 
 
   case NT_uint32:
   case NT_uint32:
     // Not much we can do here.
     // Not much we can do here.
-    nassertv(vertex <= 0x7fffffff);
+    nassertv(vertex < 0x7fffffff);
     break;
     break;
 
 
   default:
   default:
@@ -1930,6 +2057,9 @@ consider_elevate_index_type(CData *cdata, int vertex) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 void GeomPrimitive::
 do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
 do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
+  int old_strip_cut_index = get_strip_cut_index(cdata->_index_type);
+  int new_strip_cut_index = get_strip_cut_index(index_type);
+
   cdata->_index_type = index_type;
   cdata->_index_type = index_type;
 
 
   if (gobj_cat.is_debug()) {
   if (gobj_cat.is_debug()) {
@@ -1939,7 +2069,7 @@ do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
 
 
   if (!cdata->_vertices.is_null()) {
   if (!cdata->_vertices.is_null()) {
     CPT(GeomVertexArrayFormat) new_format = get_index_format();
     CPT(GeomVertexArrayFormat) new_format = get_index_format();
-    
+
     CPT(GeomVertexArrayData) array_obj = cdata->_vertices.get_read_pointer();
     CPT(GeomVertexArrayData) array_obj = cdata->_vertices.get_read_pointer();
     if (array_obj->get_array_format() != new_format) {
     if (array_obj->get_array_format() != new_format) {
       PT(GeomVertexArrayData) new_vertices = make_index_data();
       PT(GeomVertexArrayData) new_vertices = make_index_data();
@@ -1947,9 +2077,13 @@ do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
 
 
       GeomVertexReader from(array_obj, 0);
       GeomVertexReader from(array_obj, 0);
       GeomVertexWriter to(new_vertices, 0);
       GeomVertexWriter to(new_vertices, 0);
-      
+
       while (!from.is_at_end()) {
       while (!from.is_at_end()) {
-        to.set_data1i(from.get_data1i());
+        int index = from.get_data1i();
+        if (index == old_strip_cut_index) {
+          index = new_strip_cut_index;
+        }
+        to.set_data1i(index);
       }
       }
       cdata->_vertices = new_vertices;
       cdata->_vertices = new_vertices;
       cdata->_got_minmax = false;
       cdata->_got_minmax = false;
@@ -2057,7 +2191,7 @@ int GeomPrimitive::CData::
 complete_pointers(TypedWritable **p_list, BamReader *manager) {
 complete_pointers(TypedWritable **p_list, BamReader *manager) {
   int pi = CycleData::complete_pointers(p_list, manager);
   int pi = CycleData::complete_pointers(p_list, manager);
 
 
-  _vertices = DCAST(GeomVertexArrayData, p_list[pi++]);    
+  _vertices = DCAST(GeomVertexArrayData, p_list[pi++]);
 
 
   if (manager->get_file_minor_ver() < 6 && !_vertices.is_null()) {
   if (manager->get_file_minor_ver() < 6 && !_vertices.is_null()) {
     // Older bam files might have a meaningless number in
     // Older bam files might have a meaningless number in
@@ -2107,7 +2241,7 @@ check_minmax() const {
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
       unref_delete((CycleData *)_cdata);
       unref_delete((CycleData *)_cdata);
 #endif
 #endif
-      GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler, 
+      GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler,
                                           false, _current_thread);
                                           false, _current_thread);
       ((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
       ((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
@@ -2133,7 +2267,7 @@ check_minmax() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitivePipelineReader::get_first_vertex
 //     Function: GeomPrimitivePipelineReader::get_first_vertex
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GeomPrimitivePipelineReader::
 int GeomPrimitivePipelineReader::
 get_first_vertex() const {
 get_first_vertex() const {
@@ -2171,7 +2305,7 @@ get_vertex(int i) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitivePipelineReader::get_num_primitives
 //     Function: GeomPrimitivePipelineReader::get_num_primitives
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GeomPrimitivePipelineReader::
 int GeomPrimitivePipelineReader::
 get_num_primitives() const {
 get_num_primitives() const {

+ 11 - 4
panda/src/gobj/geomPrimitive.h

@@ -118,6 +118,7 @@ PUBLISHED:
   int get_primitive_start(int n) const;
   int get_primitive_start(int n) const;
   int get_primitive_end(int n) const;
   int get_primitive_end(int n) const;
   int get_primitive_num_vertices(int n) const;
   int get_primitive_num_vertices(int n) const;
+  int get_num_used_vertices() const;
 
 
   INLINE int get_num_faces() const;
   INLINE int get_num_faces() const;
   INLINE int get_primitive_num_faces(int n) const;
   INLINE int get_primitive_num_faces(int n) const;
@@ -163,6 +164,7 @@ PUBLISHED:
   void set_nonindexed_vertices(int first_vertex, int num_vertices);
   void set_nonindexed_vertices(int first_vertex, int num_vertices);
 
 
   INLINE int get_index_stride() const;
   INLINE int get_index_stride() const;
+  INLINE int get_strip_cut_index() const;
 
 
   INLINE CPTA_int get_ends() const;
   INLINE CPTA_int get_ends() const;
   PTA_int modify_ends();
   PTA_int modify_ends();
@@ -183,17 +185,21 @@ public:
   void prepare(PreparedGraphicsObjects *prepared_objects);
   void prepare(PreparedGraphicsObjects *prepared_objects);
   bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
   bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
 
 
-  IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects, 
+  IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
                                   GraphicsStateGuardianBase *gsg);
                                   GraphicsStateGuardianBase *gsg);
   bool release(PreparedGraphicsObjects *prepared_objects);
   bool release(PreparedGraphicsObjects *prepared_objects);
   int release_all();
   int release_all();
 
 
-  CPT(GeomVertexArrayFormat) get_index_format() const;
+  static const GeomVertexArrayFormat *get_index_format(NumericType index_type);
+  INLINE const GeomVertexArrayFormat *get_index_format() const;
   INLINE PT(GeomVertexArrayData) make_index_data() const;
   INLINE PT(GeomVertexArrayData) make_index_data() const;
 
 
 private:
 private:
+  static CPT(GeomVertexArrayFormat) make_index_format(NumericType index_type);
+
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   static int get_highest_index_value(NumericType index_type);
   static int get_highest_index_value(NumericType index_type);
+  static int get_strip_cut_index(NumericType index_type);
 
 
 public:
 public:
   virtual bool draw(GraphicsStateGuardianBase *gsg,
   virtual bool draw(GraphicsStateGuardianBase *gsg,
@@ -201,7 +207,7 @@ public:
                     bool force) const=0;
                     bool force) const=0;
 
 
   void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
   void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
-                         bool &found_any, 
+                         bool &found_any,
                          const GeomVertexData *vertex_data,
                          const GeomVertexData *vertex_data,
                          bool got_mat, const LMatrix4 &mat,
                          bool got_mat, const LMatrix4 &mat,
                          const InternalName *column_name,
                          const InternalName *column_name,
@@ -213,7 +219,7 @@ protected:
   virtual CPT(GeomPrimitive) doubleside_impl() const;
   virtual CPT(GeomPrimitive) doubleside_impl() const;
   virtual CPT(GeomPrimitive) reverse_impl() const;
   virtual CPT(GeomPrimitive) reverse_impl() const;
   virtual bool requires_unused_vertices() const;
   virtual bool requires_unused_vertices() const;
-  virtual void append_unused_vertices(GeomVertexArrayData *vertices, 
+  virtual void append_unused_vertices(GeomVertexArrayData *vertices,
                                       int vertex);
                                       int vertex);
 
 
 private:
 private:
@@ -358,6 +364,7 @@ public:
   INLINE int get_index_stride() const;
   INLINE int get_index_stride() const;
   INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const;
   INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const;
   INLINE const unsigned char *get_read_pointer(bool force) const;
   INLINE const unsigned char *get_read_pointer(bool force) const;
+  INLINE int get_strip_cut_index() const;
   INLINE CPTA_int get_ends() const;
   INLINE CPTA_int get_ends() const;
   INLINE CPT(GeomVertexArrayData) get_mins() const;
   INLINE CPT(GeomVertexArrayData) get_mins() const;
   INLINE CPT(GeomVertexArrayData) get_maxs() const;
   INLINE CPT(GeomVertexArrayData) get_maxs() const;

+ 16 - 4
panda/src/gobj/geomTristrips.cxx

@@ -95,6 +95,17 @@ get_geom_rendering() const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomTristrips::get_min_num_vertices_per_primitive
+//       Access: Public, Virtual
+//  Description: Returns the minimum number of vertices that must be
+//               added before close_primitive() may legally be called.
+////////////////////////////////////////////////////////////////////
+int GeomTristrips::
+get_min_num_vertices_per_primitive() const {
+  return 3;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomTristrips::get_num_unused_vertices_per_primitive
 //     Function: GeomTristrips::get_num_unused_vertices_per_primitive
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -142,6 +153,7 @@ decompose_impl() const {
   CPTA_int ends = get_ends();
   CPTA_int ends = get_ends();
 
 
   int num_vertices = get_num_vertices();
   int num_vertices = get_num_vertices();
+  int num_unused = get_num_unused_vertices_per_primitive();
 
 
   // We need a slightly different algorithm for SM_flat_first_vertex
   // We need a slightly different algorithm for SM_flat_first_vertex
   // than for SM_flat_last_vertex, to preserve the key vertex in the
   // than for SM_flat_last_vertex, to preserve the key vertex in the
@@ -150,11 +162,11 @@ decompose_impl() const {
   if (get_shade_model() == SM_flat_first_vertex) {
   if (get_shade_model() == SM_flat_first_vertex) {
     // Preserve the first vertex of each component triangle as the
     // Preserve the first vertex of each component triangle as the
     // first vertex of each generated triangle.
     // first vertex of each generated triangle.
-    int vi = -2;
+    int vi = -num_unused;
     int li = 0;
     int li = 0;
     while (li < (int)ends.size()) {
     while (li < (int)ends.size()) {
       // Skip unused vertices between tristrips.
       // Skip unused vertices between tristrips.
-      vi += 2;
+      vi += num_unused;
       int end = ends[li];
       int end = ends[li];
       nassertr(vi + 2 <= end, NULL);
       nassertr(vi + 2 <= end, NULL);
       int v0 = get_vertex(vi);
       int v0 = get_vertex(vi);
@@ -192,11 +204,11 @@ decompose_impl() const {
   } else {
   } else {
     // Preserve the last vertex of each component triangle as the
     // Preserve the last vertex of each component triangle as the
     // last vertex of each generated triangle.
     // last vertex of each generated triangle.
-    int vi = -2;
+    int vi = -num_unused;
     int li = 0;
     int li = 0;
     while (li < (int)ends.size()) {
     while (li < (int)ends.size()) {
       // Skip unused vertices between tristrips.
       // Skip unused vertices between tristrips.
-      vi += 2;
+      vi += num_unused;
       int end = ends[li];
       int end = ends[li];
       nassertr(vi + 2 <= end, NULL);
       nassertr(vi + 2 <= end, NULL);
       int v0 = get_vertex(vi);
       int v0 = get_vertex(vi);

+ 1 - 0
panda/src/gobj/geomTristrips.h

@@ -33,6 +33,7 @@ public:
   virtual PT(GeomPrimitive) make_copy() const;
   virtual PT(GeomPrimitive) make_copy() const;
   virtual PrimitiveType get_primitive_type() const;
   virtual PrimitiveType get_primitive_type() const;
   virtual int get_geom_rendering() const;
   virtual int get_geom_rendering() const;
+  virtual int get_min_num_vertices_per_primitive() const;
   virtual int get_num_unused_vertices_per_primitive() const;
   virtual int get_num_unused_vertices_per_primitive() const;
 
 
 public:
 public:

+ 4 - 0
panda/src/gobj/internalName.cxx

@@ -43,6 +43,10 @@ PT(InternalName) InternalName::_view;
 TypeHandle InternalName::_type_handle;
 TypeHandle InternalName::_type_handle;
 TypeHandle InternalName::_texcoord_type_handle;
 TypeHandle InternalName::_texcoord_type_handle;
 
 
+#ifdef HAVE_PYTHON
+InternalName::PyInternTable InternalName::_py_intern_table;
+#endif
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::Constructor
 //     Function: InternalName::Constructor
 //       Access: Private
 //       Access: Private

+ 20 - 4
panda/src/gobj/internalName.h

@@ -43,11 +43,13 @@ class EXPCL_PANDA_GOBJ InternalName : public TypedWritableReferenceCount {
 private:
 private:
   InternalName(InternalName *parent, const string &basename);
   InternalName(InternalName *parent, const string &basename);
 
 
+public:
+  INLINE static PT(InternalName) make(const string &name);
+
 PUBLISHED:
 PUBLISHED:
   virtual ~InternalName();
   virtual ~InternalName();
   virtual bool unref() const;
   virtual bool unref() const;
 
 
-  INLINE static PT(InternalName) make(const string &name);
   static PT(InternalName) make(const string &name, int index);
   static PT(InternalName) make(const string &name, int index);
   PT(InternalName) append(const string &basename);
   PT(InternalName) append(const string &basename);
 
 
@@ -88,6 +90,22 @@ PUBLISHED:
   INLINE static PT(InternalName) get_model();
   INLINE static PT(InternalName) get_model();
   INLINE static PT(InternalName) get_view();
   INLINE static PT(InternalName) get_view();
 
 
+#ifdef HAVE_PYTHON
+#if PY_MAJOR_VERSION >= 3
+  EXTENSION(static PT(InternalName) make(PyUnicodeObject *str));
+#else
+  EXTENSION(static PT(InternalName) make(PyStringObject *str));
+#endif
+#endif
+
+public:
+#ifdef HAVE_PYTHON
+  // It's OK for us to define it here since these are just pointers of
+  // which the reference is maintained indefinitely.
+  typedef phash_map<PyObject *, InternalName *, pointer_hash> PyInternTable;
+  static PyInternTable _py_intern_table;
+#endif
+
 private:
 private:
   PT(InternalName) _parent;
   PT(InternalName) _parent;
   string _basename;
   string _basename;
@@ -116,7 +134,7 @@ private:
   static PT(InternalName) _camera;
   static PT(InternalName) _camera;
   static PT(InternalName) _model;
   static PT(InternalName) _model;
   static PT(InternalName) _view;
   static PT(InternalName) _view;
-  
+
 public:
 public:
   // Datagram stuff
   // Datagram stuff
   static void register_with_read_factory();
   static void register_with_read_factory();
@@ -157,5 +175,3 @@ INLINE ostream &operator << (ostream &out, const InternalName &tcn);
 
 
 #endif
 #endif
 
 
-
-  

+ 87 - 0
panda/src/gobj/internalName_ext.cxx

@@ -0,0 +1,87 @@
+// Filename: internalName_ext.I
+// Created by:  rdb (28Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "internalName_ext.h"
+
+#ifdef HAVE_PYTHON
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::make
+//       Access: Published, Static
+//  Description: This extension method serves to allow coercion of
+//               Python interned strings to InternalName objects
+//               more efficiently by storing a mapping between
+//               Python and Panda interned strings.
+////////////////////////////////////////////////////////////////////
+#if PY_MAJOR_VERSION >= 3
+PT(InternalName) Extension<InternalName>::
+make(PyUnicodeObject *str) {
+  if (!PyUnicode_CHECK_INTERNED(str)) {
+    // Not an interned string; don't bother.
+    Py_ssize_t len = 0;
+    char *c_str = PyUnicode_AsUTF8AndSize((PyObject *)str, &len);
+    if (c_str == NULL) {
+      return NULL;
+    }
+
+    string name(c_str, len);
+    return InternalName::make(c_str, len);
+  }
+
+  InternalName::PyInternTable::const_iterator it;
+  it = InternalName::_py_intern_table.find((PyObject*)str);
+
+  if (it != InternalName::_py_intern_table.end()) {
+    return (*it).second;
+
+  } else {
+    Py_ssize_t len = 0;
+    char *c_str = PyUnicode_AsUTF8AndSize((PyObject *)str, &len);
+    string name(c_str, len);
+
+#else
+PT(InternalName) Extension<InternalName>::
+make(PyStringObject *str) {
+  if (!PyString_CHECK_INTERNED(str)) {
+    // Not an interned string; don't bother.
+    string name(PyString_AS_STRING(str), PyString_GET_SIZE(str));
+    return InternalName::make(name);
+  }
+
+  InternalName::PyInternTable::const_iterator it;
+  it = InternalName::_py_intern_table.find((PyObject*)str);
+
+  if (it != InternalName::_py_intern_table.end()) {
+    return (*it).second;
+
+  } else {
+    string name(PyString_AS_STRING(str), PyString_GET_SIZE(str));
+
+#endif  // PY_MAJOR_VERSION
+
+    PT(InternalName) iname = InternalName::make(name);
+
+    // We basically leak references to both the PyObject and the
+    // InternalName.  We may want to change that in the future if it
+    // becomes a problem.
+    Py_INCREF(str);
+    iname->ref();
+
+    InternalName::_py_intern_table.insert(make_pair((PyObject *)str, iname.p()));
+    return iname.p();
+  }
+
+}
+
+#endif  // HAVE_PYTHON

+ 44 - 0
panda/src/gobj/internalName_ext.h

@@ -0,0 +1,44 @@
+// Filename: internalName_ext.h
+// Created by:  rdb (28Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INTERNALNAME_EXT_H
+#define INTERNALNAME_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "internalName.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<InternalName>
+// Description : This class defines the extension methods for
+//               InternalName, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<InternalName> : public ExtensionBase<InternalName> {
+public:
+#if PY_MAJOR_VERSION >= 3
+  static PT(InternalName) make(PyUnicodeObject *str);
+#else
+  static PT(InternalName) make(PyStringObject *str);
+#endif
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // INTERNALNAME_EXT_H

+ 3 - 0
panda/src/gobj/p3gobj_composite1.cxx

@@ -30,3 +30,6 @@
 #include "indexBufferContext.cxx"
 #include "indexBufferContext.cxx"
 #include "internalName.cxx"
 #include "internalName.cxx"
 #include "lens.cxx"
 #include "lens.cxx"
+#include "material.cxx"
+#include "materialPool.cxx"
+#include "matrixLens.cxx"

+ 1 - 3
panda/src/gobj/p3gobj_composite2.cxx

@@ -1,6 +1,3 @@
-#include "material.cxx"
-#include "materialPool.cxx"
-#include "matrixLens.cxx"
 #include "occlusionQueryContext.cxx"
 #include "occlusionQueryContext.cxx"
 #include "orthographicLens.cxx"
 #include "orthographicLens.cxx"
 #include "perspectiveLens.cxx"
 #include "perspectiveLens.cxx"
@@ -21,6 +18,7 @@
 #include "textureReloadRequest.cxx"
 #include "textureReloadRequest.cxx"
 #include "textureStage.cxx"
 #include "textureStage.cxx"
 #include "textureStagePool.cxx"
 #include "textureStagePool.cxx"
+#include "timerQueryContext.cxx"
 #include "transformBlend.cxx"
 #include "transformBlend.cxx"
 #include "transformBlendTable.cxx"
 #include "transformBlendTable.cxx"
 #include "transformTable.cxx"
 #include "transformTable.cxx"

+ 6 - 6
panda/src/gobj/shader.I

@@ -12,16 +12,16 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::get_filename
 //     Function: Shader::get_filename
-//       Access: Public
+//       Access: Published
 //  Description: Return the Shader's filename for the given shader
 //  Description: Return the Shader's filename for the given shader
 //               type.
 //               type.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const Filename Shader::
+INLINE Filename Shader::
 get_filename(const ShaderType &type) const {
 get_filename(const ShaderType &type) const {
-  if (_filename->_separate) {
-    nassertr(type != ST_none || !_filename->_shared.empty(), "");
+  if (_filename->_separate && type == ST_none) {
     switch (type) {
     switch (type) {
       case ST_vertex:
       case ST_vertex:
         return _filename->_vertex;
         return _filename->_vertex;
@@ -51,7 +51,7 @@ get_filename(const ShaderType &type) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Shader::get_text
 //     Function: Shader::get_text
-//       Access: Public
+//       Access: Published
 //  Description: Return the Shader's text for the given shader type.
 //  Description: Return the Shader's text for the given shader type.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const string &Shader::
 INLINE const string &Shader::
@@ -146,7 +146,7 @@ have_shader_utilization() {
 //  Description: Returns the shader language in which this shader
 //  Description: Returns the shader language in which this shader
 //               was written.
 //               was written.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const Shader::ShaderLanguage Shader::
+INLINE Shader::ShaderLanguage Shader::
 get_language() const {
 get_language() const {
   return _language;
   return _language;
 }
 }

+ 2 - 2
panda/src/gobj/shader.h

@@ -96,10 +96,10 @@ PUBLISHED:
                          const string &tess_evaluation = "");
                          const string &tess_evaluation = "");
   static PT(Shader) make_compute(const ShaderLanguage &lang, const string &body);
   static PT(Shader) make_compute(const ShaderLanguage &lang, const string &body);
 
 
-  INLINE const Filename get_filename(const ShaderType &type = ST_none) const;
+  INLINE Filename get_filename(const ShaderType &type = ST_none) const;
   INLINE const string &get_text(const ShaderType &type = ST_none) const;
   INLINE const string &get_text(const ShaderType &type = ST_none) const;
   INLINE const bool get_error_flag() const;
   INLINE const bool get_error_flag() const;
-  INLINE const ShaderLanguage get_language() const;
+  INLINE ShaderLanguage get_language() const;
 
 
   INLINE static ShaderUtilization get_shader_utilization();
   INLINE static ShaderUtilization get_shader_utilization();
   INLINE static void set_shader_utilization(ShaderUtilization utl);
   INLINE static void set_shader_utilization(ShaderUtilization utl);

+ 26 - 0
panda/src/gobj/timerQueryContext.I

@@ -0,0 +1,26 @@
+// Filename: occlusionQueryContext.I
+// Created by:  rdb (22Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TimerQueryContext::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE TimerQueryContext::
+TimerQueryContext(int pstats_index) :
+  _pstats_index(pstats_index),
+  _frame_index(ClockObject::get_global_clock()->get_frame_count())
+{
+}

+ 35 - 0
panda/src/gobj/timerQueryContext.cxx

@@ -0,0 +1,35 @@
+// Filename: timerQueryContext.cxx
+// Created by:  rdb (22Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "timerQueryContext.h"
+
+TypeHandle TimerQueryContext::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: TimerQueryContext::get_timestamp
+//       Access: Public, Virtual
+//  Description: Returns the timestamp that is the result of this
+//               timer query.  There's no guarantee about which
+//               clock this uses, the only guarantee is that
+//               subtracting a start time from an end time should
+//               yield a time in seconds.
+//               If is_answer_ready() did not return true, this
+//               function may block before it returns.
+//
+//               It is only valid to call this from the draw thread.
+////////////////////////////////////////////////////////////////////
+double TimerQueryContext::
+get_timestamp() const {
+  return 0.0;
+}

+ 60 - 0
panda/src/gobj/timerQueryContext.h

@@ -0,0 +1,60 @@
+// Filename: timerQueryContext.h
+// Created by:  rdb (22Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef TIMERQUERYCONTEXT_H
+#define TIMERQUERYCONTEXT_H
+
+#include "pandabase.h"
+#include "queryContext.h"
+#include "clockObject.h"
+#include "pStatCollector.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : TimerQueryContext
+// Description :
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_GOBJ TimerQueryContext : public QueryContext {
+public:
+  INLINE TimerQueryContext(int pstats_index);
+
+  ALLOC_DELETED_CHAIN(TimerQueryContext);
+
+  virtual double get_timestamp() const=0;
+
+  int _frame_index;
+  int _pstats_index;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    QueryContext::init_type();
+    register_type(_type_handle, "TimerQueryContext",
+                  QueryContext::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class PreparedGraphicsObjects;
+};
+
+#include "timerQueryContext.I"
+
+#endif

+ 3 - 6
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -32,7 +32,6 @@ class GraphicsOutputBase;
 
 
 class VertexBufferContext;
 class VertexBufferContext;
 class IndexBufferContext;
 class IndexBufferContext;
-class OcclusionQueryContext;
 class GeomContext;
 class GeomContext;
 class GeomNode;
 class GeomNode;
 class Geom;
 class Geom;
@@ -123,9 +122,10 @@ PUBLISHED:
 
 
   virtual bool get_supports_multisample() const=0;
   virtual bool get_supports_multisample() const=0;
   virtual int get_supported_geom_rendering() const=0;
   virtual int get_supported_geom_rendering() const=0;
-  virtual bool get_supports_occlusion_query() const=0;
   virtual bool get_supports_shadow_filter() const=0;
   virtual bool get_supports_shadow_filter() const=0;
 
 
+  virtual bool get_supports_texture_srgb() const=0;
+
 public:
 public:
   // These are some general interface functions; they're defined here
   // These are some general interface functions; they're defined here
   // mainly to make it easy to call these from code in some directory
   // mainly to make it easy to call these from code in some directory
@@ -153,16 +153,13 @@ public:
 
 
   virtual ShaderContext *prepare_shader(Shader *shader)=0;
   virtual ShaderContext *prepare_shader(Shader *shader)=0;
   virtual void release_shader(ShaderContext *sc)=0;
   virtual void release_shader(ShaderContext *sc)=0;
-  
+
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data)=0;
   virtual VertexBufferContext *prepare_vertex_buffer(GeomVertexArrayData *data)=0;
   virtual void release_vertex_buffer(VertexBufferContext *vbc)=0;
   virtual void release_vertex_buffer(VertexBufferContext *vbc)=0;
 
 
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data)=0;
   virtual IndexBufferContext *prepare_index_buffer(GeomPrimitive *data)=0;
   virtual void release_index_buffer(IndexBufferContext *ibc)=0;
   virtual void release_index_buffer(IndexBufferContext *ibc)=0;
 
 
-  virtual void begin_occlusion_query()=0;
-  virtual PT(OcclusionQueryContext) end_occlusion_query()=0;
-
   virtual void dispatch_compute(int size_x, int size_y, int size_z)=0;
   virtual void dispatch_compute(int size_x, int size_y, int size_z)=0;
 
 
   virtual PT(GeomMunger) get_geom_munger(const RenderState *state,
   virtual PT(GeomMunger) get_geom_munger(const RenderState *state,

+ 7 - 2
panda/src/net/connectionManager.cxx

@@ -26,6 +26,8 @@
 #if defined(WIN32_VC) || defined(WIN64_VC)
 #if defined(WIN32_VC) || defined(WIN64_VC)
 #include <winsock2.h>  // For gethostname()
 #include <winsock2.h>  // For gethostname()
 #include <Iphlpapi.h> // For GetAdaptersAddresses()
 #include <Iphlpapi.h> // For GetAdaptersAddresses()
+#elif defined(ANDROID)
+#include <net/if.h>
 #else
 #else
 #include <net/if.h>
 #include <net/if.h>
 #include <ifaddrs.h>
 #include <ifaddrs.h>
@@ -542,14 +544,14 @@ scan_interfaces() {
         TextEncoder encoder;
         TextEncoder encoder;
         encoder.set_wtext(wstring(p->FriendlyName));
         encoder.set_wtext(wstring(p->FriendlyName));
         string friendly_name = encoder.get_text();
         string friendly_name = encoder.get_text();
-        
+
         Interface iface;
         Interface iface;
         iface.set_name(friendly_name);
         iface.set_name(friendly_name);
 
 
         if (p->PhysicalAddressLength > 0) {
         if (p->PhysicalAddressLength > 0) {
           iface.set_mac_address(format_mac_address((const unsigned char *)p->PhysicalAddress, p->PhysicalAddressLength));
           iface.set_mac_address(format_mac_address((const unsigned char *)p->PhysicalAddress, p->PhysicalAddressLength));
         }
         }
-        
+
         if (p->OperStatus == IfOperStatusUp) {
         if (p->OperStatus == IfOperStatusUp) {
           // Prefixes are a linked list, in the order Network IP,
           // Prefixes are a linked list, in the order Network IP,
           // Adapter IP, Broadcast IP (plus more).
           // Adapter IP, Broadcast IP (plus more).
@@ -586,6 +588,9 @@ scan_interfaces() {
     PANDA_FREE_ARRAY(addresses);
     PANDA_FREE_ARRAY(addresses);
   }
   }
 
 
+#elif defined(ANDROID)
+  // TODO: implementation using netlink_socket?
+
 #else  // WIN32_VC
 #else  // WIN32_VC
   struct ifaddrs *ifa;
   struct ifaddrs *ifa;
   if (getifaddrs(&ifa) != 0) {
   if (getifaddrs(&ifa) != 0) {

+ 39 - 37
panda/src/pgraph/cullableObject.cxx

@@ -78,11 +78,11 @@ munge_geom(GraphicsStateGuardianBase *gsg,
         nassertr(geom_reader.check_valid(&data_reader), false);
         nassertr(geom_reader.check_valid(&data_reader), false);
       }
       }
 #endif  // _DEBUG
 #endif  // _DEBUG
-      
+
       geom_rendering = geom_reader.get_geom_rendering();
       geom_rendering = geom_reader.get_geom_rendering();
       geom_rendering = _state->get_geom_rendering(geom_rendering);
       geom_rendering = _state->get_geom_rendering(geom_rendering);
       geom_rendering = _modelview_transform->get_geom_rendering(geom_rendering);
       geom_rendering = _modelview_transform->get_geom_rendering(geom_rendering);
-      
+
       if (geom_rendering & Geom::GR_point_bits) {
       if (geom_rendering & Geom::GR_point_bits) {
         if (geom_reader.get_primitive_type() != Geom::PT_points) {
         if (geom_reader.get_primitive_type() != Geom::PT_points) {
           if (singular_points) {
           if (singular_points) {
@@ -92,7 +92,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
         }
         }
       }
       }
     }
     }
-    
+
     GraphicsStateGuardianBase *gsg = traverser->get_gsg();
     GraphicsStateGuardianBase *gsg = traverser->get_gsg();
     int gsg_bits = gsg->get_supported_geom_rendering();
     int gsg_bits = gsg->get_supported_geom_rendering();
     if (!hardware_point_sprites) {
     if (!hardware_point_sprites) {
@@ -115,7 +115,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
       // _munged_data, and might also replace _state.
       // _munged_data, and might also replace _state.
       if (pgraph_cat.is_spam()) {
       if (pgraph_cat.is_spam()) {
         pgraph_cat.spam()
         pgraph_cat.spam()
-          << "munge_points_to_quads() for geometry with bits: " 
+          << "munge_points_to_quads() for geometry with bits: "
           << hex << geom_rendering << ", unsupported: "
           << hex << geom_rendering << ", unsupported: "
           << (unsupported_bits & Geom::GR_point_bits) << dec << "\n";
           << (unsupported_bits & Geom::GR_point_bits) << dec << "\n";
       }
       }
@@ -130,7 +130,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
       // If we have to compute the light vector, we have to animate
       // If we have to compute the light vector, we have to animate
       // the vertices in the CPU--and we have to do it before we call
       // the vertices in the CPU--and we have to do it before we call
       // munge_geom(), which might lose the tangent and binormal.
       // munge_geom(), which might lose the tangent and binormal.
-      CPT(GeomVertexData) animated_vertices = 
+      CPT(GeomVertexData) animated_vertices =
         _munged_data->animate_vertices(force, current_thread);
         _munged_data->animate_vertices(force, current_thread);
       if (animated_vertices != _munged_data) {
       if (animated_vertices != _munged_data) {
         cpu_animated = true;
         cpu_animated = true;
@@ -156,7 +156,7 @@ munge_geom(GraphicsStateGuardianBase *gsg,
       // has been munged--that is, we couldn't arrange to handle the
       // has been munged--that is, we couldn't arrange to handle the
       // animation in hardware--then we have to calculate that
       // animation in hardware--then we have to calculate that
       // animation now.
       // animation now.
-      CPT(GeomVertexData) animated_vertices = 
+      CPT(GeomVertexData) animated_vertices =
         _munged_data->animate_vertices(force, current_thread);
         _munged_data->animate_vertices(force, current_thread);
       if (animated_vertices != _munged_data) {
       if (animated_vertices != _munged_data) {
         cpu_animated = true;
         cpu_animated = true;
@@ -240,7 +240,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
 
 
   // Better get the animated vertices, in case we're showing sprites
   // Better get the animated vertices, in case we're showing sprites
   // on an animated model for some reason.
   // on an animated model for some reason.
-  CPT(GeomVertexData) source_data = 
+  CPT(GeomVertexData) source_data =
     _munged_data->animate_vertices(force, current_thread);
     _munged_data->animate_vertices(force, current_thread);
 
 
   if (!force && !source_data->request_resident()) {
   if (!force && !source_data->request_resident()) {
@@ -308,22 +308,22 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
     FormatMap::iterator fmi = _format_map.find(sformat);
     FormatMap::iterator fmi = _format_map.find(sformat);
     if (fmi != _format_map.end()) {
     if (fmi != _format_map.end()) {
       new_format = (*fmi).second;
       new_format = (*fmi).second;
-      
+
     } else {
     } else {
       // We have to construct the format now.
       // We have to construct the format now.
       PT(GeomVertexArrayFormat) new_array_format;
       PT(GeomVertexArrayFormat) new_array_format;
       if (sformat._retransform_sprites) {
       if (sformat._retransform_sprites) {
         // With retransform_sprites in effect, we will be sending ordinary
         // With retransform_sprites in effect, we will be sending ordinary
         // 3-D points to the graphics API.
         // 3-D points to the graphics API.
-        new_array_format = 
-          new GeomVertexArrayFormat(InternalName::get_vertex(), 3, 
+        new_array_format =
+          new GeomVertexArrayFormat(InternalName::get_vertex(), 3,
                                     Geom::NT_stdfloat,
                                     Geom::NT_stdfloat,
                                     Geom::C_point);
                                     Geom::C_point);
       } else {
       } else {
         // Without retransform_sprites, we will be sending 4-component
         // Without retransform_sprites, we will be sending 4-component
         // clip-space points.
         // clip-space points.
-        new_array_format = 
-          new GeomVertexArrayFormat(InternalName::get_vertex(), 4, 
+        new_array_format =
+          new GeomVertexArrayFormat(InternalName::get_vertex(), 4,
                                     Geom::NT_stdfloat,
                                     Geom::NT_stdfloat,
                                     Geom::C_clip_point);
                                     Geom::C_clip_point);
       }
       }
@@ -344,14 +344,14 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
           (InternalName::get_texcoord(), 2,
           (InternalName::get_texcoord(), 2,
            Geom::NT_stdfloat,
            Geom::NT_stdfloat,
            Geom::C_texcoord);
            Geom::C_texcoord);
-        
+
       } else if (has_texcoord) {
       } else if (has_texcoord) {
         const GeomVertexColumn *c = texcoord.get_column();
         const GeomVertexColumn *c = texcoord.get_column();
         new_array_format->add_column
         new_array_format->add_column
           (InternalName::get_texcoord(), c->get_num_components(),
           (InternalName::get_texcoord(), c->get_num_components(),
            c->get_numeric_type(), c->get_contents());
            c->get_numeric_type(), c->get_contents());
       }
       }
-      
+
       new_format = GeomVertexFormat::register_format(new_array_format);
       new_format = GeomVertexFormat::register_format(new_array_format);
       _format_map[sformat] = new_format;
       _format_map[sformat] = new_format;
     }
     }
@@ -408,7 +408,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
       LPoint3 eye = modelview.xform_point(vertex.get_data3());
       LPoint3 eye = modelview.xform_point(vertex.get_data3());
       points[vi]._eye = eye;
       points[vi]._eye = eye;
       points[vi]._dist = gsg->compute_distance_to(points[vi]._eye);
       points[vi]._dist = gsg->compute_distance_to(points[vi]._eye);
-    
+
       // The point in clip coordinates.
       // The point in clip coordinates.
       LPoint4 p4 = LPoint4(eye[0], eye[1], eye[2], 1.0f) * projection;
       LPoint4 p4 = LPoint4(eye[0], eye[1], eye[2], 1.0f) * projection;
 
 
@@ -433,7 +433,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
           scale_y /= gsg->compute_distance_to(eye);
           scale_y /= gsg->compute_distance_to(eye);
         }
         }
       }
       }
-      
+
       // Also factor in the homogeneous scale for being in clip
       // Also factor in the homogeneous scale for being in clip
       // coordinates still.
       // coordinates still.
       scale_y *= p4[3];
       scale_y *= p4[3];
@@ -447,7 +447,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
       LPoint2 c0(scale_x, scale_y);
       LPoint2 c0(scale_x, scale_y);
       LPoint2 c1(-scale_x, scale_y);
       LPoint2 c1(-scale_x, scale_y);
 
 
-      if (has_rotate) { 
+      if (has_rotate) {
         // If we have a rotate factor, apply it to those two corners.
         // If we have a rotate factor, apply it to those two corners.
         PN_stdfloat r = rotate.get_data1f();
         PN_stdfloat r = rotate.get_data1f();
         LMatrix3 mat = LMatrix3::rotate_mat(r);
         LMatrix3 mat = LMatrix3::rotate_mat(r);
@@ -461,7 +461,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
       PN_stdfloat ry = 1.0f / viewport_height;
       PN_stdfloat ry = 1.0f / viewport_height;
       c0.set(c0[0] * rx, c0[1] * ry);
       c0.set(c0[0] * rx, c0[1] * ry);
       c1.set(c1[0] * rx, c1[1] * ry);
       c1.set(c1[0] * rx, c1[1] * ry);
-    
+
       if (retransform_sprites) {
       if (retransform_sprites) {
         // With retransform_sprites in effect, we must reconvert the
         // With retransform_sprites in effect, we must reconvert the
         // resulting quad back into the original 3-D space.
         // resulting quad back into the original 3-D space.
@@ -469,7 +469,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
         new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3])));
         new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3])));
         new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3])));
         new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3])));
         new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3])));
         new_vertex.set_data4(inv_render_transform.xform(LPoint4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3])));
-      
+
         if (has_normal) {
         if (has_normal) {
           const LNormal &c = normal.get_data3();
           const LNormal &c = normal.get_data3();
           new_normal.set_data3(c);
           new_normal.set_data3(c);
@@ -477,7 +477,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
           new_normal.set_data3(c);
           new_normal.set_data3(c);
           new_normal.set_data3(c);
           new_normal.set_data3(c);
         }
         }
-      
+
       } else {
       } else {
         // Without retransform_sprites, we can simply load the
         // Without retransform_sprites, we can simply load the
         // clip-space coordinates.
         // clip-space coordinates.
@@ -485,7 +485,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
         new_vertex.set_data4(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3]);
         new_vertex.set_data4(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3]);
         new_vertex.set_data4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]);
         new_vertex.set_data4(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]);
         new_vertex.set_data4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]);
         new_vertex.set_data4(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]);
-      
+
         if (has_normal) {
         if (has_normal) {
           LNormal c = render_transform.xform_vec(normal.get_data3());
           LNormal c = render_transform.xform_vec(normal.get_data3());
           new_normal.set_data3(c);
           new_normal.set_data3(c);
@@ -521,18 +521,20 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
     nassertr(new_data->get_num_rows() == new_verts, false);
     nassertr(new_data->get_num_rows() == new_verts, false);
   }
   }
 
 
-  PT(Geom) new_geom = new Geom(new_data);
-    
-  // Create an appropriate GeomVertexArrayFormat for the primitive
-  // index.
-  static CPT(GeomVertexArrayFormat) new_prim_format;
-  if (new_prim_format == (GeomVertexArrayFormat *)NULL) {
-    new_prim_format =
-      GeomVertexArrayFormat::register_format
-      (new GeomVertexArrayFormat(InternalName::get_index(), 1, 
-                                 GeomEnums::NT_uint16, GeomEnums::C_index));
+  // Determine the format we should use to store the indices.
+  const GeomVertexArrayFormat *new_prim_format = NULL;
+  if (new_verts < 0xff) {
+    new_prim_format = GeomPrimitive::get_index_format(GeomEnums::NT_uint8);
+
+  } else if (new_verts < 0xffff) {
+    new_prim_format = GeomPrimitive::get_index_format(GeomEnums::NT_uint16);
+
+  } else {
+    new_prim_format = GeomPrimitive::get_index_format(GeomEnums::NT_uint32);
   }
   }
 
 
+  PT(Geom) new_geom = new Geom(new_data);
+
   // Replace each primitive in the Geom (it's presumably a GeomPoints
   // Replace each primitive in the Geom (it's presumably a GeomPoints
   // primitive, although it might be some other kind of primitive if
   // primitive, although it might be some other kind of primitive if
   // we got here because RenderModeAttrib::M_point is enabled) with a
   // we got here because RenderModeAttrib::M_point is enabled) with a
@@ -575,11 +577,11 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
             vertices[i] = v;
             vertices[i] = v;
           }
           }
         }
         }
-  
+
         // Now sort the points in order from back-to-front so they will
         // Now sort the points in order from back-to-front so they will
         // render properly with transparency, at least with each other.
         // render properly with transparency, at least with each other.
         sort(vertices, vertices_end, SortPoints(points));
         sort(vertices, vertices_end, SortPoints(points));
-  
+
         // Go through the points, now in sorted order, and generate a pair
         // Go through the points, now in sorted order, and generate a pair
         // of triangles for each one.  We generate indexed triangles
         // of triangles for each one.  We generate indexed triangles
         // instead of two-triangle strips, since this seems to be
         // instead of two-triangle strips, since this seems to be
@@ -589,7 +591,7 @@ munge_points_to_quads(const CullTraverser *traverser, bool force) {
         PT(GeomPrimitive) new_primitive = new GeomTriangles(Geom::UH_stream);
         PT(GeomPrimitive) new_primitive = new GeomTriangles(Geom::UH_stream);
         int new_prim_verts = 6 * num_vertices;  // two triangles per point.
         int new_prim_verts = 6 * num_vertices;  // two triangles per point.
 
 
-        PT(GeomVertexArrayData) new_index 
+        PT(GeomVertexArrayData) new_index
           = new GeomVertexArrayData(new_prim_format, GeomEnums::UH_stream);
           = new GeomVertexArrayData(new_prim_format, GeomEnums::UH_stream);
         new_index->unclean_set_num_rows(new_prim_verts);
         new_index->unclean_set_num_rows(new_prim_verts);
 
 
@@ -669,14 +671,14 @@ munge_texcoord_light_vector(const CullTraverser *traverser, bool force) {
       string source_name = tex_gen->get_source_name(stage);
       string source_name = tex_gen->get_source_name(stage);
       Light *light_obj = light.node()->as_light();
       Light *light_obj = light.node()->as_light();
       nassertr(light_obj != (Light *)NULL, false);
       nassertr(light_obj != (Light *)NULL, false);
-      
+
       // Determine the names of the tangent and binormal columns
       // Determine the names of the tangent and binormal columns
       // associated with the stage's texcoord name.
       // associated with the stage's texcoord name.
       PT(InternalName) tangent_name = InternalName::get_tangent_name(source_name);
       PT(InternalName) tangent_name = InternalName::get_tangent_name(source_name);
       PT(InternalName) binormal_name = InternalName::get_binormal_name(source_name);
       PT(InternalName) binormal_name = InternalName::get_binormal_name(source_name);
-      
+
       PT(InternalName) texcoord_name = stage->get_texcoord_name();
       PT(InternalName) texcoord_name = stage->get_texcoord_name();
-      
+
       if (_munged_data->has_column(tangent_name) &&
       if (_munged_data->has_column(tangent_name) &&
           _munged_data->has_column(binormal_name)) {
           _munged_data->has_column(binormal_name)) {
 
 

+ 1 - 1
panda/src/pgraph/lightRampAttrib.cxx

@@ -96,7 +96,7 @@ make_single_threshold(PN_stdfloat thresh0, PN_stdfloat val0) {
 CPT(RenderAttrib) LightRampAttrib::
 CPT(RenderAttrib) LightRampAttrib::
 make_double_threshold(PN_stdfloat thresh0, PN_stdfloat val0, PN_stdfloat thresh1, PN_stdfloat val1) {
 make_double_threshold(PN_stdfloat thresh0, PN_stdfloat val0, PN_stdfloat thresh1, PN_stdfloat val1) {
   LightRampAttrib *attrib = new LightRampAttrib();
   LightRampAttrib *attrib = new LightRampAttrib();
-  attrib->_mode = LRT_single_threshold;
+  attrib->_mode = LRT_double_threshold;
   attrib->_threshold[0] = thresh0;
   attrib->_threshold[0] = thresh0;
   attrib->_level[0] = val0;
   attrib->_level[0] = val0;
   attrib->_threshold[1] = thresh1;
   attrib->_threshold[1] = thresh1;

+ 1 - 1
panda/src/pgraph/transformState.cxx

@@ -2322,7 +2322,7 @@ do_calc_components() {
     _hpr.set(0.0f, 0.0f, 0.0f);
     _hpr.set(0.0f, 0.0f, 0.0f);
     _quat = LQuaternion::ident_quat();
     _quat = LQuaternion::ident_quat();
     _pos.set(0.0f, 0.0f, 0.0f);
     _pos.set(0.0f, 0.0f, 0.0f);
-    _flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale;
+    _flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale | F_identity_scale;
 
 
   } else {
   } else {
     // If we don't have components and we're not identity, the only
     // If we don't have components and we're not identity, the only

+ 3 - 4
panda/src/pgraphnodes/shaderGenerator.cxx

@@ -1180,12 +1180,11 @@ synthesize_shader(const RenderState *rs) {
           PN_stdfloat t1 = light_ramp->get_threshold(1);
           PN_stdfloat t1 = light_ramp->get_threshold(1);
           PN_stdfloat l0 = light_ramp->get_level(0);
           PN_stdfloat l0 = light_ramp->get_level(0);
           PN_stdfloat l1 = light_ramp->get_level(1);
           PN_stdfloat l1 = light_ramp->get_level(1);
-          PN_stdfloat l2 = light_ramp->get_level(2);
           text << "\t // Double-threshold light ramp\n";
           text << "\t // Double-threshold light ramp\n";
           text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
           text << "\t float lr_in = dot(tot_diffuse.rgb, float3(0.33,0.34,0.33));\n";
-          text << "\t float lr_out = " << l0 << "\n";
-          text << "\t if (lr_in > " << t0 << ") lr_out=" << l1 << ";\n";
-          text << "\t if (lr_in > " << t1 << ") lr_out=" << l2 << ";\n";
+          text << "\t float lr_out = 0.0;\n";
+          text << "\t if (lr_in > " << t0 << ") lr_out=" << l0 << ";\n";
+          text << "\t if (lr_in > " << t1 << ") lr_out=" << l1 << ";\n";
           text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
           text << "\t tot_diffuse = tot_diffuse * (lr_out / lr_in);\n";
           break;
           break;
         }
         }

+ 11 - 0
panda/src/pstatclient/config_pstats.cxx

@@ -68,6 +68,17 @@ ConfigVariableDouble pstats_target_frame_rate
           "This frame rate is marked with a different-colored line; "
           "This frame rate is marked with a different-colored line; "
           "otherwise, this setting has no effect."));
           "otherwise, this setting has no effect."));
 
 
+ConfigVariableBool pstats_gpu_timing
+("pstats-gpu-timing", false,
+ PRC_DESC("Set this true to query the graphics library for the actual time "
+          "that graphics operations take to execute on the video card.  "
+          "Enabling this will harm performance, but this information can "
+          "be more useful than the regular Draw information in tracking "
+          "down bottlenecks, because the CPU-based Draw collectors only "
+          "measure how long it takes for the API call to complete, which "
+          "is not usually an accurate reflectino of how long the actual "
+          "operation takes on the video card."));
+
 // The rest are different in that they directly control the server,
 // The rest are different in that they directly control the server,
 // not the client.
 // not the client.
 ConfigVariableBool pstats_scroll_mode
 ConfigVariableBool pstats_scroll_mode

+ 1 - 0
panda/src/pstatclient/config_pstats.h

@@ -38,6 +38,7 @@ extern EXPCL_PANDA_PSTATCLIENT ConfigVariableDouble pstats_tcp_ratio;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableString pstats_host;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableString pstats_host;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableInt pstats_port;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableInt pstats_port;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableDouble pstats_target_frame_rate;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableDouble pstats_target_frame_rate;
+extern EXPCL_PANDA_PSTATCLIENT ConfigVariableBool pstats_gpu_timing;
 
 
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableBool pstats_scroll_mode;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableBool pstats_scroll_mode;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableDouble pstats_history;
 extern EXPCL_PANDA_PSTATCLIENT ConfigVariableDouble pstats_history;

+ 72 - 37
panda/src/pstatclient/pStatClient.cxx

@@ -152,7 +152,7 @@ get_collector_fullname(int index) const {
   if (parent_index == 0) {
   if (parent_index == 0) {
     return collector->get_name();
     return collector->get_name();
   } else {
   } else {
-    return get_collector_fullname(parent_index) + ":" + 
+    return get_collector_fullname(parent_index) + ":" +
       collector->get_name();
       collector->get_name();
   }
   }
 }
 }
@@ -180,7 +180,6 @@ get_main_thread() const {
   return PStatThread((PStatClient *)this, 0);
   return PStatThread((PStatClient *)this, 0);
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PStatClient::get_current_thread
 //     Function: PStatClient::get_current_thread
 //       Access: Published
 //       Access: Published
@@ -191,7 +190,7 @@ get_main_thread() const {
 PStatThread PStatClient::
 PStatThread PStatClient::
 get_current_thread() const {
 get_current_thread() const {
   if (!client_is_connected()) {
   if (!client_is_connected()) {
-    // No need to make the relatively expensive call to 
+    // No need to make the relatively expensive call to
     // Thread::get_current_thread() if we're not even connected.
     // Thread::get_current_thread() if we're not even connected.
     return get_main_thread();
     return get_main_thread();
   }
   }
@@ -222,10 +221,10 @@ main_tick() {
 
 
 
 
     _mmap_size_pcollector.set_level(MemoryUsage::get_panda_mmap_size());
     _mmap_size_pcollector.set_level(MemoryUsage::get_panda_mmap_size());
-    
+
     TypeRegistry *type_reg = TypeRegistry::ptr();
     TypeRegistry *type_reg = TypeRegistry::ptr();
     int num_typehandles = type_reg->get_num_typehandles();
     int num_typehandles = type_reg->get_num_typehandles();
-    
+
     while ((int)type_handle_cols.size() < num_typehandles) {
     while ((int)type_handle_cols.size() < num_typehandles) {
       type_handle_cols.push_back(TypeHandleCollector());
       type_handle_cols.push_back(TypeHandleCollector());
     }
     }
@@ -261,7 +260,7 @@ main_tick() {
         case TypeHandle::MC_limit:
         case TypeHandle::MC_limit:
           // Not used.
           // Not used.
           break;
           break;
-        }          
+        }
       }
       }
     }
     }
     size_t min_usage = (single_total_usage + array_total_usage + dc_active_total_usage + dc_inactive_total_usage) / 1024;
     size_t min_usage = (single_total_usage + array_total_usage + dc_active_total_usage + dc_inactive_total_usage) / 1024;
@@ -288,7 +287,7 @@ main_tick() {
             case TypeHandle::MC_singleton:
             case TypeHandle::MC_singleton:
               category = "Heap:Single";
               category = "Heap:Single";
               break;
               break;
-              
+
             case TypeHandle::MC_array:
             case TypeHandle::MC_array:
               category = "Heap:Array";
               category = "Heap:Array";
               break;
               break;
@@ -315,11 +314,11 @@ main_tick() {
           case TypeHandle::MC_singleton:
           case TypeHandle::MC_singleton:
             single_other_usage -= usage;
             single_other_usage -= usage;
             break;
             break;
-            
+
           case TypeHandle::MC_array:
           case TypeHandle::MC_array:
             array_other_usage -= usage;
             array_other_usage -= usage;
             break;
             break;
-            
+
           case TypeHandle::MC_deleted_chain_active:
           case TypeHandle::MC_deleted_chain_active:
             dc_active_other_usage -= usage;
             dc_active_other_usage -= usage;
             break;
             break;
@@ -348,7 +347,7 @@ main_tick() {
 #endif  // DO_MEMORY_USAGE
 #endif  // DO_MEMORY_USAGE
 
 
   get_global_pstats()->client_main_tick();
   get_global_pstats()->client_main_tick();
-}  
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PStatClient::thread_tick
 //     Function: PStatClient::thread_tick
@@ -359,7 +358,7 @@ main_tick() {
 void PStatClient::
 void PStatClient::
 thread_tick(const string &sync_name) {
 thread_tick(const string &sync_name) {
   get_global_pstats()->client_thread_tick(sync_name);
   get_global_pstats()->client_thread_tick(sync_name);
-}  
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PStatClient::client_main_tick
 //     Function: PStatClient::client_main_tick
@@ -383,8 +382,8 @@ client_main_tick() {
       _threads_by_sync_name.find("Main");
       _threads_by_sync_name.find("Main");
     if (ni != _threads_by_sync_name.end()) {
     if (ni != _threads_by_sync_name.end()) {
       const vector_int &indices = (*ni).second;
       const vector_int &indices = (*ni).second;
-      for (vector_int::const_iterator vi = indices.begin(); 
-           vi != indices.end(); 
+      for (vector_int::const_iterator vi = indices.begin();
+           vi != indices.end();
            ++vi) {
            ++vi) {
         _impl->new_frame(*vi);
         _impl->new_frame(*vi);
       }
       }
@@ -407,8 +406,8 @@ client_thread_tick(const string &sync_name) {
       _threads_by_sync_name.find(sync_name);
       _threads_by_sync_name.find(sync_name);
     if (ni != _threads_by_sync_name.end()) {
     if (ni != _threads_by_sync_name.end()) {
       const vector_int &indices = (*ni).second;
       const vector_int &indices = (*ni).second;
-      for (vector_int::const_iterator vi = indices.begin(); 
-           vi != indices.end(); 
+      for (vector_int::const_iterator vi = indices.begin();
+           vi != indices.end();
            ++vi) {
            ++vi) {
         _impl->new_frame(*vi);
         _impl->new_frame(*vi);
       }
       }
@@ -463,7 +462,7 @@ PStatClient *PStatClient::
 get_global_pstats() {
 get_global_pstats() {
   if (_global_pstats == (PStatClient *)NULL) {
   if (_global_pstats == (PStatClient *)NULL) {
     _global_pstats = new PStatClient;
     _global_pstats = new PStatClient;
-    
+
     ClockObject::_start_clock_wait = start_clock_wait;
     ClockObject::_start_clock_wait = start_clock_wait;
     ClockObject::_start_clock_busy_wait = start_clock_busy_wait;
     ClockObject::_start_clock_busy_wait = start_clock_busy_wait;
     ClockObject::_stop_clock_wait = stop_clock_wait;
     ClockObject::_stop_clock_wait = stop_clock_wait;
@@ -616,8 +615,8 @@ do_make_thread(Thread *thread) {
     // We have seen a thread with this name before.  Can we re-use any
     // We have seen a thread with this name before.  Can we re-use any
     // of them?
     // of them?
     const vector_int &indices = (*ni).second;
     const vector_int &indices = (*ni).second;
-    for (vector_int::const_iterator vi = indices.begin(); 
-         vi != indices.end(); 
+    for (vector_int::const_iterator vi = indices.begin();
+         vi != indices.end();
          ++vi) {
          ++vi) {
       int index = (*vi);
       int index = (*vi);
       nassertr(index >= 0 && index < _num_threads, PStatThread());
       nassertr(index >= 0 && index < _num_threads, PStatThread());
@@ -637,20 +636,26 @@ do_make_thread(Thread *thread) {
   int new_index = _num_threads;
   int new_index = _num_threads;
   thread->set_pstats_index(new_index);
   thread->set_pstats_index(new_index);
   thread->set_pstats_callback(this);
   thread->set_pstats_callback(this);
-  _threads_by_name[thread->get_name()].push_back(new_index);
-  _threads_by_sync_name[thread->get_sync_name()].push_back(new_index);
-        
+
   InternalThread *pthread = new InternalThread(thread);
   InternalThread *pthread = new InternalThread(thread);
   add_thread(pthread);
   add_thread(pthread);
 
 
-  // We need an additional PerThreadData for this thread in all of the
-  // collectors.
-  CollectorPointer *collectors = (CollectorPointer *)_collectors;
-  for (int ci = 0; ci < _num_collectors; ++ci) {
-    Collector *collector = collectors[ci];
-    collector->_per_thread.push_back(PerThreadData());
-    nassertr((int)collector->_per_thread.size() == _num_threads, PStatThread());
-  }
+  return PStatThread(this, new_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PStatClient::make_gpu_thread
+//       Access: Private
+//  Description: Returns a PStatThread representing the GPU.
+//               This is normally called by the GSG only.
+////////////////////////////////////////////////////////////////////
+PStatThread PStatClient::
+make_gpu_thread(const string &name) {
+  ReMutexHolder holder(_lock);
+  int new_index = _num_threads;
+
+  InternalThread *pthread = new InternalThread(name, "GPU");
+  add_thread(pthread);
 
 
   return PStatThread(this, new_index);
   return PStatThread(this, new_index);
 }
 }
@@ -960,7 +965,7 @@ get_level(int collector_index, int thread_index) const {
 //  Description: This function is added as a hook into ClockObject, so
 //  Description: This function is added as a hook into ClockObject, so
 //               that we may time the delay for
 //               that we may time the delay for
 //               ClockObject::wait_until(), used for certain special
 //               ClockObject::wait_until(), used for certain special
-//               clock modes.  
+//               clock modes.
 //
 //
 //               This callback is a hack around the fact that we can't
 //               This callback is a hack around the fact that we can't
 //               let the ClockObject directly create a PStatCollector,
 //               let the ClockObject directly create a PStatCollector,
@@ -977,7 +982,7 @@ start_clock_wait() {
 //  Description: This function is added as a hook into ClockObject, so
 //  Description: This function is added as a hook into ClockObject, so
 //               that we may time the delay for
 //               that we may time the delay for
 //               ClockObject::wait_until(), used for certain special
 //               ClockObject::wait_until(), used for certain special
-//               clock modes.  
+//               clock modes.
 //
 //
 //               This callback is a hack around the fact that we can't
 //               This callback is a hack around the fact that we can't
 //               let the ClockObject directly create a PStatCollector,
 //               let the ClockObject directly create a PStatCollector,
@@ -995,7 +1000,7 @@ start_clock_busy_wait() {
 //  Description: This function is added as a hook into ClockObject, so
 //  Description: This function is added as a hook into ClockObject, so
 //               that we may time the delay for
 //               that we may time the delay for
 //               ClockObject::wait_until(), used for certain special
 //               ClockObject::wait_until(), used for certain special
-//               clock modes.  
+//               clock modes.
 //
 //
 //               This callback is a hack around the fact that we can't
 //               This callback is a hack around the fact that we can't
 //               let the ClockObject directly create a PStatCollector,
 //               let the ClockObject directly create a PStatCollector,
@@ -1051,6 +1056,9 @@ add_collector(PStatClient::Collector *collector) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PStatClient::
 void PStatClient::
 add_thread(PStatClient::InternalThread *thread) {
 add_thread(PStatClient::InternalThread *thread) {
+  _threads_by_name[thread->_name].push_back(_num_threads);
+  _threads_by_sync_name[thread->_sync_name].push_back(_num_threads);
+
   if (_num_threads >= _threads_size) {
   if (_num_threads >= _threads_size) {
     // We need to grow the array.  We have to be careful here, because
     // We need to grow the array.  We have to be careful here, because
     // there might be clients accessing the array right now who are
     // there might be clients accessing the array right now who are
@@ -1071,12 +1079,21 @@ add_thread(PStatClient::InternalThread *thread) {
     // and then no more.)
     // and then no more.)
 
 
     new_threads[_num_threads] = thread;
     new_threads[_num_threads] = thread;
-    AtomicAdjust::inc(_num_threads);
 
 
   } else {
   } else {
     ThreadPointer *threads = (ThreadPointer *)_threads;
     ThreadPointer *threads = (ThreadPointer *)_threads;
     threads[_num_threads] = thread;
     threads[_num_threads] = thread;
-    AtomicAdjust::inc(_num_threads);
+  }
+
+  AtomicAdjust::inc(_num_threads);
+
+  // We need an additional PerThreadData for this thread in all of the
+  // collectors.
+  CollectorPointer *collectors = (CollectorPointer *)_collectors;
+  for (int ci = 0; ci < _num_collectors; ++ci) {
+    Collector *collector = collectors[ci];
+    collector->_per_thread.push_back(PerThreadData());
+    nassertv((int)collector->_per_thread.size() == _num_threads);
   }
   }
 }
 }
 
 
@@ -1148,7 +1165,7 @@ make_def(const PStatClient *client, int this_index) {
   if (_def == (PStatCollectorDef *)NULL) {
   if (_def == (PStatCollectorDef *)NULL) {
     _def = new PStatCollectorDef(this_index, _name);
     _def = new PStatCollectorDef(this_index, _name);
     if (_parent_index != this_index) {
     if (_parent_index != this_index) {
-      const PStatCollectorDef *parent_def = 
+      const PStatCollectorDef *parent_def =
         client->get_collector_def(_parent_index);
         client->get_collector_def(_parent_index);
       _def->set_parent(*parent_def);
       _def->set_parent(*parent_def);
     }
     }
@@ -1157,9 +1174,9 @@ make_def(const PStatClient *client, int this_index) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PStatClient::Collector::make_def
+//     Function: PStatClient::InternalThread::Constructor
 //       Access: Private
 //       Access: Private
-//  Description: Creates the new PStatCollectorDef for this collector.
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PStatClient::InternalThread::
 PStatClient::InternalThread::
 InternalThread(Thread *thread) :
 InternalThread(Thread *thread) :
@@ -1174,4 +1191,22 @@ InternalThread(Thread *thread) :
 {
 {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PStatClient::InternalThread::Constructor
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+PStatClient::InternalThread::
+InternalThread(const string &name, const string &sync_name) :
+  _thread(NULL),
+  _name(name),
+  _sync_name(sync_name),
+  _is_active(false),
+  _frame_number(0),
+  _next_packet(0.0),
+  _thread_active(true),
+  _thread_lock(string("PStatClient::InternalThread ") + name)
+{
+}
+
 #endif // DO_PSTATS
 #endif // DO_PSTATS

+ 5 - 2
panda/src/pstatclient/pStatClient.h

@@ -35,6 +35,7 @@
 class PStatCollector;
 class PStatCollector;
 class PStatCollectorDef;
 class PStatCollectorDef;
 class PStatThread;
 class PStatThread;
+class GraphicsStateGuardian;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : PStatClient
 //       Class : PStatClient
@@ -113,6 +114,7 @@ private:
   PStatThread do_get_current_thread() const;
   PStatThread do_get_current_thread() const;
   PStatThread make_thread(Thread *thread);
   PStatThread make_thread(Thread *thread);
   PStatThread do_make_thread(Thread *thread);
   PStatThread do_make_thread(Thread *thread);
+  PStatThread make_gpu_thread(const string &name);
 
 
   bool is_active(int collector_index, int thread_index) const;
   bool is_active(int collector_index, int thread_index) const;
   bool is_started(int collector_index, int thread_index) const;
   bool is_started(int collector_index, int thread_index) const;
@@ -171,7 +173,7 @@ private:
     INLINE const string &get_name() const;
     INLINE const string &get_name() const;
     INLINE bool is_active() const;
     INLINE bool is_active() const;
     INLINE PStatCollectorDef *get_def(const PStatClient *client, int this_index) const;
     INLINE PStatCollectorDef *get_def(const PStatClient *client, int this_index) const;
-      
+
   private:
   private:
     void make_def(const PStatClient *client, int this_index);
     void make_def(const PStatClient *client, int this_index);
 
 
@@ -201,6 +203,7 @@ private:
   class InternalThread {
   class InternalThread {
   public:
   public:
     InternalThread(Thread *thread);
     InternalThread(Thread *thread);
+    InternalThread(const string &name, const string &sync_name = "Main");
 
 
     WPT(Thread) _thread;
     WPT(Thread) _thread;
     string _name;
     string _name;
@@ -248,6 +251,7 @@ private:
   friend class PStatCollector;
   friend class PStatCollector;
   friend class PStatThread;
   friend class PStatThread;
   friend class PStatClientImpl;
   friend class PStatClientImpl;
+  friend class GraphicsStateGuardian;
 };
 };
 
 
 #include "pStatClient.I"
 #include "pStatClient.I"
@@ -272,4 +276,3 @@ PUBLISHED:
 #endif  // DO_PSTATS
 #endif  // DO_PSTATS
 
 
 #endif
 #endif
-

Vissa filer visades inte eftersom för många filer har ändrats