Vulkan: Fix texture descriptor set alloc count.

We were reserving half the required descriptor sets for our pool. This
fixes the counting and ensures we won't regress by adding a test.

Also enables the cube map texture sample, and removes an UNIMPLEMENTED
warning that was spurious.

Bug: angleproject:2318

Change-Id: I371cd7c5b42e1ce980cce7bb0ef04885db72b614
Reviewed-on: https://chromium-review.googlesource.com/1014165
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Luc Ferron <lucferron@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/ProgramVk.cpp b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
index 6fb33e0..989232f 100644
--- a/src/libANGLE/renderer/vulkan/ProgramVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
@@ -431,7 +431,8 @@
 
     if (linkedUniform.isSampler())
     {
-        UNIMPLEMENTED();
+        // We could potentially cache some indexing here. For now this is a no-op since the mapping
+        // is handled entirely in ContextVk.
         return;
     }
 
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index dba6875..4261879 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -19,7 +19,7 @@
 namespace
 {
 // TODO(jmadill): Pick non-arbitrary max.
-constexpr uint32_t kDynamicDescriptorPoolMaxSets = 2048;
+constexpr uint32_t kDefaultDynamicDescriptorPoolMaxSets = 2048;
 
 constexpr VkBufferUsageFlags kLineLoopDynamicBufferUsage =
     (VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
@@ -239,7 +239,8 @@
 
 // DynamicDescriptorPool implementation.
 DynamicDescriptorPool::DynamicDescriptorPool()
-    : mCurrentAllocatedDescriptorSetCount(0),
+    : mMaxSetsPerPool(kDefaultDynamicDescriptorPoolMaxSets),
+      mCurrentAllocatedDescriptorSetCount(0),
       mUniformBufferDescriptorsPerSet(0),
       mCombinedImageSamplerDescriptorsPerSet(0)
 {
@@ -274,7 +275,7 @@
     uint32_t descriptorSetCount,
     VkDescriptorSet *descriptorSetsOut)
 {
-    if (descriptorSetCount + mCurrentAllocatedDescriptorSetCount > kDynamicDescriptorPoolMaxSets)
+    if (descriptorSetCount + mCurrentAllocatedDescriptorSetCount > mMaxSetsPerPool)
     {
         RendererVk *renderer = contextVk->getRenderer();
         Serial currentSerial = renderer->getCurrentQueueSerial();
@@ -303,17 +304,16 @@
     VkDescriptorPoolSize poolSizes[DescriptorPoolIndexCount];
     poolSizes[UniformBufferIndex].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
     poolSizes[UniformBufferIndex].descriptorCount =
-        mUniformBufferDescriptorsPerSet * kDynamicDescriptorPoolMaxSets / DescriptorPoolIndexCount;
+        mUniformBufferDescriptorsPerSet * mMaxSetsPerPool;
     poolSizes[TextureIndex].type            = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
-    poolSizes[TextureIndex].descriptorCount = mCombinedImageSamplerDescriptorsPerSet *
-                                              kDynamicDescriptorPoolMaxSets /
-                                              DescriptorPoolIndexCount;
+    poolSizes[TextureIndex].descriptorCount =
+        mCombinedImageSamplerDescriptorsPerSet * mMaxSetsPerPool;
 
     VkDescriptorPoolCreateInfo descriptorPoolInfo;
     descriptorPoolInfo.sType   = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
     descriptorPoolInfo.pNext   = nullptr;
     descriptorPoolInfo.flags   = 0;
-    descriptorPoolInfo.maxSets = kDynamicDescriptorPoolMaxSets;
+    descriptorPoolInfo.maxSets = mMaxSetsPerPool;
 
     // Reserve pools for uniform blocks and textures.
     descriptorPoolInfo.poolSizeCount = DescriptorPoolIndexCount;
@@ -324,6 +324,12 @@
     return NoError();
 }
 
+void DynamicDescriptorPool::setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
+{
+    mMaxSetsPerPool = maxSetsPerPool;
+}
+
+// LineLoopHelper implementation.
 LineLoopHelper::LineLoopHelper()
     : mDynamicIndexBuffer(kLineLoopDynamicBufferUsage, kLineLoopDynamicBufferMinSize)
 {
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
index 3b6c628..09cf845 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
@@ -101,9 +101,13 @@
                                  uint32_t descriptorSetCount,
                                  VkDescriptorSet *descriptorSetsOut);
 
+    // For testing only!
+    void setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool);
+
   private:
     Error allocateNewPool(const VkDevice &device);
 
+    uint32_t mMaxSetsPerPool;
     DescriptorPool mCurrentDescriptorSetPool;
     size_t mCurrentAllocatedDescriptorSetCount;
     uint32_t mUniformBufferDescriptorsPerSet;
diff --git a/src/tests/gl_tests/VulkanUniformUpdatesTest.cpp b/src/tests/gl_tests/VulkanUniformUpdatesTest.cpp
index 854ac37..a4e0003 100644
--- a/src/tests/gl_tests/VulkanUniformUpdatesTest.cpp
+++ b/src/tests/gl_tests/VulkanUniformUpdatesTest.cpp
@@ -28,39 +28,39 @@
 
 class VulkanUniformUpdatesTest : public ANGLETest
 {
+  protected:
+    rx::ContextVk *hackANGLE()
+    {
+        // Hack the angle!
+        const gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
+        return rx::GetImplAs<rx::ContextVk>(context);
+    }
 };
 
 // This test updates a uniform until a new buffer is allocated and then make sure the uniform
 // updates still work.
-TEST_P(VulkanUniformUpdatesTest, UpdateUniformUntilNewBufferIsAllocated)
+TEST_P(VulkanUniformUpdatesTest, UpdateUntilNewBufferIsAllocated)
 {
     ASSERT_TRUE(IsVulkan());
 
-    constexpr char kPositionUniformVertexShader[] = R"(
-precision mediump float;
-attribute vec2 position;
+    constexpr char kPositionUniformVertexShader[] = R"(attribute vec2 position;
 uniform vec2 uniPosModifier;
 void main()
 {
     gl_Position = vec4(position + uniPosModifier, 0, 1);
 })";
 
-    constexpr char kColorUniformFragmentShader[] = R"(
-precision mediump float;
+    constexpr char kColorUniformFragmentShader[] = R"(precision mediump float;
 uniform vec4 uniColor;
 void main()
 {
     gl_FragColor = uniColor;
 })";
 
-    // Hack the angle!
-    const gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
-    auto *contextVk            = rx::GetImplAs<rx::ContextVk>(context);
-
     ANGLE_GL_PROGRAM(program, kPositionUniformVertexShader, kColorUniformFragmentShader);
     glUseProgram(program);
 
-    const gl::State &state   = contextVk->getGLState();
+    const gl::State &state   = hackANGLE()->getGLState();
     rx::ProgramVk *programVk = rx::vk::GetImpl(state.getProgram());
 
     // Set a really small min size so that uniform updates often allocates a new buffer.
@@ -83,6 +83,43 @@
     }
 }
 
