| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2017 The Khronos Group Inc. |
| * Copyright (c) 2017 Samsung Electronics Co., Ltd. |
| * |
| * 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 Protected memory YCbCr image conversion tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktProtectedMemYCbCrConversionTests.hpp" |
| |
| #include "tcuImageCompare.hpp" |
| #include "tcuStringTemplate.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include "vkBuilderUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkYCbCrImageWithMemory.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkObjUtil.hpp" |
| |
| #include "vktProtectedMemContext.hpp" |
| #include "vktProtectedMemUtils.hpp" |
| #include "vktTestCaseUtil.hpp" |
| #include "vktYCbCrUtil.hpp" |
| |
| |
| namespace vkt |
| { |
| namespace ProtectedMem |
| { |
| |
| namespace |
| { |
| static const vk::VkFormat s_colorFormat = vk::VK_FORMAT_R8G8B8A8_UNORM; |
| |
| enum { |
| CHECK_SIZE = 50, |
| }; |
| |
| struct YCbCrValidationData { |
| tcu::Vec4 coord; |
| tcu::Vec4 minBound; |
| tcu::Vec4 maxBound; |
| }; |
| |
| std::vector<tcu::Vec2> computeVertexPositions (int numValues, const tcu::IVec2& renderSize) |
| { |
| std::vector<tcu::Vec2> positions(numValues); |
| for (int valNdx = 0; valNdx < numValues; valNdx++) |
| { |
| const int ix = valNdx % renderSize.x(); |
| const int iy = valNdx / renderSize.x(); |
| const float fx = -1.0f + 2.0f*((float(ix) + 0.5f) / float(renderSize.x())); |
| const float fy = -1.0f + 2.0f*((float(iy) + 0.5f) / float(renderSize.y())); |
| |
| positions[valNdx] = tcu::Vec2(fx, fy); |
| } |
| |
| return positions; |
| } |
| |
| void genTexCoords (std::vector<tcu::Vec2>& coords, const tcu::UVec2& size) |
| { |
| for (deUint32 y = 0; y < size.y(); y++) |
| for (deUint32 x = 0; x < size.x(); x++) |
| { |
| const float fx = (float)x; |
| const float fy = (float)y; |
| |
| const float fw = (float)size.x(); |
| const float fh = (float)size.y(); |
| |
| const float s = 1.5f * ((fx * 1.5f * fw + fx) / (1.5f * fw * 1.5f * fw)) - 0.25f; |
| const float t = 1.5f * ((fy * 1.5f * fh + fy) / (1.5f * fh * 1.5f * fh)) - 0.25f; |
| |
| coords.push_back(tcu::Vec2(s, t)); |
| } |
| } |
| |
| struct TestConfig |
| { |
| TestConfig (glu::ShaderType shaderType_, |
| vk::VkFormat format_, |
| vk::VkImageTiling imageTiling_, |
| vk::VkFilter textureFilter_, |
| vk::VkSamplerAddressMode addressModeU_, |
| vk::VkSamplerAddressMode addressModeV_, |
| |
| vk::VkFilter chromaFilter_, |
| vk::VkChromaLocation xChromaOffset_, |
| vk::VkChromaLocation yChromaOffset_, |
| bool explicitReconstruction_, |
| bool disjoint_, |
| |
| vk::VkSamplerYcbcrRange colorRange_, |
| vk::VkSamplerYcbcrModelConversion colorModel_, |
| vk::VkComponentMapping componentMapping_) |
| : shaderType (shaderType_) |
| , format (format_) |
| , imageTiling (imageTiling_) |
| , textureFilter (textureFilter_) |
| , addressModeU (addressModeU_) |
| , addressModeV (addressModeV_) |
| |
| , chromaFilter (chromaFilter_) |
| , xChromaOffset (xChromaOffset_) |
| , yChromaOffset (yChromaOffset_) |
| , explicitReconstruction (explicitReconstruction_) |
| , disjoint (disjoint_) |
| |
| , colorRange (colorRange_) |
| , colorModel (colorModel_) |
| , componentMapping (componentMapping_) |
| { |
| } |
| |
| glu::ShaderType shaderType; |
| vk::VkFormat format; |
| vk::VkImageTiling imageTiling; |
| vk::VkFilter textureFilter; |
| vk::VkSamplerAddressMode addressModeU; |
| vk::VkSamplerAddressMode addressModeV; |
| |
| vk::VkFilter chromaFilter; |
| vk::VkChromaLocation xChromaOffset; |
| vk::VkChromaLocation yChromaOffset; |
| bool explicitReconstruction; |
| bool disjoint; |
| |
| vk::VkSamplerYcbcrRange colorRange; |
| vk::VkSamplerYcbcrModelConversion colorModel; |
| vk::VkComponentMapping componentMapping; |
| }; |
| |
| void checkSupport (Context& context, const TestConfig) |
| { |
| checkProtectedQueueSupport(context); |
| } |
| |
| void validateFormatSupport (ProtectedContext& context, TestConfig& config) |
| { |
| tcu::TestLog& log (context.getTestContext().getLog()); |
| |
| try |
| { |
| const vk::VkFormatProperties properties (vk::getPhysicalDeviceFormatProperties(context.getInstanceDriver(), context.getPhysicalDevice(), config.format)); |
| const vk::VkFormatFeatureFlags features (config.imageTiling == vk::VK_IMAGE_TILING_OPTIMAL |
| ? properties.optimalTilingFeatures |
| : properties.linearTilingFeatures); |
| |
| if ((features & (vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT | vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) == 0) |
| TCU_THROW(NotSupportedError, "Format doesn't support YCbCr conversions"); |
| |
| if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0) |
| TCU_THROW(NotSupportedError, "Format doesn't support sampling"); |
| |
| if (config.textureFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction"); |
| |
| if (config.chromaFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction"); |
| |
| if (config.chromaFilter != config.textureFilter && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't support different chroma and texture filters"); |
| |
| if (config.explicitReconstruction && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't support explicit chroma reconstruction"); |
| |
| if (config.disjoint && ((features & vk::VK_FORMAT_FEATURE_DISJOINT_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't disjoint planes"); |
| |
| if (ycbcr::isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples"); |
| |
| if (ycbcr::isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples"); |
| |
| if (ycbcr::isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples"); |
| |
| if (ycbcr::isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0)) |
| TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples"); |
| |
| if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT) != 0) |
| config.explicitReconstruction = true; |
| |
| log << tcu::TestLog::Message << "FormatFeatures: " << vk::getFormatFeatureFlagsStr(features) << tcu::TestLog::EndMessage; |
| } |
| catch (const vk::Error& err) |
| { |
| if (err.getError() == vk::VK_ERROR_FORMAT_NOT_SUPPORTED) |
| TCU_THROW(NotSupportedError, "Format not supported"); |
| |
| throw; |
| } |
| } |
| |
| vk::Move<vk::VkSampler> createSampler (const vk::DeviceInterface& vkd, |
| const vk::VkDevice device, |
| const vk::VkFilter textureFilter, |
| const vk::VkSamplerAddressMode addressModeU, |
| const vk::VkSamplerAddressMode addressModeV, |
| const vk::VkSamplerYcbcrConversion conversion) |
| { |
| const vk::VkSamplerYcbcrConversionInfo samplerConversionInfo = |
| { |
| vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, |
| DE_NULL, |
| conversion |
| }; |
| |
| const vk::VkSamplerCreateInfo createInfo = |
| { |
| vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, |
| &samplerConversionInfo, |
| 0u, |
| textureFilter, |
| textureFilter, |
| vk::VK_SAMPLER_MIPMAP_MODE_NEAREST, |
| addressModeU, |
| addressModeV, |
| vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
| 0.0f, |
| VK_FALSE, |
| 1.0f, |
| VK_FALSE, |
| vk::VK_COMPARE_OP_ALWAYS, |
| 0.0f, |
| 0.0f, |
| vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, |
| VK_FALSE, |
| }; |
| |
| return createSampler(vkd, device, &createInfo); |
| } |
| |
| vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface& vkd, |
| const vk::VkDevice device, |
| const vk::VkImage image, |
| const vk::VkFormat format, |
| const vk::VkSamplerYcbcrConversion conversion) |
| { |
| const vk::VkSamplerYcbcrConversionInfo conversionInfo = |
| { |
| vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, |
| DE_NULL, |
| conversion |
| }; |
| |
| const vk::VkImageViewCreateInfo viewInfo = |
| { |
| vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| &conversionInfo, |
| (vk::VkImageViewCreateFlags)0, |
| image, |
| vk::VK_IMAGE_VIEW_TYPE_2D, |
| format, |
| { |
| vk::VK_COMPONENT_SWIZZLE_IDENTITY, |
| vk::VK_COMPONENT_SWIZZLE_IDENTITY, |
| vk::VK_COMPONENT_SWIZZLE_IDENTITY, |
| vk::VK_COMPONENT_SWIZZLE_IDENTITY, |
| }, |
| { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, |
| }; |
| |
| return vk::createImageView(vkd, device, &viewInfo); |
| } |
| |
| vk::Move<vk::VkSamplerYcbcrConversion> createConversion (const vk::DeviceInterface& vkd, |
| const vk::VkDevice device, |
| const vk::VkFormat format, |
| const vk::VkSamplerYcbcrModelConversion colorModel, |
| const vk::VkSamplerYcbcrRange colorRange, |
| const vk::VkChromaLocation xChromaOffset, |
| const vk::VkChromaLocation yChromaOffset, |
| const vk::VkFilter chromaFilter, |
| const vk::VkComponentMapping& componentMapping, |
| const bool explicitReconstruction) |
| { |
| const vk::VkSamplerYcbcrConversionCreateInfo conversionInfo = |
| { |
| vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, |
| DE_NULL, |
| |
| format, |
| colorModel, |
| colorRange, |
| componentMapping, |
| xChromaOffset, |
| yChromaOffset, |
| chromaFilter, |
| explicitReconstruction ? VK_TRUE : VK_FALSE |
| }; |
| |
| return vk::createSamplerYcbcrConversion(vkd, device, &conversionInfo); |
| } |
| |
| void uploadYCbCrImage (ProtectedContext& ctx, |
| const vk::VkImage image, |
| const ycbcr::MultiPlaneImageData& imageData, |
| const vk::VkAccessFlags nextAccess, |
| const vk::VkImageLayout finalLayout) |
| { |
| const vk::DeviceInterface& vk = ctx.getDeviceInterface(); |
| const vk::VkDevice device = ctx.getDevice(); |
| const vk::VkQueue queue = ctx.getQueue(); |
| const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex(); |
| |
| const vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex)); |
| const vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| |
| const vk::PlanarFormatDescription& formatDesc = imageData.getDescription(); |
| |
| std::vector<de::SharedPtr<de::MovePtr<vk::BufferWithMemory> > > stagingBuffers; |
| std::vector<vk::VkBufferMemoryBarrier> bufferBarriers; |
| |
| for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) |
| { |
| de::MovePtr<vk::BufferWithMemory> buffer (makeBuffer(ctx, |
| PROTECTION_DISABLED, |
| queueFamilyIndex, |
| (deUint32)imageData.getPlaneSize(planeNdx), |
| vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT|vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| vk::MemoryRequirement::HostVisible)); |
| |
| const vk::VkBufferMemoryBarrier bufferBarrier = |
| { |
| vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| DE_NULL, |
| (vk::VkAccessFlags)0, |
| vk::VK_ACCESS_TRANSFER_READ_BIT, |
| queueFamilyIndex, |
| queueFamilyIndex, |
| **buffer, |
| 0, |
| (deUint32)imageData.getPlaneSize(planeNdx) |
| }; |
| bufferBarriers.push_back(bufferBarrier); |
| |
| deMemcpy(buffer->getAllocation().getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx)); |
| flushAlloc(vk, device, buffer->getAllocation()); |
| stagingBuffers.push_back(de::SharedPtr<de::MovePtr<vk::BufferWithMemory> >(new de::MovePtr<vk::BufferWithMemory>(buffer.release()))); |
| } |
| |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) |
| { |
| const vk::VkImageAspectFlags aspect = formatDesc.numPlanes > 1 |
| ? vk::getPlaneAspect(planeNdx) |
| : vk::VK_IMAGE_ASPECT_COLOR_BIT; |
| |
| const vk::VkImageMemoryBarrier preCopyBarrier = |
| { |
| vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| (vk::VkAccessFlags)0, |
| vk::VK_ACCESS_TRANSFER_WRITE_BIT, |
| vk::VK_IMAGE_LAYOUT_UNDEFINED, |
| vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| queueFamilyIndex, |
| queueFamilyIndex, |
| image, |
| { aspect, 0u, 1u, 0u, 1u } |
| }; |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, |
| (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_HOST_BIT, |
| (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TRANSFER_BIT, |
| (vk::VkDependencyFlags)0u, |
| 0u, (const vk::VkMemoryBarrier*)DE_NULL, |
| (deUint32)bufferBarriers.size(), &bufferBarriers[0], |
| 1u, &preCopyBarrier); |
| } |
| |
| for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) |
| { |
| const vk::VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) |
| ? vk::getPlaneAspect(planeNdx) |
| : vk::VK_IMAGE_ASPECT_COLOR_BIT; |
| const deUint32 planeW = (formatDesc.numPlanes > 1) |
| ? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor |
| : imageData.getSize().x(); |
| const deUint32 planeH = (formatDesc.numPlanes > 1) |
| ? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor |
| : imageData.getSize().y(); |
| const vk::VkBufferImageCopy copy = |
| { |
| 0u, // bufferOffset |
| 0u, // bufferRowLength |
| 0u, // bufferImageHeight |
| { (vk::VkImageAspectFlags)aspect, 0u, 0u, 1u }, |
| vk::makeOffset3D(0u, 0u, 0u), |
| vk::makeExtent3D(planeW, planeH, 1u), |
| }; |
| |
| vk.cmdCopyBufferToImage(*cmdBuffer, ***stagingBuffers[planeNdx], image, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©); |
| } |
| |
| for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) |
| { |
| const vk::VkImageAspectFlags aspect = formatDesc.numPlanes > 1 |
| ? vk::getPlaneAspect(planeNdx) |
| : vk::VK_IMAGE_ASPECT_COLOR_BIT; |
| |
| const vk::VkImageMemoryBarrier postCopyBarrier = |
| { |
| vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| vk::VK_ACCESS_TRANSFER_WRITE_BIT, |
| nextAccess, |
| vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| finalLayout, |
| VK_QUEUE_FAMILY_IGNORED, |
| VK_QUEUE_FAMILY_IGNORED, |
| image, |
| { aspect, 0u, 1u, 0u, 1u } |
| }; |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, |
| (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TRANSFER_BIT, |
| (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, |
| (vk::VkDependencyFlags)0u, |
| 0u, (const vk::VkMemoryBarrier*)DE_NULL, |
| 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL, |
| 1u, &postCopyBarrier); |
| } |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| |
| { |
| const vk::Unique<vk::VkFence> fence (createFence(vk, device)); |
| VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull)); |
| } |
| } |
| |
| void logTestCaseInfo (tcu::TestLog& log, const TestConfig& config) |
| { |
| log << tcu::TestLog::Message << "ShaderType: " << config.shaderType << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "Format: " << config.format << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "ImageTiling: " << config.imageTiling << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "TextureFilter: " << config.textureFilter << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "AddressModeU: " << config.addressModeU << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "AddressModeV: " << config.addressModeV << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "ChromaFilter: " << config.chromaFilter << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "XChromaOffset: " << config.xChromaOffset << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "YChromaOffset: " << config.yChromaOffset << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "ExplicitReconstruction: " << (config.explicitReconstruction ? "true" : "false") << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "Disjoint: " << (config.disjoint ? "true" : "false") << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "ColorRange: " << config.colorRange << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "ColorModel: " << config.colorModel << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "ComponentMapping: " << config.componentMapping << tcu::TestLog::EndMessage; |
| } |
| |
| void logBoundImages (tcu::TestLog& log, const tcu::UVec2 size, const std::vector<tcu::Vec4>& minBounds, const std::vector<tcu::Vec4>& maxBounds) |
| { |
| tcu::TextureLevel minImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x(), size.y()); |
| tcu::TextureLevel maxImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x(), size.y()); |
| |
| for (int y = 0; y < (int)(size.y()); y++) |
| for (int x = 0; x < (int)(size.x()); x++) |
| { |
| const int ndx = x + y * (int)(size.x()); |
| minImage.getAccess().setPixel(minBounds[ndx], x, y); |
| maxImage.getAccess().setPixel(maxBounds[ndx], x, y); |
| } |
| |
| const tcu::Vec4 scale (1.0f); |
| const tcu::Vec4 bias (0.0f); |
| |
| log << tcu::TestLog::Image("MinBoundImage", "MinBoundImage", minImage.getAccess(), scale, bias); |
| log << tcu::TestLog::Image("MaxBoundImage", "MaxBoundImage", maxImage.getAccess(), scale, bias); |
| } |
| |
| bool validateImage (ProtectedContext& ctx, |
| const std::vector<YCbCrValidationData>& refData, |
| const vk::VkSampler sampler, |
| const vk::VkImageView imageView, |
| const deUint32 combinedSamplerDescriptorCount) |
| { |
| { |
| tcu::TestLog& log (ctx.getTestContext().getLog()); |
| |
| log << tcu::TestLog::Message << "Reference values:" << tcu::TestLog::EndMessage; |
| for (deUint32 ndx = 0; ndx < refData.size(); ndx++) |
| { |
| log << tcu::TestLog::Message << (ndx + 1) << refData[ndx].coord << ": [" << refData[ndx].minBound << ", " << refData[ndx].maxBound << "]" << tcu::TestLog::EndMessage; |
| } |
| } |
| |
| const deUint64 oneSec = 1000 * 1000 * 1000; |
| |
| const vk::DeviceInterface& vk = ctx.getDeviceInterface(); |
| const vk::VkDevice device = ctx.getDevice(); |
| const vk::VkQueue queue = ctx.getQueue(); |
| const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex(); |
| |
| DE_ASSERT(refData.size() >= CHECK_SIZE && CHECK_SIZE > 0); |
| const deUint32 refUniformSize = (deUint32)(sizeof(YCbCrValidationData) * refData.size()); |
| const de::UniquePtr<vk::BufferWithMemory> refUniform (makeBuffer(ctx, |
| PROTECTION_DISABLED, |
| queueFamilyIndex, |
| refUniformSize, |
| vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, |
| vk::MemoryRequirement::HostVisible)); |
| |
| // Set the reference uniform data |
| { |
| deMemcpy(refUniform->getAllocation().getHostPtr(), &refData[0], refUniformSize); |
| flushAlloc(vk, device, refUniform->getAllocation()); |
| } |
| |
| const deUint32 helperBufferSize = (deUint32)(2 * sizeof(deUint32)); |
| const de::MovePtr<vk::BufferWithMemory> helperBuffer (makeBuffer(ctx, |
| PROTECTION_ENABLED, |
| queueFamilyIndex, |
| helperBufferSize, |
| vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, |
| vk::MemoryRequirement::Protected)); |
| const vk::Unique<vk::VkShaderModule> resetSSBOShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ResetSSBO"), 0)); |
| const vk::Unique<vk::VkShaderModule> validatorShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ImageValidator"), 0)); |
| |
| // Create descriptors |
| const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(vk::DescriptorSetLayoutBuilder() |
| .addSingleSamplerBinding(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_SHADER_STAGE_COMPUTE_BIT, &sampler) |
| .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT) |
| .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT) |
| .build(vk, device)); |
| const vk::Unique<vk::VkDescriptorPool> descriptorPool(vk::DescriptorPoolBuilder() |
| .addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, combinedSamplerDescriptorCount) |
| .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u) |
| .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u) |
| .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); |
| const vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); |
| |
| // Update descriptor set infirmation |
| { |
| vk::VkDescriptorBufferInfo descRefUniform = makeDescriptorBufferInfo(**refUniform, 0, refUniformSize); |
| vk::VkDescriptorBufferInfo descBuffer = makeDescriptorBufferInfo(**helperBuffer, 0, helperBufferSize); |
| vk::VkDescriptorImageInfo descSampledImg = makeDescriptorImageInfo(sampler, imageView, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| |
| vk::DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descSampledImg) |
| .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform) |
| .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descBuffer) |
| .update(vk, device); |
| } |
| |
| const vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout)); |
| const vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex)); |
| |
| // Reset helper SSBO |
| { |
| const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device)); |
| const vk::Unique<vk::VkPipeline> resetSSBOPipeline (makeComputePipeline(vk, device, *pipelineLayout, *resetSSBOShader)); |
| const vk::Unique<vk::VkCommandBuffer> resetCmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| beginCommandBuffer(vk, *resetCmdBuffer); |
| |
| vk.cmdBindPipeline(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *resetSSBOPipeline); |
| vk.cmdBindDescriptorSets(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL); |
| vk.cmdDispatch(*resetCmdBuffer, 1u, 1u, 1u); |
| |
| endCommandBuffer(vk, *resetCmdBuffer); |
| VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *resetCmdBuffer, *fence, ~0ull)); |
| } |
| |
| // Create validation compute commands & submit |
| vk::VkResult queueSubmitResult; |
| { |
| const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device)); |
| const vk::Unique<vk::VkPipeline> validationPipeline (makeComputePipeline(vk, device, *pipelineLayout, *validatorShader)); |
| const vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *validationPipeline); |
| vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL); |
| vk.cmdDispatch(*cmdBuffer, CHECK_SIZE, 1u, 1u); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| |
| queueSubmitResult = queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, oneSec * 5); |
| } |
| |
| // \todo do we need to check the fence status? |
| if (queueSubmitResult == vk::VK_TIMEOUT) |
| return false; |
| |
| // at this point the submit result should be VK_TRUE |
| VK_CHECK(queueSubmitResult); |
| return true; |
| } |
| |
| void testShaders (vk::SourceCollections& dst, const TestConfig config) |
| { |
| const char* const shaderHeader = |
| "layout(constant_id = 1) const float threshold = 0.01f;\n" |
| "layout(set = 0, binding = 0) uniform highp sampler2D protectedImage;\n" |
| "\n" |
| "struct validationData {\n" |
| " highp vec4 imageCoord;\n" |
| " highp vec4 imageRefMinBound;\n" |
| " highp vec4 imageRefMaxBound;\n" |
| "};\n" |
| "layout(std140, set = 0, binding = 1) uniform Data\n" |
| "{\n" |
| " validationData ref[250];\n" |
| "};\n"; |
| |
| const char* const compareFunction = |
| "bool compare(highp vec4 value, highp vec4 minValue, highp vec4 maxValue)\n" |
| "{\n" |
| " return all(greaterThanEqual(value, minValue - threshold)) && all(lessThanEqual(value, maxValue + threshold));\n" |
| "}\n"; |
| |
| std::map<std::string, std::string> validatorSpec; |
| validatorSpec["CHECK_SIZE"] = de::toString((deUint32)CHECK_SIZE); |
| validatorSpec["SHADER_HEADER"] = shaderHeader; |
| validatorSpec["COMPARE_FUNCTION"] = compareFunction; |
| |
| const char* const validatorShader = |
| "#version 450\n" |
| "\n" |
| "${SHADER_HEADER}" |
| "\n" |
| "layout(std140, set = 0, binding = 2) buffer ProtectedHelper\n" |
| "{\n" |
| " highp uint zero;\n" |
| " highp uint unusedOut;\n" |
| "} helper;\n" |
| "\n" |
| "void error()\n" |
| "{\n" |
| " for (uint x = 0u; x < 10u; x += helper.zero)\n" |
| " atomicAdd(helper.unusedOut, 1u);\n" |
| "}\n" |
| "\n" |
| "${COMPARE_FUNCTION}" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " int idx = int(gl_GlobalInvocationID.x);\n" |
| " vec4 currentValue = texture(protectedImage, ref[idx].imageCoord.xy);\n" |
| " if (!compare(currentValue, ref[idx].imageRefMinBound, ref[idx].imageRefMaxBound))\n" |
| " {\n" |
| " error();\n" |
| " }\n" |
| "}\n"; |
| |
| const char* const resetSSBOShader = |
| "#version 450\n" |
| "layout(local_size_x = 1) in;\n" |
| "\n" |
| "layout(std140, set=0, binding=2) buffer ProtectedHelper\n" |
| "{\n" |
| " highp uint zero; // set to 0\n" |
| " highp uint unusedOut;\n" |
| "} helper;\n" |
| "\n" |
| "void main (void)\n" |
| "{\n" |
| " helper.zero = 0;\n" |
| " helper.unusedOut = 0;\n" |
| "}\n"; |
| |
| dst.glslSources.add("ResetSSBO") << glu::ComputeSource(resetSSBOShader); |
| dst.glslSources.add("ImageValidator") << glu::ComputeSource(tcu::StringTemplate(validatorShader).specialize(validatorSpec)); |
| |
| if (config.shaderType == glu::SHADERTYPE_COMPUTE) |
| return; // Bail early as the YCbCr image validator already have the test programs set for compute tests |
| |
| const char* const compareOperation = |
| " highp vec4 currentValue = texture(protectedImage, ref[v_idx].imageCoord.xy);\n" |
| " if (compare(currentValue, ref[v_idx].imageRefMinBound, ref[v_idx].imageRefMaxBound))\n" |
| " {\n" |
| " o_color = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n" // everything is ok, green |
| " }\n" |
| " else" |
| " {\n" |
| " o_color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n" |
| " }\n"; |
| |
| std::map<std::string, std::string> shaderSpec; |
| shaderSpec["SHADER_HEADER"] = shaderHeader; |
| shaderSpec["COMPARE_FUNCTION"] = compareFunction; |
| shaderSpec["COMPARE_OPERATION"] = compareOperation; |
| |
| if (config.shaderType == glu::SHADERTYPE_VERTEX) |
| { |
| const char* const vertexShader = |
| "#version 450\n" |
| "${SHADER_HEADER}\n" |
| "\n" |
| "layout(location = 0) in highp vec2 a_position;\n" |
| "layout(location = 0) flat out highp vec4 o_color;\n" |
| "\n" |
| "${COMPARE_FUNCTION}" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " gl_Position = vec4(a_position, 0.0f, 1.0f);\n" |
| " gl_PointSize = 1.0f;\n" |
| " int v_idx = gl_VertexIndex;\n" |
| "${COMPARE_OPERATION}" |
| "}\n"; |
| |
| const char* const fragmentShader = |
| "#version 450\n" |
| "\n" |
| "layout(location = 0) flat in highp vec4 v_color;\n" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " o_color = v_color;\n" |
| "}\n"; |
| |
| dst.glslSources.add("vert") << glu::VertexSource(tcu::StringTemplate(vertexShader).specialize(shaderSpec)); |
| dst.glslSources.add("frag") << glu::FragmentSource(fragmentShader); |
| } |
| else if (config.shaderType == glu::SHADERTYPE_FRAGMENT) |
| { |
| const char* const vertexShader = |
| "#version 450\n" |
| "layout(location = 0) in highp vec2 a_position;\n" |
| "layout(location = 0) flat out highp int o_idx;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " gl_Position = vec4(a_position, 0.0f, 1.0f);\n" |
| " gl_PointSize = 1.0f;\n" |
| " o_idx = gl_VertexIndex;\n" |
| "}\n"; |
| |
| const char* const fragmentShader = |
| "#version 450\n" |
| "${SHADER_HEADER}\n" |
| "\n" |
| "layout(location = 0) flat in highp int v_idx;\n" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "\n" |
| "${COMPARE_FUNCTION}" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| "${COMPARE_OPERATION}" |
| "}\n"; |
| |
| dst.glslSources.add("vert") << glu::VertexSource(vertexShader); |
| dst.glslSources.add("frag") << glu::FragmentSource(tcu::StringTemplate(fragmentShader).specialize(shaderSpec)); |
| } |
| } |
| |
| de::MovePtr<vk::YCbCrImageWithMemory> createYcbcrImage2D (ProtectedContext& context, |
| const ProtectionMode protectionMode, |
| const deUint32 width, |
| const deUint32 height, |
| const vk::VkFormat format, |
| const vk::VkImageCreateFlags createFlags, |
| const vk::VkImageUsageFlags usageFlags) |
| { |
| const vk::DeviceInterface& vk = context.getDeviceInterface(); |
| const vk::VkDevice& device = context.getDevice(); |
| vk::Allocator& allocator = context.getDefaultAllocator(); |
| const deUint32 queueIdx = context.getQueueFamilyIndex(); |
| #ifndef NOT_PROTECTED |
| const deUint32 flags = (protectionMode == PROTECTION_ENABLED) ? vk::VK_IMAGE_CREATE_PROTECTED_BIT : 0x0; |
| const vk::MemoryRequirement memReq = (protectionMode == PROTECTION_ENABLED) ? vk::MemoryRequirement::Protected : vk::MemoryRequirement::Any; |
| #else |
| const deUint32 flags = 0x0; |
| const vk::MemoryRequirement memReq = vk::MemoryRequirement::Any; |
| DE_UNREF(protectionMode); |
| #endif |
| |
| const vk::VkImageCreateInfo params = |
| { |
| vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType stype |
| DE_NULL, // const void* pNext |
| (vk::VkImageCreateFlags)(flags | createFlags), // VkImageCreateFlags flags |
| vk::VK_IMAGE_TYPE_2D, // VkImageType imageType |
| format, // VkFormat format |
| { width, height, 1 }, // VkExtent3D extent |
| 1u, // deUint32 mipLevels |
| 1u, // deUint32 arrayLayers |
| vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| usageFlags, // VkImageUsageFlags usage |
| vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 1u, // deUint32 queueFamilyIndexCount |
| &queueIdx, // const deUint32* pQueueFamilyIndices |
| vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout |
| }; |
| |
| return de::MovePtr<vk::YCbCrImageWithMemory>(new vk::YCbCrImageWithMemory(vk, device, allocator, params, memReq)); |
| } |
| |
| |
| void renderYCbCrToColor (ProtectedContext& ctx, |
| const tcu::UVec2 size, |
| const vk::VkSampler ycbcrSampler, |
| const vk::VkImageView ycbcrImageView, |
| const vk::VkImage colorImage, |
| const vk::VkImageView colorImageView, |
| const std::vector<YCbCrValidationData>& referenceData, |
| const std::vector<tcu::Vec2>& posCoords, |
| const deUint32 combinedSamplerDescriptorCount) |
| { |
| const vk::DeviceInterface& vk = ctx.getDeviceInterface(); |
| const vk::VkDevice device = ctx.getDevice(); |
| const vk::VkQueue queue = ctx.getQueue(); |
| const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex(); |
| |
| const vk::Unique<vk::VkRenderPass> renderPass (createRenderPass(ctx, s_colorFormat)); |
| const vk::Unique<vk::VkFramebuffer> framebuffer (createFramebuffer(ctx, size.x(), size.y(), *renderPass, colorImageView)); |
| const vk::Unique<vk::VkShaderModule> vertexShader (createShaderModule(vk, device, ctx.getBinaryCollection().get("vert"), 0)); |
| const vk::Unique<vk::VkShaderModule> fragmentShader (createShaderModule(vk, device, ctx.getBinaryCollection().get("frag"), 0)); |
| const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout (vk::DescriptorSetLayoutBuilder() |
| .addSingleSamplerBinding(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| vk::VK_SHADER_STAGE_ALL, |
| &ycbcrSampler) |
| .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL) |
| .build(vk, device)); |
| const vk::Unique<vk::VkDescriptorPool> descriptorPool (vk::DescriptorPoolBuilder() |
| .addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, combinedSamplerDescriptorCount) |
| .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u) |
| .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); |
| const vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); |
| const vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout)); |
| |
| |
| const deUint32 refUniformSize = (deUint32)(sizeof(YCbCrValidationData) * referenceData.size()); |
| const de::UniquePtr<vk::BufferWithMemory> refUniform (makeBuffer(ctx, |
| PROTECTION_DISABLED, |
| queueFamilyIndex, |
| refUniformSize, |
| vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, |
| vk::MemoryRequirement::HostVisible)); |
| |
| // Set the reference uniform data |
| { |
| deMemcpy(refUniform->getAllocation().getHostPtr(), &referenceData[0], refUniformSize); |
| flushAlloc(vk, device, refUniform->getAllocation()); |
| } |
| |
| // Update descriptor set |
| { |
| vk::VkDescriptorImageInfo ycbcrSampled (makeDescriptorImageInfo(ycbcrSampler, ycbcrImageView, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)); |
| vk::VkDescriptorBufferInfo descRefUniform = makeDescriptorBufferInfo(**refUniform, 0, refUniformSize); |
| vk::DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &ycbcrSampled) |
| .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform) |
| .update(vk, device); |
| } |
| |
| VertexBindings vertexBindings; |
| VertexAttribs vertexAttribs; |
| de::MovePtr<vk::BufferWithMemory> vertexBuffer; |
| { |
| const deUint32 bufferSize = (deUint32)(sizeof(tcu::Vec2) * posCoords.size()); |
| { |
| const vk::VkVertexInputBindingDescription inputBinding = |
| { |
| 0u, // deUint32 binding; |
| sizeof(tcu::Vec2), // deUint32 strideInBytes; |
| vk::VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate; |
| }; |
| const vk::VkVertexInputAttributeDescription inputAttribute = |
| { |
| 0u, // deUint32 location; |
| 0u, // deUint32 binding; |
| vk::VK_FORMAT_R32G32_SFLOAT, // VkFormat format; |
| 0u // deUint32 offsetInBytes; |
| }; |
| |
| vertexBindings.push_back(inputBinding); |
| vertexAttribs.push_back(inputAttribute); |
| } |
| |
| vertexBuffer = makeBuffer(ctx, |
| PROTECTION_DISABLED, |
| queueFamilyIndex, |
| bufferSize, |
| vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, |
| vk::MemoryRequirement::HostVisible); |
| |
| deMemcpy(vertexBuffer->getAllocation().getHostPtr(), &posCoords[0], bufferSize); |
| flushAlloc(vk, device, vertexBuffer->getAllocation()); |
| } |
| |
| const vk::Unique<vk::VkPipeline> pipeline (makeGraphicsPipeline(vk, |
| device, |
| *pipelineLayout, |
| *renderPass, |
| *vertexShader, |
| *fragmentShader, |
| vertexBindings, |
| vertexAttribs, |
| size, |
| vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)); |
| const vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex)); |
| const vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| { |
| const vk::VkImageMemoryBarrier attachmentStartBarrier = |
| { |
| vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| 0u, |
| vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
| vk::VK_IMAGE_LAYOUT_UNDEFINED, |
| vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| queueFamilyIndex, |
| queueFamilyIndex, |
| colorImage, |
| { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } |
| }; |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, |
| (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, |
| (vk::VkDependencyFlags)0u, |
| 0u, (const vk::VkMemoryBarrier*)DE_NULL, |
| 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL, |
| 1u, &attachmentStartBarrier); |
| } |
| |
| beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, vk::makeRect2D(0, 0, size.x(), size.y()), tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f)); |
| |
| vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL); |
| |
| { |
| const vk::VkDeviceSize vertexBufferOffset = 0; |
| vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &**vertexBuffer, &vertexBufferOffset); |
| } |
| |
| vk.cmdDraw(*cmdBuffer, /*vertexCount*/ (deUint32)posCoords.size(), 1u, 0u, 0u); |
| |
| endRenderPass(vk, *cmdBuffer); |
| |
| // color attachment render end barrier |
| { |
| const vk::VkImageMemoryBarrier attachmentEndBarrier = |
| { |
| vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, |
| DE_NULL, |
| vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, |
| vk::VK_ACCESS_SHADER_READ_BIT, |
| vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, |
| queueFamilyIndex, |
| queueFamilyIndex, |
| colorImage, |
| { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } |
| }; |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, |
| (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, |
| (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, |
| (vk::VkDependencyFlags)0u, |
| 0u, (const vk::VkMemoryBarrier*)DE_NULL, |
| 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL, |
| 1u, &attachmentEndBarrier); |
| } |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| |
| // Submit command buffer |
| { |
| const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device)); |
| VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull)); |
| } |
| } |
| |
| void generateYCbCrImage (ProtectedContext& ctx, |
| const TestConfig& config, |
| const tcu::UVec2 size, |
| const std::vector<tcu::Vec2>& texCoords, |
| ycbcr::MultiPlaneImageData& ycbcrSrc, |
| std::vector<tcu::Vec4>& ycbcrMinBounds, |
| std::vector<tcu::Vec4>& ycbcrMaxBounds) |
| { |
| tcu::TestLog& log (ctx.getTestContext().getLog()); |
| const std::vector<tcu::FloatFormat> filteringPrecision (ycbcr::getPrecision(config.format)); |
| const std::vector<tcu::FloatFormat> conversionPrecision (ycbcr::getPrecision(config.format)); |
| const tcu::UVec4 bitDepth (ycbcr::getYCbCrBitDepth(config.format)); |
| bool explicitReconstruction = config.explicitReconstruction; |
| const deUint32 subTexelPrecisionBits (vk::getPhysicalDeviceProperties(ctx.getInstanceDriver(), |
| ctx.getPhysicalDevice()).limits.subTexelPrecisionBits); |
| |
| |
| const vk::PlanarFormatDescription planeInfo (vk::getPlanarFormatDescription(config.format)); |
| |
| deUint32 nullAccessData (0u); |
| ycbcr::ChannelAccess nullAccess (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(size.x(), size.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessData, 0u); |
| deUint32 nullAccessAlphaData (~0u); |
| ycbcr::ChannelAccess nullAccessAlpha (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(size.x(), size.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessAlphaData, 0u); |
| ycbcr::ChannelAccess rChannelAccess (planeInfo.hasChannelNdx(0) ? getChannelAccess(ycbcrSrc, planeInfo, size, 0) : nullAccess); |
| ycbcr::ChannelAccess gChannelAccess (planeInfo.hasChannelNdx(1) ? getChannelAccess(ycbcrSrc, planeInfo, size, 1) : nullAccess); |
| ycbcr::ChannelAccess bChannelAccess (planeInfo.hasChannelNdx(2) ? getChannelAccess(ycbcrSrc, planeInfo, size, 2) : nullAccess); |
| ycbcr::ChannelAccess aChannelAccess (planeInfo.hasChannelNdx(3) ? getChannelAccess(ycbcrSrc, planeInfo, size, 3) : nullAccessAlpha); |
| const bool implicitNearestCosited ((config.chromaFilter == vk::VK_FILTER_NEAREST && !explicitReconstruction) && |
| (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN || config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)); |
| |
| for (deUint32 planeNdx = 0; planeNdx < planeInfo.numPlanes; planeNdx++) |
| deMemset(ycbcrSrc.getPlanePtr(planeNdx), 0u, ycbcrSrc.getPlaneSize(planeNdx)); |
| |
| // \todo Limit values to only values that produce defined values using selected colorRange and colorModel? The verification code handles those cases already correctly. |
| if (planeInfo.hasChannelNdx(0)) |
| { |
| for (int y = 0; y < rChannelAccess.getSize().y(); y++) |
| for (int x = 0; x < rChannelAccess.getSize().x(); x++) |
| rChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)x / (float)rChannelAccess.getSize().x()); |
| } |
| |
| if (planeInfo.hasChannelNdx(1)) |
| { |
| for (int y = 0; y < gChannelAccess.getSize().y(); y++) |
| for (int x = 0; x < gChannelAccess.getSize().x(); x++) |
| gChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)y / (float)gChannelAccess.getSize().y()); |
| } |
| |
| if (planeInfo.hasChannelNdx(2)) |
| { |
| for (int y = 0; y < bChannelAccess.getSize().y(); y++) |
| for (int x = 0; x < bChannelAccess.getSize().x(); x++) |
| bChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)(x + y) / (float)(bChannelAccess.getSize().x() + bChannelAccess.getSize().y())); |
| } |
| |
| if (planeInfo.hasChannelNdx(3)) |
| { |
| for (int y = 0; y < aChannelAccess.getSize().y(); y++) |
| for (int x = 0; x < aChannelAccess.getSize().x(); x++) |
| aChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)(x * y) / (float)(aChannelAccess.getSize().x() * aChannelAccess.getSize().y())); |
| } |
| |
| std::vector<tcu::Vec4> uvBounds; |
| std::vector<tcu::IVec4> ijBounds; |
| ycbcr::calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, texCoords, filteringPrecision, conversionPrecision, subTexelPrecisionBits, config.textureFilter, config.colorModel, config.colorRange, config.chromaFilter, config.xChromaOffset, config.yChromaOffset, config.componentMapping, explicitReconstruction, config.addressModeU, config.addressModeV, ycbcrMinBounds, ycbcrMaxBounds, uvBounds, ijBounds); |
| |
| // Handle case: If implicit reconstruction and chromaFilter == NEAREST, an implementation may behave as if both chroma offsets are MIDPOINT. |
| if (implicitNearestCosited) |
| { |
| std::vector<tcu::Vec4> relaxedYcbcrMinBounds; |
| std::vector<tcu::Vec4> relaxedYcbcrMaxBounds; |
| |
| ycbcr::calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, texCoords, filteringPrecision, conversionPrecision, subTexelPrecisionBits, config.textureFilter, config.colorModel, config.colorRange, config.chromaFilter, vk::VK_CHROMA_LOCATION_MIDPOINT, vk::VK_CHROMA_LOCATION_MIDPOINT, config.componentMapping, explicitReconstruction, config.addressModeU, config.addressModeV, relaxedYcbcrMinBounds, relaxedYcbcrMaxBounds, uvBounds, ijBounds); |
| |
| DE_ASSERT(relaxedYcbcrMinBounds.size() == ycbcrMinBounds.size()); |
| DE_ASSERT(relaxedYcbcrMaxBounds.size() == ycbcrMaxBounds.size()); |
| |
| for (size_t i = 0; i < ycbcrMinBounds.size(); i++) |
| { |
| ycbcrMinBounds[i] = tcu::Vec4(de::min<float>(ycbcrMinBounds[i].x(), relaxedYcbcrMinBounds[i].x()), |
| de::min<float>(ycbcrMinBounds[i].y(), relaxedYcbcrMinBounds[i].y()), |
| de::min<float>(ycbcrMinBounds[i].z(), relaxedYcbcrMinBounds[i].z()), |
| de::min<float>(ycbcrMinBounds[i].w(), relaxedYcbcrMinBounds[i].w())); |
| |
| ycbcrMaxBounds[i] = tcu::Vec4(de::max<float>(ycbcrMaxBounds[i].x(), relaxedYcbcrMaxBounds[i].x()), |
| de::max<float>(ycbcrMaxBounds[i].y(), relaxedYcbcrMaxBounds[i].y()), |
| de::max<float>(ycbcrMaxBounds[i].z(), relaxedYcbcrMaxBounds[i].z()), |
| de::max<float>(ycbcrMaxBounds[i].w(), relaxedYcbcrMaxBounds[i].w())); |
| } |
| } |
| |
| if (vk::isYCbCrFormat(config.format)) |
| { |
| tcu::TextureLevel rImage (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), rChannelAccess.getSize().x(), rChannelAccess.getSize().y()); |
| tcu::TextureLevel gImage (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), gChannelAccess.getSize().x(), gChannelAccess.getSize().y()); |
| tcu::TextureLevel bImage (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), bChannelAccess.getSize().x(), bChannelAccess.getSize().y()); |
| tcu::TextureLevel aImage (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), aChannelAccess.getSize().x(), aChannelAccess.getSize().y()); |
| |
| for (int y = 0; y < (int)rChannelAccess.getSize().y(); y++) |
| for (int x = 0; x < (int)rChannelAccess.getSize().x(); x++) |
| rImage.getAccess().setPixel(tcu::Vec4(rChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y); |
| |
| for (int y = 0; y < (int)gChannelAccess.getSize().y(); y++) |
| for (int x = 0; x < (int)gChannelAccess.getSize().x(); x++) |
| gImage.getAccess().setPixel(tcu::Vec4(gChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y); |
| |
| for (int y = 0; y < (int)bChannelAccess.getSize().y(); y++) |
| for (int x = 0; x < (int)bChannelAccess.getSize().x(); x++) |
| bImage.getAccess().setPixel(tcu::Vec4(bChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y); |
| |
| for (int y = 0; y < (int)aChannelAccess.getSize().y(); y++) |
| for (int x = 0; x < (int)aChannelAccess.getSize().x(); x++) |
| aImage.getAccess().setPixel(tcu::Vec4(aChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y); |
| |
| { |
| const tcu::Vec4 scale (1.0f); |
| const tcu::Vec4 bias (0.0f); |
| |
| log << tcu::TestLog::Image("SourceImageR", "SourceImageR", rImage.getAccess(), scale, bias); |
| log << tcu::TestLog::Image("SourceImageG", "SourceImageG", gImage.getAccess(), scale, bias); |
| log << tcu::TestLog::Image("SourceImageB", "SourceImageB", bImage.getAccess(), scale, bias); |
| log << tcu::TestLog::Image("SourceImageA", "SourceImageA", aImage.getAccess(), scale, bias); |
| } |
| } |
| else |
| { |
| tcu::TextureLevel ycbcrSrcImage (vk::mapVkFormat(config.format), size.x(), size.y()); |
| |
| for (int y = 0; y < (int)size.y(); y++) |
| for (int x = 0; x < (int)size.x(); x++) |
| { |
| const tcu::IVec3 pos (x, y, 0); |
| ycbcrSrcImage.getAccess().setPixel(tcu::Vec4(rChannelAccess.getChannel(pos), |
| gChannelAccess.getChannel(pos), |
| bChannelAccess.getChannel(pos), |
| aChannelAccess.getChannel(pos)), |
| x, y); |
| } |
| |
| log << tcu::TestLog::Image("SourceImage", "SourceImage", ycbcrSrcImage.getAccess()); |
| } |
| } |
| |
| tcu::TestStatus conversionTest (Context& context, TestConfig config) |
| { |
| std::vector<std::string> requiredDevExt; |
| requiredDevExt.push_back("VK_KHR_sampler_ycbcr_conversion"); |
| requiredDevExt.push_back("VK_KHR_get_memory_requirements2"); |
| requiredDevExt.push_back("VK_KHR_bind_memory2"); |
| requiredDevExt.push_back("VK_KHR_maintenance1"); |
| |
| const tcu::UVec2 size (ycbcr::isXChromaSubsampled(config.format) ? 12 : 7, |
| ycbcr::isYChromaSubsampled(config.format) ? 8 : 13); |
| |
| ProtectedContext ctx (context, std::vector<std::string>(), requiredDevExt); |
| const vk::DeviceInterface& vk = ctx.getDeviceInterface(); |
| const vk::VkDevice device = ctx.getDevice(); |
| const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex(); |
| |
| tcu::TestLog& log (context.getTestContext().getLog()); |
| |
| validateFormatSupport(ctx, config); |
| logTestCaseInfo(log, config); |
| |
| const vk::VkImageCreateFlagBits ycbcrImageFlags = config.disjoint |
| ? vk::VK_IMAGE_CREATE_DISJOINT_BIT |
| : (vk::VkImageCreateFlagBits)0u; |
| const de::MovePtr<vk::YCbCrImageWithMemory> ycbcrImage (createYcbcrImage2D(ctx, PROTECTION_ENABLED, |
| size.x(), size.y(), |
| config.format, |
| ycbcrImageFlags, |
| vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT |
| | vk::VK_IMAGE_USAGE_SAMPLED_BIT)); |
| const vk::Unique<vk::VkSamplerYcbcrConversion> conversion (createConversion(vk, |
| device, |
| config.format, |
| config.colorModel, |
| config.colorRange, |
| config.xChromaOffset, |
| config.yChromaOffset, |
| config.chromaFilter, |
| config.componentMapping, |
| config.explicitReconstruction)); |
| const vk::Unique<vk::VkSampler> ycbcrSampler (createSampler(vk, |
| device, |
| config.textureFilter, |
| config.addressModeU, |
| config.addressModeV, |
| *conversion)); |
| const vk::Unique<vk::VkImageView> ycbcrImageView (createImageView(vk, device, **ycbcrImage, config.format, *conversion)); |
| |
| deUint32 combinedSamplerDescriptorCount = 1; |
| { |
| const vk::VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = |
| { |
| vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType |
| DE_NULL, // pNext |
| config.format, // format |
| vk::VK_IMAGE_TYPE_2D, // type |
| vk::VK_IMAGE_TILING_OPTIMAL, // tiling |
| vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| vk::VK_IMAGE_USAGE_SAMPLED_BIT, // usage |
| ycbcrImageFlags // flags |
| }; |
| |
| vk::VkSamplerYcbcrConversionImageFormatProperties samplerYcbcrConversionImage = {}; |
| samplerYcbcrConversionImage.sType = vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES; |
| samplerYcbcrConversionImage.pNext = DE_NULL; |
| |
| vk::VkImageFormatProperties2 imageFormatProperties = {}; |
| imageFormatProperties.sType = vk::VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; |
| imageFormatProperties.pNext = &samplerYcbcrConversionImage; |
| |
| VK_CHECK(context.getInstanceInterface().getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties)); |
| combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount; |
| } |
| |
| // Input attributes |
| std::vector<tcu::Vec2> texCoords; |
| std::vector<tcu::Vec2> posCoords; |
| genTexCoords(texCoords, size); |
| posCoords = computeVertexPositions((deUint32)texCoords.size(), size.cast<int>()); |
| |
| // Input validation data |
| std::vector<tcu::Vec4> ycbcrMinBounds; |
| std::vector<tcu::Vec4> ycbcrMaxBounds; |
| |
| // Generate input ycbcr image and conversion reference |
| { |
| ycbcr::MultiPlaneImageData ycbcrSrc (config.format, size); |
| |
| generateYCbCrImage(ctx, config, size, texCoords, ycbcrSrc, ycbcrMinBounds, ycbcrMaxBounds); |
| logBoundImages(log, size, ycbcrMinBounds, ycbcrMaxBounds); |
| uploadYCbCrImage(ctx, |
| **ycbcrImage, |
| ycbcrSrc, |
| vk::VK_ACCESS_SHADER_READ_BIT, |
| vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| } |
| |
| // Build up the reference data structure |
| DE_ASSERT(posCoords.size() == ycbcrMinBounds.size()); |
| DE_ASSERT(posCoords.size() == ycbcrMaxBounds.size()); |
| DE_ASSERT(texCoords.size() >= CHECK_SIZE); |
| std::vector<YCbCrValidationData> referenceData; |
| std::vector<YCbCrValidationData> colorReferenceData; |
| |
| for (deUint32 ndx = 0; ndx < texCoords.size(); ++ndx) |
| { |
| YCbCrValidationData data; |
| data.coord = texCoords[ndx].toWidth<4>(); |
| data.minBound = ycbcrMinBounds[ndx]; |
| data.maxBound = ycbcrMaxBounds[ndx]; |
| |
| referenceData.push_back(data); |
| |
| YCbCrValidationData colorData; |
| colorData.coord = posCoords[ndx].toWidth<4>(); |
| colorData.minBound = tcu::Vec4(0.0f, 0.9f, 0.0f, 1.0f); |
| colorData.maxBound = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); |
| |
| colorReferenceData.push_back(colorData); |
| } |
| |
| if (config.shaderType == glu::SHADERTYPE_VERTEX |
| || config.shaderType == glu::SHADERTYPE_FRAGMENT) |
| { |
| const de::UniquePtr<vk::ImageWithMemory> colorImage (createImage2D(ctx, |
| PROTECTION_ENABLED, |
| queueFamilyIndex, |
| size.x(), |
| size.y(), |
| s_colorFormat, |
| vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
| | vk::VK_IMAGE_USAGE_SAMPLED_BIT)); |
| const vk::Unique<vk::VkImageView> colorImageView (createImageView(ctx, **colorImage, s_colorFormat)); |
| const vk::Unique<vk::VkSampler> colorSampler (makeSampler(vk, device)); |
| |
| renderYCbCrToColor(ctx, size, *ycbcrSampler, *ycbcrImageView, **colorImage, *colorImageView, referenceData, posCoords, combinedSamplerDescriptorCount); |
| |
| if (!validateImage(ctx, colorReferenceData, *colorSampler, *colorImageView, combinedSamplerDescriptorCount)) |
| return tcu::TestStatus::fail("YCbCr image conversion via fragment shader failed"); |
| } |
| else if (config.shaderType == glu::SHADERTYPE_COMPUTE) |
| { |
| if (!validateImage(ctx, referenceData, *ycbcrSampler, *ycbcrImageView, combinedSamplerDescriptorCount)) |
| return tcu::TestStatus::fail("YCbCr image conversion via compute shader failed"); |
| } |
| else |
| { |
| TCU_THROW(NotSupportedError, "Unsupported shader test type"); |
| } |
| |
| return tcu::TestStatus::pass("YCbCr image conversion was OK"); |
| } |
| |
| } // anonymous |
| |
| |
| tcu::TestCaseGroup* createYCbCrConversionTests (tcu::TestContext& testCtx) |
| { |
| de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "ycbcr", "YCbCr conversion tests")); |
| |
| struct { |
| const char * name; |
| const glu::ShaderType type; |
| } shaderTypes[] = |
| { |
| { "fragment", glu::SHADERTYPE_FRAGMENT }, |
| { "compute", glu::SHADERTYPE_COMPUTE } |
| }; |
| |
| struct RangeNamePair |
| { |
| const char* name; |
| vk::VkSamplerYcbcrRange value; |
| }; |
| struct ChromaLocationNamePair |
| { |
| const char* name; |
| vk::VkChromaLocation value; |
| }; |
| |
| const vk::VkComponentMapping identitySwizzle = |
| { |
| vk::VK_COMPONENT_SWIZZLE_IDENTITY, |
| vk::VK_COMPONENT_SWIZZLE_IDENTITY, |
| vk::VK_COMPONENT_SWIZZLE_IDENTITY, |
| vk::VK_COMPONENT_SWIZZLE_IDENTITY |
| }; |
| |
| const RangeNamePair colorRanges[] = |
| { |
| { "itu_full", vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL }, |
| { "itu_narrow", vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW } |
| }; |
| |
| const ChromaLocationNamePair chromaLocations[] = |
| { |
| { "cosited", vk::VK_CHROMA_LOCATION_COSITED_EVEN }, |
| { "midpoint", vk::VK_CHROMA_LOCATION_MIDPOINT } |
| }; |
| |
| const struct |
| { |
| const char* const name; |
| const vk::VkSamplerYcbcrModelConversion value; |
| } colorModels[] = |
| { |
| { "rgb_identity", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY }, |
| { "ycbcr_identity", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY }, |
| { "ycbcr_709", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 }, |
| { "ycbcr_601", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 }, |
| { "ycbcr_2020", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 } |
| }; |
| |
| const struct |
| { |
| const char* name; |
| vk::VkImageTiling value; |
| } imageTilings[] = |
| { |
| { "tiling_linear", vk::VK_IMAGE_TILING_LINEAR }, |
| { "tiling_optimal", vk::VK_IMAGE_TILING_OPTIMAL } |
| }; |
| |
| const deUint32 tilingNdx = 1; |
| const vk::VkImageTiling tiling = imageTilings[tilingNdx].value; |
| const char* tilingName = imageTilings[tilingNdx].name; |
| |
| const vk::VkFormat testFormats[] = |
| { |
| // noChromaSubsampledFormats |
| vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16, |
| vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16, |
| vk::VK_FORMAT_R5G6B5_UNORM_PACK16, |
| vk::VK_FORMAT_B5G6R5_UNORM_PACK16, |
| vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16, |
| vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16, |
| vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16, |
| vk::VK_FORMAT_R8G8B8_UNORM, |
| vk::VK_FORMAT_B8G8R8_UNORM, |
| vk::VK_FORMAT_R8G8B8A8_UNORM, |
| vk::VK_FORMAT_B8G8R8A8_UNORM, |
| vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32, |
| vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32, |
| vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32, |
| vk::VK_FORMAT_R16G16B16_UNORM, |
| vk::VK_FORMAT_R16G16B16A16_UNORM, |
| vk::VK_FORMAT_R10X6_UNORM_PACK16, |
| vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16, |
| vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, |
| vk::VK_FORMAT_R12X4_UNORM_PACK16, |
| vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16, |
| vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, |
| vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, |
| vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, |
| vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, |
| vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, |
| |
| // xChromaSubsampledFormats |
| vk::VK_FORMAT_G8B8G8R8_422_UNORM, |
| vk::VK_FORMAT_B8G8R8G8_422_UNORM, |
| vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, |
| vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, |
| |
| vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, |
| vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, |
| vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, |
| vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, |
| vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, |
| vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, |
| vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, |
| vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, |
| vk::VK_FORMAT_G16B16G16R16_422_UNORM, |
| vk::VK_FORMAT_B16G16R16G16_422_UNORM, |
| vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, |
| vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, |
| |
| // xyChromaSubsampledFormats |
| vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, |
| vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, |
| vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, |
| vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, |
| vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, |
| vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, |
| vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, |
| vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, |
| |
| // Extended YCbCr formats |
| vk::VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT, |
| vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT, |
| vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT, |
| vk::VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT, |
| }; |
| |
| for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(testFormats); formatNdx++) |
| { |
| const vk::VkFormat format (testFormats[formatNdx]); |
| const std::string formatName (de::toLower(std::string(getFormatName(format)).substr(10))); |
| de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str())); |
| |
| for (size_t shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderNdx++) |
| { |
| const char* shaderTypeName = shaderTypes[shaderNdx].name; |
| de::MovePtr<tcu::TestCaseGroup> shaderGroup (new tcu::TestCaseGroup(testCtx, shaderTypeName, "YCbCr conversion tests")); |
| |
| for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++) |
| { |
| const char* const colorModelName (colorModels[modelNdx].name); |
| const vk::VkSamplerYcbcrModelConversion colorModel (colorModels[modelNdx].value); |
| |
| if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY && ycbcr::getYCbCrFormatChannelCount(format) < 3) |
| continue; |
| |
| de::MovePtr<tcu::TestCaseGroup> colorModelGroup (new tcu::TestCaseGroup(testCtx, colorModelName, "YCbCr conversion tests")); |
| |
| for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++) |
| { |
| const char* const colorRangeName (colorRanges[rangeNdx].name); |
| const vk::VkSamplerYcbcrRange colorRange (colorRanges[rangeNdx].value); |
| |
| // Narrow range doesn't really work with formats that have less than 8 bits |
| if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW) |
| { |
| const tcu::UVec4 bitDepth (ycbcr::getYCbCrBitDepth(format)); |
| if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8) |
| continue; |
| } |
| |
| de::MovePtr<tcu::TestCaseGroup> colorRangeGroup (new tcu::TestCaseGroup(testCtx, colorRangeName, ("Tests for color range " + std::string(colorRangeName)).c_str())); |
| |
| for (size_t chromaOffsetNdx = 0; chromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); chromaOffsetNdx++) |
| { |
| const char* const chromaOffsetName (chromaLocations[chromaOffsetNdx].name); |
| const vk::VkChromaLocation chromaOffset (chromaLocations[chromaOffsetNdx].value); |
| |
| |
| for (deUint32 disjointNdx = 0; disjointNdx < 2; ++disjointNdx) |
| { |
| bool disjoint = (disjointNdx == 1); |
| const TestConfig config (shaderTypes[shaderNdx].type, |
| format, |
| tiling, |
| vk::VK_FILTER_NEAREST, |
| vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
| vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
| vk::VK_FILTER_NEAREST, |
| chromaOffset, |
| chromaOffset, |
| false, |
| disjoint, |
| colorRange, |
| colorModel, |
| identitySwizzle); |
| |
| addFunctionCaseWithPrograms(colorRangeGroup.get(), |
| std::string(tilingName) + "_" + chromaOffsetName + (disjoint ? "_disjoint" : ""), |
| "", |
| checkSupport, |
| testShaders, |
| conversionTest, |
| config); |
| } |
| } |
| |
| colorModelGroup->addChild(colorRangeGroup.release()); |
| } |
| |
| shaderGroup->addChild(colorModelGroup.release()); |
| } |
| |
| formatGroup->addChild(shaderGroup.release()); |
| |
| } |
| testGroup->addChild(formatGroup.release()); |
| } |
| |
| return testGroup.release(); |
| } |
| |
| } // ProtectedMem |
| } // vkt |