blob: ed1926922e8fffb85b764648930156a7fa583073 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2017 The Khronos Group Inc.
* Copyright (c) 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file vktSparseResourcesImageAlignedMipSize.cpp
* \brief Aligned mip size tests.
*//*--------------------------------------------------------------------*/
#include "vktSparseResourcesBufferSparseBinding.hpp"
#include "vktSparseResourcesTestsUtil.hpp"
#include "vktSparseResourcesBase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkDefs.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkPlatform.hpp"
#include "vkPrograms.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkTypeUtil.hpp"
#include "deUniquePtr.hpp"
#include "deStringUtil.hpp"
#include <string>
#include <vector>
using namespace vk;
namespace vkt
{
namespace sparse
{
namespace
{
class ImageAlignedMipSizeCase : public TestCase
{
public:
ImageAlignedMipSizeCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const ImageType imageType,
const tcu::UVec3& imageSize,
const VkFormat format);
void initPrograms (SourceCollections& sourceCollections) const {DE_UNREF(sourceCollections);}
TestInstance* createInstance (Context& context) const;
virtual void checkSupport (Context& context) const;
private:
const ImageType m_imageType;
const tcu::UVec3 m_imageSize;
const VkFormat m_format;
};
ImageAlignedMipSizeCase::ImageAlignedMipSizeCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const ImageType imageType,
const tcu::UVec3& imageSize,
const VkFormat format)
: TestCase (testCtx, name, description)
, m_imageType (imageType)
, m_imageSize (imageSize)
, m_format (format)
{
}
void ImageAlignedMipSizeCase::checkSupport (Context& context) const
{
const InstanceInterface& instance = context.getInstanceInterface();
const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
// Check the image size does not exceed device limits
if (!isImageSizeSupported(instance, physicalDevice, m_imageType, m_imageSize))
TCU_THROW(NotSupportedError, "Image size not supported for device");
// Check if device supports sparse operations for image type
if (!checkSparseSupportForImageType(instance, physicalDevice, m_imageType))
TCU_THROW(NotSupportedError, "Sparse residency for image type is not supported");
if (formatIsR64(m_format))
{
context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
if (context.getShaderImageAtomicInt64FeaturesEXT().sparseImageInt64Atomics == VK_FALSE)
{
TCU_THROW(NotSupportedError, "sparseImageInt64Atomics is not supported for device");
}
}
}
class ImageAlignedMipSizeInstance : public SparseResourcesBaseInstance
{
public:
ImageAlignedMipSizeInstance (Context& context,
const ImageType imageType,
const tcu::UVec3& imageSize,
const VkFormat format);
tcu::TestStatus iterate (void);
private:
const ImageType m_imageType;
const tcu::UVec3 m_imageSize;
const VkFormat m_format;
};
ImageAlignedMipSizeInstance::ImageAlignedMipSizeInstance (Context& context,
const ImageType imageType,
const tcu::UVec3& imageSize,
const VkFormat format)
: SparseResourcesBaseInstance (context)
, m_imageType (imageType)
, m_imageSize (imageSize)
, m_format (format)
{
}
tcu::TestStatus ImageAlignedMipSizeInstance::iterate (void)
{
const InstanceInterface& instance = m_context.getInstanceInterface();
const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
const VkPhysicalDeviceProperties physicalDeviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
VkImageCreateInfo imageCreateInfo;
VkSparseImageMemoryRequirements aspectRequirements;
VkExtent3D imageGranularity;
const VkPhysicalDeviceSparseProperties sparseProperties = physicalDeviceProperties.sparseProperties;
const PlanarFormatDescription formatDescription = getPlanarFormatDescription(m_format);
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.pNext = DE_NULL;
imageCreateInfo.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
imageCreateInfo.imageType = mapImageType(m_imageType);
imageCreateInfo.format = m_format;
imageCreateInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageSize));
imageCreateInfo.arrayLayers = getNumLayers(m_imageType, m_imageSize);
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_STORAGE_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.queueFamilyIndexCount = 0u;
imageCreateInfo.pQueueFamilyIndices = DE_NULL;
if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
{
imageCreateInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
// Check if device supports sparse operations for image format
if (!checkSparseSupportForImageFormat(instance, physicalDevice, imageCreateInfo))
TCU_THROW(NotSupportedError, "The image format does not support sparse operations");
{
VkImageFormatProperties imageFormatProperties;
if (instance.getPhysicalDeviceImageFormatProperties(physicalDevice,
imageCreateInfo.format,
imageCreateInfo.imageType,
imageCreateInfo.tiling,
imageCreateInfo.usage,
imageCreateInfo.flags,
&imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
{
TCU_THROW(NotSupportedError, "Image format does not support sparse operations");
}
imageCreateInfo.mipLevels = getMipmapCount(m_format, formatDescription, imageFormatProperties, imageCreateInfo.extent);
}
{
QueueRequirementsVec queueRequirements;
queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
createDeviceSupportingQueues(queueRequirements);
}
{
const DeviceInterface& deviceInterface = getDeviceInterface();
// Create sparse image
const Unique<VkImage> imageSparse (createImage(deviceInterface, getDevice(), &imageCreateInfo));
// Get sparse image sparse memory requirements
const std::vector<VkSparseImageMemoryRequirements> sparseMemoryRequirements = getImageSparseMemoryRequirements(deviceInterface, getDevice(), *imageSparse);
DE_ASSERT(sparseMemoryRequirements.size() != 0);
const deUint32 colorAspectIndex = getSparseAspectRequirementsIndex(sparseMemoryRequirements, VK_IMAGE_ASPECT_COLOR_BIT);
if (colorAspectIndex == NO_MATCH_FOUND)
TCU_THROW(NotSupportedError, "Not supported image aspect - the test supports currently only VK_IMAGE_ASPECT_COLOR_BIT");
aspectRequirements = sparseMemoryRequirements[colorAspectIndex];
imageGranularity = aspectRequirements.formatProperties.imageGranularity;
}
if (sparseProperties.residencyAlignedMipSize)
{
deUint32 lod = 0;
VkExtent3D extent;
do
{
extent = mipLevelExtents(imageCreateInfo.extent, lod);
if ( extent.width % imageGranularity.width != 0
|| extent.height % imageGranularity.height != 0
|| extent.depth % imageGranularity.depth != 0)
{
break;
}
lod++;
}
while (extent.width != 1 || extent.height != 1 || extent.depth != 1);
if (lod != aspectRequirements.imageMipTailFirstLod)
return tcu::TestStatus::fail("Unexpected first LOD for mip tail.");
else
return tcu::TestStatus::pass("pass");
}
else if (aspectRequirements.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT)
{
return tcu::TestStatus::fail("Aligned mip size flag doesn't match in device and image properties.");
}
else
{
return tcu::TestStatus::pass("Aligned mip size not enabled.");
}
}
TestInstance* ImageAlignedMipSizeCase::createInstance (Context& context) const
{
return new ImageAlignedMipSizeInstance(context, m_imageType, m_imageSize, m_format);
}
} // anonymous ns
tcu::TestCaseGroup* createImageAlignedMipSizeTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "aligned_mip_size", "Aligned mip size"));
const std::vector<TestImageParameters> imageParameters
{
{ IMAGE_TYPE_2D, { tcu::UVec3(512u, 256u, 1u) }, getTestFormats(IMAGE_TYPE_2D) },
{ IMAGE_TYPE_2D_ARRAY, { tcu::UVec3(512u, 256u, 6u) }, getTestFormats(IMAGE_TYPE_2D_ARRAY) },
{ IMAGE_TYPE_CUBE, { tcu::UVec3(256u, 256u, 1u) }, getTestFormats(IMAGE_TYPE_CUBE) },
{ IMAGE_TYPE_CUBE_ARRAY, { tcu::UVec3(256u, 256u, 6u) }, getTestFormats(IMAGE_TYPE_CUBE_ARRAY) },
{ IMAGE_TYPE_3D, { tcu::UVec3(512u, 256u, 16u) }, getTestFormats(IMAGE_TYPE_3D) }
};
for (size_t imageTypeNdx = 0; imageTypeNdx < imageParameters.size(); ++imageTypeNdx)
{
const ImageType imageType = imageParameters[imageTypeNdx].imageType;
de::MovePtr<tcu::TestCaseGroup> imageTypeGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str(), ""));
for (size_t formatNdx = 0; formatNdx < imageParameters[imageTypeNdx].formats.size(); ++formatNdx)
{
VkFormat format = imageParameters[imageTypeNdx].formats[formatNdx].format;
tcu::UVec3 imageSizeAlignment = getImageSizeAlignment(format);
const std::string name = getImageFormatID(format);
const tcu::UVec3 imageSize = imageParameters[imageTypeNdx].imageSizes[0];
// skip test for images with odd sizes for some YCbCr formats
if ((imageSize.x() % imageSizeAlignment.x()) != 0)
continue;
if ((imageSize.y() % imageSizeAlignment.y()) != 0)
continue;
imageTypeGroup->addChild(new ImageAlignedMipSizeCase(testCtx, name.c_str(), "", imageType, imageSize, format));
}
testGroup->addChild(imageTypeGroup.release());
}
return testGroup.release();
}
} // sparse
} // vkt