Test interaction of image_view_min_lod, robustness2 and gather
This commits adds a new set of tests that verify texture gather
operations interact correctly with robustness2 and image_view_min_lod.
Specifically, texture gathering always retrieves pixel values from the
base level, and image_view_min_lod may not make that level available on
the sampled texture. With robustness2, reading from those texels should
result in zeros.
New tests:
dEQP-VK.texture.mipmap.min_lod_gather.*
Components: Vulkan
VK-GL-CTS issue: 3808
Change-Id: Id6e5fe445e45e75bb419bebe0da59ea22cf452d9
diff --git a/android/cts/main/vk-master-2022-03-01/texture.txt b/android/cts/main/vk-master-2022-03-01/texture.txt
index 54722fc..7b80066 100644
--- a/android/cts/main/vk-master-2022-03-01/texture.txt
+++ b/android/cts/main/vk-master-2022-03-01/texture.txt
@@ -4467,6 +4467,14 @@
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.nearest_linear_integer_texel_coord
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.linear_linear
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.linear_linear_integer_texel_coord
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_0
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_1
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_2
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_3
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_0
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_1
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_2
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_3
dEQP-VK.texture.filtering_anisotropy.single_level.anisotropy_2.mag_nearest_min_nearest
dEQP-VK.texture.filtering_anisotropy.single_level.anisotropy_2.mag_linear_min_nearest
dEQP-VK.texture.filtering_anisotropy.single_level.anisotropy_2.mag_nearest_min_linear
diff --git a/android/cts/main/vk-master/texture.txt b/android/cts/main/vk-master/texture.txt
index 87f4530..7faf0a4 100644
--- a/android/cts/main/vk-master/texture.txt
+++ b/android/cts/main/vk-master/texture.txt
@@ -12166,6 +12166,14 @@
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.nearest_linear_integer_texel_coord
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.linear_linear
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.linear_linear_integer_texel_coord
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_0
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_1
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_2
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_3
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_0
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_1
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_2
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_3
dEQP-VK.texture.filtering_anisotropy.basic.anisotropy_2.mag_nearest_min_nearest
dEQP-VK.texture.filtering_anisotropy.basic.anisotropy_2.mag_linear_min_nearest
dEQP-VK.texture.filtering_anisotropy.basic.anisotropy_2.mag_nearest_min_linear
diff --git a/external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.cpp b/external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.cpp
index a7ba7bf..9650f50 100644
--- a/external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.cpp
+++ b/external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.cpp
@@ -35,9 +35,20 @@
#include "tcuTexLookupVerifier.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorUtil.hpp"
+#include "tcuCommandLine.hpp"
#include "vkImageUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkImageWithMemory.hpp"
+#include "vkBufferWithMemory.hpp"
+#include "vkObjUtil.hpp"
+#include "vkCmdUtil.hpp"
+#include "vkBarrierUtil.hpp"
+#include "vkBuilderUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktTextureTestUtil.hpp"
+#include "vktCustomInstancesDevices.hpp"
+
+#include <memory>
using namespace vk;
@@ -2131,7 +2142,7 @@
if (m_params.testType == util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD_INT_TEX_COORD)
return new Texture2DImageViewMinLodIntTexCoordTestInstance(context, m_params);
else
- return new Texture2DImageViewMinLodBaseLevelIntTexCoordTestInstance(context, m_params);
+ return new Texture2DImageViewMinLodBaseLevelIntTexCoordTestInstance(context, m_params);
}
class Texture3DImageViewMinLodIntTexCoordTestInstance : public Texture3DLodControlTestInstance
@@ -2311,6 +2322,540 @@
return new Texture3DImageViewMinLodBaseLevelIntTexCoordTestInstance(context, m_params);
}
+// Texture gather tests.
+enum class GatherMinLod
+{
+ MINLOD_0_1, // 0.1
+ MINLOD_1_1, // 1.1
+};
+
+struct GatherParams
+{
+ uint32_t randomSeed; // Seed for the pseudorandom number generator.
+ GatherMinLod minLod; // Idea: make it 0.1 or 1.1
+ int component; // 0, 1, 2, 3 for the gather operation.
+
+ float getNumericMinLod (void) const
+ {
+ float lod = 0.0f;
+
+ switch (minLod)
+ {
+ case GatherMinLod::MINLOD_0_1: lod = 0.1f; break;
+ case GatherMinLod::MINLOD_1_1: lod = 1.1f; break;
+ default: DE_ASSERT(false); break;
+ }
+
+ return lod;
+ }
+
+ uint32_t getMinLodInteger (void) const
+ {
+ uint32_t lod = 0u;
+
+ switch (minLod)
+ {
+ case GatherMinLod::MINLOD_0_1: lod = 0u; break;
+ case GatherMinLod::MINLOD_1_1: lod = 1u; break;
+ default: DE_ASSERT(false); break;
+ }
+
+ return lod;
+ }
+
+ bool needsRobustness2 (void) const
+ {
+ return (getNumericMinLod() >= 1.0f);
+ }
+};
+
+class TextureGatherMinLodTest : public vkt::TestCase
+{
+public:
+ TextureGatherMinLodTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const GatherParams& params)
+ : vkt::TestCase (testCtx, name, description)
+ , m_params (params)
+ {}
+ virtual ~TextureGatherMinLodTest (void) {}
+
+ void initPrograms (vk::SourceCollections& programCollection) const override;
+ TestInstance* createInstance (Context& context) const override;
+ void checkSupport (Context& context) const override;
+
+protected:
+ GatherParams m_params;
+};
+
+class TextureGatherMinLodInstance : public vkt::TestInstance
+{
+public:
+ TextureGatherMinLodInstance (Context& context, const GatherParams& params)
+ : vkt::TestInstance (context)
+ , m_params (params)
+ {}
+ virtual ~TextureGatherMinLodInstance (void) {}
+
+ tcu::TestStatus iterate (void) override;
+
+protected:
+ GatherParams m_params;
+};
+
+// Test idea: create texture with 3 levels, each of them having a unique nonzero color. Render gathering the color from a fixed
+// position in that texture (center point). Use the minLod parameter when creating the view to control which one should be the
+// output color. If minLod is 0.1, minLodInteger should be 0 and gathering from the base level is defined, so we should get the
+// output color from the base level. If minLod is 1.1, gathering texels from the base level requires robustness2 and will result in
+// zeros instead of the color from levels 0 or 1.
+void TextureGatherMinLodTest::initPrograms (vk::SourceCollections &programCollection) const
+{
+ // Full screen triangle covering the whole viewport.
+ std::ostringstream vert;
+ vert
+ << "#version 450\n"
+ << "\n"
+ << "vec2 positions[3] = vec2[](\n"
+ << " vec2(-1.0, -1.0),\n"
+ << " vec2(3.0, -1.0),\n"
+ << " vec2(-1.0, 3.0)\n"
+ << ");\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);\n"
+ << "}\n"
+ ;
+ programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
+
+ std::ostringstream frag;
+ frag
+ << "#version 450\n"
+ << "\n"
+ << "layout (location=0) out vec4 outColor;\n"
+ << "layout (set=0, binding=0) uniform sampler2D u_sampler;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const vec2 gatherCoords = vec2(0.5, 0.5);\n"
+ << " const vec4 gatherRes = textureGather(u_sampler, gatherCoords, " << m_params.component << ");\n"
+ << " outColor = vec4(gatherRes.xyz, 1.0);\n"
+ << "}\n";
+ ;
+ programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
+}
+
+void TextureGatherMinLodTest::checkSupport (Context& context) const
+{
+ context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
+ context.requireDeviceFunctionality("VK_EXT_image_view_min_lod");
+
+ if (m_params.needsRobustness2())
+ {
+ context.requireDeviceFunctionality("VK_EXT_robustness2");
+
+ VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = initVulkanStructure();
+ VkPhysicalDeviceFeatures2 features2 = initVulkanStructure(&robustness2Features);
+
+ context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
+
+ if (robustness2Features.robustImageAccess2 == DE_FALSE)
+ TCU_THROW(NotSupportedError, "robustImageAccess2 not supported");
+ }
+}
+
+TestInstance* TextureGatherMinLodTest::createInstance (Context& context) const
+{
+ return new TextureGatherMinLodInstance(context, m_params);
+}
+
+// Device helper: this is needed because we sometimes need a custom device with robustImageAccess2.
+class DeviceHelper
+{
+public:
+ virtual ~DeviceHelper () {}
+ virtual const DeviceInterface& getDeviceInterface (void) const = 0;
+ virtual VkDevice getDevice (void) const = 0;
+ virtual uint32_t getQueueFamilyIndex (void) const = 0;
+ virtual VkQueue getQueue (void) const = 0;
+ virtual Allocator& getAllocator (void) const = 0;
+};
+
+// This one just reuses the default device from the context.
+class ContextDeviceHelper : public DeviceHelper
+{
+public:
+ ContextDeviceHelper (Context& context)
+ : m_deviceInterface (context.getDeviceInterface())
+ , m_device (context.getDevice())
+ , m_queueFamilyIndex (context.getUniversalQueueFamilyIndex())
+ , m_queue (context.getUniversalQueue())
+ , m_allocator (context.getDefaultAllocator())
+ {}
+
+ virtual ~ContextDeviceHelper () {}
+
+ const DeviceInterface& getDeviceInterface (void) const override { return m_deviceInterface; }
+ VkDevice getDevice (void) const override { return m_device; }
+ uint32_t getQueueFamilyIndex (void) const override { return m_queueFamilyIndex; }
+ VkQueue getQueue (void) const override { return m_queue; }
+ Allocator& getAllocator (void) const override { return m_allocator; }
+
+protected:
+ const DeviceInterface& m_deviceInterface;
+ const VkDevice m_device;
+ const uint32_t m_queueFamilyIndex;
+ const VkQueue m_queue;
+ Allocator& m_allocator;
+};
+
+// This one creates a new device with robustImageAccess2.
+class RobustImageAccess2DeviceHelper : public DeviceHelper
+{
+public:
+ RobustImageAccess2DeviceHelper (Context& context)
+ {
+ const auto& vkp = context.getPlatformInterface();
+ const auto& vki = context.getInstanceInterface();
+ const auto instance = context.getInstance();
+ const auto physicalDevice = context.getPhysicalDevice();
+ const auto queuePriority = 1.0f;
+
+ // Queue index first.
+ m_queueFamilyIndex = context.getUniversalQueueFamilyIndex();
+
+ // Create a universal queue that supports graphics and compute.
+ const VkDeviceQueueCreateInfo queueParams =
+ {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ 0u, // VkDeviceQueueCreateFlags flags;
+ m_queueFamilyIndex, // deUint32 queueFamilyIndex;
+ 1u, // deUint32 queueCount;
+ &queuePriority // const float* pQueuePriorities;
+ };
+
+ const char* extensions[] =
+ {
+ "VK_EXT_robustness2",
+ };
+
+ VkPhysicalDeviceImageViewMinLodFeaturesEXT minLodfeatures = initVulkanStructure();
+ VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = initVulkanStructure(&minLodfeatures);
+ VkPhysicalDeviceFeatures2 features2 = initVulkanStructure(&robustness2Features);
+
+ vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
+
+ const VkDeviceCreateInfo deviceCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType;
+ &features2, //pNext;
+ 0u, //flags
+ 1u, //queueRecordCount;
+ &queueParams, //pRequestedQueues;
+ 0u, //layerCount;
+ nullptr, //ppEnabledLayerNames;
+ static_cast<uint32_t>(de::arrayLength(extensions)), // deUint32 enabledExtensionCount;
+ extensions, // const char* const* ppEnabledExtensionNames;
+ nullptr, //pEnabledFeatures;
+ };
+
+ m_device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki, physicalDevice, &deviceCreateInfo);
+ m_vkd .reset(new DeviceDriver(vkp, instance, m_device.get()));
+ m_queue = getDeviceQueue(*m_vkd, *m_device, m_queueFamilyIndex, 0u);
+ m_allocator .reset(new SimpleAllocator(*m_vkd, m_device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
+ }
+
+ virtual ~RobustImageAccess2DeviceHelper () {}
+
+ const DeviceInterface& getDeviceInterface (void) const override { return *m_vkd; }
+ VkDevice getDevice (void) const override { return m_device.get(); }
+ uint32_t getQueueFamilyIndex (void) const override { return m_queueFamilyIndex; }
+ VkQueue getQueue (void) const override { return m_queue; }
+ Allocator& getAllocator (void) const override { return *m_allocator; }
+
+protected:
+ Move<VkDevice> m_device;
+ std::unique_ptr<DeviceDriver> m_vkd;
+ deUint32 m_queueFamilyIndex;
+ VkQueue m_queue;
+ std::unique_ptr<SimpleAllocator> m_allocator;
+};
+
+std::unique_ptr<DeviceHelper> g_robustness2DeviceHelper;
+std::unique_ptr<DeviceHelper> g_contextDeviceHelper;
+
+DeviceHelper& getDeviceHelper (Context& context, bool needsRobustness2)
+{
+ if (needsRobustness2)
+ {
+ if (!g_robustness2DeviceHelper)
+ g_robustness2DeviceHelper.reset(new RobustImageAccess2DeviceHelper(context));
+ return *g_robustness2DeviceHelper;
+ }
+
+ if (!g_contextDeviceHelper)
+ g_contextDeviceHelper.reset(new ContextDeviceHelper(context));
+ return *g_contextDeviceHelper;
+}
+
+// Cleanup function for the test group.
+void destroyDeviceHelpers (tcu::TestCaseGroup*)
+{
+ g_robustness2DeviceHelper.reset(nullptr);
+ g_contextDeviceHelper.reset(nullptr);
+}
+
+tcu::TestStatus TextureGatherMinLodInstance::iterate (void)
+{
+ const auto& deviceHelper = getDeviceHelper(m_context, m_params.needsRobustness2());
+ const auto& vkd = deviceHelper.getDeviceInterface();
+ const auto device = deviceHelper.getDevice();
+ const auto queueIndex = deviceHelper.getQueueFamilyIndex();
+ const auto queue = deviceHelper.getQueue();
+ auto& alloc = deviceHelper.getAllocator();
+
+ const auto imageFormat = VK_FORMAT_R8G8B8A8_UNORM;
+ const auto tcuFormat = mapVkFormat(imageFormat);
+ const auto colorExtent = makeExtent3D(1u, 1u, 1u);
+ const tcu::IVec3 iColorExtent (static_cast<int>(colorExtent.width), static_cast<int>(colorExtent.height), static_cast<int>(colorExtent.depth));
+ const auto texExtent = makeExtent3D(8u, 8u, 1u);
+ const auto texMipLevels = 3u;
+ const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
+ const auto texUsage = (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
+ const auto minLodF = m_params.getNumericMinLod();
+ const auto minLodU = m_params.getMinLodInteger();
+ const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
+
+ // Color attachment: a simple 1x1 image.
+ const VkImageCreateInfo colorCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ nullptr, // const void* pNext;
+ 0u, // VkImageCreateFlags flags;
+ VK_IMAGE_TYPE_2D, // VkImageType imageType;
+ imageFormat, // VkFormat format;
+ colorExtent, // VkExtent3D extent;
+ 1u, // uint32_t mipLevels;
+ 1u, // uint32_t arrayLayers;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
+ colorUsage, // VkImageUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 0u, // uint32_t queueFamilyIndexCount;
+ nullptr, // const uint32_t* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
+ };
+
+ ImageWithMemory colorBuffer (vkd, device, alloc, colorCreateInfo, MemoryRequirement::Any);
+ const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+ const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
+ const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
+
+ // Texture: an 8x8 image with several mip levels.
+ const VkImageCreateInfo texCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ nullptr, // const void* pNext;
+ 0u, // VkImageCreateFlags flags;
+ VK_IMAGE_TYPE_2D, // VkImageType imageType;
+ imageFormat, // VkFormat format;
+ texExtent, // VkExtent3D extent;
+ texMipLevels, // uint32_t mipLevels;
+ 1u, // uint32_t arrayLayers;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
+ texUsage, // VkImageUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 0u, // uint32_t queueFamilyIndexCount;
+ nullptr, // const uint32_t* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
+ };
+
+ ImageWithMemory texture (vkd, device, alloc, texCreateInfo, MemoryRequirement::Any);
+ const auto texSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, texMipLevels, 0u, 1u);
+
+ DE_ASSERT(texMipLevels > 0u);
+ DE_ASSERT(minLodU < texMipLevels);
+
+ const VkImageViewMinLodCreateInfoEXT texMinLodInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT, // VkStructureType sType;
+ nullptr, // const void* pNext;
+ minLodF, // float minLod;
+ };
+
+ const VkImageViewCreateInfo texViewCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
+ &texMinLodInfo, // const void* pNext;
+ 0u, // VkImageViewCreateFlags flags;
+ texture.get(), // VkImage image;
+ VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
+ imageFormat, // VkFormat format;
+ makeComponentMappingRGBA(), // VkComponentMapping components;
+ texSRR, // VkImageSubresourceRange subresourceRange;
+ };
+
+ const auto texView = createImageView(vkd, device, &texViewCreateInfo);
+
+ // Verification buffer for the color attachment.
+ const auto verifBufferSize = static_cast<VkDeviceSize>(iColorExtent.x() * iColorExtent.y() * iColorExtent.z() * tcu::getPixelSize(tcuFormat));
+ const auto verifBufferCreateInfo = makeBufferCreateInfo(verifBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+ BufferWithMemory verifBuffer (vkd, device, alloc, verifBufferCreateInfo, MemoryRequirement::HostVisible);
+ auto& verifBufferAlloc = verifBuffer.getAllocation();
+ void* verifBufferData = verifBufferAlloc.getHostPtr();
+
+ // Descriptor set layout.
+ DescriptorSetLayoutBuilder setLayoutBuilder;
+ setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
+ const auto setLayout = setLayoutBuilder.build(vkd, device);
+
+ // Pipeline layout.
+ const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
+
+ // Sampler.
+ const VkSamplerCreateInfo samplerCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
+ nullptr, // const void* pNext;
+ 0u, // VkSamplerCreateFlags flags;
+ VK_FILTER_LINEAR, // VkFilter magFilter;
+ VK_FILTER_LINEAR, // VkFilter minFilter;
+ VK_SAMPLER_MIPMAP_MODE_LINEAR, // VkSamplerMipmapMode mipmapMode;
+ VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeU;
+ VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeV;
+ VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeW;
+ 0.0f, // float mipLodBias;
+ VK_FALSE, // VkBool32 anisotropyEnable;
+ 0.0f, // float maxAnisotropy;
+ VK_FALSE, // VkBool32 compareEnable;
+ VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
+ 0.0f, // float minLod;
+ static_cast<float>(texMipLevels), // float maxLod;
+ VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
+ VK_FALSE, // VkBool32 unnormalizedCoordinates;
+ };
+ const auto sampler = createSampler(vkd, device, &samplerCreateInfo);
+
+ // Descriptor pool and set.
+ DescriptorPoolBuilder poolBuilder;
+ poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
+ const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+ const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
+
+ // Update descriptor set.
+ DescriptorSetUpdateBuilder setUpdateBuilder;
+ const auto combinedSamplerInfo = makeDescriptorImageInfo(sampler.get(), texView.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ setUpdateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &combinedSamplerInfo);
+ setUpdateBuilder.update(vkd, device);
+
+ // Render pass and framebuffer.
+ const auto renderPass = makeRenderPass(vkd, device, imageFormat);
+ const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), colorExtent.width, colorExtent.height);
+
+ // Shader modules.
+ const auto& binaries = m_context.getBinaryCollection();
+ const auto vertModule = createShaderModule(vkd, device, binaries.get("vert"));
+ const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"));
+
+ // Viewports and scissors.
+ std::vector<VkViewport> viewports (1u, makeViewport(colorExtent));
+ std::vector<VkRect2D> scissors (1u, makeRect2D(colorExtent));
+
+ // Pipeline.
+ const VkPipelineVertexInputStateCreateInfo vertexInputState = initVulkanStructure();
+
+ const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
+ vertModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(),
+ renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ 0u/*subpass*/, 0u/*patchControlPoints*/, &vertexInputState);
+
+ // Command pool and buffer.
+ const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
+ const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+ const auto cmdBuffer = cmdBufferPtr.get();
+
+ beginCommandBuffer(vkd, cmdBuffer);
+
+ // Move the whole texture to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
+ const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture.get(), texSRR);
+ cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier);
+
+ // Fill each texture mip level with a different pseudorandom nonzero color.
+ std::vector<tcu::Vec4> levelColors;
+ de::Random rnd (m_params.randomSeed);
+
+ levelColors.reserve(texMipLevels);
+
+ const auto minColor = 0.004f; // Slightly above 1/255.
+ const auto maxColor = 1.0f;
+
+ for (uint32_t level = 0u; level < texMipLevels; ++level)
+ {
+ const auto r = rnd.getFloat(minColor, maxColor);
+ const auto g = rnd.getFloat(minColor, maxColor);
+ const auto b = rnd.getFloat(minColor, maxColor);
+ const auto a = rnd.getFloat(minColor, maxColor);
+ const auto levelColor = makeClearValueColorF32(r, g, b, a).color;
+ const auto levelRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, level, 1u, 0u, 1u);
+
+ levelColors.emplace_back(r, g, b, a);
+ vkd.cmdClearColorImage(cmdBuffer, texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &levelColor, 1u, &levelRange);
+ }
+
+ // Move the whole texture to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+ const auto postClearBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, texture.get(), texSRR);
+ cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, &postClearBarrier);
+
+ beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
+ vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
+ vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
+ vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u); // This has to match the vertex shader.
+ endRenderPass(vkd, cmdBuffer);
+
+ // Copy color buffer to verification buffer.
+ const auto postColorBarier = makeImageMemoryBarrier(
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ colorBuffer.get(), colorSRR);
+ cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &postColorBarier);
+
+ const auto copyRegion = makeBufferImageCopy(colorExtent, colorSRL);
+ vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u, ©Region);
+
+ const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
+ cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
+
+ endCommandBuffer(vkd, cmdBuffer);
+ submitCommandsAndWait(vkd, device, queue, cmdBuffer);
+
+ // Verify color buffer.
+ invalidateAlloc(vkd, device, verifBufferAlloc);
+ tcu::ConstPixelBufferAccess resultAccess (tcuFormat, iColorExtent, verifBufferData);
+
+ const auto resultColor = resultAccess.getPixel(0, 0);
+ const auto srcLevelColor = levelColors.at(minLodU);
+ const auto compColor = srcLevelColor[m_params.component];
+ const auto expectedColor = (m_params.needsRobustness2() // This has to match the fragment shader.
+ ? tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)
+ : tcu::Vec4(compColor, compColor, compColor, 1.0f));
+ const auto threshold = (m_params.needsRobustness2()
+ ? 0.0f
+ : 0.005f); // 1/255 < 0.005 < 2/255
+
+ const auto diff = abs(resultColor - expectedColor);
+ const tcu::Vec4 thresholdVec (threshold, threshold, threshold, 0.0f);
+ const auto thresholdMet = tcu::lessThanEqual(diff, thresholdVec);
+
+ if (!tcu::boolAll(thresholdMet))
+ {
+ std::ostringstream msg;
+ msg << "Unexpected output buffer color: expected " << expectedColor << " but found " << resultColor << " [diff=" << diff << "]";
+ TCU_FAIL(msg.str());
+ }
+
+ return tcu::TestStatus::pass("Pass");
+}
+
#endif // CTS_USES_VULKANSC
} // anonymous
@@ -2387,6 +2932,55 @@
} // util
+void populateMinLodGatherGroup (tcu::TestCaseGroup* minLodGatherGroup)
+{
+ using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
+
+ const struct
+ {
+ GatherMinLod minLod;
+ const char* name;
+ } GatherMinLodCases[] =
+ {
+ { GatherMinLod::MINLOD_0_1, "minlod_0_1" },
+ { GatherMinLod::MINLOD_1_1, "minlod_1_1" },
+ };
+
+ const struct
+ {
+ int component;
+ const char* name;
+ } ComponentCases[] =
+ {
+ { 0, "component_0" },
+ { 1, "component_1" },
+ { 2, "component_2" },
+ { 3, "component_3" },
+ };
+
+ auto& testCtx = minLodGatherGroup->getTestContext();
+
+ for (const auto& gatherMinLodCase : GatherMinLodCases)
+ {
+ GroupPtr minLodGroup (new tcu::TestCaseGroup(testCtx, gatherMinLodCase.name, ""));
+
+ for (const auto& componentCase : ComponentCases)
+ {
+ const uint32_t seed = (static_cast<uint32_t>(gatherMinLodCase.minLod) + 1000u) * 1000u
+ + (static_cast<uint32_t>(componentCase.component) + 1000u);
+
+ GatherParams params;
+ params.randomSeed = seed;
+ params.minLod = gatherMinLodCase.minLod;
+ params.component = componentCase.component;
+
+ minLodGroup->addChild(new TextureGatherMinLodTest(testCtx, componentCase.name, "", params));
+ }
+
+ minLodGatherGroup->addChild(minLodGroup.release());
+ }
+}
+
#endif // CTS_USES_VULKANSC
void populateTextureMipmappingTests (tcu::TestCaseGroup* textureMipmappingTests)
@@ -2968,19 +3562,19 @@
// BASE_LEVEL
for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
{
- Texture3DMipmapTestCaseParameters testParameters;
+ Texture3DMipmapTestCaseParameters testParameters;
testParameters.minFilter = minFilterModes[minFilter].mode;
testParameters.minFilterName = minFilterModes[minFilter].name;
testParameters.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
testParameters.programs.push_back(PROGRAM_3D_FLOAT);
- testParameters.testType = util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD;
+ testParameters.testType = util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD;
imageViewMinLodBaseLevelGroup3D->addChild(new TextureTestCase<Texture3DImageViewMinLodBaseLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
std::ostringstream name;
name << minFilterModes[minFilter].name << "_integer_texel_coord";
- testParameters.testType = util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD_INT_TEX_COORD_BASELEVEL;
+ testParameters.testType = util::TextureCommonTestCaseParameters::TEST_IMAGE_VIEW_MINLOD_INT_TEX_COORD_BASELEVEL;
imageViewMinLodBaseLevelGroup3D->addChild(new Texture3DImageViewMinLodIntTexCoordTest(testCtx, name.str().c_str(), "", testParameters));
}
@@ -3000,6 +3594,13 @@
textureMipmappingTests->addChild(group3D.release());
}
+
+#ifndef CTS_USES_VULKANSC
+ {
+ const auto minLodGatherGroup = createTestGroup(testCtx, "min_lod_gather", "Test minLod with textureGather operations", populateMinLodGatherGroup, destroyDeviceHelpers);
+ textureMipmappingTests->addChild(minLodGatherGroup);
+ }
+#endif // CTS_USES_VULKANSC
}
tcu::TestCaseGroup* createTextureMipmappingTests (tcu::TestContext& testCtx)
diff --git a/external/vulkancts/mustpass/main/vk-default/texture.txt b/external/vulkancts/mustpass/main/vk-default/texture.txt
index 9c926a1..3006f3d 100644
--- a/external/vulkancts/mustpass/main/vk-default/texture.txt
+++ b/external/vulkancts/mustpass/main/vk-default/texture.txt
@@ -12166,6 +12166,14 @@
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.nearest_linear_integer_texel_coord
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.linear_linear
dEQP-VK.texture.mipmap.3d.image_view_min_lod.base_level.linear_linear_integer_texel_coord
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_0
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_1
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_2
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_0_1.component_3
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_0
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_1
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_2
+dEQP-VK.texture.mipmap.min_lod_gather.minlod_1_1.component_3
dEQP-VK.texture.filtering_anisotropy.basic.anisotropy_2.mag_nearest_min_nearest
dEQP-VK.texture.filtering_anisotropy.basic.anisotropy_2.mag_linear_min_nearest
dEQP-VK.texture.filtering_anisotropy.basic.anisotropy_2.mag_nearest_min_linear