• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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