1 #ifndef _VKTYCBCRUTIL_HPP 2 #define _VKTYCBCRUTIL_HPP 3 /*------------------------------------------------------------------------- 4 * Vulkan Conformance Tests 5 * ------------------------ 6 * 7 * Copyright (c) 2017 Google Inc. 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief YCbCr Test Utilities 24 *//*--------------------------------------------------------------------*/ 25 26 #include "tcuDefs.hpp" 27 28 #include "vktTestCase.hpp" 29 30 #include "vkImageUtil.hpp" 31 #include "vkMemUtil.hpp" 32 #include "vkRef.hpp" 33 34 #include "deSharedPtr.hpp" 35 #include "deRandom.hpp" 36 37 #include "tcuTextureUtil.hpp" 38 #include "tcuFloatFormat.hpp" 39 #include "tcuFloat.hpp" 40 #include "tcuInterval.hpp" 41 #include "tcuFloatFormat.hpp" 42 #include "tcuFloat.hpp" 43 44 #include <vector> 45 #include <fstream> 46 47 namespace vkt 48 { 49 namespace ycbcr 50 { 51 52 #define VK_YCBCR_FORMAT_FIRST VK_FORMAT_G8B8G8R8_422_UNORM 53 #define VK_YCBCR_FORMAT_LAST ((vk::VkFormat)(VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM + 1)) 54 55 typedef de::SharedPtr<vk::Allocation> AllocationSp; 56 typedef de::SharedPtr<vk::Unique<vk::VkBuffer>> VkBufferSp; 57 58 class MultiPlaneImageData 59 { 60 public: 61 MultiPlaneImageData(vk::VkFormat format, const tcu::UVec2 &size); 62 MultiPlaneImageData(const MultiPlaneImageData &); 63 ~MultiPlaneImageData(void); 64 getFormat(void) const65 vk::VkFormat getFormat(void) const 66 { 67 return m_format; 68 } getDescription(void) const69 const vk::PlanarFormatDescription &getDescription(void) const 70 { 71 return m_description; 72 } getSize(void) const73 const tcu::UVec2 &getSize(void) const 74 { 75 return m_size; 76 } 77 getPlaneSize(uint32_t planeNdx) const78 size_t getPlaneSize(uint32_t planeNdx) const 79 { 80 return m_planeData[planeNdx].size(); 81 } getPlanePtr(uint32_t planeNdx)82 void *getPlanePtr(uint32_t planeNdx) 83 { 84 return &m_planeData[planeNdx][0]; 85 } getPlanePtr(uint32_t planeNdx) const86 const void *getPlanePtr(uint32_t planeNdx) const 87 { 88 return &m_planeData[planeNdx][0]; 89 } 90 91 tcu::PixelBufferAccess getChannelAccess(uint32_t channelNdx); 92 tcu::ConstPixelBufferAccess getChannelAccess(uint32_t channelNdx) const; 93 94 private: 95 MultiPlaneImageData &operator=(const MultiPlaneImageData &); 96 97 const vk::VkFormat m_format; 98 const vk::PlanarFormatDescription m_description; 99 const tcu::UVec2 m_size; 100 101 std::vector<uint8_t> m_planeData[vk::PlanarFormatDescription::MAX_PLANES]; 102 }; 103 104 template <typename planeType> 105 class YCbCrContent 106 { 107 108 public: YCbCrContent()109 YCbCrContent() 110 { 111 } 112 ~YCbCrContent()113 ~YCbCrContent() 114 { 115 } 116 getFrame(std::string fileName,uint32_t width,uint32_t height,int frameIndex)117 static de::MovePtr<std::vector<planeType>> getFrame(std::string fileName, uint32_t width, uint32_t height, 118 int frameIndex) 119 { 120 tcu::FileResource fileResource(fileName.c_str()); 121 uint32_t uOffset = width * height; 122 uint32_t frameSize = uOffset + (uOffset / 2); 123 uint32_t position = frameSize * frameIndex; 124 de::MovePtr<std::vector<planeType>> content(new std::vector<planeType>(0)); 125 126 if (position > fileResource.getSize()) 127 { 128 TCU_THROW(NotSupportedError, "Position is higher than the file size, check the frame index provided"); 129 } 130 131 fileResource.setPosition(position * sizeof(planeType)); 132 content->resize(frameSize); 133 fileResource.read(content->data(), frameSize); 134 return content; 135 } 136 save(const std::vector<planeType> & data,const std::string & outputFileName)137 static bool save(const std::vector<planeType> &data, const std::string &outputFileName) 138 { 139 std::ofstream outFile(outputFileName, std::ios::binary | std::ios::out); 140 141 if (!outFile.is_open()) 142 { 143 std::cerr << "Error: Unable to open output file '" << outputFileName << "'." << std::endl; 144 return false; 145 } 146 147 if (data.empty()) 148 { 149 std::cerr << "Error: Data is empty or doesn't exist" << std::endl; 150 return false; 151 } 152 153 outFile.write(reinterpret_cast<const char *>(data.data()), data.size() * sizeof(planeType)); 154 outFile.close(); 155 156 return true; 157 } 158 }; 159 160 void extractI420Frame(std::vector<uint8_t> &videoDataPtr, uint32_t frameNumber, uint32_t width, uint32_t height, 161 vkt::ycbcr::MultiPlaneImageData *imageData, bool half_size); 162 163 void checkImageSupport(Context &context, vk::VkFormat format, vk::VkImageCreateFlags createFlags, 164 vk::VkImageTiling tiling = vk::VK_IMAGE_TILING_OPTIMAL); 165 166 void fillRandomNoNaN(de::Random *randomGen, uint8_t *const data, uint32_t size, const vk::VkFormat format); 167 void fillRandom(de::Random *randomGen, MultiPlaneImageData *imageData, 168 const vk::VkFormat format = vk::VK_FORMAT_UNDEFINED, bool noNan = false); 169 void fillGradient(MultiPlaneImageData *imageData, const tcu::Vec4 &minVal, const tcu::Vec4 &maxVal); 170 void fillZero(MultiPlaneImageData *imageData); 171 172 std::vector<de::SharedPtr<vk::Allocation>> allocateAndBindImageMemory( 173 const vk::DeviceInterface &vkd, vk::VkDevice device, vk::Allocator &allocator, vk::VkImage image, 174 vk::VkFormat format, vk::VkImageCreateFlags createFlags, 175 vk::MemoryRequirement requirement = vk::MemoryRequirement::Any); 176 177 void uploadImage(const vk::DeviceInterface &vkd, vk::VkDevice device, uint32_t queueFamilyNdx, vk::Allocator &allocator, 178 vk::VkImage image, const MultiPlaneImageData &imageData, vk::VkAccessFlags nextAccess, 179 vk::VkImageLayout finalLayout, uint32_t arrayLayer = 0u); 180 181 void fillImageMemory(const vk::DeviceInterface &vkd, vk::VkDevice device, uint32_t queueFamilyNdx, vk::VkImage image, 182 const std::vector<de::SharedPtr<vk::Allocation>> &memory, const MultiPlaneImageData &imageData, 183 vk::VkAccessFlags nextAccess, vk::VkImageLayout finalLayout, uint32_t arrayLayer = 0u); 184 185 void downloadImage(const vk::DeviceInterface &vkd, vk::VkDevice device, uint32_t queueFamilyNdx, 186 vk::Allocator &allocator, vk::VkImage image, MultiPlaneImageData *imageData, 187 vk::VkAccessFlags prevAccess, vk::VkImageLayout initialLayout, uint32_t baseArrayLayer = 0); 188 189 void readImageMemory(const vk::DeviceInterface &vkd, vk::VkDevice device, uint32_t queueFamilyNdx, vk::VkImage image, 190 const std::vector<de::SharedPtr<vk::Allocation>> &memory, MultiPlaneImageData *imageData, 191 vk::VkAccessFlags prevAccess, vk::VkImageLayout initialLayout); 192 193 class ChannelAccess 194 { 195 public: 196 ChannelAccess(tcu::TextureChannelClass channelClass, uint8_t channelSize, const tcu::IVec3 &size, 197 const tcu::IVec3 &bitPitch, void *data, uint32_t bitOffset); 198 getSize(void) const199 const tcu::IVec3 &getSize(void) const 200 { 201 return m_size; 202 } getBitPitch(void) const203 const tcu::IVec3 &getBitPitch(void) const 204 { 205 return m_bitPitch; 206 } getDataPtr(void) const207 void *getDataPtr(void) const 208 { 209 return m_data; 210 } 211 212 tcu::Interval getChannel(const tcu::FloatFormat &conversionFormat, const tcu::IVec3 &pos) const; 213 uint32_t getChannelUint(const tcu::IVec3 &pos) const; 214 float getChannel(const tcu::IVec3 &pos) const; 215 void setChannel(const tcu::IVec3 &pos, uint32_t x); 216 void setChannel(const tcu::IVec3 &pos, float x); 217 218 private: 219 const tcu::TextureChannelClass m_channelClass; 220 const uint8_t m_channelSize; 221 const tcu::IVec3 m_size; 222 const tcu::IVec3 m_bitPitch; 223 void *const m_data; 224 const int32_t m_bitOffset; 225 }; 226 227 ChannelAccess getChannelAccess(ycbcr::MultiPlaneImageData &data, const vk::PlanarFormatDescription &formatInfo, 228 const tcu::UVec2 &size, int channelNdx); 229 230 bool isYChromaSubsampled(vk::VkFormat format); 231 232 bool isXChromaSubsampled(vk::VkFormat format); 233 234 bool areLsb6BitsDontCare(vk::VkFormat srcFormat, vk::VkFormat dstFormat); 235 236 bool areLsb4BitsDontCare(vk::VkFormat srcFormat, vk::VkFormat dstFormat); 237 238 tcu::UVec4 getYCbCrBitDepth(vk::VkFormat format); 239 240 std::vector<tcu::FloatFormat> getPrecision(vk::VkFormat format); 241 242 uint32_t getYCbCrFormatChannelCount(vk::VkFormat format); 243 244 int wrap(vk::VkSamplerAddressMode addressMode, int coord, int size); 245 246 int divFloor(int a, int b); 247 248 void calculateBounds(const ChannelAccess &rPlane, const ChannelAccess &gPlane, const ChannelAccess &bPlane, 249 const ChannelAccess &aPlane, const tcu::UVec4 &bitDepth, const std::vector<tcu::Vec2> &sts, 250 const std::vector<tcu::FloatFormat> &filteringFormat, 251 const std::vector<tcu::FloatFormat> &conversionFormat, const uint32_t subTexelPrecisionBits, 252 vk::VkFilter filter, vk::VkSamplerYcbcrModelConversion colorModel, vk::VkSamplerYcbcrRange range, 253 vk::VkFilter chromaFilter, vk::VkChromaLocation xChromaOffset, vk::VkChromaLocation yChromaOffset, 254 const vk::VkComponentMapping &componentMapping, bool explicitReconstruction, 255 vk::VkSamplerAddressMode addressModeU, vk::VkSamplerAddressMode addressModeV, 256 std::vector<tcu::Vec4> &minBounds, std::vector<tcu::Vec4> &maxBounds, 257 std::vector<tcu::Vec4> &uvBounds, std::vector<tcu::IVec4> &ijBounds); 258 259 template <typename planeType> // T can be uint8_t for 8-bit or uint16_t for 16-bit 260 class YCbCrConvUtil 261 { YCbCrConvUtil()262 YCbCrConvUtil() 263 { 264 } 265 ~YCbCrConvUtil()266 virtual ~YCbCrConvUtil() 267 { 268 } 269 270 public: 271 // This method will convert multiplanar NV12 to one plane I420 MultiPlanarNV12toI420(vkt::ycbcr::MultiPlaneImageData * imageData)272 static de::MovePtr<std::vector<planeType>> MultiPlanarNV12toI420(vkt::ycbcr::MultiPlaneImageData *imageData) 273 { 274 uint32_t i; 275 uint16_t msbShift; 276 planeType *yPlaneData = static_cast<planeType *>(imageData->getPlanePtr(0)); 277 planeType *uvPlaneData = static_cast<planeType *>(imageData->getPlanePtr(1)); 278 tcu::UVec4 channelDepths = ycbcr::getYCbCrBitDepth(imageData->getFormat()); 279 int bitDepth = channelDepths.x(); 280 const uint32_t width = imageData->getSize().x(); 281 const uint32_t height = imageData->getSize().y(); 282 uint32_t ySize = width * height; 283 uint32_t frameSize = ySize + (ySize / 2); 284 de::MovePtr<std::vector<planeType>> YUVDataPtr = 285 de::MovePtr<std::vector<planeType>>(new std::vector<planeType>(frameSize)); 286 planeType *y_plane = YUVDataPtr.get()->data(); 287 planeType *u_plane = y_plane + ySize; 288 planeType *v_plane = u_plane + (ySize / 4); 289 290 DE_ASSERT(bitDepth == 8 || bitDepth == 10 || bitDepth == 12 || bitDepth == 16); 291 TCU_CHECK_AND_THROW(InternalError, bitDepth != 16, "16-bit samples have not been tested yet"); 292 if (bitDepth == 12) 293 msbShift = 4; 294 else if (bitDepth == 10) 295 msbShift = 6; 296 else 297 msbShift = 0; 298 299 for (i = 0; i < ySize; i++) 300 { 301 y_plane[i] = yPlaneData[i] >> msbShift; 302 } 303 304 for (i = 0; i < ySize / 4; i++) 305 { 306 u_plane[i] = uvPlaneData[2 * i] >> msbShift; 307 v_plane[i] = uvPlaneData[2 * i + 1] >> msbShift; 308 } 309 310 return YUVDataPtr; 311 } 312 }; 313 314 } // namespace ycbcr 315 } // namespace vkt 316 317 #endif // _VKTYCBCRUTIL_HPP 318