blob: b24afdc4f0ec0393dfec821b4778c4eff30c9a24 [file] [log] [blame]
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// VulkanDescriptorSetTest:
// Various tests related for Vulkan descriptor sets.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/ProgramVk.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
using namespace angle;
namespace
{
class VulkanDescriptorSetTest : public ANGLETest<>
{
protected:
VulkanDescriptorSetTest() {}
void testSetUp() override
{
mMaxSetsPerPool = rx::vk::DynamicDescriptorPool::GetMaxSetsPerPoolForTesting();
mMaxSetsPerPoolMultiplier =
rx::vk::DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting();
}
void testTearDown() override
{
rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(mMaxSetsPerPool);
rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(
mMaxSetsPerPoolMultiplier);
}
static constexpr uint32_t kMaxSetsForTesting = 1;
static constexpr uint32_t kMaxSetsMultiplierForTesting = 1;
void limitMaxSets()
{
rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(kMaxSetsForTesting);
rx::vk::DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(
kMaxSetsMultiplierForTesting);
}
private:
uint32_t mMaxSetsPerPool;
uint32_t mMaxSetsPerPoolMultiplier;
};
// Test atomic counter read.
TEST_P(VulkanDescriptorSetTest, AtomicCounterReadLimitedDescriptorPool)
{
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/42260658
ANGLE_SKIP_TEST_IF(IsD3D11());
// Must be before program creation to limit the descriptor pool sizes when creating the pipeline
// layout.
limitMaxSets();
constexpr char kFS[] =
"#version 310 es\n"
"precision highp float;\n"
"layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
"out highp vec4 my_color;\n"
"void main()\n"
"{\n"
" my_color = vec4(0.0);\n"
" uint a1 = atomicCounter(ac);\n"
" if (a1 == 3u) my_color = vec4(1.0);\n"
"}\n";
ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
glUseProgram(program);
// The initial value of counter 'ac' is 3u.
unsigned int bufferData[3] = {11u, 3u, 1u};
GLBuffer atomicCounterBuffer;
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
for (int i = 0; i < 5; ++i)
{
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
}
}
class VulkanDescriptorSetLayoutDescTest : public ANGLETest<>
{
protected:
VulkanDescriptorSetLayoutDescTest() {}
void testSetUp() override { ANGLETest::testSetUp(); }
void testTearDown() override { ANGLETest::testTearDown(); }
gl::Context *hackContext() const
{
egl::Display *display = static_cast<egl::Display *>(getEGLWindow()->getDisplay());
gl::ContextID contextID = {
static_cast<GLuint>(reinterpret_cast<uintptr_t>(getEGLWindow()->getContext()))};
return display->getContext(contextID);
}
rx::ContextVk *hackANGLE() const
{
// Hack the angle!
return rx::GetImplAs<rx::ContextVk>(hackContext());
}
struct DescriptorSetBinding
{
uint32_t bindingIndex;
VkDescriptorType type;
uint32_t bindingCount;
VkShaderStageFlagBits shaderStage;
};
const std::array<DescriptorSetBinding, 12> mBindings = {{
{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
{2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT},
{3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
{4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_VERTEX_BIT},
{5, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
{6, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT},
{7, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
{8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT},
{9, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
{10, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_VERTEX_BIT},
{11, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
}};
void addBindings(const std::vector<uint32_t> &bindingIndices,
rx::vk::DescriptorSetLayoutDesc *desc)
{
for (uint32_t index : bindingIndices)
{
ASSERT(index < mBindings.size());
const DescriptorSetBinding &binding = mBindings[index];
desc->addBinding(binding.bindingIndex, binding.type, binding.bindingCount,
binding.shaderStage, nullptr);
}
}
rx::vk::DescriptorSetLayoutDesc mDescriptorSetLayoutDesc;
rx::DescriptorSetLayoutCache mDescriptorSetLayoutCache;
};
// Test basic interaction between DescriptorSetLayoutDesc and DescriptorSetLayoutCache
TEST_P(VulkanDescriptorSetLayoutDescTest, Basic)
{
const std::vector<uint32_t> bindingsPattern1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
const std::vector<uint32_t> bindingsPattern2 = {0, 1};
const std::vector<uint32_t> bindingsPattern3 = {0, 1, 5, 9};
angle::Result result;
rx::ContextVk *contextVk = hackANGLE();
rx::vk::DescriptorSetLayoutPtr descriptorSetLayout;
mDescriptorSetLayoutDesc = {};
addBindings(bindingsPattern1, &mDescriptorSetLayoutDesc);
result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
&descriptorSetLayout);
EXPECT_EQ(result, angle::Result::Continue);
EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 1u);
mDescriptorSetLayoutDesc = {};
addBindings(bindingsPattern2, &mDescriptorSetLayoutDesc);
result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
&descriptorSetLayout);
EXPECT_EQ(result, angle::Result::Continue);
EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 2u);
mDescriptorSetLayoutDesc = {};
addBindings(bindingsPattern3, &mDescriptorSetLayoutDesc);
size_t reusedDescHash = mDescriptorSetLayoutDesc.hash();
result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
&descriptorSetLayout);
EXPECT_EQ(result, angle::Result::Continue);
EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 3u);
rx::vk::DescriptorSetLayoutDesc desc;
addBindings(bindingsPattern3, &desc);
size_t newDescHash = desc.hash();
EXPECT_EQ(reusedDescHash, newDescHash);
result =
mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, desc, &descriptorSetLayout);
EXPECT_EQ(result, angle::Result::Continue);
EXPECT_EQ(mDescriptorSetLayoutCache.getCacheHitCount(), 1u);
EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 3u);
descriptorSetLayout.reset();
mDescriptorSetLayoutCache.destroy(contextVk->getRenderer());
}
ANGLE_INSTANTIATE_TEST(VulkanDescriptorSetTest, ES31_VULKAN(), ES31_VULKAN_SWIFTSHADER());
ANGLE_INSTANTIATE_TEST(VulkanDescriptorSetLayoutDescTest, ES31_VULKAN());
} // namespace