Added PointSprites Support for renderers that do not support Geometry Shaders

Change-Id: Iae9ac5f8fbba68dba5e49ccda7bb7eebb05c8e9a
Reviewed-on: https://chromium-review.googlesource.com/240450
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index e7deac9..5a2a781 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -420,6 +420,22 @@
         }
     }
 
+    // If gl_PointSize is used in the shader then pointsprites rendering is expected.
+    // If the renderer does not support Geometry shaders then Instanced PointSprite emulation
+    // may must be used.
+    bool usesPointSize = sourceShader.find("GL_USES_POINT_SIZE") != std::string::npos;
+    bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
+
+    // Instanced PointSprite emulation requires additional entries in the
+    // VS_INPUT structure to support the vertices that make up the quad vertices.
+    // These values must be in sync with the cooresponding values added during inputlayout creation
+    // in InputLayoutCache::applyVertexBuffers().
+    if (useInstancedPointSpriteEmulation)
+    {
+        structHLSL += "    float3 spriteVertexPos : SPRITEPOSITION0;\n";
+        structHLSL += "    float2 spriteTexCoord : SPRITETEXCOORD0;\n";
+    }
+
     std::string replacementHLSL = "struct VS_INPUT\n"
                                   "{\n" +
                                   structHLSL +
@@ -694,6 +710,7 @@
     bool usesFragCoord = fragmentShader->mUsesFragCoord;
     bool usesPointCoord = fragmentShader->mUsesPointCoord;
     bool usesPointSize = vertexShader->mUsesPointSize;
+    bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
 
     if (usesFragColor && usesFragData)
     {
@@ -720,12 +737,27 @@
     }
 
     const std::string &varyingHLSL = generateVaryingHLSL(vertexShader);
+
+    // Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader VS_OUTPUT
+    // structure to ensure compatibility with the generated PS_INPUT of the pixel shader.
+    // GeometryShader PointSprite emulation does not require this additional entry because the
+    // GS_OUTPUT of the Geometry shader contains the pointCoord value and already matches the PS_INPUT of the
+    // generated pixel shader.
     const SemanticInfo &vertexSemantics = getSemanticInfo(registers, usesFragCoord,
-                                                          false, usesPointSize, false);
+                                                          (useInstancedPointSpriteEmulation && usesPointCoord),
+                                                          usesPointSize, false);
 
     storeUserLinkedVaryings(vertexShader, linkedVaryings);
     storeBuiltinLinkedVaryings(vertexSemantics, linkedVaryings);
 
+    // Instanced PointSprite emulation requires additional entries originally generated in the
+    // GeometryShader HLSL.  These include pointsize clamp values.
+    if (useInstancedPointSpriteEmulation)
+    {
+        vertexHLSL += "static float minPointSize = " + Str((int)mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n"
+                      "static float maxPointSize = " + Str((int)mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n";
+    }
+
     // Add stub string to be replaced when shader is dynamically defined by its layout
     vertexHLSL += "\n" + VERTEX_ATTRIBUTE_STUB_STRING + "\n"
                   "struct VS_OUTPUT\n" + generateVaryingLinkHLSL(vertexSemantics, varyingHLSL) + "\n"
@@ -802,6 +834,22 @@
         }
     }
 
+    // Instanced PointSprite emulation requires additional entries to calculate
+    // the final output vertex positions of the quad that represents each sprite.
+    if (useInstancedPointSpriteEmulation)
+    {
+        vertexHLSL += "\n"
+                      "    gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n"
+                      "    output.dx_Position.xyz += float3(input.spriteVertexPos.x * gl_PointSize / (dx_ViewCoords.x*2), input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2), input.spriteVertexPos.z) * output.dx_Position.w;\n"
+                      "    output.gl_PointSize = gl_PointSize;\n";
+
+        if (usesPointCoord)
+        {
+            vertexHLSL += "\n"
+                          "    output.gl_PointCoord = input.spriteTexCoord;\n";
+        }
+    }
+
     vertexHLSL += "\n"
                   "    return output;\n"
                   "}\n";