| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2020 The Khronos Group 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 |
| * \brief YCbCr filtering tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "tcuVectorUtil.hpp" |
| #include "tcuTexVerifierUtil.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkMemUtil.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkBarrierUtil.hpp" |
| #include "vktTestCase.hpp" |
| #include "vktTestGroupUtil.hpp" |
| #include "vktYCbCrFilteringTests.hpp" |
| #include "vktDrawUtil.hpp" |
| #include "vktYCbCrUtil.hpp" |
| #include "gluTextureTestUtil.hpp" |
| #include <string> |
| #include <vector> |
| |
| using namespace vk; |
| using namespace vkt::drawutil; |
| |
| namespace vkt |
| { |
| namespace ycbcr |
| { |
| namespace |
| { |
| |
| using std::vector; |
| using std::string; |
| using tcu::TestLog; |
| using tcu::Sampler; |
| using namespace glu::TextureTestUtil; |
| |
| class LinearFilteringTestInstance: public TestInstance |
| { |
| public: |
| LinearFilteringTestInstance(Context& context, VkFormat format, VkFilter chromaFiltering); |
| ~LinearFilteringTestInstance() = default; |
| |
| protected: |
| |
| VkSamplerCreateInfo getSamplerInfo (const VkSamplerYcbcrConversionInfo* samplerConversionInfo); |
| Move<VkDescriptorSetLayout> createDescriptorSetLayout (VkSampler sampler); |
| Move<VkDescriptorPool> createDescriptorPool (const deUint32 combinedSamplerDescriptorCount); |
| Move<VkDescriptorSet> createDescriptorSet (VkDescriptorPool descPool, |
| VkDescriptorSetLayout descLayout); |
| Move<VkSamplerYcbcrConversion> createYCbCrConversion (void); |
| Move<VkImage> createImage (deUint32 width, deUint32 height); |
| Move<VkImageView> createImageView (const VkSamplerYcbcrConversionInfo& samplerConversionInfo, VkImage image); |
| void bindImage (VkDescriptorSet descriptorSet, |
| VkImageView imageView, |
| VkSampler sampler); |
| tcu::TestStatus iterate (void); |
| |
| private: |
| |
| struct FilterCase |
| { |
| const tcu::UVec2 imageSize; |
| const tcu::UVec2 renderSize; |
| }; |
| |
| const VkFormat m_format; |
| const VkFilter m_chromaFiltering; |
| const DeviceInterface& m_vkd; |
| const VkDevice m_device; |
| int m_caseIndex; |
| const vector<FilterCase> m_cases; |
| }; |
| |
| LinearFilteringTestInstance::LinearFilteringTestInstance(Context& context, VkFormat format, VkFilter chromaFiltering) |
| : TestInstance (context) |
| , m_format (format) |
| , m_chromaFiltering (chromaFiltering) |
| , m_vkd (m_context.getDeviceInterface()) |
| , m_device (m_context.getDevice()) |
| , m_caseIndex (0) |
| , m_cases { |
| { { 8, 8}, {64, 64} }, |
| { {64, 32}, {32, 64} } |
| } |
| { |
| } |
| |
| VkSamplerCreateInfo LinearFilteringTestInstance::getSamplerInfo(const VkSamplerYcbcrConversionInfo* samplerConversionInfo) |
| { |
| return |
| { |
| VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, |
| samplerConversionInfo, |
| 0u, |
| VK_FILTER_LINEAR, // magFilter |
| VK_FILTER_LINEAR, // minFilter |
| VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW |
| 0.0f, // mipLodBias |
| VK_FALSE, // anisotropyEnable |
| 1.0f, // maxAnisotropy |
| VK_FALSE, // compareEnable |
| VK_COMPARE_OP_ALWAYS, // compareOp |
| 0.0f, // minLod |
| 0.0f, // maxLod |
| VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor |
| VK_FALSE, // unnormalizedCoords |
| }; |
| } |
| |
| Move<VkDescriptorSetLayout> LinearFilteringTestInstance::createDescriptorSetLayout(VkSampler sampler) |
| { |
| const VkDescriptorSetLayoutBinding binding = |
| { |
| 0u, // binding |
| VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| 1u, // descriptorCount |
| VK_SHADER_STAGE_ALL, |
| &sampler |
| }; |
| const VkDescriptorSetLayoutCreateInfo layoutInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, |
| DE_NULL, |
| (VkDescriptorSetLayoutCreateFlags)0u, |
| 1u, |
| &binding, |
| }; |
| |
| return ::createDescriptorSetLayout(m_vkd, m_device, &layoutInfo); |
| } |
| |
| Move<VkDescriptorPool> LinearFilteringTestInstance::createDescriptorPool(const deUint32 combinedSamplerDescriptorCount) |
| { |
| const VkDescriptorPoolSize poolSizes[] = |
| { |
| { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, combinedSamplerDescriptorCount }, |
| }; |
| const VkDescriptorPoolCreateInfo poolInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, |
| DE_NULL, |
| (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, |
| 1u, // maxSets |
| DE_LENGTH_OF_ARRAY(poolSizes), |
| poolSizes, |
| }; |
| |
| return ::createDescriptorPool(m_vkd, m_device, &poolInfo); |
| } |
| |
| Move<VkDescriptorSet> LinearFilteringTestInstance::createDescriptorSet(VkDescriptorPool descPool, |
| VkDescriptorSetLayout descLayout) |
| { |
| const VkDescriptorSetAllocateInfo allocInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
| DE_NULL, |
| descPool, |
| 1u, |
| &descLayout, |
| }; |
| |
| return allocateDescriptorSet(m_vkd, m_device, &allocInfo); |
| } |
| |
| Move<VkSamplerYcbcrConversion> LinearFilteringTestInstance::createYCbCrConversion() |
| { |
| const VkSamplerYcbcrConversionCreateInfo conversionInfo = |
| { |
| VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, |
| DE_NULL, |
| m_format, |
| VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, |
| VK_SAMPLER_YCBCR_RANGE_ITU_FULL, |
| { |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| }, |
| VK_CHROMA_LOCATION_MIDPOINT, |
| VK_CHROMA_LOCATION_MIDPOINT, |
| m_chromaFiltering, // chromaFilter |
| VK_FALSE, // forceExplicitReconstruction |
| }; |
| |
| return createSamplerYcbcrConversion(m_vkd, m_device, &conversionInfo); |
| } |
| |
| Move<VkImage> LinearFilteringTestInstance::createImage(deUint32 width, deUint32 height) |
| { |
| VkImageCreateFlags createFlags = 0u; |
| const VkImageCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| DE_NULL, |
| createFlags, |
| VK_IMAGE_TYPE_2D, |
| m_format, |
| makeExtent3D(width, height, 1u), |
| 1u, // mipLevels |
| 1u, // arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, |
| VK_IMAGE_TILING_OPTIMAL, |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, |
| VK_SHARING_MODE_EXCLUSIVE, |
| 0u, |
| (const deUint32*)DE_NULL, |
| VK_IMAGE_LAYOUT_UNDEFINED, |
| }; |
| |
| return ::createImage(m_vkd, m_device, &createInfo); |
| } |
| |
| Move<VkImageView> LinearFilteringTestInstance::createImageView(const VkSamplerYcbcrConversionInfo& samplerConversionInfo, VkImage image) |
| { |
| const VkImageViewCreateInfo viewInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| &samplerConversionInfo, |
| (VkImageViewCreateFlags)0, |
| image, |
| VK_IMAGE_VIEW_TYPE_2D, |
| m_format, |
| { |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, |
| }, |
| { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, |
| }; |
| |
| return ::createImageView(m_vkd, m_device, &viewInfo); |
| } |
| |
| void LinearFilteringTestInstance::bindImage(VkDescriptorSet descriptorSet, |
| VkImageView imageView, |
| VkSampler sampler) |
| { |
| const VkDescriptorImageInfo imageInfo = |
| { |
| sampler, |
| imageView, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL |
| }; |
| const VkWriteDescriptorSet descriptorWrite = |
| { |
| VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, |
| DE_NULL, |
| descriptorSet, |
| 0u, // dstBinding |
| 0u, // dstArrayElement |
| 1u, // descriptorCount |
| VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| &imageInfo, |
| (const VkDescriptorBufferInfo*)DE_NULL, |
| (const VkBufferView*)DE_NULL, |
| }; |
| |
| m_vkd.updateDescriptorSets(m_device, 1u, &descriptorWrite, 0u, DE_NULL); |
| } |
| |
| tcu::TestStatus LinearFilteringTestInstance::iterate(void) |
| { |
| const tcu::UVec2 imageSize (m_cases[m_caseIndex].imageSize); |
| const tcu::UVec2 renderSize (m_cases[m_caseIndex].renderSize); |
| const auto& instInt (m_context.getInstanceInterface()); |
| auto physicalDevice (m_context.getPhysicalDevice()); |
| const Unique<VkSamplerYcbcrConversion> conversion (createYCbCrConversion()); |
| const VkSamplerYcbcrConversionInfo samplerConvInfo { VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, DE_NULL, *conversion }; |
| const VkSamplerCreateInfo samplerCreateInfo (getSamplerInfo(&samplerConvInfo)); |
| const Unique<VkSampler> sampler (createSampler(m_vkd, m_device, &samplerCreateInfo)); |
| |
| deUint32 combinedSamplerDescriptorCount = 1; |
| { |
| const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = |
| { |
| VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType |
| DE_NULL, // pNext |
| m_format, // format |
| VK_IMAGE_TYPE_2D, // type |
| VK_IMAGE_TILING_OPTIMAL, // tiling |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| VK_IMAGE_USAGE_SAMPLED_BIT, // usage |
| (VkImageCreateFlags)0u // flags |
| }; |
| |
| VkSamplerYcbcrConversionImageFormatProperties samplerYcbcrConversionImage = {}; |
| samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES; |
| samplerYcbcrConversionImage.pNext = DE_NULL; |
| |
| VkImageFormatProperties2 imageFormatProperties = {}; |
| imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; |
| imageFormatProperties.pNext = &samplerYcbcrConversionImage; |
| |
| VK_CHECK(instInt.getPhysicalDeviceImageFormatProperties2(physicalDevice, &imageFormatInfo, &imageFormatProperties)); |
| combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount; |
| } |
| |
| const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(*sampler)); |
| const Unique<VkDescriptorPool> descPool (createDescriptorPool(combinedSamplerDescriptorCount)); |
| const Unique<VkDescriptorSet> descSet (createDescriptorSet(*descPool, *descLayout)); |
| const Unique<VkImage> testImage (createImage(imageSize.x(), imageSize.y())); |
| const vector<AllocationSp> allocations (allocateAndBindImageMemory(m_vkd, m_device, m_context.getDefaultAllocator(), *testImage, m_format, 0u)); |
| const Unique<VkImageView> imageView (createImageView(samplerConvInfo, *testImage)); |
| |
| // create and bind image with test data |
| MultiPlaneImageData imageData(m_format, imageSize); |
| fillGradient(&imageData, tcu::Vec4(0.0f), tcu::Vec4(1.0f)); |
| uploadImage(m_vkd, |
| m_device, |
| m_context.getUniversalQueueFamilyIndex(), |
| m_context.getDefaultAllocator(), |
| *testImage, |
| imageData, |
| (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, |
| 0); |
| bindImage(*descSet, *imageView, *sampler); |
| |
| const vector<tcu::Vec4> vertices = |
| { |
| { -1.0f, -1.0f, 0.0f, 1.0f }, |
| { +1.0f, -1.0f, 0.0f, 1.0f }, |
| { -1.0f, +1.0f, 0.0f, 1.0f }, |
| { +1.0f, +1.0f, 0.0f, 1.0f } |
| }; |
| VulkanProgram program({ |
| VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert")), |
| VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag")) |
| }); |
| program.descriptorSet = *descSet; |
| program.descriptorSetLayout = *descLayout; |
| |
| PipelineState pipelineState (m_context.getDeviceProperties().limits.subPixelPrecisionBits); |
| const DrawCallData drawCallData (VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices); |
| FrameBufferState frameBufferState (renderSize.x(), renderSize.y()); |
| VulkanDrawContext renderer (m_context, frameBufferState); |
| |
| // render full screen quad |
| renderer.registerDrawObject(pipelineState, program, drawCallData); |
| renderer.draw(); |
| |
| // get rendered image |
| tcu::ConstPixelBufferAccess resImage(renderer.getColorPixels()); |
| |
| // construct ChannelAccess objects required to create reference results |
| const vk::PlanarFormatDescription planeInfo = imageData.getDescription(); |
| deUint32 nullAccessData (0u); |
| ChannelAccess nullAccess (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(imageSize.x(), imageSize.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessData, 0u); |
| deUint32 nullAccessAlphaData (~0u); |
| ChannelAccess nullAccessAlpha (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(imageSize.x(), imageSize.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessAlphaData, 0u); |
| ChannelAccess rChannelAccess (planeInfo.hasChannelNdx(0) ? getChannelAccess(imageData, planeInfo, imageSize, 0) : nullAccess); |
| ChannelAccess gChannelAccess (planeInfo.hasChannelNdx(1) ? getChannelAccess(imageData, planeInfo, imageSize, 1) : nullAccess); |
| ChannelAccess bChannelAccess (planeInfo.hasChannelNdx(2) ? getChannelAccess(imageData, planeInfo, imageSize, 2) : nullAccess); |
| ChannelAccess aChannelAccess (planeInfo.hasChannelNdx(3) ? getChannelAccess(imageData, planeInfo, imageSize, 3) : nullAccessAlpha); |
| const VkFormatProperties formatProperties (getPhysicalDeviceFormatProperties(instInt, physicalDevice, m_format)); |
| const VkFormatFeatureFlags featureFlags (formatProperties.optimalTilingFeatures); |
| const bool explicitReconstruction (featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT); |
| |
| // calulate texture coordinates used by fragment shader |
| vector<tcu::Vec2> sts; |
| for (deUint32 y = 0; y < renderSize.y(); y++) |
| for (deUint32 x = 0; x < renderSize.x(); x++) |
| { |
| const float s = ((float)x + 0.5f) / (float)renderSize.x(); |
| const float t = ((float)y + 0.5f) / (float)renderSize.y(); |
| |
| sts.push_back(tcu::Vec2(s, t)); |
| } |
| |
| // calculate minimum and maximum values between which the results should be placed |
| const tcu::UVec4 bitDepth (getYCbCrBitDepth(m_format)); |
| const std::vector<tcu::FloatFormat> filteringPrecision (getPrecision(m_format)); |
| const std::vector<tcu::FloatFormat> conversionPrecision (getPrecision(m_format)); |
| const deUint32 subTexelPrecisionBits (vk::getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits.subTexelPrecisionBits); |
| const vk::VkComponentMapping componentMapping = { vk::VK_COMPONENT_SWIZZLE_IDENTITY, vk::VK_COMPONENT_SWIZZLE_IDENTITY, vk::VK_COMPONENT_SWIZZLE_IDENTITY, vk::VK_COMPONENT_SWIZZLE_IDENTITY }; |
| |
| std::vector<tcu::Vec4> minBound; |
| std::vector<tcu::Vec4> maxBound; |
| std::vector<tcu::Vec4> uvBound; |
| std::vector<tcu::IVec4> ijBound; |
| calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, sts, filteringPrecision, conversionPrecision, subTexelPrecisionBits, VK_FILTER_LINEAR, VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, VK_SAMPLER_YCBCR_RANGE_ITU_FULL, m_chromaFiltering, VK_CHROMA_LOCATION_MIDPOINT, VK_CHROMA_LOCATION_MIDPOINT, componentMapping, explicitReconstruction, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, minBound, maxBound, uvBound, ijBound); |
| |
| // log result and reference images |
| TestLog& log (m_context.getTestContext().getLog()); |
| { |
| const tcu::Vec4 scale (1.0f); |
| const tcu::Vec4 bias (0.0f); |
| vector<deUint8> minData (renderSize.x() * renderSize.y() * sizeof(tcu::Vec4), 255); |
| vector<deUint8> maxData (renderSize.x() * renderSize.y() * sizeof(tcu::Vec4), 255); |
| tcu::TextureFormat refFormat (vk::mapVkFormat(frameBufferState.colorFormat)); |
| tcu::PixelBufferAccess minImage (refFormat, renderSize.x(), renderSize.y(), 1, minData.data()); |
| tcu::PixelBufferAccess maxImage (refFormat, renderSize.x(), renderSize.y(), 1, maxData.data()); |
| { |
| deUint32 ndx = 0; |
| for (deUint32 y = 0; y < renderSize.y(); y++) |
| for (deUint32 x = 0; x < renderSize.x(); x++) |
| { |
| minImage.setPixel(minBound[ndx], x, y); |
| maxImage.setPixel(maxBound[ndx], x, y); |
| ndx++; |
| } |
| } |
| |
| log << TestLog::Image("MinBoundImage", "MinBoundImage", minImage, scale, bias); |
| log << TestLog::Image("MaxBoundImage", "MaxBoundImage", maxImage, scale, bias); |
| log << TestLog::Image("ResImage", "ResImage", resImage, scale, bias); |
| } |
| |
| bool isOk = true; |
| { |
| deUint32 ndx = 0; |
| VkFilter textureFilter = VK_FILTER_LINEAR; |
| size_t errorCount = 0; |
| |
| for (deUint32 y = 0; y < renderSize.y(); y++) |
| for (deUint32 x = 0; x < renderSize.x(); x++) |
| { |
| tcu::Vec4 resValue = resImage.getPixel(x, y); |
| bool fail = tcu::boolAny(tcu::lessThan(resValue, minBound[ndx])) || tcu::boolAny(tcu::greaterThan(resValue, maxBound[ndx])); |
| |
| if (fail) |
| { |
| log << TestLog::Message << "Fail: " << sts[ndx] << " " << resValue << TestLog::EndMessage; |
| log << TestLog::Message << " Min : " << minBound[ndx] << TestLog::EndMessage; |
| log << TestLog::Message << " Max : " << maxBound[ndx] << TestLog::EndMessage; |
| log << TestLog::Message << " Threshold: " << (maxBound[ndx] - minBound[ndx]) << TestLog::EndMessage; |
| log << TestLog::Message << " UMin : " << uvBound[ndx][0] << TestLog::EndMessage; |
| log << TestLog::Message << " UMax : " << uvBound[ndx][1] << TestLog::EndMessage; |
| log << TestLog::Message << " VMin : " << uvBound[ndx][2] << TestLog::EndMessage; |
| log << TestLog::Message << " VMax : " << uvBound[ndx][3] << TestLog::EndMessage; |
| log << TestLog::Message << " IMin : " << ijBound[ndx][0] << TestLog::EndMessage; |
| log << TestLog::Message << " IMax : " << ijBound[ndx][1] << TestLog::EndMessage; |
| log << TestLog::Message << " JMin : " << ijBound[ndx][2] << TestLog::EndMessage; |
| log << TestLog::Message << " JMax : " << ijBound[ndx][3] << TestLog::EndMessage; |
| |
| if (isXChromaSubsampled(m_format)) |
| { |
| log << TestLog::Message << " LumaAlphaValues : " << TestLog::EndMessage; |
| log << TestLog::Message << " Offset : (" << ijBound[ndx][0] << ", " << ijBound[ndx][2] << ")" << TestLog::EndMessage; |
| |
| for (deInt32 k = ijBound[ndx][2]; k <= ijBound[ndx][3] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); k++) |
| { |
| const deInt32 wrappedK = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, k, gChannelAccess.getSize().y()); |
| bool first = true; |
| std::ostringstream line; |
| |
| for (deInt32 j = ijBound[ndx][0]; j <= ijBound[ndx][1] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); j++) |
| { |
| const deInt32 wrappedJ = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, j, gChannelAccess.getSize().x()); |
| |
| if (!first) |
| { |
| line << ", "; |
| first = false; |
| } |
| |
| line << "(" << std::setfill(' ') << std::setw(5) << gChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) |
| << ", " << std::setfill(' ') << std::setw(5) << aChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) << ")"; |
| } |
| log << TestLog::Message << " " << line.str() << TestLog::EndMessage; |
| } |
| |
| { |
| const tcu::IVec2 chromaJRange(divFloor(ijBound[ndx][0], 2) - 1, divFloor(ijBound[ndx][1] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0), 2) + 1); |
| const tcu::IVec2 chromaKRange(isYChromaSubsampled(m_format) |
| ? tcu::IVec2(divFloor(ijBound[ndx][2], 2) - 1, divFloor(ijBound[ndx][3] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0), 2) + 1) |
| : tcu::IVec2(ijBound[ndx][2], ijBound[ndx][3] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0))); |
| |
| log << TestLog::Message << " ChromaValues : " << TestLog::EndMessage; |
| log << TestLog::Message << " Offset : (" << chromaJRange[0] << ", " << chromaKRange[0] << ")" << TestLog::EndMessage; |
| |
| for (deInt32 k = chromaKRange[0]; k <= chromaKRange[1]; k++) |
| { |
| const deInt32 wrappedK = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, k, rChannelAccess.getSize().y()); |
| bool first = true; |
| std::ostringstream line; |
| |
| for (deInt32 j = chromaJRange[0]; j <= chromaJRange[1]; j++) |
| { |
| const deInt32 wrappedJ = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, j, rChannelAccess.getSize().x()); |
| |
| if (!first) |
| { |
| line << ", "; |
| first = false; |
| } |
| |
| line << "(" << std::setfill(' ') << std::setw(5) << rChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) |
| << ", " << std::setfill(' ') << std::setw(5) << bChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) << ")"; |
| } |
| log << TestLog::Message << " " << line.str() << TestLog::EndMessage; |
| } |
| } |
| } |
| else |
| { |
| log << TestLog::Message << " Values : " << TestLog::EndMessage; |
| log << TestLog::Message << " Offset : (" << ijBound[ndx][0] << ", " << ijBound[ndx][2] << ")" << TestLog::EndMessage; |
| |
| for (deInt32 k = ijBound[ndx][2]; k <= ijBound[ndx][3] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); k++) |
| { |
| const deInt32 wrappedK = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, k, rChannelAccess.getSize().y()); |
| bool first = true; |
| std::ostringstream line; |
| |
| for (deInt32 j = ijBound[ndx][0]; j <= ijBound[ndx][1] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); j++) |
| { |
| const deInt32 wrappedJ = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, j, rChannelAccess.getSize().x()); |
| |
| if (!first) |
| { |
| line << ", "; |
| first = false; |
| } |
| |
| line << "(" << std::setfill(' ') << std::setw(5) << rChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) |
| << ", " << std::setfill(' ') << std::setw(5) << gChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) |
| << ", " << std::setfill(' ') << std::setw(5) << bChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) |
| << ", " << std::setfill(' ') << std::setw(5) << aChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) << ")"; |
| } |
| log << TestLog::Message << " " << line.str() << TestLog::EndMessage; |
| } |
| } |
| |
| errorCount++; |
| isOk = false; |
| |
| if (errorCount > 30) |
| { |
| log << TestLog::Message << "Encountered " << errorCount << " errors. Omitting rest of the per result logs." << TestLog::EndMessage; |
| break; |
| } |
| } |
| ndx++; |
| } |
| } |
| |
| if (!isOk) |
| return tcu::TestStatus::fail("Result comparison failed"); |
| if (++m_caseIndex < (int)m_cases.size()) |
| return tcu::TestStatus::incomplete(); |
| return tcu::TestStatus::pass("Pass"); |
| } |
| |
| class LinearFilteringTestCase : public vkt::TestCase |
| { |
| public: |
| LinearFilteringTestCase(tcu::TestContext &context, const char* name, const char* description, VkFormat format, VkFilter chromaFiltering); |
| |
| protected: |
| void checkSupport(Context& context) const; |
| vkt::TestInstance* createInstance(vkt::Context& context) const; |
| void initPrograms(SourceCollections& programCollection) const; |
| |
| private: |
| VkFormat m_format; |
| VkFilter m_chromaFiltering; |
| }; |
| |
| LinearFilteringTestCase::LinearFilteringTestCase(tcu::TestContext &context, const char* name, const char* description, VkFormat format, VkFilter chromaFiltering) |
| : TestCase(context, name, description) |
| , m_format(format) |
| , m_chromaFiltering(chromaFiltering) |
| { |
| } |
| |
| void LinearFilteringTestCase::checkSupport(Context& context) const |
| { |
| context.requireDeviceFunctionality("VK_KHR_sampler_ycbcr_conversion"); |
| |
| const auto& instInt = context.getInstanceInterface(); |
| auto physicalDevice = context.getPhysicalDevice(); |
| const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(instInt, physicalDevice, m_format); |
| const VkFormatFeatureFlags featureFlags = formatProperties.optimalTilingFeatures; |
| |
| if ((featureFlags & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0) |
| TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format"); |
| |
| if ((featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) == 0) |
| TCU_THROW(NotSupportedError, "Linear filtering not supported for format"); |
| |
| if (m_chromaFiltering != VK_FILTER_LINEAR && |
| (featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT) == 0) |
| TCU_THROW(NotSupportedError, "Different chroma, min, and mag filters not supported for format"); |
| } |
| |
| vkt::TestInstance* LinearFilteringTestCase::createInstance(vkt::Context& context) const |
| { |
| return new LinearFilteringTestInstance(context, m_format, m_chromaFiltering); |
| } |
| |
| void LinearFilteringTestCase::initPrograms(SourceCollections& programCollection) const |
| { |
| static const char* vertShader = |
| "#version 450\n" |
| "precision mediump int; precision highp float;\n" |
| "layout(location = 0) in vec4 a_position;\n" |
| "layout(location = 0) out vec2 v_texCoord;\n" |
| "out gl_PerVertex { vec4 gl_Position; };\n" |
| "\n" |
| "void main (void)\n" |
| "{\n" |
| " v_texCoord = a_position.xy * 0.5 + 0.5;\n" |
| " gl_Position = a_position;\n" |
| "}\n"; |
| |
| static const char* fragShader = |
| "#version 450\n" |
| "precision mediump int; precision highp float;\n" |
| "layout(location = 0) in vec2 v_texCoord;\n" |
| "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" |
| "layout (set=0, binding=0) uniform sampler2D u_sampler;\n" |
| "void main (void)\n" |
| "{\n" |
| " dEQP_FragColor = vec4(texture(u_sampler, v_texCoord));\n" |
| "}\n"; |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(vertShader); |
| programCollection.glslSources.add("frag") << glu::FragmentSource(fragShader); |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createFilteringTests (tcu::TestContext& testCtx) |
| { |
| struct YCbCrFormatData |
| { |
| const char* const name; |
| const VkFormat format; |
| }; |
| |
| static const std::vector<YCbCrFormatData> ycbcrFormats = |
| { |
| { "g8_b8_r8_3plane_420_unorm", VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM }, |
| { "g8_b8r8_2plane_420_unorm", VK_FORMAT_G8_B8R8_2PLANE_420_UNORM }, |
| }; |
| |
| de::MovePtr<tcu::TestCaseGroup> filteringTests(new tcu::TestCaseGroup(testCtx, "filtering", "YCbCr filtering tests")); |
| |
| for (const auto& ycbcrFormat : ycbcrFormats) |
| { |
| { |
| const std::string name = std::string("linear_sampler_") + ycbcrFormat.name; |
| filteringTests->addChild(new LinearFilteringTestCase(filteringTests->getTestContext(), name.c_str(), "", ycbcrFormat.format, VK_FILTER_NEAREST)); |
| } |
| |
| { |
| const std::string name = std::string("linear_sampler_with_chroma_linear_filtering_") + ycbcrFormat.name; |
| filteringTests->addChild(new LinearFilteringTestCase(filteringTests->getTestContext(), name.c_str(), "", ycbcrFormat.format, VK_FILTER_LINEAR)); |
| } |
| } |
| |
| return filteringTests.release(); |
| } |
| |
| } // ycbcr |
| |
| } // vkt |