+// Force uniform updates until the dynamic descriptor pool wraps into a new pool allocation.
+TEST_P(VulkanUniformUpdatesTest, DescriptorPoolUpdates)
+{
+    ASSERT_TRUE(IsVulkan());
+
+    // Force a small limit on the max sets per pool to more easily trigger a new allocation.
+    constexpr uint32_t kMaxSetsForTesting                = 32;
+    rx::vk::DynamicDescriptorPool *dynamicDescriptorPool = hackANGLE()->getDynamicDescriptorPool();
+    dynamicDescriptorPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
+
+    // Initialize texture program.
+    GLuint program = get2DTexturedQuadProgram();
+    ASSERT_NE(0u, program);
+    glUseProgram(program);
+
+    GLint texLoc = glGetUniformLocation(program, "tex");
+    ASSERT_NE(-1, texLoc);
+
+    // Initialize basic red texture.
+    const std::vector<GLColor> redColors(4, GLColor::red);
+    GLTexture texture;
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, redColors.data());
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    ASSERT_GL_NO_ERROR();
+
+    // Draw multiple times, each iteration will create a new descriptor set.
+    for (uint32_t iteration = 0; iteration < kMaxSetsForTesting * 8; ++iteration)
+    {
+        glUniform1i(texLoc, 0);
+        drawQuad(program, "position", 0.5f, 1.0f, true);
+        swapBuffers();
+        ASSERT_GL_NO_ERROR();
+    }
+}
+
 ANGLE_INSTANTIATE_TEST(VulkanUniformUpdatesTest, ES2_VULKAN());
 
 }  // anonymous namespace