Vulkan: clamp dynamic line width to supported values

On my Apple M1, MoltenVK reports wide lines are not supported. Trying to
use vkCmdSetLineWidth with any value other than 1.0f will cause MoltenVK
to throw an exception and stop accepting render commands.

I originally tried making this a change in the frontend Context class,
by clamping the value to the supported line width range. But that
approach failed the WebGL conformance tests, because queries of of
GL_LINE_WIDTH must match the value specified by glLineWidth.

OpenGL ES docs state:

    The line width specified by glLineWidth is always returned when
    GL_LINE_WIDTH is queried. Clamping and rounding have no effect on
    the specified value.

Bug: angleproject:7317
Change-Id: I7a3c3454e1483f9124fd70b7e9f2138bd717e1de
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3654264
Auto-Submit: Steven Noonan <steven@valvesoftware.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index 0b0b3f1..8cc172b 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -2470,7 +2470,11 @@
 angle::Result ContextVk::handleDirtyGraphicsDynamicLineWidth(DirtyBits::Iterator *dirtyBitsIterator,
                                                              DirtyBits dirtyBitMask)
 {
-    mRenderPassCommandBuffer->setLineWidth(mState.getLineWidth());
+    // Clamp line width to min/max allowed values. It's not invalid GL to
+    // provide out-of-range line widths, but it _is_ invalid Vulkan.
+    const float lineWidth = gl::clamp(mState.getLineWidth(), mState.getCaps().minAliasedLineWidth,
+                                      mState.getCaps().maxAliasedLineWidth);
+    mRenderPassCommandBuffer->setLineWidth(lineWidth);
     return angle::Result::Continue;
 }
 
diff --git a/src/tests/gl_tests/StateChangeTest.cpp b/src/tests/gl_tests/StateChangeTest.cpp
index dd72bb8..05ff62a 100644
--- a/src/tests/gl_tests/StateChangeTest.cpp
+++ b/src/tests/gl_tests/StateChangeTest.cpp
@@ -8374,6 +8374,44 @@
     ASSERT_GL_NO_ERROR();
 }
 
+// Tests state change for out-of-range value for glLineWidth. The expectation
+// here is primarily that rendering backends do not crash with invalid line
+// width values.
+TEST_P(StateChangeTestES3, LineWidthOutOfRangeDoesntCrash)
+{
+    GLfloat range[2] = {1};
+    glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
+    EXPECT_GL_NO_ERROR();
+
+    constexpr char kVS[] = R"(#version 300 es
+precision highp float;
+void main()
+{
+    gl_Position = vec4(gl_VertexID == 0 ? -1.0 : 1.0, -1.0, 0.0, 1.0);
+})";
+
+    constexpr char kFS[] = R"(#version 300 es
+precision highp float;
+out vec4 colorOut;
+void main()
+{
+    colorOut = vec4(1.0);
+})";
+
+    ANGLE_GL_PROGRAM(program, kVS, kFS);
+    glUseProgram(program);
+
+    glClearColor(0, 0, 0, 1);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glLineWidth(range[1] + 1.0f);
+    glDrawArrays(GL_LINES, 0, 2);
+
+    glFinish();
+
+    ASSERT_GL_NO_ERROR();
+}
+
 // Tests state change for glPolygonOffset.
 TEST_P(StateChangeTestES3, PolygonOffset)
 {