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 #include "vkCmdUtil.hpp"
30
31 #include "tcuTextureUtil.hpp"
32 #include "deMath.h"
33 #include "deFloat16.h"
34 #include "tcuVector.hpp"
35 #include "tcuVectorUtil.hpp"
36
37 #include "deSTLUtil.hpp"
38 #include "deUniquePtr.hpp"
39
40 namespace vkt
41 {
42 namespace ycbcr
43 {
44
45 using namespace vk;
46
47 using de::MovePtr;
48 using tcu::FloatFormat;
49 using tcu::Interval;
50 using tcu::IVec2;
51 using tcu::IVec4;
52 using tcu::UVec2;
53 using tcu::UVec4;
54 using tcu::Vec2;
55 using tcu::Vec4;
56 using std::vector;
57 using std::string;
58
59 typedef de::SharedPtr<Allocation> AllocationSp;
60 typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp;
61
62 // MultiPlaneImageData
63
MultiPlaneImageData(VkFormat format,const UVec2 & size)64 MultiPlaneImageData::MultiPlaneImageData (VkFormat format, const UVec2& size)
65 : m_format (format)
66 , m_description (getPlanarFormatDescription(format))
67 , m_size (size)
68 {
69 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
70 {
71 const deUint32 planeW = size.x() / m_description.planes[planeNdx].widthDivisor;
72 const deUint32 planeH = size.y() / m_description.planes[planeNdx].heightDivisor;
73 const deUint32 planeSize = m_description.planes[planeNdx].elementSizeBytes * planeW * planeH;
74
75 m_planeData[planeNdx].resize(planeSize);
76 }
77 }
78
MultiPlaneImageData(const MultiPlaneImageData & other)79 MultiPlaneImageData::MultiPlaneImageData (const MultiPlaneImageData& other)
80 : m_format (other.m_format)
81 , m_description (other.m_description)
82 , m_size (other.m_size)
83 {
84 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
85 m_planeData[planeNdx] = other.m_planeData[planeNdx];
86 }
87
~MultiPlaneImageData(void)88 MultiPlaneImageData::~MultiPlaneImageData (void)
89 {
90 }
91
getChannelAccess(deUint32 channelNdx)92 tcu::PixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx)
93 {
94 void* planePtrs[PlanarFormatDescription::MAX_PLANES];
95 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES];
96
97 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
98 {
99 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor;
100
101 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW;
102 planePtrs[planeNdx] = &m_planeData[planeNdx][0];
103 }
104
105 return vk::getChannelAccess(m_description,
106 m_size,
107 planeRowPitches,
108 planePtrs,
109 channelNdx);
110 }
111
getChannelAccess(deUint32 channelNdx) const112 tcu::ConstPixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) const
113 {
114 const void* planePtrs[PlanarFormatDescription::MAX_PLANES];
115 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES];
116
117 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
118 {
119 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor;
120
121 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW;
122 planePtrs[planeNdx] = &m_planeData[planeNdx][0];
123 }
124
125 return vk::getChannelAccess(m_description,
126 m_size,
127 planeRowPitches,
128 planePtrs,
129 channelNdx);
130 }
131
132 // Misc utilities
133
134 namespace
135 {
136
allocateStagingBuffers(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,const MultiPlaneImageData & imageData,vector<VkBufferSp> * buffers,vector<AllocationSp> * allocations)137 void allocateStagingBuffers (const DeviceInterface& vkd,
138 VkDevice device,
139 Allocator& allocator,
140 const MultiPlaneImageData& imageData,
141 vector<VkBufferSp>* buffers,
142 vector<AllocationSp>* allocations)
143 {
144 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
145 {
146 const VkBufferCreateInfo bufferInfo =
147 {
148 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
149 DE_NULL,
150 (VkBufferCreateFlags)0u,
151 (VkDeviceSize)imageData.getPlaneSize(planeNdx),
152 VK_BUFFER_USAGE_TRANSFER_SRC_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT,
153 VK_SHARING_MODE_EXCLUSIVE,
154 0u,
155 (const deUint32*)DE_NULL,
156 };
157 Move<VkBuffer> buffer (createBuffer(vkd, device, &bufferInfo));
158 MovePtr<Allocation> allocation (allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer),
159 MemoryRequirement::HostVisible|MemoryRequirement::Any));
160
161 VK_CHECK(vkd.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
162
163 buffers->push_back(VkBufferSp(new Unique<VkBuffer>(buffer)));
164 allocations->push_back(AllocationSp(allocation.release()));
165 }
166 }
167
allocateAndWriteStagingBuffers(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,const MultiPlaneImageData & imageData,vector<VkBufferSp> * buffers,vector<AllocationSp> * allocations)168 void allocateAndWriteStagingBuffers (const DeviceInterface& vkd,
169 VkDevice device,
170 Allocator& allocator,
171 const MultiPlaneImageData& imageData,
172 vector<VkBufferSp>* buffers,
173 vector<AllocationSp>* allocations)
174 {
175 allocateStagingBuffers(vkd, device, allocator, imageData, buffers, allocations);
176
177 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
178 {
179 deMemcpy((*allocations)[planeNdx]->getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx));
180 flushMappedMemoryRange(vkd, device, (*allocations)[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
181 }
182 }
183
readStagingBuffers(MultiPlaneImageData * imageData,const DeviceInterface & vkd,VkDevice device,const vector<AllocationSp> & allocations)184 void readStagingBuffers (MultiPlaneImageData* imageData,
185 const DeviceInterface& vkd,
186 VkDevice device,
187 const vector<AllocationSp>& allocations)
188 {
189 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
190 {
191 invalidateMappedMemoryRange(vkd, device, allocations[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
192 deMemcpy(imageData->getPlanePtr(planeNdx), allocations[planeNdx]->getHostPtr(), imageData->getPlaneSize(planeNdx));
193 }
194 }
195
196 } // anonymous
197
checkImageSupport(Context & context,VkFormat format,VkImageCreateFlags createFlags,VkImageTiling tiling)198 void checkImageSupport (Context& context, VkFormat format, VkImageCreateFlags createFlags, VkImageTiling tiling)
199 {
200 const bool disjoint = (createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0;
201 const VkPhysicalDeviceSamplerYcbcrConversionFeatures features = context.getSamplerYCbCrConversionFeatures();
202 vector<string> reqExts;
203
204 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_sampler_ycbcr_conversion"))
205 reqExts.push_back("VK_KHR_sampler_ycbcr_conversion");
206
207 if (disjoint)
208 {
209 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_bind_memory2"))
210 reqExts.push_back("VK_KHR_bind_memory2");
211 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_get_memory_requirements2"))
212 reqExts.push_back("VK_KHR_get_memory_requirements2");
213 }
214
215 for (vector<string>::const_iterator extIter = reqExts.begin(); extIter != reqExts.end(); ++extIter)
216 {
217 if (!isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), *extIter))
218 TCU_THROW(NotSupportedError, (*extIter + " is not supported").c_str());
219 }
220
221 if (features.samplerYcbcrConversion == VK_FALSE)
222 {
223 TCU_THROW(NotSupportedError, "samplerYcbcrConversion is not supported");
224 }
225
226 {
227 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
228 context.getPhysicalDevice(),
229 format);
230 const VkFormatFeatureFlags featureFlags = tiling == VK_IMAGE_TILING_OPTIMAL
231 ? formatProperties.optimalTilingFeatures
232 : formatProperties.linearTilingFeatures;
233
234 if ((featureFlags & (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT | VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) == 0)
235 TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format");
236
237 if (disjoint && ((featureFlags & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
238 TCU_THROW(NotSupportedError, "Disjoint planes are not supported for format");
239 }
240 }
241
fillRandom(de::Random * randomGen,MultiPlaneImageData * imageData)242 void fillRandom (de::Random* randomGen, MultiPlaneImageData* imageData)
243 {
244 // \todo [pyry] Optimize, take into account bits that must be 0
245
246 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
247 {
248 const size_t planeSize = imageData->getPlaneSize(planeNdx);
249 deUint8* const planePtr = (deUint8*)imageData->getPlanePtr(planeNdx);
250
251 for (size_t ndx = 0; ndx < planeSize; ++ndx)
252 planePtr[ndx] = randomGen->getUint8();
253 }
254 }
255
fillGradient(MultiPlaneImageData * imageData,const tcu::Vec4 & minVal,const tcu::Vec4 & maxVal)256 void fillGradient (MultiPlaneImageData* imageData, const tcu::Vec4& minVal, const tcu::Vec4& maxVal)
257 {
258 const PlanarFormatDescription& formatInfo = imageData->getDescription();
259
260 // \todo [pyry] Optimize: no point in re-rendering source gradient for each channel.
261
262 for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
263 {
264 if (formatInfo.hasChannelNdx(channelNdx))
265 {
266 const tcu::PixelBufferAccess channelAccess = imageData->getChannelAccess(channelNdx);
267 tcu::TextureLevel tmpTexture (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), channelAccess.getWidth(), channelAccess.getHeight());
268 const tcu::ConstPixelBufferAccess tmpAccess = tmpTexture.getAccess();
269
270 tcu::fillWithComponentGradients(tmpTexture, minVal, maxVal);
271
272 for (int y = 0; y < channelAccess.getHeight(); ++y)
273 for (int x = 0; x < channelAccess.getWidth(); ++x)
274 {
275 channelAccess.setPixel(tcu::Vec4(tmpAccess.getPixel(x, y)[channelNdx]), x, y);
276 }
277 }
278 }
279 }
280
allocateAndBindImageMemory(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,VkImage image,VkFormat format,VkImageCreateFlags createFlags,vk::MemoryRequirement requirement)281 vector<AllocationSp> allocateAndBindImageMemory (const DeviceInterface& vkd,
282 VkDevice device,
283 Allocator& allocator,
284 VkImage image,
285 VkFormat format,
286 VkImageCreateFlags createFlags,
287 vk::MemoryRequirement requirement)
288 {
289 vector<AllocationSp> allocations;
290
291 if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
292 {
293 const deUint32 numPlanes = getPlaneCount(format);
294
295 for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
296 {
297 const VkImageAspectFlagBits planeAspect = getPlaneAspect(planeNdx);
298 const VkMemoryRequirements reqs = getImagePlaneMemoryRequirements(vkd, device, image, planeAspect);
299
300 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
301
302 bindImagePlaneMemory(vkd, device, image, allocations.back()->getMemory(), allocations.back()->getOffset(), planeAspect);
303 }
304 }
305 else
306 {
307 const VkMemoryRequirements reqs = getImageMemoryRequirements(vkd, device, image);
308
309 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
310
311 VK_CHECK(vkd.bindImageMemory(device, image, allocations.back()->getMemory(), allocations.back()->getOffset()));
312 }
313
314 return allocations;
315 }
316
uploadImage(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,Allocator & allocator,VkImage image,const MultiPlaneImageData & imageData,VkAccessFlags nextAccess,VkImageLayout finalLayout)317 void uploadImage (const DeviceInterface& vkd,
318 VkDevice device,
319 deUint32 queueFamilyNdx,
320 Allocator& allocator,
321 VkImage image,
322 const MultiPlaneImageData& imageData,
323 VkAccessFlags nextAccess,
324 VkImageLayout finalLayout)
325 {
326 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
327 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
328 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
329 vector<VkBufferSp> stagingBuffers;
330 vector<AllocationSp> stagingMemory;
331
332 const PlanarFormatDescription& formatDesc = imageData.getDescription();
333
334 allocateAndWriteStagingBuffers(vkd, device, allocator, imageData, &stagingBuffers, &stagingMemory);
335
336 beginCommandBuffer(vkd, *cmdBuffer);
337
338 {
339 const VkImageMemoryBarrier preCopyBarrier =
340 {
341 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
342 DE_NULL,
343 (VkAccessFlags)0,
344 VK_ACCESS_TRANSFER_WRITE_BIT,
345 VK_IMAGE_LAYOUT_UNDEFINED,
346 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
347 VK_QUEUE_FAMILY_IGNORED,
348 VK_QUEUE_FAMILY_IGNORED,
349 image,
350 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
351 };
352
353 vkd.cmdPipelineBarrier(*cmdBuffer,
354 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
355 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
356 (VkDependencyFlags)0u,
357 0u,
358 (const VkMemoryBarrier*)DE_NULL,
359 0u,
360 (const VkBufferMemoryBarrier*)DE_NULL,
361 1u,
362 &preCopyBarrier);
363 }
364
365 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
366 {
367 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
368 ? getPlaneAspect(planeNdx)
369 : VK_IMAGE_ASPECT_COLOR_BIT;
370 const deUint32 planeW = (formatDesc.numPlanes > 1)
371 ? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor
372 : imageData.getSize().x();
373 const deUint32 planeH = (formatDesc.numPlanes > 1)
374 ? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor
375 : imageData.getSize().y();
376 const VkBufferImageCopy copy =
377 {
378 0u, // bufferOffset
379 0u, // bufferRowLength
380 0u, // bufferImageHeight
381 { (VkImageAspectFlags)aspect, 0u, 0u, 1u },
382 makeOffset3D(0u, 0u, 0u),
383 makeExtent3D(planeW, planeH, 1u),
384 };
385
386 vkd.cmdCopyBufferToImage(*cmdBuffer, **stagingBuffers[planeNdx], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©);
387 }
388
389 {
390 const VkImageMemoryBarrier postCopyBarrier =
391 {
392 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
393 DE_NULL,
394 VK_ACCESS_TRANSFER_WRITE_BIT,
395 nextAccess,
396 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
397 finalLayout,
398 VK_QUEUE_FAMILY_IGNORED,
399 VK_QUEUE_FAMILY_IGNORED,
400 image,
401 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
402 };
403
404 vkd.cmdPipelineBarrier(*cmdBuffer,
405 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
406 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
407 (VkDependencyFlags)0u,
408 0u,
409 (const VkMemoryBarrier*)DE_NULL,
410 0u,
411 (const VkBufferMemoryBarrier*)DE_NULL,
412 1u,
413 &postCopyBarrier);
414 }
415
416 endCommandBuffer(vkd, *cmdBuffer);
417
418 submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
419 }
420
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)421 void fillImageMemory (const vk::DeviceInterface& vkd,
422 vk::VkDevice device,
423 deUint32 queueFamilyNdx,
424 vk::VkImage image,
425 const std::vector<de::SharedPtr<vk::Allocation> >& allocations,
426 const MultiPlaneImageData& imageData,
427 vk::VkAccessFlags nextAccess,
428 vk::VkImageLayout finalLayout)
429 {
430 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
431 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
432 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
433 const PlanarFormatDescription& formatDesc = imageData.getDescription();
434
435 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
436 {
437 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
438 ? getPlaneAspect(planeNdx)
439 : VK_IMAGE_ASPECT_COLOR_BIT;
440 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1
441 ? allocations[planeNdx]
442 : allocations[0];
443 const size_t planeSize = imageData.getPlaneSize(planeNdx);
444 const deUint32 planeH = imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
445 const VkImageSubresource subresource =
446 {
447 static_cast<vk::VkImageAspectFlags>(aspect),
448 0u,
449 0u,
450 };
451 VkSubresourceLayout layout;
452
453 vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
454
455 for (deUint32 row = 0; row < planeH; ++row)
456 {
457 const size_t rowSize = planeSize / planeH;
458 void* const dstPtr = ((deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
459 const void* const srcPtr = ((const deUint8*)imageData.getPlanePtr(planeNdx)) + row * rowSize;
460
461 deMemcpy(dstPtr, srcPtr, rowSize);
462 }
463 flushMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
464 }
465
466 beginCommandBuffer(vkd, *cmdBuffer);
467
468 {
469 const VkImageMemoryBarrier postCopyBarrier =
470 {
471 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
472 DE_NULL,
473 0u,
474 nextAccess,
475 VK_IMAGE_LAYOUT_PREINITIALIZED,
476 finalLayout,
477 VK_QUEUE_FAMILY_IGNORED,
478 VK_QUEUE_FAMILY_IGNORED,
479 image,
480 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
481 };
482
483 vkd.cmdPipelineBarrier(*cmdBuffer,
484 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
485 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
486 (VkDependencyFlags)0u,
487 0u,
488 (const VkMemoryBarrier*)DE_NULL,
489 0u,
490 (const VkBufferMemoryBarrier*)DE_NULL,
491 1u,
492 &postCopyBarrier);
493 }
494
495 endCommandBuffer(vkd, *cmdBuffer);
496
497 submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
498 }
499
downloadImage(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,Allocator & allocator,VkImage image,MultiPlaneImageData * imageData,VkAccessFlags prevAccess,VkImageLayout initialLayout)500 void downloadImage (const DeviceInterface& vkd,
501 VkDevice device,
502 deUint32 queueFamilyNdx,
503 Allocator& allocator,
504 VkImage image,
505 MultiPlaneImageData* imageData,
506 VkAccessFlags prevAccess,
507 VkImageLayout initialLayout)
508 {
509 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
510 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
511 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
512 vector<VkBufferSp> stagingBuffers;
513 vector<AllocationSp> stagingMemory;
514
515 const PlanarFormatDescription& formatDesc = imageData->getDescription();
516
517 allocateStagingBuffers(vkd, device, allocator, *imageData, &stagingBuffers, &stagingMemory);
518
519 beginCommandBuffer(vkd, *cmdBuffer);
520
521 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
522 {
523 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
524 ? getPlaneAspect(planeNdx)
525 : VK_IMAGE_ASPECT_COLOR_BIT;
526 {
527 const VkImageMemoryBarrier preCopyBarrier =
528 {
529 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
530 DE_NULL,
531 prevAccess,
532 VK_ACCESS_TRANSFER_READ_BIT,
533 initialLayout,
534 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
535 VK_QUEUE_FAMILY_IGNORED,
536 VK_QUEUE_FAMILY_IGNORED,
537 image,
538 {
539 static_cast<vk::VkImageAspectFlags>(aspect),
540 0u,
541 1u,
542 0u,
543 1u
544 }
545 };
546
547 vkd.cmdPipelineBarrier(*cmdBuffer,
548 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
549 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
550 (VkDependencyFlags)0u,
551 0u,
552 (const VkMemoryBarrier*)DE_NULL,
553 0u,
554 (const VkBufferMemoryBarrier*)DE_NULL,
555 1u,
556 &preCopyBarrier);
557 }
558 {
559 const deUint32 planeW = (formatDesc.numPlanes > 1)
560 ? imageData->getSize().x() / formatDesc.planes[planeNdx].widthDivisor
561 : imageData->getSize().x();
562 const deUint32 planeH = (formatDesc.numPlanes > 1)
563 ? imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor
564 : imageData->getSize().y();
565 const VkBufferImageCopy copy =
566 {
567 0u, // bufferOffset
568 0u, // bufferRowLength
569 0u, // bufferImageHeight
570 { (VkImageAspectFlags)aspect, 0u, 0u, 1u },
571 makeOffset3D(0u, 0u, 0u),
572 makeExtent3D(planeW, planeH, 1u),
573 };
574
575 vkd.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **stagingBuffers[planeNdx], 1u, ©);
576 }
577 {
578 const VkBufferMemoryBarrier postCopyBarrier =
579 {
580 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
581 DE_NULL,
582 VK_ACCESS_TRANSFER_WRITE_BIT,
583 VK_ACCESS_HOST_READ_BIT,
584 VK_QUEUE_FAMILY_IGNORED,
585 VK_QUEUE_FAMILY_IGNORED,
586 **stagingBuffers[planeNdx],
587 0u,
588 VK_WHOLE_SIZE
589 };
590
591 vkd.cmdPipelineBarrier(*cmdBuffer,
592 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
593 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
594 (VkDependencyFlags)0u,
595 0u,
596 (const VkMemoryBarrier*)DE_NULL,
597 1u,
598 &postCopyBarrier,
599 0u,
600 (const VkImageMemoryBarrier*)DE_NULL);
601 }
602 }
603
604 endCommandBuffer(vkd, *cmdBuffer);
605
606 submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
607
608 readStagingBuffers(imageData, vkd, device, stagingMemory);
609 }
610
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)611 void readImageMemory (const vk::DeviceInterface& vkd,
612 vk::VkDevice device,
613 deUint32 queueFamilyNdx,
614 vk::VkImage image,
615 const std::vector<de::SharedPtr<vk::Allocation> >& allocations,
616 MultiPlaneImageData* imageData,
617 vk::VkAccessFlags prevAccess,
618 vk::VkImageLayout initialLayout)
619 {
620 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
621 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
622 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
623 const PlanarFormatDescription& formatDesc = imageData->getDescription();
624
625 beginCommandBuffer(vkd, *cmdBuffer);
626
627 {
628 const VkImageMemoryBarrier preCopyBarrier =
629 {
630 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
631 DE_NULL,
632 prevAccess,
633 vk::VK_ACCESS_HOST_READ_BIT,
634 initialLayout,
635 VK_IMAGE_LAYOUT_GENERAL,
636 VK_QUEUE_FAMILY_IGNORED,
637 VK_QUEUE_FAMILY_IGNORED,
638 image,
639 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
640 };
641
642 vkd.cmdPipelineBarrier(*cmdBuffer,
643 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
644 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
645 (VkDependencyFlags)0u,
646 0u,
647 (const VkMemoryBarrier*)DE_NULL,
648 0u,
649 (const VkBufferMemoryBarrier*)DE_NULL,
650 1u,
651 &preCopyBarrier);
652 }
653
654 endCommandBuffer(vkd, *cmdBuffer);
655
656 submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
657
658 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
659 {
660 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
661 ? getPlaneAspect(planeNdx)
662 : VK_IMAGE_ASPECT_COLOR_BIT;
663 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1
664 ? allocations[planeNdx]
665 : allocations[0];
666 const size_t planeSize = imageData->getPlaneSize(planeNdx);
667 const deUint32 planeH = imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
668 const VkImageSubresource subresource =
669 {
670 static_cast<vk::VkImageAspectFlags>(aspect),
671 0u,
672 0u,
673 };
674 VkSubresourceLayout layout;
675
676 vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
677
678 invalidateMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
679
680 for (deUint32 row = 0; row < planeH; ++row)
681 {
682 const size_t rowSize = planeSize / planeH;
683 const void* const srcPtr = ((const deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
684 void* const dstPtr = ((deUint8*)imageData->getPlanePtr(planeNdx)) + row * rowSize;
685
686 deMemcpy(dstPtr, srcPtr, rowSize);
687 }
688 }
689 }
690
691 // ChannelAccess utilities
692 namespace
693 {
694
695 //! Extend < 32b signed integer to 32b
signExtend(deUint32 src,int bits)696 inline deInt32 signExtend (deUint32 src, int bits)
697 {
698 const deUint32 signBit = 1u << (bits-1);
699
700 src |= ~((src & signBit) - 1);
701
702 return (deInt32)src;
703 }
704
divRoundUp(deUint32 a,deUint32 b)705 deUint32 divRoundUp (deUint32 a, deUint32 b)
706 {
707 if (a % b == 0)
708 return a / b;
709 else
710 return (a / b) + 1;
711 }
712
713 // \todo Taken from tcuTexture.cpp
714 // \todo [2011-09-21 pyry] Move to tcutil?
715 template <typename T>
convertSatRte(float f)716 inline T convertSatRte (float f)
717 {
718 // \note Doesn't work for 64-bit types
719 DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
720 DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
721
722 deInt64 minVal = std::numeric_limits<T>::min();
723 deInt64 maxVal = std::numeric_limits<T>::max();
724 float q = deFloatFrac(f);
725 deInt64 intVal = (deInt64)(f-q);
726
727 // Rounding.
728 if (q == 0.5f)
729 {
730 if (intVal % 2 != 0)
731 intVal++;
732 }
733 else if (q > 0.5f)
734 intVal++;
735 // else Don't add anything
736
737 // Saturate.
738 intVal = de::max(minVal, de::min(maxVal, intVal));
739
740 return (T)intVal;
741 }
742
743 } // anonymous
744
ChannelAccess(tcu::TextureChannelClass channelClass,deUint8 channelSize,const tcu::IVec3 & size,const tcu::IVec3 & bitPitch,void * data,deUint32 bitOffset)745 ChannelAccess::ChannelAccess (tcu::TextureChannelClass channelClass,
746 deUint8 channelSize,
747 const tcu::IVec3& size,
748 const tcu::IVec3& bitPitch,
749 void* data,
750 deUint32 bitOffset)
751 : m_channelClass (channelClass)
752 , m_channelSize (channelSize)
753 , m_size (size)
754 , m_bitPitch (bitPitch)
755
756 , m_data ((deUint8*)data + (bitOffset / 8))
757 , m_bitOffset (bitOffset % 8)
758 {
759 }
760
getChannelUint(const tcu::IVec3 & pos) const761 deUint32 ChannelAccess::getChannelUint (const tcu::IVec3& pos) const
762 {
763 DE_ASSERT(pos[0] < m_size[0]);
764 DE_ASSERT(pos[1] < m_size[1]);
765 DE_ASSERT(pos[2] < m_size[2]);
766
767 const deInt32 bitOffset (m_bitOffset + tcu::dot(m_bitPitch, pos));
768 const deUint8* const firstByte = ((const deUint8*)m_data) + (bitOffset / 8);
769 const deUint32 byteCount = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
770 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
771 const deUint32 offset = bitOffset % 8;
772 deUint32 bits = 0u;
773
774 deMemcpy(&bits, firstByte, byteCount);
775
776 return (bits >> offset) & mask;
777 }
778
setChannel(const tcu::IVec3 & pos,deUint32 x)779 void ChannelAccess::setChannel (const tcu::IVec3& pos, deUint32 x)
780 {
781 DE_ASSERT(pos[0] < m_size[0]);
782 DE_ASSERT(pos[1] < m_size[1]);
783 DE_ASSERT(pos[2] < m_size[2]);
784
785 const deInt32 bitOffset (m_bitOffset + tcu::dot(m_bitPitch, pos));
786 deUint8* const firstByte = ((deUint8*)m_data) + (bitOffset / 8);
787 const deUint32 byteCount = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
788 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
789 const deUint32 offset = bitOffset % 8;
790
791 const deUint32 bits = (x & mask) << offset;
792 deUint32 oldBits = 0;
793
794 deMemcpy(&oldBits, firstByte, byteCount);
795
796 {
797 const deUint32 newBits = bits | (oldBits & (~(mask << offset)));
798
799 deMemcpy(firstByte, &newBits, byteCount);
800 }
801 }
802
getChannel(const tcu::IVec3 & pos) const803 float ChannelAccess::getChannel (const tcu::IVec3& pos) const
804 {
805 const deUint32 bits (getChannelUint(pos));
806
807 switch (m_channelClass)
808 {
809 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
810 return (float)bits / (float)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u));
811
812 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
813 return (float)bits;
814
815 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
816 return de::max(-1.0f, (float)signExtend(bits, m_channelSize) / (float)((0x1u << (m_channelSize - 1u)) - 1u));
817
818 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
819 return (float)signExtend(bits, m_channelSize);
820
821 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
822 if (m_channelSize == 32)
823 return tcu::Float32(bits).asFloat();
824 else
825 {
826 DE_FATAL("Float type not supported");
827 return -1.0f;
828 }
829
830 default:
831 DE_FATAL("Unknown texture channel class");
832 return -1.0f;
833 }
834 }
835
getChannel(const tcu::FloatFormat & conversionFormat,const tcu::IVec3 & pos) const836 tcu::Interval ChannelAccess::getChannel (const tcu::FloatFormat& conversionFormat,
837 const tcu::IVec3& pos) const
838 {
839 const deUint32 bits (getChannelUint(pos));
840
841 switch (m_channelClass)
842 {
843 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
844 return conversionFormat.roundOut(conversionFormat.roundOut((double)bits, false)
845 / conversionFormat.roundOut((double)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u)), false), false);
846
847 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
848 return conversionFormat.roundOut((double)bits, false);
849
850 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
851 {
852 const tcu::Interval result (conversionFormat.roundOut(conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false)
853 / conversionFormat.roundOut((double)((0x1u << (m_channelSize - 1u)) - 1u), false), false));
854
855 return tcu::Interval(de::max(-1.0, result.lo()), de::max(-1.0, result.hi()));
856 }
857
858 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
859 return conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false);
860
861 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
862 if (m_channelSize == 32)
863 return conversionFormat.roundOut(tcu::Float32(bits).asFloat(), false);
864 else
865 {
866 DE_FATAL("Float type not supported");
867 return tcu::Interval();
868 }
869
870 default:
871 DE_FATAL("Unknown texture channel class");
872 return tcu::Interval();
873 }
874 }
875
setChannel(const tcu::IVec3 & pos,float x)876 void ChannelAccess::setChannel (const tcu::IVec3& pos, float x)
877 {
878 DE_ASSERT(pos[0] < m_size[0]);
879 DE_ASSERT(pos[1] < m_size[1]);
880 DE_ASSERT(pos[2] < m_size[2]);
881
882 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
883
884 switch (m_channelClass)
885 {
886 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
887 {
888 const deUint32 maxValue (mask);
889 const deUint32 value (de::min(maxValue, (deUint32)convertSatRte<deUint32>(x * (float)maxValue)));
890 setChannel(pos, value);
891 break;
892 }
893
894 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
895 {
896 const deInt32 range ((0x1u << (m_channelSize - 1u)) - 1u);
897 const deUint32 value ((deUint32)de::clamp<deInt32>(convertSatRte<deInt32>(x * (float)range), -range, range));
898 setChannel(pos, value);
899 break;
900 }
901
902 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
903 {
904 const deUint32 maxValue (mask);
905 const deUint32 value (de::min(maxValue, (deUint32)x));
906 setChannel(pos, value);
907 break;
908 }
909
910 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
911 {
912 const deInt32 minValue (-(deInt32)(1u << (m_channelSize - 1u)));
913 const deInt32 maxValue ((deInt32)((1u << (m_channelSize - 1u)) - 1u));
914 const deUint32 value ((deUint32)de::clamp((deInt32)x, minValue, maxValue));
915 setChannel(pos, value);
916 break;
917 }
918
919 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
920 {
921 if (m_channelSize == 32)
922 {
923 const deUint32 value = tcu::Float32(x).bits();
924 setChannel(pos, value);
925 }
926 else
927 DE_FATAL("Float type not supported");
928 break;
929 }
930
931 default:
932 DE_FATAL("Unknown texture channel class");
933 }
934 }
935
getChannelAccess(MultiPlaneImageData & data,const vk::PlanarFormatDescription & formatInfo,const UVec2 & size,int channelNdx)936 ChannelAccess getChannelAccess (MultiPlaneImageData& data,
937 const vk::PlanarFormatDescription& formatInfo,
938 const UVec2& size,
939 int channelNdx)
940 {
941 DE_ASSERT(formatInfo.hasChannelNdx(channelNdx));
942
943 const deUint32 planeNdx = formatInfo.channels[channelNdx].planeNdx;
944 const deUint32 valueOffsetBits = formatInfo.channels[channelNdx].offsetBits;
945 const deUint32 pixelStrideBytes = formatInfo.channels[channelNdx].strideBytes;
946 const deUint32 pixelStrideBits = pixelStrideBytes * 8;
947 const deUint8 sizeBits = formatInfo.channels[channelNdx].sizeBits;
948
949 DE_ASSERT(size.x() % formatInfo.planes[planeNdx].widthDivisor == 0);
950 DE_ASSERT(size.y() % formatInfo.planes[planeNdx].heightDivisor == 0);
951
952 deUint32 accessWidth = size.x() / formatInfo.planes[planeNdx].widthDivisor;
953 const deUint32 accessHeight = size.y() / formatInfo.planes[planeNdx].heightDivisor;
954 const deUint32 elementSizeBytes = formatInfo.planes[planeNdx].elementSizeBytes;
955
956 const deUint32 rowPitch = formatInfo.planes[planeNdx].elementSizeBytes * accessWidth;
957 const deUint32 rowPitchBits = rowPitch * 8;
958
959 if (pixelStrideBytes != elementSizeBytes)
960 {
961 DE_ASSERT(elementSizeBytes % pixelStrideBytes == 0);
962 accessWidth *= elementSizeBytes/pixelStrideBytes;
963 }
964
965 return ChannelAccess((tcu::TextureChannelClass)formatInfo.channels[channelNdx].type, sizeBits, tcu::IVec3(accessWidth, accessHeight, 1u), tcu::IVec3((int)pixelStrideBits, (int)rowPitchBits, 0), data.getPlanePtr(planeNdx), (deUint32)valueOffsetBits);
966 }
967
isXChromaSubsampled(vk::VkFormat format)968 bool isXChromaSubsampled (vk::VkFormat format)
969 {
970 switch (format)
971 {
972 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
973 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
974 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
975 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
976 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
977 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
978 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
979 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
980 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
981 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
982 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
983 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
984 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
985 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
986 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
987 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
988 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
989 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
990 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
991 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
992 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
993 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
994 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
995 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
996 return true;
997
998 default:
999 return false;
1000 }
1001 }
1002
isYChromaSubsampled(vk::VkFormat format)1003 bool isYChromaSubsampled (vk::VkFormat format)
1004 {
1005 switch (format)
1006 {
1007 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1008 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1009 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1010 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1011 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1012 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1013 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1014 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1015 return true;
1016
1017 default:
1018 return false;
1019 }
1020 }
1021
areLsb6BitsDontCare(vk::VkFormat srcFormat,vk::VkFormat dstFormat)1022 bool areLsb6BitsDontCare(vk::VkFormat srcFormat, vk::VkFormat dstFormat)
1023 {
1024 if ((srcFormat == vk::VK_FORMAT_R10X6_UNORM_PACK16) ||
1025 (dstFormat == vk::VK_FORMAT_R10X6_UNORM_PACK16) ||
1026 (srcFormat == vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16) ||
1027 (dstFormat == vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16) ||
1028 (srcFormat == vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16) ||
1029 (dstFormat == vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16) ||
1030 (srcFormat == vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) ||
1031 (dstFormat == vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) ||
1032 (srcFormat == vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) ||
1033 (dstFormat == vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) ||
1034 (srcFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16) ||
1035 (dstFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16) ||
1036 (srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16) ||
1037 (dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16) ||
1038 (srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16) ||
1039 (dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16) ||
1040 (srcFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16) ||
1041 (dstFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16) ||
1042 (srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16) ||
1043 (dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16))
1044 {
1045 return true;
1046 }
1047
1048 return false;
1049 }
1050
areLsb4BitsDontCare(vk::VkFormat srcFormat,vk::VkFormat dstFormat)1051 bool areLsb4BitsDontCare(vk::VkFormat srcFormat, vk::VkFormat dstFormat)
1052 {
1053 if ((srcFormat == vk::VK_FORMAT_R12X4_UNORM_PACK16) ||
1054 (dstFormat == vk::VK_FORMAT_R12X4_UNORM_PACK16) ||
1055 (srcFormat == vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16) ||
1056 (dstFormat == vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16) ||
1057 (srcFormat == vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16) ||
1058 (dstFormat == vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16) ||
1059 (srcFormat == vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) ||
1060 (dstFormat == vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) ||
1061 (srcFormat == vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) ||
1062 (dstFormat == vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) ||
1063 (srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16) ||
1064 (dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16) ||
1065 (srcFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16) ||
1066 (dstFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16) ||
1067 (srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16) ||
1068 (dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16) ||
1069 (srcFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16) ||
1070 (dstFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16) ||
1071 (srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16) ||
1072 (dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16))
1073 {
1074 return true;
1075 }
1076
1077 return false;
1078 }
1079
1080 // \note Used for range expansion
getYCbCrBitDepth(vk::VkFormat format)1081 tcu::UVec4 getYCbCrBitDepth (vk::VkFormat format)
1082 {
1083 switch (format)
1084 {
1085 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1086 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1087 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1088 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1089 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1090 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1091 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1092 return tcu::UVec4(8, 8, 8, 0);
1093
1094 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1095 return tcu::UVec4(10, 0, 0, 0);
1096
1097 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1098 return tcu::UVec4(10, 10, 0, 0);
1099
1100 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1101 return tcu::UVec4(10, 10, 10, 10);
1102
1103 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1104 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1105 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1106 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1107 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1108 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1109 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1110 return tcu::UVec4(10, 10, 10, 0);
1111
1112 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1113 return tcu::UVec4(12, 0, 0, 0);
1114
1115 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1116 return tcu::UVec4(12, 12, 0, 0);
1117
1118 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1119 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1120 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1121 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1122 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1123 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1124 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1125 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1126 return tcu::UVec4(12, 12, 12, 12);
1127
1128 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1129 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1130 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1131 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1132 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1133 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1134 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1135 return tcu::UVec4(16, 16, 16, 0);
1136
1137 default:
1138 return tcu::getTextureFormatBitDepth(vk::mapVkFormat(format)).cast<deUint32>();
1139 }
1140 }
1141
1142 // \note Taken from explicit lod filtering tests
getYCbCrFilteringPrecision(vk::VkFormat format)1143 tcu::FloatFormat getYCbCrFilteringPrecision (vk::VkFormat format)
1144 {
1145 const tcu::FloatFormat reallyLow (0, 0, 6, false, tcu::YES);
1146 const tcu::FloatFormat low (0, 0, 7, false, tcu::YES);
1147 const tcu::FloatFormat fp16 (-14, 15, 10, false);
1148 const tcu::FloatFormat fp32 (-126, 127, 23, true);
1149
1150 switch (format)
1151 {
1152 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1153 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1154 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1155 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1156 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1157 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1158 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1159 return reallyLow;
1160
1161 case vk::VK_FORMAT_R8G8B8_UNORM:
1162 case vk::VK_FORMAT_B8G8R8_UNORM:
1163 case vk::VK_FORMAT_R8G8B8A8_UNORM:
1164 case vk::VK_FORMAT_B8G8R8A8_UNORM:
1165 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1166 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1167 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1168 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1169 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1170 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1171 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1172 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1173 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1174 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1175 return low;
1176
1177 case vk::VK_FORMAT_R16G16B16_UNORM:
1178 case vk::VK_FORMAT_R16G16B16A16_UNORM:
1179 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1180 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1181 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1182 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1183 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1184 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1185 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1186 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1187 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1188 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1189 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1190 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1191 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1192 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1193 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1194 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1195 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1196 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1197 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1198 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1199 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1200 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1201 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1202 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1203 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1204 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1205 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1206 return fp16;
1207
1208 default:
1209 DE_FATAL("Precision not defined for format");
1210 return fp32;
1211 }
1212 }
1213
1214 // \note Taken from explicit lod filtering tests
getYCbCrConversionPrecision(vk::VkFormat format)1215 tcu::FloatFormat getYCbCrConversionPrecision (vk::VkFormat format)
1216 {
1217 const tcu::FloatFormat reallyLow (0, 0, 8, false, tcu::YES);
1218 const tcu::FloatFormat fp16 (-14, 15, 10, false);
1219 const tcu::FloatFormat fp32 (-126, 127, 23, true);
1220
1221 switch (format)
1222 {
1223 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1224 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1225 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1226 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1227 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1228 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1229 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1230 return reallyLow;
1231
1232 case vk::VK_FORMAT_R8G8B8_UNORM:
1233 case vk::VK_FORMAT_B8G8R8_UNORM:
1234 case vk::VK_FORMAT_R8G8B8A8_UNORM:
1235 case vk::VK_FORMAT_B8G8R8A8_UNORM:
1236 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1237 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1238 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1239 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1240 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1241 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1242 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1243 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1244 return reallyLow;
1245
1246 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1247 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1248 case vk::VK_FORMAT_R16G16B16_UNORM:
1249 case vk::VK_FORMAT_R16G16B16A16_UNORM:
1250 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1251 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1252 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1253 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1254 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1255 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1256 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1257 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1258 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1259 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1260 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1261 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1262 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1263 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1264 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1265 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1266 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1267 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1268 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1269 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1270 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1271 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1272 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1273 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1274 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1275 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1276 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1277 return fp16;
1278
1279 default:
1280 DE_FATAL("Precision not defined for format");
1281 return fp32;
1282 }
1283 }
1284
getYCbCrFormatChannelCount(vk::VkFormat format)1285 deUint32 getYCbCrFormatChannelCount (vk::VkFormat format)
1286 {
1287 switch (format)
1288 {
1289 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1290 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1291 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1292 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1293 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1294 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1295 case vk::VK_FORMAT_B8G8R8A8_UNORM:
1296 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1297 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1298 case vk::VK_FORMAT_R16G16B16A16_UNORM:
1299 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1300 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1301 case vk::VK_FORMAT_R8G8B8A8_UNORM:
1302 return 4;
1303
1304 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1305 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1306 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1307 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1308 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1309 case vk::VK_FORMAT_B8G8R8_UNORM:
1310 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1311 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1312 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1313 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1314 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1315 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1316 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1317 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1318 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1319 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1320 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1321 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1322 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1323 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1324 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1325 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1326 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1327 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1328 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1329 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1330 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1331 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1332 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1333 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1334 case vk::VK_FORMAT_R16G16B16_UNORM:
1335 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1336 case vk::VK_FORMAT_R8G8B8_UNORM:
1337 return 3;
1338
1339 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1340 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1341 return 2;
1342
1343 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1344 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1345 return 1;
1346
1347 default:
1348 DE_FATAL("Unknown number of channels");
1349 return -1;
1350 }
1351 }
1352
1353 // YCbCr color conversion utilities
1354 namespace
1355 {
1356
rangeExpandChroma(vk::VkSamplerYcbcrRange range,const tcu::FloatFormat & conversionFormat,const deUint32 bits,const tcu::Interval & sample)1357 tcu::Interval rangeExpandChroma (vk::VkSamplerYcbcrRange range,
1358 const tcu::FloatFormat& conversionFormat,
1359 const deUint32 bits,
1360 const tcu::Interval& sample)
1361 {
1362 const deUint32 values (0x1u << bits);
1363
1364 switch (range)
1365 {
1366 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
1367 return conversionFormat.roundOut(sample - conversionFormat.roundOut(tcu::Interval((double)(0x1u << (bits - 1u)) / (double)((0x1u << bits) - 1u)), false), false);
1368
1369 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
1370 {
1371 const tcu::Interval a (conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false));
1372 const tcu::Interval dividend (conversionFormat.roundOut(a - tcu::Interval((double)(128u * (0x1u << (bits - 8u)))), false));
1373 const tcu::Interval divisor ((double)(224u * (0x1u << (bits - 8u))));
1374 const tcu::Interval result (conversionFormat.roundOut(dividend / divisor, false));
1375
1376 return result;
1377 }
1378
1379 default:
1380 DE_FATAL("Unknown YCbCrRange");
1381 return tcu::Interval();
1382 }
1383 }
1384
rangeExpandLuma(vk::VkSamplerYcbcrRange range,const tcu::FloatFormat & conversionFormat,const deUint32 bits,const tcu::Interval & sample)1385 tcu::Interval rangeExpandLuma (vk::VkSamplerYcbcrRange range,
1386 const tcu::FloatFormat& conversionFormat,
1387 const deUint32 bits,
1388 const tcu::Interval& sample)
1389 {
1390 const deUint32 values (0x1u << bits);
1391
1392 switch (range)
1393 {
1394 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
1395 return conversionFormat.roundOut(sample, false);
1396
1397 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
1398 {
1399 const tcu::Interval a (conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false));
1400 const tcu::Interval dividend (conversionFormat.roundOut(a - tcu::Interval((double)(16u * (0x1u << (bits - 8u)))), false));
1401 const tcu::Interval divisor ((double)(219u * (0x1u << (bits - 8u))));
1402 const tcu::Interval result (conversionFormat.roundOut(dividend / divisor, false));
1403
1404 return result;
1405 }
1406
1407 default:
1408 DE_FATAL("Unknown YCbCrRange");
1409 return tcu::Interval();
1410 }
1411 }
1412
clampMaybe(const tcu::Interval & x,double min,double max)1413 tcu::Interval clampMaybe (const tcu::Interval& x,
1414 double min,
1415 double max)
1416 {
1417 tcu::Interval result = x;
1418
1419 DE_ASSERT(min <= max);
1420
1421 if (x.lo() < min)
1422 result = result | tcu::Interval(min);
1423
1424 if (x.hi() > max)
1425 result = result | tcu::Interval(max);
1426
1427 return result;
1428 }
1429
convertColor(vk::VkSamplerYcbcrModelConversion colorModel,vk::VkSamplerYcbcrRange range,const tcu::FloatFormat & conversionFormat,const tcu::UVec4 & bitDepth,const tcu::Interval input[4],tcu::Interval output[4])1430 void convertColor (vk::VkSamplerYcbcrModelConversion colorModel,
1431 vk::VkSamplerYcbcrRange range,
1432 const tcu::FloatFormat& conversionFormat,
1433 const tcu::UVec4& bitDepth,
1434 const tcu::Interval input[4],
1435 tcu::Interval output[4])
1436 {
1437 switch (colorModel)
1438 {
1439 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:
1440 {
1441 for (size_t ndx = 0; ndx < 4; ndx++)
1442 output[ndx] = input[ndx];
1443 break;
1444 }
1445
1446 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:
1447 {
1448 output[0] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]), -0.5, 0.5);
1449 output[1] = clampMaybe(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]), 0.0, 1.0);
1450 output[2] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]), -0.5, 0.5);
1451 output[3] = input[3];
1452 break;
1453 }
1454
1455 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:
1456 {
1457 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1458 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1459 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1460
1461 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0));
1462 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5));
1463 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5));
1464
1465 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.402 * crClamped, false), false);
1466 output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut((0.202008 / 0.587) * cbClamped, false), false) - conversionFormat.roundOut((0.419198 / 0.587) * crClamped, false), false);
1467 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.772 * cbClamped, false), false);
1468 output[3] = input[3];
1469 break;
1470 }
1471
1472 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:
1473 {
1474 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1475 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1476 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1477
1478 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0));
1479 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5));
1480 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5));
1481
1482 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.5748 * crClamped, false), false);
1483 output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut((0.13397432 / 0.7152) * cbClamped, false), false) - conversionFormat.roundOut((0.33480248 / 0.7152) * crClamped, false), false);
1484 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8556 * cbClamped, false), false);
1485 output[3] = input[3];
1486 break;
1487 }
1488
1489 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:
1490 {
1491 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1492 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1493 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1494
1495 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0));
1496 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5));
1497 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5));
1498
1499 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.4746 * crClamped, false), false);
1500 output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut(conversionFormat.roundOut(0.11156702 / 0.6780, false) * cbClamped, false), false) - conversionFormat.roundOut(conversionFormat.roundOut(0.38737742 / 0.6780, false) * crClamped, false), false);
1501 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8814 * cbClamped, false), false);
1502 output[3] = input[3];
1503 break;
1504 }
1505
1506 default:
1507 DE_FATAL("Unknown YCbCrModel");
1508 }
1509
1510 if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY)
1511 {
1512 for (int ndx = 0; ndx < 3; ndx++)
1513 output[ndx] = clampMaybe(output[ndx], 0.0, 1.0);
1514 }
1515 }
1516
mirror(int coord)1517 int mirror (int coord)
1518 {
1519 return coord >= 0 ? coord : -(1 + coord);
1520 }
1521
imod(int a,int b)1522 int imod (int a, int b)
1523 {
1524 int m = a % b;
1525 return m < 0 ? m + b : m;
1526 }
1527
frac(const tcu::Interval & x)1528 tcu::Interval frac (const tcu::Interval& x)
1529 {
1530 if (x.hi() - x.lo() >= 1.0)
1531 return tcu::Interval(0.0, 1.0);
1532 else
1533 {
1534 const tcu::Interval ret (deFrac(x.lo()), deFrac(x.hi()));
1535
1536 return ret;
1537 }
1538 }
1539
calculateUV(const tcu::FloatFormat & coordFormat,const tcu::Interval & st,const int size)1540 tcu::Interval calculateUV (const tcu::FloatFormat& coordFormat,
1541 const tcu::Interval& st,
1542 const int size)
1543 {
1544 return coordFormat.roundOut(coordFormat.roundOut(st, false) * tcu::Interval((double)size), false);
1545 }
1546
calculateNearestIJRange(const tcu::FloatFormat & coordFormat,const tcu::Interval & uv)1547 tcu::IVec2 calculateNearestIJRange (const tcu::FloatFormat& coordFormat,
1548 const tcu::Interval& uv)
1549 {
1550 const tcu::Interval ij (coordFormat.roundOut(coordFormat.roundOut(uv, false) - tcu::Interval(0.5), false));
1551
1552 return tcu::IVec2(deRoundToInt32(ij.lo() - coordFormat.ulp(ij.lo(), 1)), deRoundToInt32(ij.hi() + coordFormat.ulp(ij.hi(), 1)));
1553 }
1554
1555 // Calculate range of pixel coordinates that can be used as lower coordinate for linear sampling
calculateLinearIJRange(const tcu::FloatFormat & coordFormat,const tcu::Interval & uv)1556 tcu::IVec2 calculateLinearIJRange (const tcu::FloatFormat& coordFormat,
1557 const tcu::Interval& uv)
1558 {
1559 const tcu::Interval ij (coordFormat.roundOut(uv - tcu::Interval(0.5), false));
1560
1561 return tcu::IVec2(deFloorToInt32(ij.lo()), deFloorToInt32(ij.hi()));
1562 }
1563
calculateAB(const deUint32 subTexelPrecisionBits,const tcu::Interval & uv,int ij)1564 tcu::Interval calculateAB (const deUint32 subTexelPrecisionBits,
1565 const tcu::Interval& uv,
1566 int ij)
1567 {
1568 const deUint32 subdivisions = 0x1u << subTexelPrecisionBits;
1569 const tcu::Interval ab (frac((uv - 0.5) & tcu::Interval((double)ij, (double)(ij + 1))));
1570 const tcu::Interval gridAB (ab * tcu::Interval(subdivisions));
1571 const tcu::Interval rounded (de::max(deFloor(gridAB.lo()) / subdivisions, 0.0) , de::min(deCeil(gridAB.hi()) / subdivisions, 1.0));
1572
1573 return rounded;
1574 }
1575
lookupWrapped(const ChannelAccess & access,const tcu::FloatFormat & conversionFormat,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,const tcu::IVec2 & coord)1576 tcu::Interval lookupWrapped (const ChannelAccess& access,
1577 const tcu::FloatFormat& conversionFormat,
1578 vk::VkSamplerAddressMode addressModeU,
1579 vk::VkSamplerAddressMode addressModeV,
1580 const tcu::IVec2& coord)
1581 {
1582 return access.getChannel(conversionFormat,
1583 tcu::IVec3(wrap(addressModeU, coord.x(), access.getSize().x()), wrap(addressModeV, coord.y(), access.getSize().y()), 0));
1584 }
1585
linearInterpolate(const tcu::FloatFormat & filteringFormat,const tcu::Interval & a,const tcu::Interval & b,const tcu::Interval & p00,const tcu::Interval & p10,const tcu::Interval & p01,const tcu::Interval & p11)1586 tcu::Interval linearInterpolate (const tcu::FloatFormat& filteringFormat,
1587 const tcu::Interval& a,
1588 const tcu::Interval& b,
1589 const tcu::Interval& p00,
1590 const tcu::Interval& p10,
1591 const tcu::Interval& p01,
1592 const tcu::Interval& p11)
1593 {
1594 const tcu::Interval p[4] =
1595 {
1596 p00,
1597 p10,
1598 p01,
1599 p11
1600 };
1601 tcu::Interval result (0.0);
1602
1603 for (size_t ndx = 0; ndx < 4; ndx++)
1604 {
1605 const tcu::Interval weightA (filteringFormat.roundOut((ndx % 2) == 0 ? (1.0 - a) : a, false));
1606 const tcu::Interval weightB (filteringFormat.roundOut((ndx / 2) == 0 ? (1.0 - b) : b, false));
1607 const tcu::Interval weight (filteringFormat.roundOut(weightA * weightB, false));
1608
1609 result = filteringFormat.roundOut(result + filteringFormat.roundOut(p[ndx] * weight, false), false);
1610 }
1611
1612 return result;
1613 }
1614
calculateImplicitChromaUV(const tcu::FloatFormat & coordFormat,vk::VkChromaLocation offset,const tcu::Interval & uv)1615 tcu::Interval calculateImplicitChromaUV (const tcu::FloatFormat& coordFormat,
1616 vk::VkChromaLocation offset,
1617 const tcu::Interval& uv)
1618 {
1619 if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
1620 return coordFormat.roundOut(0.5 * coordFormat.roundOut(uv + 0.5, false), false);
1621 else
1622 return coordFormat.roundOut(0.5 * uv, false);
1623 }
1624
linearSample(const ChannelAccess & access,const tcu::FloatFormat & conversionFormat,const tcu::FloatFormat & filteringFormat,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,const tcu::IVec2 & coord,const tcu::Interval & a,const tcu::Interval & b)1625 tcu::Interval linearSample (const ChannelAccess& access,
1626 const tcu::FloatFormat& conversionFormat,
1627 const tcu::FloatFormat& filteringFormat,
1628 vk::VkSamplerAddressMode addressModeU,
1629 vk::VkSamplerAddressMode addressModeV,
1630 const tcu::IVec2& coord,
1631 const tcu::Interval& a,
1632 const tcu::Interval& b)
1633 {
1634 return linearInterpolate(filteringFormat, a, b,
1635 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 0)),
1636 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 0)),
1637 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 1)),
1638 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 1)));
1639 }
1640
reconstructLinearXChromaSample(const tcu::FloatFormat & filteringFormat,const tcu::FloatFormat & conversionFormat,vk::VkChromaLocation offset,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,const ChannelAccess & access,int i,int j)1641 tcu::Interval reconstructLinearXChromaSample (const tcu::FloatFormat& filteringFormat,
1642 const tcu::FloatFormat& conversionFormat,
1643 vk::VkChromaLocation offset,
1644 vk::VkSamplerAddressMode addressModeU,
1645 vk::VkSamplerAddressMode addressModeV,
1646 const ChannelAccess& access,
1647 int i,
1648 int j)
1649 {
1650 const int subI = divFloor(i, 2);
1651
1652 if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
1653 {
1654 if (i % 2 == 0)
1655 return lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j));
1656 else
1657 {
1658 const tcu::Interval a (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1659 const tcu::Interval b (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false));
1660
1661 return filteringFormat.roundOut(a + b, false);
1662 }
1663 }
1664 else if (offset == vk::VK_CHROMA_LOCATION_MIDPOINT)
1665 {
1666 if (i % 2 == 0)
1667 {
1668 const tcu::Interval a (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI - 1, j)), false));
1669 const tcu::Interval b (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1670
1671 return filteringFormat.roundOut(a + b, false);
1672 }
1673 else
1674 {
1675 const tcu::Interval a (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false));
1676 const tcu::Interval b (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1677
1678 return filteringFormat.roundOut(a + b, false);
1679 }
1680 }
1681 else
1682 {
1683 DE_FATAL("Unknown sample location");
1684 return tcu::Interval();
1685 }
1686 }
1687
reconstructLinearXYChromaSample(const tcu::FloatFormat & filteringFormat,const tcu::FloatFormat & conversionFormat,vk::VkChromaLocation xOffset,vk::VkChromaLocation yOffset,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,const ChannelAccess & access,int i,int j)1688 tcu::Interval reconstructLinearXYChromaSample (const tcu::FloatFormat& filteringFormat,
1689 const tcu::FloatFormat& conversionFormat,
1690 vk::VkChromaLocation xOffset,
1691 vk::VkChromaLocation yOffset,
1692 vk::VkSamplerAddressMode addressModeU,
1693 vk::VkSamplerAddressMode addressModeV,
1694 const ChannelAccess& access,
1695 int i,
1696 int j)
1697 {
1698 const int subI = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1699 ? divFloor(i, 2)
1700 : (i % 2 == 0 ? divFloor(i, 2) - 1 : divFloor(i, 2));
1701 const int subJ = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1702 ? divFloor(j, 2)
1703 : (j % 2 == 0 ? divFloor(j, 2) - 1 : divFloor(j, 2));
1704
1705 const double a = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1706 ? (i % 2 == 0 ? 0.0 : 0.5)
1707 : (i % 2 == 0 ? 0.25 : 0.75);
1708 const double b = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1709 ? (j % 2 == 0 ? 0.0 : 0.5)
1710 : (j % 2 == 0 ? 0.25 : 0.75);
1711
1712 return linearInterpolate(filteringFormat, a, b,
1713 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ)),
1714 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ)),
1715 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ + 1)),
1716 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ + 1)));
1717 }
1718
swizzle(vk::VkComponentSwizzle swizzle,const ChannelAccess & identityPlane,const ChannelAccess & rPlane,const ChannelAccess & gPlane,const ChannelAccess & bPlane,const ChannelAccess & aPlane)1719 const ChannelAccess& swizzle (vk::VkComponentSwizzle swizzle,
1720 const ChannelAccess& identityPlane,
1721 const ChannelAccess& rPlane,
1722 const ChannelAccess& gPlane,
1723 const ChannelAccess& bPlane,
1724 const ChannelAccess& aPlane)
1725 {
1726 switch (swizzle)
1727 {
1728 case vk::VK_COMPONENT_SWIZZLE_IDENTITY: return identityPlane;
1729 case vk::VK_COMPONENT_SWIZZLE_R: return rPlane;
1730 case vk::VK_COMPONENT_SWIZZLE_G: return gPlane;
1731 case vk::VK_COMPONENT_SWIZZLE_B: return bPlane;
1732 case vk::VK_COMPONENT_SWIZZLE_A: return aPlane;
1733
1734 default:
1735 DE_FATAL("Unsupported swizzle");
1736 return identityPlane;
1737 }
1738 }
1739
1740 } // anonymous
1741
wrap(vk::VkSamplerAddressMode addressMode,int coord,int size)1742 int wrap (vk::VkSamplerAddressMode addressMode,
1743 int coord,
1744 int size)
1745 {
1746 switch (addressMode)
1747 {
1748 case vk::VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
1749 return (size - 1) - mirror(imod(coord, 2 * size) - size);
1750
1751 case vk::VK_SAMPLER_ADDRESS_MODE_REPEAT:
1752 return imod(coord, size);
1753
1754 case vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1755 return de::clamp(coord, 0, size - 1);
1756
1757 case vk::VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
1758 return de::clamp(mirror(coord), 0, size - 1);
1759
1760 default:
1761 DE_FATAL("Unknown wrap mode");
1762 return ~0;
1763 }
1764 }
1765
divFloor(int a,int b)1766 int divFloor (int a, int b)
1767 {
1768 if (a % b == 0)
1769 return a / b;
1770 else if (a > 0)
1771 return a / b;
1772 else
1773 return (a / b) - 1;
1774 }
1775
calculateBounds(const ChannelAccess & rPlane,const ChannelAccess & gPlane,const ChannelAccess & bPlane,const ChannelAccess & aPlane,const UVec4 & bitDepth,const vector<Vec2> & sts,const FloatFormat & filteringFormat,const FloatFormat & conversionFormat,const deUint32 subTexelPrecisionBits,vk::VkFilter filter,vk::VkSamplerYcbcrModelConversion colorModel,vk::VkSamplerYcbcrRange range,vk::VkFilter chromaFilter,vk::VkChromaLocation xChromaOffset,vk::VkChromaLocation yChromaOffset,const vk::VkComponentMapping & componentMapping,bool explicitReconstruction,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,std::vector<Vec4> & minBounds,std::vector<Vec4> & maxBounds,std::vector<Vec4> & uvBounds,std::vector<IVec4> & ijBounds)1776 void calculateBounds (const ChannelAccess& rPlane,
1777 const ChannelAccess& gPlane,
1778 const ChannelAccess& bPlane,
1779 const ChannelAccess& aPlane,
1780 const UVec4& bitDepth,
1781 const vector<Vec2>& sts,
1782 const FloatFormat& filteringFormat,
1783 const FloatFormat& conversionFormat,
1784 const deUint32 subTexelPrecisionBits,
1785 vk::VkFilter filter,
1786 vk::VkSamplerYcbcrModelConversion colorModel,
1787 vk::VkSamplerYcbcrRange range,
1788 vk::VkFilter chromaFilter,
1789 vk::VkChromaLocation xChromaOffset,
1790 vk::VkChromaLocation yChromaOffset,
1791 const vk::VkComponentMapping& componentMapping,
1792 bool explicitReconstruction,
1793 vk::VkSamplerAddressMode addressModeU,
1794 vk::VkSamplerAddressMode addressModeV,
1795 std::vector<Vec4>& minBounds,
1796 std::vector<Vec4>& maxBounds,
1797 std::vector<Vec4>& uvBounds,
1798 std::vector<IVec4>& ijBounds)
1799 {
1800 const FloatFormat highp (-126, 127, 23, true,
1801 tcu::MAYBE, // subnormals
1802 tcu::YES, // infinities
1803 tcu::MAYBE); // NaN
1804 const FloatFormat coordFormat (-32, 32, 16, true);
1805 const ChannelAccess& rAccess (swizzle(componentMapping.r, rPlane, rPlane, gPlane, bPlane, aPlane));
1806 const ChannelAccess& gAccess (swizzle(componentMapping.g, gPlane, rPlane, gPlane, bPlane, aPlane));
1807 const ChannelAccess& bAccess (swizzle(componentMapping.b, bPlane, rPlane, gPlane, bPlane, aPlane));
1808 const ChannelAccess& aAccess (swizzle(componentMapping.a, aPlane, rPlane, gPlane, bPlane, aPlane));
1809
1810 const bool subsampledX = gAccess.getSize().x() > rAccess.getSize().x();
1811 const bool subsampledY = gAccess.getSize().y() > rAccess.getSize().y();
1812
1813 minBounds.resize(sts.size(), Vec4(TCU_INFINITY));
1814 maxBounds.resize(sts.size(), Vec4(-TCU_INFINITY));
1815
1816 uvBounds.resize(sts.size(), Vec4(TCU_INFINITY, -TCU_INFINITY, TCU_INFINITY, -TCU_INFINITY));
1817 ijBounds.resize(sts.size(), IVec4(0x7FFFFFFF, -1 -0x7FFFFFFF, 0x7FFFFFFF, -1 -0x7FFFFFFF));
1818
1819 // Chroma plane sizes must match
1820 DE_ASSERT(rAccess.getSize() == bAccess.getSize());
1821
1822 // Luma plane sizes must match
1823 DE_ASSERT(gAccess.getSize() == aAccess.getSize());
1824
1825 // Luma plane size must match chroma plane or be twice as big
1826 DE_ASSERT(rAccess.getSize().x() == gAccess.getSize().x() || 2 * rAccess.getSize().x() == gAccess.getSize().x());
1827 DE_ASSERT(rAccess.getSize().y() == gAccess.getSize().y() || 2 * rAccess.getSize().y() == gAccess.getSize().y());
1828
1829 for (size_t ndx = 0; ndx < sts.size(); ndx++)
1830 {
1831 const Vec2 st (sts[ndx]);
1832 Interval bounds[4];
1833
1834 const Interval u (calculateUV(coordFormat, st[0], gAccess.getSize().x()));
1835 const Interval v (calculateUV(coordFormat, st[1], gAccess.getSize().y()));
1836
1837 uvBounds[ndx][0] = (float)u.lo();
1838 uvBounds[ndx][1] = (float)u.hi();
1839
1840 uvBounds[ndx][2] = (float)v.lo();
1841 uvBounds[ndx][3] = (float)v.hi();
1842
1843 if (filter == vk::VK_FILTER_NEAREST)
1844 {
1845 const IVec2 iRange (calculateNearestIJRange(coordFormat, u));
1846 const IVec2 jRange (calculateNearestIJRange(coordFormat, v));
1847
1848 ijBounds[ndx][0] = iRange[0];
1849 ijBounds[ndx][1] = iRange[1];
1850
1851 ijBounds[ndx][2] = jRange[0];
1852 ijBounds[ndx][3] = jRange[1];
1853
1854 for (int j = jRange.x(); j <= jRange.y(); j++)
1855 for (int i = iRange.x(); i <= iRange.y(); i++)
1856 {
1857 const Interval gValue (lookupWrapped(gAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1858 const Interval aValue (lookupWrapped(aAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1859
1860 if (subsampledX || subsampledY)
1861 {
1862 if (explicitReconstruction)
1863 {
1864 if (chromaFilter == vk::VK_FILTER_NEAREST)
1865 {
1866 // Nearest, Reconstructed chroma with explicit nearest filtering
1867 const int subI = subsampledX ? i / 2 : i;
1868 const int subJ = subsampledY ? j / 2 : j;
1869 const Interval srcColor[] =
1870 {
1871 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1872 gValue,
1873 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1874 aValue
1875 };
1876 Interval dstColor[4];
1877
1878 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1879
1880 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1881 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1882 }
1883 else if (chromaFilter == vk::VK_FILTER_LINEAR)
1884 {
1885 if (subsampledX && subsampledY)
1886 {
1887 // Nearest, Reconstructed both chroma samples with explicit linear filtering
1888 const Interval rValue (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j));
1889 const Interval bValue (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j));
1890 const Interval srcColor[] =
1891 {
1892 rValue,
1893 gValue,
1894 bValue,
1895 aValue
1896 };
1897 Interval dstColor[4];
1898
1899 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1900
1901 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1902 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1903 }
1904 else if (subsampledX)
1905 {
1906 // Nearest, Reconstructed x chroma samples with explicit linear filtering
1907 const Interval rValue (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j));
1908 const Interval bValue (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j));
1909 const Interval srcColor[] =
1910 {
1911 rValue,
1912 gValue,
1913 bValue,
1914 aValue
1915 };
1916 Interval dstColor[4];
1917
1918 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1919
1920 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1921 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1922 }
1923 else
1924 DE_FATAL("Unexpected chroma reconstruction");
1925 }
1926 else
1927 DE_FATAL("Unknown filter");
1928 }
1929 else
1930 {
1931 const Interval chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
1932 const Interval chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
1933
1934 if (chromaFilter == vk::VK_FILTER_NEAREST)
1935 {
1936 // Nearest, reconstructed chroma samples with implicit nearest filtering
1937 const IVec2 chromaIRange (subsampledX ? calculateNearestIJRange(coordFormat, chromaU) : IVec2(i, i));
1938 const IVec2 chromaJRange (subsampledY ? calculateNearestIJRange(coordFormat, chromaV) : IVec2(j, j));
1939
1940 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1941 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
1942 {
1943 const Interval srcColor[] =
1944 {
1945 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1946 gValue,
1947 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1948 aValue
1949 };
1950 Interval dstColor[4];
1951
1952 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1953
1954 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1955 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1956 }
1957 }
1958 else if (chromaFilter == vk::VK_FILTER_LINEAR)
1959 {
1960 // Nearest, reconstructed chroma samples with implicit linear filtering
1961 const IVec2 chromaIRange (subsampledX ? calculateLinearIJRange(coordFormat, chromaU) : IVec2(i, i));
1962 const IVec2 chromaJRange (subsampledY ? calculateLinearIJRange(coordFormat, chromaV) : IVec2(j, j));
1963
1964 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1965 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
1966 {
1967 const Interval chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
1968 const Interval chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
1969
1970 const Interval srcColor[] =
1971 {
1972 linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
1973 gValue,
1974 linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
1975 aValue
1976 };
1977 Interval dstColor[4];
1978
1979 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1980
1981 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1982 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1983 }
1984 }
1985 else
1986 DE_FATAL("Unknown filter");
1987 }
1988 }
1989 else
1990 {
1991 // Linear, no chroma subsampling
1992 const Interval srcColor[] =
1993 {
1994 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
1995 gValue,
1996 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
1997 aValue
1998 };
1999 Interval dstColor[4];
2000
2001 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2002
2003 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2004 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2005 }
2006 }
2007 }
2008 else if (filter == vk::VK_FILTER_LINEAR)
2009 {
2010 const IVec2 iRange (calculateLinearIJRange(coordFormat, u));
2011 const IVec2 jRange (calculateLinearIJRange(coordFormat, v));
2012
2013 ijBounds[ndx][0] = iRange[0];
2014 ijBounds[ndx][1] = iRange[1];
2015
2016 ijBounds[ndx][2] = jRange[0];
2017 ijBounds[ndx][3] = jRange[1];
2018
2019 for (int j = jRange.x(); j <= jRange.y(); j++)
2020 for (int i = iRange.x(); i <= iRange.y(); i++)
2021 {
2022 const Interval lumaA (calculateAB(subTexelPrecisionBits, u, i));
2023 const Interval lumaB (calculateAB(subTexelPrecisionBits, v, j));
2024
2025 const Interval gValue (linearSample(gAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
2026 const Interval aValue (linearSample(aAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
2027
2028 if (subsampledX || subsampledY)
2029 {
2030 if (explicitReconstruction)
2031 {
2032 if (chromaFilter == vk::VK_FILTER_NEAREST)
2033 {
2034 const Interval srcColor[] =
2035 {
2036 linearInterpolate(filteringFormat, lumaA, lumaB,
2037 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))),
2038 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))),
2039 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
2040 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
2041 gValue,
2042 linearInterpolate(filteringFormat, lumaA, lumaB,
2043 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))),
2044 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))),
2045 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
2046 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
2047 aValue
2048 };
2049 Interval dstColor[4];
2050
2051 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2052
2053 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2054 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2055 }
2056 else if (chromaFilter == vk::VK_FILTER_LINEAR)
2057 {
2058 if (subsampledX && subsampledY)
2059 {
2060 // Linear, Reconstructed xx chroma samples with explicit linear filtering
2061 const Interval rValue (linearInterpolate(filteringFormat, lumaA, lumaB,
2062 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j),
2063 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
2064 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
2065 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
2066 const Interval bValue (linearInterpolate(filteringFormat, lumaA, lumaB,
2067 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j),
2068 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
2069 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
2070 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
2071 const Interval srcColor[] =
2072 {
2073 rValue,
2074 gValue,
2075 bValue,
2076 aValue
2077 };
2078 Interval dstColor[4];
2079
2080 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2081
2082 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2083 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2084
2085 }
2086 else if (subsampledX)
2087 {
2088 // Linear, Reconstructed x chroma samples with explicit linear filtering
2089 const Interval rValue (linearInterpolate(filteringFormat, lumaA, lumaB,
2090 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j),
2091 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
2092 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
2093 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
2094 const Interval bValue (linearInterpolate(filteringFormat, lumaA, lumaB,
2095 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j),
2096 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
2097 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
2098 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
2099 const Interval srcColor[] =
2100 {
2101 rValue,
2102 gValue,
2103 bValue,
2104 aValue
2105 };
2106 Interval dstColor[4];
2107
2108 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2109
2110 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2111 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2112 }
2113 else
2114 DE_FATAL("Unknown subsampling config");
2115 }
2116 else
2117 DE_FATAL("Unknown chroma filter");
2118 }
2119 else
2120 {
2121 const Interval chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
2122 const Interval chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
2123
2124 if (chromaFilter == vk::VK_FILTER_NEAREST)
2125 {
2126 const IVec2 chromaIRange (calculateNearestIJRange(coordFormat, chromaU));
2127 const IVec2 chromaJRange (calculateNearestIJRange(coordFormat, chromaV));
2128
2129 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2130 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2131 {
2132 const Interval srcColor[] =
2133 {
2134 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2135 gValue,
2136 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2137 aValue
2138 };
2139 Interval dstColor[4];
2140
2141 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2142
2143 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2144 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2145 }
2146 }
2147 else if (chromaFilter == vk::VK_FILTER_LINEAR)
2148 {
2149 const IVec2 chromaIRange (calculateNearestIJRange(coordFormat, chromaU));
2150 const IVec2 chromaJRange (calculateNearestIJRange(coordFormat, chromaV));
2151
2152 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2153 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2154 {
2155 const Interval chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
2156 const Interval chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
2157
2158 const Interval rValue (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
2159 const Interval bValue (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
2160
2161 const Interval srcColor[] =
2162 {
2163 rValue,
2164 gValue,
2165 bValue,
2166 aValue
2167 };
2168 Interval dstColor[4];
2169 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2170
2171 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2172 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2173 }
2174 }
2175 else
2176 DE_FATAL("Unknown chroma filter");
2177 }
2178 }
2179 else
2180 {
2181 const Interval chromaA (lumaA);
2182 const Interval chromaB (lumaB);
2183 const Interval rValue (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
2184 const Interval bValue (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
2185 const Interval srcColor[] =
2186 {
2187 rValue,
2188 gValue,
2189 bValue,
2190 aValue
2191 };
2192 Interval dstColor[4];
2193
2194 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2195
2196 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2197 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2198 }
2199 }
2200 }
2201 else
2202 DE_FATAL("Unknown filter");
2203
2204 minBounds[ndx] = Vec4((float)bounds[0].lo(), (float)bounds[1].lo(), (float)bounds[2].lo(), (float)bounds[3].lo());
2205 maxBounds[ndx] = Vec4((float)bounds[0].hi(), (float)bounds[1].hi(), (float)bounds[2].hi(), (float)bounds[3].hi());
2206 }
2207 }
2208
2209
2210 } // ycbcr
2211 } // vkt
2212