1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // VulkanDescriptorSetTest:
7 // Various tests related for Vulkan descriptor sets.
8 //
9
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Display.h"
15 #include "libANGLE/angletypes.h"
16 #include "libANGLE/renderer/vulkan/ContextVk.h"
17 #include "libANGLE/renderer/vulkan/ProgramVk.h"
18 #include "libANGLE/renderer/vulkan/vk_helpers.h"
19
20 using namespace angle;
21
22 namespace
23 {
24
25 class VulkanDescriptorSetTest : public ANGLETest<>
26 {
27 protected:
VulkanDescriptorSetTest()28 VulkanDescriptorSetTest() {}
29
testSetUp()30 void testSetUp() override
31 {
32 mMaxSetsPerPool = rx::vk::DynamicDescriptorPool::GetMaxSetsPerPoolForTesting();
33 mMaxSetsPerPoolMultiplier =
34 rx::vk::DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting();
35 }
36
testTearDown()37 void testTearDown() override
38 {
39 rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(mMaxSetsPerPool);
40 rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(
41 mMaxSetsPerPoolMultiplier);
42 }
43
44 static constexpr uint32_t kMaxSetsForTesting = 1;
45 static constexpr uint32_t kMaxSetsMultiplierForTesting = 1;
46
limitMaxSets()47 void limitMaxSets()
48 {
49 rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(kMaxSetsForTesting);
50 rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(
51 kMaxSetsMultiplierForTesting);
52 }
53
54 private:
55 uint32_t mMaxSetsPerPool;
56 uint32_t mMaxSetsPerPoolMultiplier;
57 };
58
59 // Test atomic counter read.
TEST_P(VulkanDescriptorSetTest,AtomicCounterReadLimitedDescriptorPool)60 TEST_P(VulkanDescriptorSetTest, AtomicCounterReadLimitedDescriptorPool)
61 {
62 // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
63 // http://anglebug.com/42260658
64 ANGLE_SKIP_TEST_IF(IsD3D11());
65
66 // Must be before program creation to limit the descriptor pool sizes when creating the pipeline
67 // layout.
68 limitMaxSets();
69
70 constexpr char kFS[] =
71 "#version 310 es\n"
72 "precision highp float;\n"
73 "layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
74 "out highp vec4 my_color;\n"
75 "void main()\n"
76 "{\n"
77 " my_color = vec4(0.0);\n"
78 " uint a1 = atomicCounter(ac);\n"
79 " if (a1 == 3u) my_color = vec4(1.0);\n"
80 "}\n";
81
82 ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
83
84 glUseProgram(program);
85
86 // The initial value of counter 'ac' is 3u.
87 unsigned int bufferData[3] = {11u, 3u, 1u};
88 GLBuffer atomicCounterBuffer;
89 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
90 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
91
92 for (int i = 0; i < 5; ++i)
93 {
94 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
95 drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
96 ASSERT_GL_NO_ERROR();
97 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
98 }
99 }
100
101 class VulkanDescriptorSetLayoutDescTest : public ANGLETest<>
102 {
103 protected:
VulkanDescriptorSetLayoutDescTest()104 VulkanDescriptorSetLayoutDescTest() {}
105
testSetUp()106 void testSetUp() override { ANGLETest::testSetUp(); }
107
testTearDown()108 void testTearDown() override { ANGLETest::testTearDown(); }
109
hackContext() const110 gl::Context *hackContext() const
111 {
112 egl::Display *display = static_cast<egl::Display *>(getEGLWindow()->getDisplay());
113 gl::ContextID contextID = {
114 static_cast<GLuint>(reinterpret_cast<uintptr_t>(getEGLWindow()->getContext()))};
115 return display->getContext(contextID);
116 }
117
hackANGLE() const118 rx::ContextVk *hackANGLE() const
119 {
120 // Hack the angle!
121 return rx::GetImplAs<rx::ContextVk>(hackContext());
122 }
123
124 struct DescriptorSetBinding
125 {
126 uint32_t bindingIndex;
127 VkDescriptorType type;
128 uint32_t bindingCount;
129 VkShaderStageFlagBits shaderStage;
130 };
131
132 const std::array<DescriptorSetBinding, 12> mBindings = {{
133 {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT},
134 {1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
135 {2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT},
136 {3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
137 {4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_VERTEX_BIT},
138 {5, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
139 {6, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT},
140 {7, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
141 {8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT},
142 {9, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
143 {10, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_VERTEX_BIT},
144 {11, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
145 }};
146
addBindings(const std::vector<uint32_t> & bindingIndices,rx::vk::DescriptorSetLayoutDesc * desc)147 void addBindings(const std::vector<uint32_t> &bindingIndices,
148 rx::vk::DescriptorSetLayoutDesc *desc)
149 {
150 for (uint32_t index : bindingIndices)
151 {
152 ASSERT(index < mBindings.size());
153 const DescriptorSetBinding &binding = mBindings[index];
154 desc->addBinding(binding.bindingIndex, binding.type, binding.bindingCount,
155 binding.shaderStage, nullptr);
156 }
157 }
158
159 rx::vk::DescriptorSetLayoutDesc mDescriptorSetLayoutDesc;
160 rx::DescriptorSetLayoutCache mDescriptorSetLayoutCache;
161 };
162
163 // Test basic interaction between DescriptorSetLayoutDesc and DescriptorSetLayoutCache
TEST_P(VulkanDescriptorSetLayoutDescTest,Basic)164 TEST_P(VulkanDescriptorSetLayoutDescTest, Basic)
165 {
166 const std::vector<uint32_t> bindingsPattern1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
167 const std::vector<uint32_t> bindingsPattern2 = {0, 1};
168 const std::vector<uint32_t> bindingsPattern3 = {0, 1, 5, 9};
169
170 angle::Result result;
171 rx::ContextVk *contextVk = hackANGLE();
172 rx::vk::DescriptorSetLayoutPtr descriptorSetLayout;
173
174 mDescriptorSetLayoutDesc = {};
175 addBindings(bindingsPattern1, &mDescriptorSetLayoutDesc);
176 result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
177 &descriptorSetLayout);
178 EXPECT_EQ(result, angle::Result::Continue);
179 EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 1u);
180
181 mDescriptorSetLayoutDesc = {};
182 addBindings(bindingsPattern2, &mDescriptorSetLayoutDesc);
183 result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
184 &descriptorSetLayout);
185 EXPECT_EQ(result, angle::Result::Continue);
186 EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 2u);
187
188 mDescriptorSetLayoutDesc = {};
189 addBindings(bindingsPattern3, &mDescriptorSetLayoutDesc);
190 size_t reusedDescHash = mDescriptorSetLayoutDesc.hash();
191 result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
192 &descriptorSetLayout);
193 EXPECT_EQ(result, angle::Result::Continue);
194 EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 3u);
195
196 rx::vk::DescriptorSetLayoutDesc desc;
197 addBindings(bindingsPattern3, &desc);
198 size_t newDescHash = desc.hash();
199 EXPECT_EQ(reusedDescHash, newDescHash);
200
201 result =
202 mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, desc, &descriptorSetLayout);
203 EXPECT_EQ(result, angle::Result::Continue);
204 EXPECT_EQ(mDescriptorSetLayoutCache.getCacheHitCount(), 1u);
205 EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 3u);
206
207 descriptorSetLayout.reset();
208 mDescriptorSetLayoutCache.destroy(contextVk->getRenderer());
209 }
210
211 ANGLE_INSTANTIATE_TEST(VulkanDescriptorSetTest, ES31_VULKAN(), ES31_VULKAN_SWIFTSHADER());
212 ANGLE_INSTANTIATE_TEST(VulkanDescriptorSetLayoutDescTest, ES31_VULKAN());
213
214 } // namespace
215