1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief YCbCr Test Utilities
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktYCbCrUtil.hpp"
25
26 #include "vkQueryUtil.hpp"
27 #include "vkRefUtil.hpp"
28 #include "vkTypeUtil.hpp"
29
30 #include "tcuTextureUtil.hpp"
31
32 #include "deSTLUtil.hpp"
33 #include "deUniquePtr.hpp"
34
35 namespace vkt
36 {
37 namespace ycbcr
38 {
39
40 using namespace vk;
41
42 using de::MovePtr;
43 using tcu::UVec2;
44 using std::vector;
45 using std::string;
46
47 typedef de::SharedPtr<Allocation> AllocationSp;
48 typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp;
49
50 // MultiPlaneImageData
51
MultiPlaneImageData(VkFormat format,const UVec2 & size)52 MultiPlaneImageData::MultiPlaneImageData (VkFormat format, const UVec2& size)
53 : m_format (format)
54 , m_description (getPlanarFormatDescription(format))
55 , m_size (size)
56 {
57 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
58 {
59 const deUint32 planeW = size.x() / m_description.planes[planeNdx].widthDivisor;
60 const deUint32 planeH = size.y() / m_description.planes[planeNdx].heightDivisor;
61 const deUint32 planeSize = m_description.planes[planeNdx].elementSizeBytes * planeW * planeH;
62
63 m_planeData[planeNdx].resize(planeSize);
64 }
65 }
66
MultiPlaneImageData(const MultiPlaneImageData & other)67 MultiPlaneImageData::MultiPlaneImageData (const MultiPlaneImageData& other)
68 : m_format (other.m_format)
69 , m_description (other.m_description)
70 , m_size (other.m_size)
71 {
72 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
73 m_planeData[planeNdx] = other.m_planeData[planeNdx];
74 }
75
~MultiPlaneImageData(void)76 MultiPlaneImageData::~MultiPlaneImageData (void)
77 {
78 }
79
getChannelAccess(deUint32 channelNdx)80 tcu::PixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx)
81 {
82 void* planePtrs[PlanarFormatDescription::MAX_PLANES];
83 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES];
84
85 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
86 {
87 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor;
88
89 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW;
90 planePtrs[planeNdx] = &m_planeData[planeNdx][0];
91 }
92
93 return vk::getChannelAccess(m_description,
94 m_size,
95 planeRowPitches,
96 planePtrs,
97 channelNdx);
98 }
99
getChannelAccess(deUint32 channelNdx) const100 tcu::ConstPixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) const
101 {
102 const void* planePtrs[PlanarFormatDescription::MAX_PLANES];
103 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES];
104
105 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
106 {
107 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor;
108
109 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW;
110 planePtrs[planeNdx] = &m_planeData[planeNdx][0];
111 }
112
113 return vk::getChannelAccess(m_description,
114 m_size,
115 planeRowPitches,
116 planePtrs,
117 channelNdx);
118 }
119
120 // Misc utilities
121
122 namespace
123 {
124
allocateStagingBuffers(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,const MultiPlaneImageData & imageData,vector<VkBufferSp> * buffers,vector<AllocationSp> * allocations)125 void allocateStagingBuffers (const DeviceInterface& vkd,
126 VkDevice device,
127 Allocator& allocator,
128 const MultiPlaneImageData& imageData,
129 vector<VkBufferSp>* buffers,
130 vector<AllocationSp>* allocations)
131 {
132 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
133 {
134 const VkBufferCreateInfo bufferInfo =
135 {
136 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
137 DE_NULL,
138 (VkBufferCreateFlags)0u,
139 (VkDeviceSize)imageData.getPlaneSize(planeNdx),
140 VK_BUFFER_USAGE_TRANSFER_SRC_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT,
141 VK_SHARING_MODE_EXCLUSIVE,
142 0u,
143 (const deUint32*)DE_NULL,
144 };
145 Move<VkBuffer> buffer (createBuffer(vkd, device, &bufferInfo));
146 MovePtr<Allocation> allocation (allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer),
147 MemoryRequirement::HostVisible|MemoryRequirement::Any));
148
149 VK_CHECK(vkd.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
150
151 buffers->push_back(VkBufferSp(new Unique<VkBuffer>(buffer)));
152 allocations->push_back(AllocationSp(allocation.release()));
153 }
154 }
155
allocateAndWriteStagingBuffers(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,const MultiPlaneImageData & imageData,vector<VkBufferSp> * buffers,vector<AllocationSp> * allocations)156 void allocateAndWriteStagingBuffers (const DeviceInterface& vkd,
157 VkDevice device,
158 Allocator& allocator,
159 const MultiPlaneImageData& imageData,
160 vector<VkBufferSp>* buffers,
161 vector<AllocationSp>* allocations)
162 {
163 allocateStagingBuffers(vkd, device, allocator, imageData, buffers, allocations);
164
165 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
166 {
167 deMemcpy((*allocations)[planeNdx]->getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx));
168 flushMappedMemoryRange(vkd, device, (*allocations)[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
169 }
170 }
171
readStagingBuffers(MultiPlaneImageData * imageData,const DeviceInterface & vkd,VkDevice device,const vector<AllocationSp> & allocations)172 void readStagingBuffers (MultiPlaneImageData* imageData,
173 const DeviceInterface& vkd,
174 VkDevice device,
175 const vector<AllocationSp>& allocations)
176 {
177 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
178 {
179 invalidateMappedMemoryRange(vkd, device, allocations[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
180 deMemcpy(imageData->getPlanePtr(planeNdx), allocations[planeNdx]->getHostPtr(), imageData->getPlaneSize(planeNdx));
181 }
182 }
183
184 } // anonymous
185
checkImageSupport(Context & context,VkFormat format,VkImageCreateFlags createFlags,VkImageTiling tiling)186 void checkImageSupport (Context& context, VkFormat format, VkImageCreateFlags createFlags, VkImageTiling tiling)
187 {
188 const bool disjoint = (createFlags & VK_IMAGE_CREATE_DISJOINT_BIT_KHR) != 0;
189 const VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR* features = findStructure<VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR>(context.getDeviceFeatures2().pNext);
190 vector<string> reqExts;
191
192 reqExts.push_back("VK_KHR_sampler_ycbcr_conversion");
193
194 if (disjoint)
195 {
196 reqExts.push_back("VK_KHR_bind_memory2");
197 reqExts.push_back("VK_KHR_get_memory_requirements2");
198 }
199
200 for (vector<string>::const_iterator extIter = reqExts.begin(); extIter != reqExts.end(); ++extIter)
201 {
202 if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), *extIter))
203 TCU_THROW(NotSupportedError, (*extIter + " is not supported").c_str());
204 }
205
206 if (!features || features->samplerYcbcrConversion == VK_FALSE)
207 TCU_THROW(NotSupportedError, "samplerYcbcrConversion is not supported");
208
209 {
210 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
211 context.getPhysicalDevice(),
212 format);
213 const VkFormatFeatureFlags featureFlags = tiling == VK_IMAGE_TILING_OPTIMAL
214 ? formatProperties.optimalTilingFeatures
215 : formatProperties.linearTilingFeatures;
216
217 if ((featureFlags & (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR | VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR)) == 0)
218 TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format");
219
220 if (disjoint && ((featureFlags & VK_FORMAT_FEATURE_DISJOINT_BIT_KHR) == 0))
221 TCU_THROW(NotSupportedError, "Disjoint planes are not supported for format");
222 }
223 }
224
fillRandom(de::Random * randomGen,MultiPlaneImageData * imageData)225 void fillRandom (de::Random* randomGen, MultiPlaneImageData* imageData)
226 {
227 // \todo [pyry] Optimize, take into account bits that must be 0
228
229 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
230 {
231 const size_t planeSize = imageData->getPlaneSize(planeNdx);
232 deUint8* const planePtr = (deUint8*)imageData->getPlanePtr(planeNdx);
233
234 for (size_t ndx = 0; ndx < planeSize; ++ndx)
235 planePtr[ndx] = randomGen->getUint8();
236 }
237 }
238
fillGradient(MultiPlaneImageData * imageData,const tcu::Vec4 & minVal,const tcu::Vec4 & maxVal)239 void fillGradient (MultiPlaneImageData* imageData, const tcu::Vec4& minVal, const tcu::Vec4& maxVal)
240 {
241 const PlanarFormatDescription& formatInfo = imageData->getDescription();
242
243 // \todo [pyry] Optimize: no point in re-rendering source gradient for each channel.
244
245 for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
246 {
247 if (formatInfo.hasChannelNdx(channelNdx))
248 {
249 const tcu::PixelBufferAccess channelAccess = imageData->getChannelAccess(channelNdx);
250 tcu::TextureLevel tmpTexture (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), channelAccess.getWidth(), channelAccess.getHeight());
251 const tcu::ConstPixelBufferAccess tmpAccess = tmpTexture.getAccess();
252
253 tcu::fillWithComponentGradients(tmpTexture, minVal, maxVal);
254
255 for (int y = 0; y < channelAccess.getHeight(); ++y)
256 for (int x = 0; x < channelAccess.getWidth(); ++x)
257 {
258 channelAccess.setPixel(tcu::Vec4(tmpAccess.getPixel(x, y)[channelNdx]), x, y);
259 }
260 }
261 }
262 }
263
allocateAndBindImageMemory(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,VkImage image,VkFormat format,VkImageCreateFlags createFlags,vk::MemoryRequirement requirement)264 vector<AllocationSp> allocateAndBindImageMemory (const DeviceInterface& vkd,
265 VkDevice device,
266 Allocator& allocator,
267 VkImage image,
268 VkFormat format,
269 VkImageCreateFlags createFlags,
270 vk::MemoryRequirement requirement)
271 {
272 vector<AllocationSp> allocations;
273
274 if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT_KHR) != 0)
275 {
276 const deUint32 numPlanes = getPlaneCount(format);
277
278 for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
279 {
280 const VkImageAspectFlagBits planeAspect = getPlaneAspect(planeNdx);
281 const VkMemoryRequirements reqs = getImagePlaneMemoryRequirements(vkd, device, image, planeAspect);
282
283 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
284
285 bindImagePlaneMemory(vkd, device, image, allocations.back()->getMemory(), allocations.back()->getOffset(), planeAspect);
286 }
287 }
288 else
289 {
290 const VkMemoryRequirements reqs = getImageMemoryRequirements(vkd, device, image);
291
292 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
293
294 VK_CHECK(vkd.bindImageMemory(device, image, allocations.back()->getMemory(), allocations.back()->getOffset()));
295 }
296
297 return allocations;
298 }
299
uploadImage(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,Allocator & allocator,VkImage image,const MultiPlaneImageData & imageData,VkAccessFlags nextAccess,VkImageLayout finalLayout)300 void uploadImage (const DeviceInterface& vkd,
301 VkDevice device,
302 deUint32 queueFamilyNdx,
303 Allocator& allocator,
304 VkImage image,
305 const MultiPlaneImageData& imageData,
306 VkAccessFlags nextAccess,
307 VkImageLayout finalLayout)
308 {
309 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
310 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
311 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
312 vector<VkBufferSp> stagingBuffers;
313 vector<AllocationSp> stagingMemory;
314
315 const PlanarFormatDescription& formatDesc = imageData.getDescription();
316
317 allocateAndWriteStagingBuffers(vkd, device, allocator, imageData, &stagingBuffers, &stagingMemory);
318
319 {
320 const VkCommandBufferBeginInfo beginInfo =
321 {
322 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
323 DE_NULL,
324 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
325 (const VkCommandBufferInheritanceInfo*)DE_NULL
326 };
327
328 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
329 }
330
331 {
332 const VkImageMemoryBarrier preCopyBarrier =
333 {
334 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
335 DE_NULL,
336 (VkAccessFlags)0,
337 VK_ACCESS_TRANSFER_WRITE_BIT,
338 VK_IMAGE_LAYOUT_UNDEFINED,
339 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
340 VK_QUEUE_FAMILY_IGNORED,
341 VK_QUEUE_FAMILY_IGNORED,
342 image,
343 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
344 };
345
346 vkd.cmdPipelineBarrier(*cmdBuffer,
347 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
348 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
349 (VkDependencyFlags)0u,
350 0u,
351 (const VkMemoryBarrier*)DE_NULL,
352 0u,
353 (const VkBufferMemoryBarrier*)DE_NULL,
354 1u,
355 &preCopyBarrier);
356 }
357
358 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
359 {
360 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
361 ? getPlaneAspect(planeNdx)
362 : VK_IMAGE_ASPECT_COLOR_BIT;
363 const deUint32 planeW = (formatDesc.numPlanes > 1)
364 ? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor
365 : imageData.getSize().x();
366 const deUint32 planeH = (formatDesc.numPlanes > 1)
367 ? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor
368 : imageData.getSize().y();
369 const VkBufferImageCopy copy =
370 {
371 0u, // bufferOffset
372 0u, // bufferRowLength
373 0u, // bufferImageHeight
374 { (VkImageAspectFlags)aspect, 0u, 0u, 1u },
375 makeOffset3D(0u, 0u, 0u),
376 makeExtent3D(planeW, planeH, 1u),
377 };
378
379 vkd.cmdCopyBufferToImage(*cmdBuffer, **stagingBuffers[planeNdx], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©);
380 }
381
382 {
383 const VkImageMemoryBarrier postCopyBarrier =
384 {
385 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
386 DE_NULL,
387 VK_ACCESS_TRANSFER_WRITE_BIT,
388 nextAccess,
389 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
390 finalLayout,
391 VK_QUEUE_FAMILY_IGNORED,
392 VK_QUEUE_FAMILY_IGNORED,
393 image,
394 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
395 };
396
397 vkd.cmdPipelineBarrier(*cmdBuffer,
398 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
399 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
400 (VkDependencyFlags)0u,
401 0u,
402 (const VkMemoryBarrier*)DE_NULL,
403 0u,
404 (const VkBufferMemoryBarrier*)DE_NULL,
405 1u,
406 &postCopyBarrier);
407 }
408
409 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
410
411 {
412 const Unique<VkFence> fence (createFence(vkd, device));
413 const VkSubmitInfo submitInfo =
414 {
415 VK_STRUCTURE_TYPE_SUBMIT_INFO,
416 DE_NULL,
417 0u,
418 (const VkSemaphore*)DE_NULL,
419 (const VkPipelineStageFlags*)DE_NULL,
420 1u,
421 &*cmdBuffer,
422 0u,
423 (const VkSemaphore*)DE_NULL,
424 };
425
426 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
427 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
428 }
429 }
430
fillImageMemory(const vk::DeviceInterface & vkd,vk::VkDevice device,deUint32 queueFamilyNdx,vk::VkImage image,const std::vector<de::SharedPtr<vk::Allocation>> & allocations,const MultiPlaneImageData & imageData,vk::VkAccessFlags nextAccess,vk::VkImageLayout finalLayout)431 void fillImageMemory (const vk::DeviceInterface& vkd,
432 vk::VkDevice device,
433 deUint32 queueFamilyNdx,
434 vk::VkImage image,
435 const std::vector<de::SharedPtr<vk::Allocation> >& allocations,
436 const MultiPlaneImageData& imageData,
437 vk::VkAccessFlags nextAccess,
438 vk::VkImageLayout finalLayout)
439 {
440 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
441 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
442 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
443 const PlanarFormatDescription& formatDesc = imageData.getDescription();
444
445 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
446 {
447 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
448 ? getPlaneAspect(planeNdx)
449 : VK_IMAGE_ASPECT_COLOR_BIT;
450 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1
451 ? allocations[planeNdx]
452 : allocations[0];
453 const size_t planeSize = imageData.getPlaneSize(planeNdx);
454 const deUint32 planeH = imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
455 const VkImageSubresource subresource =
456 {
457 aspect,
458 0u,
459 0u,
460 };
461 VkSubresourceLayout layout;
462
463 vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
464
465 for (deUint32 row = 0; row < planeH; ++row)
466 {
467 const size_t rowSize = planeSize / planeH;
468 void* const dstPtr = ((deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
469 const void* const srcPtr = ((const deUint8*)imageData.getPlanePtr(planeNdx)) + row * rowSize;
470
471 deMemcpy(dstPtr, srcPtr, rowSize);
472 }
473 flushMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
474 }
475
476 {
477 const VkCommandBufferBeginInfo beginInfo =
478 {
479 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
480 DE_NULL,
481 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
482 (const VkCommandBufferInheritanceInfo*)DE_NULL
483 };
484
485 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
486 }
487
488
489 {
490 const VkImageMemoryBarrier postCopyBarrier =
491 {
492 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
493 DE_NULL,
494 0u,
495 nextAccess,
496 VK_IMAGE_LAYOUT_PREINITIALIZED,
497 finalLayout,
498 VK_QUEUE_FAMILY_IGNORED,
499 VK_QUEUE_FAMILY_IGNORED,
500 image,
501 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
502 };
503
504 vkd.cmdPipelineBarrier(*cmdBuffer,
505 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
506 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
507 (VkDependencyFlags)0u,
508 0u,
509 (const VkMemoryBarrier*)DE_NULL,
510 0u,
511 (const VkBufferMemoryBarrier*)DE_NULL,
512 1u,
513 &postCopyBarrier);
514 }
515
516 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
517
518 {
519 const Unique<VkFence> fence (createFence(vkd, device));
520 const VkSubmitInfo submitInfo =
521 {
522 VK_STRUCTURE_TYPE_SUBMIT_INFO,
523 DE_NULL,
524 0u,
525 (const VkSemaphore*)DE_NULL,
526 (const VkPipelineStageFlags*)DE_NULL,
527 1u,
528 &*cmdBuffer,
529 0u,
530 (const VkSemaphore*)DE_NULL,
531 };
532
533 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
534 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
535 }
536 }
537
downloadImage(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,Allocator & allocator,VkImage image,MultiPlaneImageData * imageData,VkAccessFlags prevAccess,VkImageLayout initialLayout)538 void downloadImage (const DeviceInterface& vkd,
539 VkDevice device,
540 deUint32 queueFamilyNdx,
541 Allocator& allocator,
542 VkImage image,
543 MultiPlaneImageData* imageData,
544 VkAccessFlags prevAccess,
545 VkImageLayout initialLayout)
546 {
547 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
548 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
549 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
550 vector<VkBufferSp> stagingBuffers;
551 vector<AllocationSp> stagingMemory;
552
553 const PlanarFormatDescription& formatDesc = imageData->getDescription();
554
555 allocateStagingBuffers(vkd, device, allocator, *imageData, &stagingBuffers, &stagingMemory);
556
557 {
558 const VkCommandBufferBeginInfo beginInfo =
559 {
560 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
561 DE_NULL,
562 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
563 (const VkCommandBufferInheritanceInfo*)DE_NULL
564 };
565
566 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
567 }
568
569 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
570 {
571 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
572 ? getPlaneAspect(planeNdx)
573 : VK_IMAGE_ASPECT_COLOR_BIT;
574 {
575 const VkImageMemoryBarrier preCopyBarrier =
576 {
577 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
578 DE_NULL,
579 prevAccess,
580 VK_ACCESS_TRANSFER_READ_BIT,
581 initialLayout,
582 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
583 VK_QUEUE_FAMILY_IGNORED,
584 VK_QUEUE_FAMILY_IGNORED,
585 image,
586 {
587 aspect,
588 0u,
589 1u,
590 0u,
591 1u
592 }
593 };
594
595 vkd.cmdPipelineBarrier(*cmdBuffer,
596 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
597 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
598 (VkDependencyFlags)0u,
599 0u,
600 (const VkMemoryBarrier*)DE_NULL,
601 0u,
602 (const VkBufferMemoryBarrier*)DE_NULL,
603 1u,
604 &preCopyBarrier);
605 }
606 {
607 const deUint32 planeW = (formatDesc.numPlanes > 1)
608 ? imageData->getSize().x() / formatDesc.planes[planeNdx].widthDivisor
609 : imageData->getSize().x();
610 const deUint32 planeH = (formatDesc.numPlanes > 1)
611 ? imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor
612 : imageData->getSize().y();
613 const VkBufferImageCopy copy =
614 {
615 0u, // bufferOffset
616 0u, // bufferRowLength
617 0u, // bufferImageHeight
618 { (VkImageAspectFlags)aspect, 0u, 0u, 1u },
619 makeOffset3D(0u, 0u, 0u),
620 makeExtent3D(planeW, planeH, 1u),
621 };
622
623 vkd.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **stagingBuffers[planeNdx], 1u, ©);
624 }
625 {
626 const VkBufferMemoryBarrier postCopyBarrier =
627 {
628 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
629 DE_NULL,
630 VK_ACCESS_TRANSFER_WRITE_BIT,
631 VK_ACCESS_HOST_READ_BIT,
632 VK_QUEUE_FAMILY_IGNORED,
633 VK_QUEUE_FAMILY_IGNORED,
634 **stagingBuffers[planeNdx],
635 0u,
636 VK_WHOLE_SIZE
637 };
638
639 vkd.cmdPipelineBarrier(*cmdBuffer,
640 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
641 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
642 (VkDependencyFlags)0u,
643 0u,
644 (const VkMemoryBarrier*)DE_NULL,
645 1u,
646 &postCopyBarrier,
647 0u,
648 (const VkImageMemoryBarrier*)DE_NULL);
649 }
650 }
651
652 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
653
654 {
655 const Unique<VkFence> fence (createFence(vkd, device));
656 const VkSubmitInfo submitInfo =
657 {
658 VK_STRUCTURE_TYPE_SUBMIT_INFO,
659 DE_NULL,
660 0u,
661 (const VkSemaphore*)DE_NULL,
662 (const VkPipelineStageFlags*)DE_NULL,
663 1u,
664 &*cmdBuffer,
665 0u,
666 (const VkSemaphore*)DE_NULL,
667 };
668
669 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
670 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
671 }
672
673 readStagingBuffers(imageData, vkd, device, stagingMemory);
674 }
675
readImageMemory(const vk::DeviceInterface & vkd,vk::VkDevice device,deUint32 queueFamilyNdx,vk::VkImage image,const std::vector<de::SharedPtr<vk::Allocation>> & allocations,MultiPlaneImageData * imageData,vk::VkAccessFlags prevAccess,vk::VkImageLayout initialLayout)676 void readImageMemory (const vk::DeviceInterface& vkd,
677 vk::VkDevice device,
678 deUint32 queueFamilyNdx,
679 vk::VkImage image,
680 const std::vector<de::SharedPtr<vk::Allocation> >& allocations,
681 MultiPlaneImageData* imageData,
682 vk::VkAccessFlags prevAccess,
683 vk::VkImageLayout initialLayout)
684 {
685 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
686 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
687 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
688 const PlanarFormatDescription& formatDesc = imageData->getDescription();
689
690 {
691 const VkCommandBufferBeginInfo beginInfo =
692 {
693 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
694 DE_NULL,
695 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
696 (const VkCommandBufferInheritanceInfo*)DE_NULL
697 };
698
699 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
700 }
701
702 {
703 const VkImageMemoryBarrier preCopyBarrier =
704 {
705 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
706 DE_NULL,
707 prevAccess,
708 vk::VK_ACCESS_HOST_READ_BIT,
709 initialLayout,
710 VK_IMAGE_LAYOUT_GENERAL,
711 VK_QUEUE_FAMILY_IGNORED,
712 VK_QUEUE_FAMILY_IGNORED,
713 image,
714 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
715 };
716
717 vkd.cmdPipelineBarrier(*cmdBuffer,
718 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
719 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
720 (VkDependencyFlags)0u,
721 0u,
722 (const VkMemoryBarrier*)DE_NULL,
723 0u,
724 (const VkBufferMemoryBarrier*)DE_NULL,
725 1u,
726 &preCopyBarrier);
727 }
728
729 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
730
731 {
732 const Unique<VkFence> fence (createFence(vkd, device));
733 const VkSubmitInfo submitInfo =
734 {
735 VK_STRUCTURE_TYPE_SUBMIT_INFO,
736 DE_NULL,
737 0u,
738 (const VkSemaphore*)DE_NULL,
739 (const VkPipelineStageFlags*)DE_NULL,
740 1u,
741 &*cmdBuffer,
742 0u,
743 (const VkSemaphore*)DE_NULL,
744 };
745
746 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
747 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
748 }
749
750 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
751 {
752 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
753 ? getPlaneAspect(planeNdx)
754 : VK_IMAGE_ASPECT_COLOR_BIT;
755 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1
756 ? allocations[planeNdx]
757 : allocations[0];
758 const size_t planeSize = imageData->getPlaneSize(planeNdx);
759 const deUint32 planeH = imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
760 const VkImageSubresource subresource =
761 {
762 aspect,
763 0u,
764 0u,
765 };
766 VkSubresourceLayout layout;
767
768 vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
769
770 invalidateMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
771
772 for (deUint32 row = 0; row < planeH; ++row)
773 {
774 const size_t rowSize = planeSize / planeH;
775 const void* const srcPtr = ((const deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
776 void* const dstPtr = ((deUint8*)imageData->getPlanePtr(planeNdx)) + row * rowSize;
777
778 deMemcpy(dstPtr, srcPtr, rowSize);
779 }
780 }
781 }
782
783 } // ycbcr
784 } // vkt
785