1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group Inc.
6 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Protected memory YCbCr image conversion tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktProtectedMemYCbCrConversionTests.hpp"
26
27 #include "tcuImageCompare.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "tcuTestLog.hpp"
30
31 #include "vkBuilderUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkYCbCrImageWithMemory.hpp"
36 #include "vkCmdUtil.hpp"
37
38 #include "vktProtectedMemContext.hpp"
39 #include "vktProtectedMemUtils.hpp"
40 #include "vktTestCaseUtil.hpp"
41 #include "vktYCbCrUtil.hpp"
42
43
44 namespace vkt
45 {
46 namespace ProtectedMem
47 {
48
49 namespace
50 {
51 static const vk::VkFormat s_colorFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
52
53 enum {
54 CHECK_SIZE = 50,
55 };
56
57 struct YCbCrValidationData {
58 tcu::Vec4 coord;
59 tcu::Vec4 minBound;
60 tcu::Vec4 maxBound;
61 };
62
computeVertexPositions(int numValues,const tcu::IVec2 & renderSize)63 std::vector<tcu::Vec2> computeVertexPositions (int numValues, const tcu::IVec2& renderSize)
64 {
65 std::vector<tcu::Vec2> positions(numValues);
66 for (int valNdx = 0; valNdx < numValues; valNdx++)
67 {
68 const int ix = valNdx % renderSize.x();
69 const int iy = valNdx / renderSize.x();
70 const float fx = -1.0f + 2.0f*((float(ix) + 0.5f) / float(renderSize.x()));
71 const float fy = -1.0f + 2.0f*((float(iy) + 0.5f) / float(renderSize.y()));
72
73 positions[valNdx] = tcu::Vec2(fx, fy);
74 }
75
76 return positions;
77 }
78
genTexCoords(std::vector<tcu::Vec2> & coords,const tcu::UVec2 & size)79 void genTexCoords (std::vector<tcu::Vec2>& coords, const tcu::UVec2& size)
80 {
81 for (deUint32 y = 0; y < size.y(); y++)
82 for (deUint32 x = 0; x < size.x(); x++)
83 {
84 const float fx = (float)x;
85 const float fy = (float)y;
86
87 const float fw = (float)size.x();
88 const float fh = (float)size.y();
89
90 const float s = 1.5f * ((fx * 1.5f * fw + fx) / (1.5f * fw * 1.5f * fw)) - 0.25f;
91 const float t = 1.5f * ((fy * 1.5f * fh + fy) / (1.5f * fh * 1.5f * fh)) - 0.25f;
92
93 coords.push_back(tcu::Vec2(s, t));
94 }
95 }
96
97 struct TestConfig
98 {
TestConfigvkt::ProtectedMem::__anon3fc0f0030111::TestConfig99 TestConfig (glu::ShaderType shaderType_,
100 vk::VkFormat format_,
101 vk::VkImageTiling imageTiling_,
102 vk::VkFilter textureFilter_,
103 vk::VkSamplerAddressMode addressModeU_,
104 vk::VkSamplerAddressMode addressModeV_,
105
106 vk::VkFilter chromaFilter_,
107 vk::VkChromaLocation xChromaOffset_,
108 vk::VkChromaLocation yChromaOffset_,
109 bool explicitReconstruction_,
110 bool disjoint_,
111
112 vk::VkSamplerYcbcrRange colorRange_,
113 vk::VkSamplerYcbcrModelConversion colorModel_,
114 vk::VkComponentMapping componentMapping_)
115 : shaderType (shaderType_)
116 , format (format_)
117 , imageTiling (imageTiling_)
118 , textureFilter (textureFilter_)
119 , addressModeU (addressModeU_)
120 , addressModeV (addressModeV_)
121
122 , chromaFilter (chromaFilter_)
123 , xChromaOffset (xChromaOffset_)
124 , yChromaOffset (yChromaOffset_)
125 , explicitReconstruction (explicitReconstruction_)
126 , disjoint (disjoint_)
127
128 , colorRange (colorRange_)
129 , colorModel (colorModel_)
130 , componentMapping (componentMapping_)
131 {
132 }
133
134 glu::ShaderType shaderType;
135 vk::VkFormat format;
136 vk::VkImageTiling imageTiling;
137 vk::VkFilter textureFilter;
138 vk::VkSamplerAddressMode addressModeU;
139 vk::VkSamplerAddressMode addressModeV;
140
141 vk::VkFilter chromaFilter;
142 vk::VkChromaLocation xChromaOffset;
143 vk::VkChromaLocation yChromaOffset;
144 bool explicitReconstruction;
145 bool disjoint;
146
147 vk::VkSamplerYcbcrRange colorRange;
148 vk::VkSamplerYcbcrModelConversion colorModel;
149 vk::VkComponentMapping componentMapping;
150 };
151
152
validateFormatSupport(ProtectedContext & context,TestConfig & config)153 void validateFormatSupport (ProtectedContext& context, TestConfig& config)
154 {
155 tcu::TestLog& log (context.getTestContext().getLog());
156
157 try
158 {
159 const vk::VkFormatProperties properties (vk::getPhysicalDeviceFormatProperties(context.getInstanceDriver(), context.getPhysicalDevice(), config.format));
160 const vk::VkFormatFeatureFlags features (config.imageTiling == vk::VK_IMAGE_TILING_OPTIMAL
161 ? properties.optimalTilingFeatures
162 : properties.linearTilingFeatures);
163
164 if ((features & (vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT | vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) == 0)
165 TCU_THROW(NotSupportedError, "Format doesn't support YCbCr conversions");
166
167 if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0)
168 TCU_THROW(NotSupportedError, "Format doesn't support sampling");
169
170 if (config.textureFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0))
171 TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction");
172
173 if (config.chromaFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0))
174 TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction");
175
176 if (config.chromaFilter != config.textureFilter && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT) == 0))
177 TCU_THROW(NotSupportedError, "Format doesn't support different chroma and texture filters");
178
179 if (config.explicitReconstruction && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT) == 0))
180 TCU_THROW(NotSupportedError, "Format doesn't support explicit chroma reconstruction");
181
182 if (config.disjoint && ((features & vk::VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
183 TCU_THROW(NotSupportedError, "Format doesn't disjoint planes");
184
185 if (ycbcr::isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0))
186 TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples");
187
188 if (ycbcr::isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0))
189 TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples");
190
191 if (ycbcr::isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0))
192 TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples");
193
194 if (ycbcr::isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0))
195 TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples");
196
197 if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT) != 0)
198 config.explicitReconstruction = true;
199
200 log << tcu::TestLog::Message << "FormatFeatures: " << vk::getFormatFeatureFlagsStr(features) << tcu::TestLog::EndMessage;
201 }
202 catch (const vk::Error& err)
203 {
204 if (err.getError() == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
205 TCU_THROW(NotSupportedError, "Format not supported");
206
207 throw;
208 }
209 }
210
createSampler(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkFilter textureFilter,const vk::VkSamplerAddressMode addressModeU,const vk::VkSamplerAddressMode addressModeV,const vk::VkSamplerYcbcrConversion conversion)211 vk::Move<vk::VkSampler> createSampler (const vk::DeviceInterface& vkd,
212 const vk::VkDevice device,
213 const vk::VkFilter textureFilter,
214 const vk::VkSamplerAddressMode addressModeU,
215 const vk::VkSamplerAddressMode addressModeV,
216 const vk::VkSamplerYcbcrConversion conversion)
217 {
218 const vk::VkSamplerYcbcrConversionInfo samplerConversionInfo =
219 {
220 vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
221 DE_NULL,
222 conversion
223 };
224
225 const vk::VkSamplerCreateInfo createInfo =
226 {
227 vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
228 &samplerConversionInfo,
229 0u,
230 textureFilter,
231 textureFilter,
232 vk::VK_SAMPLER_MIPMAP_MODE_NEAREST,
233 addressModeU,
234 addressModeV,
235 vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
236 0.0f,
237 VK_FALSE,
238 1.0f,
239 VK_FALSE,
240 vk::VK_COMPARE_OP_ALWAYS,
241 0.0f,
242 0.0f,
243 vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
244 VK_FALSE,
245 };
246
247 return createSampler(vkd, device, &createInfo);
248 }
249
createImageView(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkImage image,const vk::VkFormat format,const vk::VkSamplerYcbcrConversion conversion)250 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface& vkd,
251 const vk::VkDevice device,
252 const vk::VkImage image,
253 const vk::VkFormat format,
254 const vk::VkSamplerYcbcrConversion conversion)
255 {
256 const vk::VkSamplerYcbcrConversionInfo conversionInfo =
257 {
258 vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
259 DE_NULL,
260 conversion
261 };
262
263 const vk::VkImageViewCreateInfo viewInfo =
264 {
265 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
266 &conversionInfo,
267 (vk::VkImageViewCreateFlags)0,
268 image,
269 vk::VK_IMAGE_VIEW_TYPE_2D,
270 format,
271 {
272 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
273 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
274 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
275 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
276 },
277 { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
278 };
279
280 return vk::createImageView(vkd, device, &viewInfo);
281 }
282
createConversion(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkFormat format,const vk::VkSamplerYcbcrModelConversion colorModel,const vk::VkSamplerYcbcrRange colorRange,const vk::VkChromaLocation xChromaOffset,const vk::VkChromaLocation yChromaOffset,const vk::VkFilter chromaFilter,const vk::VkComponentMapping & componentMapping,const bool explicitReconstruction)283 vk::Move<vk::VkSamplerYcbcrConversion> createConversion (const vk::DeviceInterface& vkd,
284 const vk::VkDevice device,
285 const vk::VkFormat format,
286 const vk::VkSamplerYcbcrModelConversion colorModel,
287 const vk::VkSamplerYcbcrRange colorRange,
288 const vk::VkChromaLocation xChromaOffset,
289 const vk::VkChromaLocation yChromaOffset,
290 const vk::VkFilter chromaFilter,
291 const vk::VkComponentMapping& componentMapping,
292 const bool explicitReconstruction)
293 {
294 const vk::VkSamplerYcbcrConversionCreateInfo conversionInfo =
295 {
296 vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
297 DE_NULL,
298
299 format,
300 colorModel,
301 colorRange,
302 componentMapping,
303 xChromaOffset,
304 yChromaOffset,
305 chromaFilter,
306 explicitReconstruction ? VK_TRUE : VK_FALSE
307 };
308
309 return vk::createSamplerYcbcrConversion(vkd, device, &conversionInfo);
310 }
311
uploadYCbCrImage(ProtectedContext & ctx,const vk::VkImage image,const ycbcr::MultiPlaneImageData & imageData,const vk::VkAccessFlags nextAccess,const vk::VkImageLayout finalLayout)312 void uploadYCbCrImage (ProtectedContext& ctx,
313 const vk::VkImage image,
314 const ycbcr::MultiPlaneImageData& imageData,
315 const vk::VkAccessFlags nextAccess,
316 const vk::VkImageLayout finalLayout)
317 {
318 const vk::DeviceInterface& vk = ctx.getDeviceInterface();
319 const vk::VkDevice device = ctx.getDevice();
320 const vk::VkQueue queue = ctx.getQueue();
321 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex();
322
323 const vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
324 const vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
325
326 const vk::PlanarFormatDescription& formatDesc = imageData.getDescription();
327
328 std::vector<de::SharedPtr<de::MovePtr<vk::BufferWithMemory> > > stagingBuffers;
329 std::vector<vk::VkBufferMemoryBarrier> bufferBarriers;
330
331 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
332 {
333 de::MovePtr<vk::BufferWithMemory> buffer (makeBuffer(ctx,
334 PROTECTION_DISABLED,
335 queueFamilyIndex,
336 (deUint32)imageData.getPlaneSize(planeNdx),
337 vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT|vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
338 vk::MemoryRequirement::HostVisible));
339
340 const vk::VkBufferMemoryBarrier bufferBarrier =
341 {
342 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
343 DE_NULL,
344 (vk::VkAccessFlags)0,
345 vk::VK_ACCESS_TRANSFER_READ_BIT,
346 queueFamilyIndex,
347 queueFamilyIndex,
348 **buffer,
349 0,
350 (deUint32)imageData.getPlaneSize(planeNdx)
351 };
352 bufferBarriers.push_back(bufferBarrier);
353
354 deMemcpy(buffer->getAllocation().getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx));
355 flushMappedMemoryRange(vk, device, buffer->getAllocation().getMemory(), buffer->getAllocation().getOffset(), (deUint32)imageData.getPlaneSize(planeNdx));
356 stagingBuffers.push_back(de::SharedPtr<de::MovePtr<vk::BufferWithMemory> >(new de::MovePtr<vk::BufferWithMemory>(buffer.release())));
357 }
358
359
360 beginCommandBuffer(vk, *cmdBuffer);
361
362 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
363 {
364 const vk::VkImageAspectFlagBits aspect = formatDesc.numPlanes > 1
365 ? vk::getPlaneAspect(planeNdx)
366 : vk::VK_IMAGE_ASPECT_COLOR_BIT;
367
368 const vk::VkImageMemoryBarrier preCopyBarrier =
369 {
370 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
371 DE_NULL,
372 (vk::VkAccessFlags)0,
373 vk::VK_ACCESS_TRANSFER_WRITE_BIT,
374 vk::VK_IMAGE_LAYOUT_UNDEFINED,
375 vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
376 queueFamilyIndex,
377 queueFamilyIndex,
378 image,
379 { aspect, 0u, 1u, 0u, 1u }
380 };
381
382 vk.cmdPipelineBarrier(*cmdBuffer,
383 (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_HOST_BIT,
384 (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
385 (vk::VkDependencyFlags)0u,
386 0u, (const vk::VkMemoryBarrier*)DE_NULL,
387 (deUint32)bufferBarriers.size(), &bufferBarriers[0],
388 1u, &preCopyBarrier);
389 }
390
391 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
392 {
393 const vk::VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
394 ? vk::getPlaneAspect(planeNdx)
395 : vk::VK_IMAGE_ASPECT_COLOR_BIT;
396 const deUint32 planeW = (formatDesc.numPlanes > 1)
397 ? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor
398 : imageData.getSize().x();
399 const deUint32 planeH = (formatDesc.numPlanes > 1)
400 ? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor
401 : imageData.getSize().y();
402 const vk::VkBufferImageCopy copy =
403 {
404 0u, // bufferOffset
405 0u, // bufferRowLength
406 0u, // bufferImageHeight
407 { (vk::VkImageAspectFlags)aspect, 0u, 0u, 1u },
408 vk::makeOffset3D(0u, 0u, 0u),
409 vk::makeExtent3D(planeW, planeH, 1u),
410 };
411
412 vk.cmdCopyBufferToImage(*cmdBuffer, ***stagingBuffers[planeNdx], image, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©);
413 }
414
415 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
416 {
417 const vk::VkImageAspectFlagBits aspect = formatDesc.numPlanes > 1
418 ? vk::getPlaneAspect(planeNdx)
419 : vk::VK_IMAGE_ASPECT_COLOR_BIT;
420
421 const vk::VkImageMemoryBarrier postCopyBarrier =
422 {
423 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
424 DE_NULL,
425 vk::VK_ACCESS_TRANSFER_WRITE_BIT,
426 nextAccess,
427 vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
428 finalLayout,
429 VK_QUEUE_FAMILY_IGNORED,
430 VK_QUEUE_FAMILY_IGNORED,
431 image,
432 { aspect, 0u, 1u, 0u, 1u }
433 };
434
435 vk.cmdPipelineBarrier(*cmdBuffer,
436 (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
437 (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
438 (vk::VkDependencyFlags)0u,
439 0u, (const vk::VkMemoryBarrier*)DE_NULL,
440 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL,
441 1u, &postCopyBarrier);
442 }
443
444 endCommandBuffer(vk, *cmdBuffer);
445
446 {
447 const vk::Unique<vk::VkFence> fence (createFence(vk, device));
448 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
449 }
450 }
451
logTestCaseInfo(tcu::TestLog & log,const TestConfig & config)452 void logTestCaseInfo (tcu::TestLog& log, const TestConfig& config)
453 {
454 log << tcu::TestLog::Message << "ShaderType: " << config.shaderType << tcu::TestLog::EndMessage;
455 log << tcu::TestLog::Message << "Format: " << config.format << tcu::TestLog::EndMessage;
456 log << tcu::TestLog::Message << "ImageTiling: " << config.imageTiling << tcu::TestLog::EndMessage;
457 log << tcu::TestLog::Message << "TextureFilter: " << config.textureFilter << tcu::TestLog::EndMessage;
458 log << tcu::TestLog::Message << "AddressModeU: " << config.addressModeU << tcu::TestLog::EndMessage;
459 log << tcu::TestLog::Message << "AddressModeV: " << config.addressModeV << tcu::TestLog::EndMessage;
460 log << tcu::TestLog::Message << "ChromaFilter: " << config.chromaFilter << tcu::TestLog::EndMessage;
461 log << tcu::TestLog::Message << "XChromaOffset: " << config.xChromaOffset << tcu::TestLog::EndMessage;
462 log << tcu::TestLog::Message << "YChromaOffset: " << config.yChromaOffset << tcu::TestLog::EndMessage;
463 log << tcu::TestLog::Message << "ExplicitReconstruction: " << (config.explicitReconstruction ? "true" : "false") << tcu::TestLog::EndMessage;
464 log << tcu::TestLog::Message << "Disjoint: " << (config.disjoint ? "true" : "false") << tcu::TestLog::EndMessage;
465 log << tcu::TestLog::Message << "ColorRange: " << config.colorRange << tcu::TestLog::EndMessage;
466 log << tcu::TestLog::Message << "ColorModel: " << config.colorModel << tcu::TestLog::EndMessage;
467 log << tcu::TestLog::Message << "ComponentMapping: " << config.componentMapping << tcu::TestLog::EndMessage;
468 }
469
logBoundImages(tcu::TestLog & log,const tcu::UVec2 size,const std::vector<tcu::Vec4> & minBounds,const std::vector<tcu::Vec4> & maxBounds)470 void logBoundImages (tcu::TestLog& log, const tcu::UVec2 size, const std::vector<tcu::Vec4>& minBounds, const std::vector<tcu::Vec4>& maxBounds)
471 {
472 tcu::TextureLevel minImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x(), size.y());
473 tcu::TextureLevel maxImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x(), size.y());
474
475 for (int y = 0; y < (int)(size.y()); y++)
476 for (int x = 0; x < (int)(size.x()); x++)
477 {
478 const int ndx = x + y * (int)(size.x());
479 minImage.getAccess().setPixel(minBounds[ndx], x, y);
480 maxImage.getAccess().setPixel(maxBounds[ndx], x, y);
481 }
482
483 const tcu::Vec4 scale (1.0f);
484 const tcu::Vec4 bias (0.0f);
485
486 log << tcu::TestLog::Image("MinBoundImage", "MinBoundImage", minImage.getAccess(), scale, bias);
487 log << tcu::TestLog::Image("MaxBoundImage", "MaxBoundImage", maxImage.getAccess(), scale, bias);
488 }
489
validateImage(ProtectedContext & ctx,const std::vector<YCbCrValidationData> & refData,const vk::VkSampler sampler,const vk::VkImageView imageView)490 bool validateImage (ProtectedContext& ctx,
491 const std::vector<YCbCrValidationData>& refData,
492 const vk::VkSampler sampler,
493 const vk::VkImageView imageView)
494 {
495 {
496 tcu::TestLog& log (ctx.getTestContext().getLog());
497
498 log << tcu::TestLog::Message << "Reference values:" << tcu::TestLog::EndMessage;
499 for (deUint32 ndx = 0; ndx < refData.size(); ndx++)
500 {
501 log << tcu::TestLog::Message << (ndx + 1) << refData[ndx].coord << ": [" << refData[ndx].minBound << ", " << refData[ndx].maxBound << "]" << tcu::TestLog::EndMessage;
502 }
503 }
504
505 const deUint64 oneSec = 1000 * 1000 * 1000;
506
507 const vk::DeviceInterface& vk = ctx.getDeviceInterface();
508 const vk::VkDevice device = ctx.getDevice();
509 const vk::VkQueue queue = ctx.getQueue();
510 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex();
511
512 DE_ASSERT(refData.size() >= CHECK_SIZE && CHECK_SIZE > 0);
513 const deUint32 refUniformSize = (deUint32)(sizeof(YCbCrValidationData) * refData.size());
514 const de::UniquePtr<vk::BufferWithMemory> refUniform (makeBuffer(ctx,
515 PROTECTION_DISABLED,
516 queueFamilyIndex,
517 refUniformSize,
518 vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
519 vk::MemoryRequirement::HostVisible));
520
521 // Set the reference uniform data
522 {
523 deMemcpy(refUniform->getAllocation().getHostPtr(), &refData[0], refUniformSize);
524 vk::flushMappedMemoryRange(vk, device, refUniform->getAllocation().getMemory(), refUniform->getAllocation().getOffset(), refUniformSize);
525 }
526
527 const deUint32 helperBufferSize = (deUint32)(2 * sizeof(deUint32));
528 const de::MovePtr<vk::BufferWithMemory> helperBuffer (makeBuffer(ctx,
529 PROTECTION_ENABLED,
530 queueFamilyIndex,
531 helperBufferSize,
532 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
533 vk::MemoryRequirement::Protected));
534 const vk::Unique<vk::VkShaderModule> resetSSBOShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ResetSSBO"), 0));
535 const vk::Unique<vk::VkShaderModule> validatorShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ImageValidator"), 0));
536
537 // Create descriptors
538 const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(vk::DescriptorSetLayoutBuilder()
539 .addSingleSamplerBinding(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_SHADER_STAGE_COMPUTE_BIT, &sampler)
540 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
541 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
542 .build(vk, device));
543 const vk::Unique<vk::VkDescriptorPool> descriptorPool(vk::DescriptorPoolBuilder()
544 .addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u)
545 .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
546 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
547 .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
548 const vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
549
550 // Update descriptor set infirmation
551 {
552 vk::VkDescriptorBufferInfo descRefUniform = makeDescriptorBufferInfo(**refUniform, 0, refUniformSize);
553 vk::VkDescriptorBufferInfo descBuffer = makeDescriptorBufferInfo(**helperBuffer, 0, helperBufferSize);
554 vk::VkDescriptorImageInfo descSampledImg = makeDescriptorImageInfo(sampler, imageView, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
555
556 vk::DescriptorSetUpdateBuilder()
557 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descSampledImg)
558 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform)
559 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descBuffer)
560 .update(vk, device);
561 }
562
563 const vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
564 const vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
565
566 // Reset helper SSBO
567 {
568 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device));
569 const vk::Unique<vk::VkPipeline> resetSSBOPipeline (makeComputePipeline(vk, device, *pipelineLayout, *resetSSBOShader, DE_NULL));
570 const vk::Unique<vk::VkCommandBuffer> resetCmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
571 beginCommandBuffer(vk, *resetCmdBuffer);
572
573 vk.cmdBindPipeline(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *resetSSBOPipeline);
574 vk.cmdBindDescriptorSets(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
575 vk.cmdDispatch(*resetCmdBuffer, 1u, 1u, 1u);
576
577 endCommandBuffer(vk, *resetCmdBuffer);
578 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *resetCmdBuffer, *fence, ~0ull));
579 }
580
581 // Create validation compute commands & submit
582 vk::VkResult queueSubmitResult;
583 {
584 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device));
585 const vk::Unique<vk::VkPipeline> validationPipeline (makeComputePipeline(vk, device, *pipelineLayout, *validatorShader, DE_NULL));
586 const vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
587
588 beginCommandBuffer(vk, *cmdBuffer);
589
590 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *validationPipeline);
591 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
592 vk.cmdDispatch(*cmdBuffer, CHECK_SIZE, 1u, 1u);
593
594 endCommandBuffer(vk, *cmdBuffer);
595
596 queueSubmitResult = queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, oneSec * 5);
597 }
598
599 // \todo do we need to check the fence status?
600 if (queueSubmitResult == vk::VK_TIMEOUT)
601 return false;
602
603 // at this point the submit result should be VK_TRUE
604 VK_CHECK(queueSubmitResult);
605 return true;
606 }
607
testShaders(vk::SourceCollections & dst,const TestConfig config)608 void testShaders (vk::SourceCollections& dst, const TestConfig config)
609 {
610 const char* const shaderHeader =
611 "layout(constant_id = 1) const float threshold = 0.01f;\n"
612 "layout(set = 0, binding = 0) uniform highp sampler2D protectedImage;\n"
613 "\n"
614 "struct validationData {\n"
615 " highp vec4 imageCoord;\n"
616 " highp vec4 imageRefMinBound;\n"
617 " highp vec4 imageRefMaxBound;\n"
618 "};\n"
619 "layout(std140, set = 0, binding = 1) uniform Data\n"
620 "{\n"
621 " validationData ref[250];\n"
622 "};\n";
623
624 const char* const compareFunction =
625 "bool compare(highp vec4 value, highp vec4 minValue, highp vec4 maxValue)\n"
626 "{\n"
627 " return all(greaterThanEqual(value, minValue - threshold)) && all(lessThanEqual(value, maxValue + threshold));\n"
628 "}\n";
629
630 std::map<std::string, std::string> validatorSpec;
631 validatorSpec["CHECK_SIZE"] = de::toString((deUint32)CHECK_SIZE);
632 validatorSpec["SHADER_HEADER"] = shaderHeader;
633 validatorSpec["COMPARE_FUNCTION"] = compareFunction;
634
635 const char* const validatorShader =
636 "#version 450\n"
637 "\n"
638 "${SHADER_HEADER}"
639 "\n"
640 "layout(std140, set = 0, binding = 2) buffer ProtectedHelper\n"
641 "{\n"
642 " highp uint zero;\n"
643 " highp uint dummyOut;\n"
644 "} helper;\n"
645 "\n"
646 "void error()\n"
647 "{\n"
648 " for (uint x = 0u; x < 10u; x += helper.zero)\n"
649 " atomicAdd(helper.dummyOut, 1u);\n"
650 "}\n"
651 "\n"
652 "${COMPARE_FUNCTION}"
653 "\n"
654 "void main(void)\n"
655 "{\n"
656 " int idx = int(gl_GlobalInvocationID.x);\n"
657 " vec4 currentValue = texture(protectedImage, ref[idx].imageCoord.xy);\n"
658 " if (!compare(currentValue, ref[idx].imageRefMinBound, ref[idx].imageRefMaxBound))\n"
659 " {\n"
660 " error();\n"
661 " }\n"
662 "}\n";
663
664 const char* const resetSSBOShader =
665 "#version 450\n"
666 "layout(local_size_x = 1) in;\n"
667 "\n"
668 "layout(std140, set=0, binding=2) buffer ProtectedHelper\n"
669 "{\n"
670 " highp uint zero; // set to 0\n"
671 " highp uint dummyOut;\n"
672 "} helper;\n"
673 "\n"
674 "void main (void)\n"
675 "{\n"
676 " helper.zero = 0;\n"
677 " helper.dummyOut = 0;\n"
678 "}\n";
679
680 dst.glslSources.add("ResetSSBO") << glu::ComputeSource(resetSSBOShader);
681 dst.glslSources.add("ImageValidator") << glu::ComputeSource(tcu::StringTemplate(validatorShader).specialize(validatorSpec));
682
683 if (config.shaderType == glu::SHADERTYPE_COMPUTE)
684 return; // Bail early as the YCbCr image validator already have the test programs set for compute tests
685
686 const char* const compareOperation =
687 " highp vec4 currentValue = texture(protectedImage, ref[v_idx].imageCoord.xy);\n"
688 " if (compare(currentValue, ref[v_idx].imageRefMinBound, ref[v_idx].imageRefMaxBound))\n"
689 " {\n"
690 " o_color = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n" // everything is ok, green
691 " }\n"
692 " else"
693 " {\n"
694 " o_color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
695 " }\n";
696
697 std::map<std::string, std::string> shaderSpec;
698 shaderSpec["SHADER_HEADER"] = shaderHeader;
699 shaderSpec["COMPARE_FUNCTION"] = compareFunction;
700 shaderSpec["COMPARE_OPERATION"] = compareOperation;
701
702 if (config.shaderType == glu::SHADERTYPE_VERTEX)
703 {
704 const char* const vertexShader =
705 "#version 450\n"
706 "${SHADER_HEADER}\n"
707 "\n"
708 "layout(location = 0) in highp vec2 a_position;\n"
709 "layout(location = 0) flat out highp vec4 o_color;\n"
710 "\n"
711 "${COMPARE_FUNCTION}"
712 "\n"
713 "void main(void)\n"
714 "{\n"
715 " gl_Position = vec4(a_position, 0.0f, 1.0f);\n"
716 " gl_PointSize = 1.0f;\n"
717 " int v_idx = gl_VertexIndex;\n"
718 "${COMPARE_OPERATION}"
719 "}\n";
720
721 const char* const fragmentShader =
722 "#version 450\n"
723 "\n"
724 "layout(location = 0) flat in highp vec4 v_color;\n"
725 "layout(location = 0) out highp vec4 o_color;\n"
726 "\n"
727 "void main(void)\n"
728 "{\n"
729 " o_color = v_color;\n"
730 "}\n";
731
732 dst.glslSources.add("vert") << glu::VertexSource(tcu::StringTemplate(vertexShader).specialize(shaderSpec));
733 dst.glslSources.add("frag") << glu::FragmentSource(fragmentShader);
734 }
735 else if (config.shaderType == glu::SHADERTYPE_FRAGMENT)
736 {
737 const char* const vertexShader =
738 "#version 450\n"
739 "layout(location = 0) in highp vec2 a_position;\n"
740 "layout(location = 0) flat out highp int o_idx;\n"
741 "\n"
742 "void main(void)\n"
743 "{\n"
744 " gl_Position = vec4(a_position, 0.0f, 1.0f);\n"
745 " gl_PointSize = 1.0f;\n"
746 " o_idx = gl_VertexIndex;\n"
747 "}\n";
748
749 const char* const fragmentShader =
750 "#version 450\n"
751 "${SHADER_HEADER}\n"
752 "\n"
753 "layout(location = 0) flat in highp int v_idx;\n"
754 "layout(location = 0) out highp vec4 o_color;\n"
755 "\n"
756 "${COMPARE_FUNCTION}"
757 "\n"
758 "void main(void)\n"
759 "{\n"
760 "${COMPARE_OPERATION}"
761 "}\n";
762
763 dst.glslSources.add("vert") << glu::VertexSource(vertexShader);
764 dst.glslSources.add("frag") << glu::FragmentSource(tcu::StringTemplate(fragmentShader).specialize(shaderSpec));
765 }
766 }
767
createYcbcrImage2D(ProtectedContext & context,const ProtectionMode protectionMode,const deUint32 width,const deUint32 height,const vk::VkFormat format,const vk::VkImageCreateFlags createFlags,const vk::VkImageUsageFlags usageFlags)768 de::MovePtr<vk::YCbCrImageWithMemory> createYcbcrImage2D (ProtectedContext& context,
769 const ProtectionMode protectionMode,
770 const deUint32 width,
771 const deUint32 height,
772 const vk::VkFormat format,
773 const vk::VkImageCreateFlags createFlags,
774 const vk::VkImageUsageFlags usageFlags)
775 {
776 const vk::DeviceInterface& vk = context.getDeviceInterface();
777 const vk::VkDevice& device = context.getDevice();
778 vk::Allocator& allocator = context.getDefaultAllocator();
779 const deUint32 queueIdx = context.getQueueFamilyIndex();
780 #ifndef NOT_PROTECTED
781 const deUint32 flags = (protectionMode == PROTECTION_ENABLED) ? vk::VK_IMAGE_CREATE_PROTECTED_BIT : 0x0;
782 const vk::MemoryRequirement memReq = (protectionMode == PROTECTION_ENABLED) ? vk::MemoryRequirement::Protected : vk::MemoryRequirement::Any;
783 #else
784 const deUint32 flags = 0x0;
785 const vk::MemoryRequirement memReq = vk::MemoryRequirement::Any;
786 DE_UNREF(protectionMode);
787 #endif
788
789 const vk::VkImageCreateInfo params =
790 {
791 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType stype
792 DE_NULL, // const void* pNext
793 (vk::VkImageCreateFlags)(flags | createFlags), // VkImageCreateFlags flags
794 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType
795 format, // VkFormat format
796 { width, height, 1 }, // VkExtent3D extent
797 1u, // deUint32 mipLevels
798 1u, // deUint32 arrayLayers
799 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
800 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling
801 usageFlags, // VkImageUsageFlags usage
802 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
803 1u, // deUint32 queueFamilyIndexCount
804 &queueIdx, // const deUint32* pQueueFamilyIndices
805 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
806 };
807
808 return de::MovePtr<vk::YCbCrImageWithMemory>(new vk::YCbCrImageWithMemory(vk, device, allocator, params, memReq));
809 }
810
811
renderYCbCrToColor(ProtectedContext & ctx,const tcu::UVec2 size,const vk::VkSampler ycbcrSampler,const vk::VkImageView ycbcrImageView,const vk::VkImage colorImage,const vk::VkImageView colorImageView,const std::vector<YCbCrValidationData> & referenceData,const std::vector<tcu::Vec2> & posCoords)812 void renderYCbCrToColor (ProtectedContext& ctx,
813 const tcu::UVec2 size,
814 const vk::VkSampler ycbcrSampler,
815 const vk::VkImageView ycbcrImageView,
816 const vk::VkImage colorImage,
817 const vk::VkImageView colorImageView,
818 const std::vector<YCbCrValidationData>& referenceData,
819 const std::vector<tcu::Vec2>& posCoords)
820 {
821 const vk::DeviceInterface& vk = ctx.getDeviceInterface();
822 const vk::VkDevice device = ctx.getDevice();
823 const vk::VkQueue queue = ctx.getQueue();
824 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex();
825
826 const vk::Unique<vk::VkRenderPass> renderPass (createRenderPass(ctx, s_colorFormat));
827 const vk::Unique<vk::VkFramebuffer> framebuffer (createFramebuffer(ctx, size.x(), size.y(), *renderPass, colorImageView));
828 const vk::Unique<vk::VkShaderModule> vertexShader (createShaderModule(vk, device, ctx.getBinaryCollection().get("vert"), 0));
829 const vk::Unique<vk::VkShaderModule> fragmentShader (createShaderModule(vk, device, ctx.getBinaryCollection().get("frag"), 0));
830 const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout (vk::DescriptorSetLayoutBuilder()
831 .addSingleSamplerBinding(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
832 vk::VK_SHADER_STAGE_ALL,
833 &ycbcrSampler)
834 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL)
835 .build(vk, device));
836 const vk::Unique<vk::VkDescriptorPool> descriptorPool (vk::DescriptorPoolBuilder()
837 .addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u)
838 .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
839 .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
840 const vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
841 const vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
842
843
844 const deUint32 refUniformSize = (deUint32)(sizeof(YCbCrValidationData) * referenceData.size());
845 const de::UniquePtr<vk::BufferWithMemory> refUniform (makeBuffer(ctx,
846 PROTECTION_DISABLED,
847 queueFamilyIndex,
848 refUniformSize,
849 vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
850 vk::MemoryRequirement::HostVisible));
851
852 // Set the reference uniform data
853 {
854 deMemcpy(refUniform->getAllocation().getHostPtr(), &referenceData[0], refUniformSize);
855 vk::flushMappedMemoryRange(vk, device, refUniform->getAllocation().getMemory(), refUniform->getAllocation().getOffset(), refUniformSize);
856 }
857
858 // Update descriptor set
859 {
860 vk::VkDescriptorImageInfo ycbcrSampled (makeDescriptorImageInfo(ycbcrSampler, ycbcrImageView, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
861 vk::VkDescriptorBufferInfo descRefUniform = makeDescriptorBufferInfo(**refUniform, 0, refUniformSize);
862 vk::DescriptorSetUpdateBuilder()
863 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &ycbcrSampled)
864 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform)
865 .update(vk, device);
866 }
867
868 VertexBindings vertexBindings;
869 VertexAttribs vertexAttribs;
870 de::MovePtr<vk::BufferWithMemory> vertexBuffer;
871 {
872 const deUint32 bufferSize = (deUint32)(sizeof(tcu::Vec2) * posCoords.size());
873 {
874 const vk::VkVertexInputBindingDescription inputBinding =
875 {
876 0u, // deUint32 binding;
877 sizeof(tcu::Vec2), // deUint32 strideInBytes;
878 vk::VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
879 };
880 const vk::VkVertexInputAttributeDescription inputAttribute =
881 {
882 0u, // deUint32 location;
883 0u, // deUint32 binding;
884 vk::VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
885 0u // deUint32 offsetInBytes;
886 };
887
888 vertexBindings.push_back(inputBinding);
889 vertexAttribs.push_back(inputAttribute);
890 }
891
892 vertexBuffer = makeBuffer(ctx,
893 PROTECTION_DISABLED,
894 queueFamilyIndex,
895 bufferSize,
896 vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
897 vk::MemoryRequirement::HostVisible);
898
899 deMemcpy(vertexBuffer->getAllocation().getHostPtr(), &posCoords[0], bufferSize);
900 vk::flushMappedMemoryRange(vk, device, vertexBuffer->getAllocation().getMemory(), vertexBuffer->getAllocation().getOffset(), bufferSize);
901 }
902
903 const vk::Unique<vk::VkPipeline> pipeline (makeGraphicsPipeline(vk,
904 device,
905 *pipelineLayout,
906 *renderPass,
907 *vertexShader,
908 *fragmentShader,
909 vertexBindings,
910 vertexAttribs,
911 size,
912 vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST));
913 const vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
914 const vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
915
916 beginCommandBuffer(vk, *cmdBuffer);
917 {
918 const vk::VkImageMemoryBarrier attachmentStartBarrier =
919 {
920 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
921 DE_NULL,
922 0u,
923 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
924 vk::VK_IMAGE_LAYOUT_UNDEFINED,
925 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
926 queueFamilyIndex,
927 queueFamilyIndex,
928 colorImage,
929 { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
930 };
931
932 vk.cmdPipelineBarrier(*cmdBuffer,
933 (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
934 (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
935 (vk::VkDependencyFlags)0u,
936 0u, (const vk::VkMemoryBarrier*)DE_NULL,
937 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL,
938 1u, &attachmentStartBarrier);
939 }
940
941 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, vk::makeRect2D(0, 0, size.x(), size.y()), tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f));
942
943 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
944 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
945
946 {
947 const vk::VkDeviceSize vertexBufferOffset = 0;
948 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &**vertexBuffer, &vertexBufferOffset);
949 }
950
951 vk.cmdDraw(*cmdBuffer, /*vertexCount*/ (deUint32)posCoords.size(), 1u, 0u, 0u);
952
953 endRenderPass(vk, *cmdBuffer);
954
955 // color attachment render end barrier
956 {
957 const vk::VkImageMemoryBarrier attachmentEndBarrier =
958 {
959 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
960 DE_NULL,
961 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
962 vk::VK_ACCESS_SHADER_READ_BIT,
963 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
964 vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
965 queueFamilyIndex,
966 queueFamilyIndex,
967 colorImage,
968 { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
969 };
970
971 vk.cmdPipelineBarrier(*cmdBuffer,
972 (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
973 (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
974 (vk::VkDependencyFlags)0u,
975 0u, (const vk::VkMemoryBarrier*)DE_NULL,
976 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL,
977 1u, &attachmentEndBarrier);
978 }
979
980 endCommandBuffer(vk, *cmdBuffer);
981
982 // Submit command buffer
983 {
984 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device));
985 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
986 }
987 }
988
generateYCbCrImage(ProtectedContext & ctx,const TestConfig & config,const tcu::UVec2 size,const std::vector<tcu::Vec2> & texCoords,ycbcr::MultiPlaneImageData & ycbcrSrc,std::vector<tcu::Vec4> & ycbcrMinBounds,std::vector<tcu::Vec4> & ycbcrMaxBounds)989 void generateYCbCrImage (ProtectedContext& ctx,
990 const TestConfig& config,
991 const tcu::UVec2 size,
992 const std::vector<tcu::Vec2>& texCoords,
993 ycbcr::MultiPlaneImageData& ycbcrSrc,
994 std::vector<tcu::Vec4>& ycbcrMinBounds,
995 std::vector<tcu::Vec4>& ycbcrMaxBounds)
996 {
997 tcu::TestLog& log (ctx.getTestContext().getLog());
998 const tcu::FloatFormat filteringPrecision (ycbcr::getYCbCrFilteringPrecision(config.format));
999 const tcu::FloatFormat conversionPrecision (ycbcr::getYCbCrConversionPrecision(config.format));
1000 const tcu::UVec4 bitDepth (ycbcr::getYCbCrBitDepth(config.format));
1001 bool explicitReconstruction = config.explicitReconstruction;
1002 const deUint32 subTexelPrecisionBits (vk::getPhysicalDeviceProperties(ctx.getInstanceDriver(),
1003 ctx.getPhysicalDevice()).limits.subTexelPrecisionBits);
1004
1005
1006 const vk::PlanarFormatDescription planeInfo (vk::getPlanarFormatDescription(config.format));
1007
1008 deUint32 nullAccessData (0u);
1009 ycbcr::ChannelAccess nullAccess (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(size.x(), size.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessData, 0u);
1010 deUint32 nullAccessAlphaData (~0u);
1011 ycbcr::ChannelAccess nullAccessAlpha (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(size.x(), size.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessAlphaData, 0u);
1012 ycbcr::ChannelAccess rChannelAccess (planeInfo.hasChannelNdx(0) ? getChannelAccess(ycbcrSrc, planeInfo, size, 0) : nullAccess);
1013 ycbcr::ChannelAccess gChannelAccess (planeInfo.hasChannelNdx(1) ? getChannelAccess(ycbcrSrc, planeInfo, size, 1) : nullAccess);
1014 ycbcr::ChannelAccess bChannelAccess (planeInfo.hasChannelNdx(2) ? getChannelAccess(ycbcrSrc, planeInfo, size, 2) : nullAccess);
1015 ycbcr::ChannelAccess aChannelAccess (planeInfo.hasChannelNdx(3) ? getChannelAccess(ycbcrSrc, planeInfo, size, 3) : nullAccessAlpha);
1016 const bool implicitNearestCosited ((config.chromaFilter == vk::VK_FILTER_NEAREST && !explicitReconstruction) &&
1017 (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR || config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR));
1018
1019 for (deUint32 planeNdx = 0; planeNdx < planeInfo.numPlanes; planeNdx++)
1020 deMemset(ycbcrSrc.getPlanePtr(planeNdx), 0u, ycbcrSrc.getPlaneSize(planeNdx));
1021
1022 // \todo Limit values to only values that produce defined values using selected colorRange and colorModel? The verification code handles those cases already correctly.
1023 if (planeInfo.hasChannelNdx(0))
1024 {
1025 for (int y = 0; y < rChannelAccess.getSize().y(); y++)
1026 for (int x = 0; x < rChannelAccess.getSize().x(); x++)
1027 rChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)x / (float)rChannelAccess.getSize().x());
1028 }
1029
1030 if (planeInfo.hasChannelNdx(1))
1031 {
1032 for (int y = 0; y < gChannelAccess.getSize().y(); y++)
1033 for (int x = 0; x < gChannelAccess.getSize().x(); x++)
1034 gChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)y / (float)gChannelAccess.getSize().y());
1035 }
1036
1037 if (planeInfo.hasChannelNdx(2))
1038 {
1039 for (int y = 0; y < bChannelAccess.getSize().y(); y++)
1040 for (int x = 0; x < bChannelAccess.getSize().x(); x++)
1041 bChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)(x + y) / (float)(bChannelAccess.getSize().x() + bChannelAccess.getSize().y()));
1042 }
1043
1044 if (planeInfo.hasChannelNdx(3))
1045 {
1046 for (int y = 0; y < aChannelAccess.getSize().y(); y++)
1047 for (int x = 0; x < aChannelAccess.getSize().x(); x++)
1048 aChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)(x * y) / (float)(aChannelAccess.getSize().x() * aChannelAccess.getSize().y()));
1049 }
1050
1051 std::vector<tcu::Vec4> uvBounds;
1052 std::vector<tcu::IVec4> ijBounds;
1053 ycbcr::calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, texCoords, filteringPrecision, conversionPrecision, subTexelPrecisionBits, config.textureFilter, config.colorModel, config.colorRange, config.chromaFilter, config.xChromaOffset, config.yChromaOffset, config.componentMapping, explicitReconstruction, config.addressModeU, config.addressModeV, ycbcrMinBounds, ycbcrMaxBounds, uvBounds, ijBounds);
1054
1055 // Handle case: If implicit reconstruction and chromaFilter == NEAREST, an implementation may behave as if both chroma offsets are MIDPOINT.
1056 if (implicitNearestCosited)
1057 {
1058 std::vector<tcu::Vec4> relaxedYcbcrMinBounds;
1059 std::vector<tcu::Vec4> relaxedYcbcrMaxBounds;
1060
1061 ycbcr::calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, texCoords, filteringPrecision, conversionPrecision, subTexelPrecisionBits, config.textureFilter, config.colorModel, config.colorRange, config.chromaFilter, vk::VK_CHROMA_LOCATION_MIDPOINT_KHR, vk::VK_CHROMA_LOCATION_MIDPOINT_KHR, config.componentMapping, explicitReconstruction, config.addressModeU, config.addressModeV, relaxedYcbcrMinBounds, relaxedYcbcrMaxBounds, uvBounds, ijBounds);
1062
1063 DE_ASSERT(relaxedYcbcrMinBounds.size() == ycbcrMinBounds.size());
1064 DE_ASSERT(relaxedYcbcrMaxBounds.size() == ycbcrMaxBounds.size());
1065
1066 for (size_t i = 0; i < ycbcrMinBounds.size(); i++)
1067 {
1068 ycbcrMinBounds[i] = tcu::Vec4(de::min<float>(ycbcrMinBounds[i].x(), relaxedYcbcrMinBounds[i].x()),
1069 de::min<float>(ycbcrMinBounds[i].y(), relaxedYcbcrMinBounds[i].y()),
1070 de::min<float>(ycbcrMinBounds[i].z(), relaxedYcbcrMinBounds[i].z()),
1071 de::min<float>(ycbcrMinBounds[i].w(), relaxedYcbcrMinBounds[i].w()));
1072
1073 ycbcrMaxBounds[i] = tcu::Vec4(de::max<float>(ycbcrMaxBounds[i].x(), relaxedYcbcrMaxBounds[i].x()),
1074 de::max<float>(ycbcrMaxBounds[i].y(), relaxedYcbcrMaxBounds[i].y()),
1075 de::max<float>(ycbcrMaxBounds[i].z(), relaxedYcbcrMaxBounds[i].z()),
1076 de::max<float>(ycbcrMaxBounds[i].w(), relaxedYcbcrMaxBounds[i].w()));
1077 }
1078 }
1079
1080 if (vk::isYCbCrFormat(config.format))
1081 {
1082 tcu::TextureLevel rImage (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), rChannelAccess.getSize().x(), rChannelAccess.getSize().y());
1083 tcu::TextureLevel gImage (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), gChannelAccess.getSize().x(), gChannelAccess.getSize().y());
1084 tcu::TextureLevel bImage (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), bChannelAccess.getSize().x(), bChannelAccess.getSize().y());
1085 tcu::TextureLevel aImage (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), aChannelAccess.getSize().x(), aChannelAccess.getSize().y());
1086
1087 for (int y = 0; y < (int)rChannelAccess.getSize().y(); y++)
1088 for (int x = 0; x < (int)rChannelAccess.getSize().x(); x++)
1089 rImage.getAccess().setPixel(tcu::Vec4(rChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y);
1090
1091 for (int y = 0; y < (int)gChannelAccess.getSize().y(); y++)
1092 for (int x = 0; x < (int)gChannelAccess.getSize().x(); x++)
1093 gImage.getAccess().setPixel(tcu::Vec4(gChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y);
1094
1095 for (int y = 0; y < (int)bChannelAccess.getSize().y(); y++)
1096 for (int x = 0; x < (int)bChannelAccess.getSize().x(); x++)
1097 bImage.getAccess().setPixel(tcu::Vec4(bChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y);
1098
1099 for (int y = 0; y < (int)aChannelAccess.getSize().y(); y++)
1100 for (int x = 0; x < (int)aChannelAccess.getSize().x(); x++)
1101 aImage.getAccess().setPixel(tcu::Vec4(aChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y);
1102
1103 {
1104 const tcu::Vec4 scale (1.0f);
1105 const tcu::Vec4 bias (0.0f);
1106
1107 log << tcu::TestLog::Image("SourceImageR", "SourceImageR", rImage.getAccess(), scale, bias);
1108 log << tcu::TestLog::Image("SourceImageG", "SourceImageG", gImage.getAccess(), scale, bias);
1109 log << tcu::TestLog::Image("SourceImageB", "SourceImageB", bImage.getAccess(), scale, bias);
1110 log << tcu::TestLog::Image("SourceImageA", "SourceImageA", aImage.getAccess(), scale, bias);
1111 }
1112 }
1113 else
1114 {
1115 tcu::TextureLevel ycbcrSrcImage (vk::mapVkFormat(config.format), size.x(), size.y());
1116
1117 for (int y = 0; y < (int)size.y(); y++)
1118 for (int x = 0; x < (int)size.x(); x++)
1119 {
1120 const tcu::IVec3 pos (x, y, 0);
1121 ycbcrSrcImage.getAccess().setPixel(tcu::Vec4(rChannelAccess.getChannel(pos),
1122 gChannelAccess.getChannel(pos),
1123 bChannelAccess.getChannel(pos),
1124 aChannelAccess.getChannel(pos)),
1125 x, y);
1126 }
1127
1128 log << tcu::TestLog::Image("SourceImage", "SourceImage", ycbcrSrcImage.getAccess());
1129 }
1130 }
1131
conversionTest(Context & context,TestConfig config)1132 tcu::TestStatus conversionTest (Context& context, TestConfig config)
1133 {
1134 std::vector<std::string> requiredDevExt;
1135 requiredDevExt.push_back("VK_KHR_sampler_ycbcr_conversion");
1136 requiredDevExt.push_back("VK_KHR_get_memory_requirements2");
1137 requiredDevExt.push_back("VK_KHR_bind_memory2");
1138 requiredDevExt.push_back("VK_KHR_maintenance1");
1139
1140 const tcu::UVec2 size (ycbcr::isXChromaSubsampled(config.format) ? 12 : 7,
1141 ycbcr::isYChromaSubsampled(config.format) ? 8 : 13);
1142
1143 ProtectedContext ctx (context, std::vector<std::string>(), requiredDevExt);
1144 const vk::DeviceInterface& vk = ctx.getDeviceInterface();
1145 const vk::VkDevice device = ctx.getDevice();
1146 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex();
1147
1148 tcu::TestLog& log (context.getTestContext().getLog());
1149
1150 validateFormatSupport(ctx, config);
1151 logTestCaseInfo(log, config);
1152
1153 const vk::VkImageCreateFlagBits ycbcrImageFlags = config.disjoint
1154 ? vk::VK_IMAGE_CREATE_DISJOINT_BIT
1155 : (vk::VkImageCreateFlagBits)0u;
1156 const de::MovePtr<vk::YCbCrImageWithMemory> ycbcrImage (createYcbcrImage2D(ctx, PROTECTION_ENABLED,
1157 size.x(), size.y(),
1158 config.format,
1159 ycbcrImageFlags,
1160 vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT
1161 | vk::VK_IMAGE_USAGE_SAMPLED_BIT));
1162 const vk::Unique<vk::VkSamplerYcbcrConversion> conversion (createConversion(vk,
1163 device,
1164 config.format,
1165 config.colorModel,
1166 config.colorRange,
1167 config.xChromaOffset,
1168 config.yChromaOffset,
1169 config.chromaFilter,
1170 config.componentMapping,
1171 config.explicitReconstruction));
1172 const vk::Unique<vk::VkSampler> ycbcrSampler (createSampler(vk,
1173 device,
1174 config.textureFilter,
1175 config.addressModeU,
1176 config.addressModeV,
1177 *conversion));
1178 const vk::Unique<vk::VkImageView> ycbcrImageView (createImageView(vk, device, **ycbcrImage, config.format, *conversion));
1179
1180
1181 // Input attributes
1182 std::vector<tcu::Vec2> texCoords;
1183 std::vector<tcu::Vec2> posCoords;
1184 genTexCoords(texCoords, size);
1185 posCoords = computeVertexPositions((deUint32)texCoords.size(), size.cast<int>());
1186
1187 // Input validation data
1188 std::vector<tcu::Vec4> ycbcrMinBounds;
1189 std::vector<tcu::Vec4> ycbcrMaxBounds;
1190
1191 // Generate input ycbcr image and conversion reference
1192 {
1193 ycbcr::MultiPlaneImageData ycbcrSrc (config.format, size);
1194
1195 generateYCbCrImage(ctx, config, size, texCoords, ycbcrSrc, ycbcrMinBounds, ycbcrMaxBounds);
1196 logBoundImages(log, size, ycbcrMinBounds, ycbcrMaxBounds);
1197 uploadYCbCrImage(ctx,
1198 **ycbcrImage,
1199 ycbcrSrc,
1200 vk::VK_ACCESS_SHADER_READ_BIT,
1201 vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1202 }
1203
1204 // Build up the reference data structure
1205 DE_ASSERT(posCoords.size() == ycbcrMinBounds.size());
1206 DE_ASSERT(posCoords.size() == ycbcrMaxBounds.size());
1207 DE_ASSERT(texCoords.size() >= CHECK_SIZE);
1208 std::vector<YCbCrValidationData> referenceData;
1209 std::vector<YCbCrValidationData> colorReferenceData;
1210
1211 for (deUint32 ndx = 0; ndx < texCoords.size(); ++ndx)
1212 {
1213 YCbCrValidationData data;
1214 data.coord = texCoords[ndx].toWidth<4>();
1215 data.minBound = ycbcrMinBounds[ndx];
1216 data.maxBound = ycbcrMaxBounds[ndx];
1217
1218 referenceData.push_back(data);
1219
1220 YCbCrValidationData colorData;
1221 colorData.coord = posCoords[ndx].toWidth<4>();
1222 colorData.minBound = tcu::Vec4(0.0f, 0.9f, 0.0f, 1.0f);
1223 colorData.maxBound = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1224
1225 colorReferenceData.push_back(colorData);
1226 }
1227
1228 if (config.shaderType == glu::SHADERTYPE_VERTEX
1229 || config.shaderType == glu::SHADERTYPE_FRAGMENT)
1230 {
1231 const de::UniquePtr<vk::ImageWithMemory> colorImage (createImage2D(ctx,
1232 PROTECTION_ENABLED,
1233 queueFamilyIndex,
1234 size.x(),
1235 size.y(),
1236 s_colorFormat,
1237 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
1238 | vk::VK_IMAGE_USAGE_SAMPLED_BIT));
1239 const vk::Unique<vk::VkImageView> colorImageView (createImageView(ctx, **colorImage, s_colorFormat));
1240 const vk::Unique<vk::VkSampler> colorSampler (makeSampler(vk, device));
1241
1242 renderYCbCrToColor(ctx, size, *ycbcrSampler, *ycbcrImageView, **colorImage, *colorImageView, referenceData, posCoords);
1243
1244 if (!validateImage(ctx, colorReferenceData, *colorSampler, *colorImageView))
1245 return tcu::TestStatus::fail("YCbCr image conversion via fragment shader failed");
1246 }
1247 else if (config.shaderType == glu::SHADERTYPE_COMPUTE)
1248 {
1249 if (!validateImage(ctx, referenceData, *ycbcrSampler, *ycbcrImageView))
1250 return tcu::TestStatus::fail("YCbCr image conversion via compute shader failed");
1251 }
1252 else
1253 {
1254 TCU_THROW(NotSupportedError, "Unsupported shader test type");
1255 }
1256
1257 return tcu::TestStatus::pass("YCbCr image conversion was OK");
1258 }
1259
1260 } // anonymous
1261
1262
createYCbCrConversionTests(tcu::TestContext & testCtx)1263 tcu::TestCaseGroup* createYCbCrConversionTests (tcu::TestContext& testCtx)
1264 {
1265 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "ycbcr", "YCbCr conversion tests"));
1266
1267 struct {
1268 const char * name;
1269 const glu::ShaderType type;
1270 } shaderTypes[] =
1271 {
1272 { "fragment", glu::SHADERTYPE_FRAGMENT },
1273 { "compute", glu::SHADERTYPE_COMPUTE }
1274 };
1275
1276 struct RangeNamePair
1277 {
1278 const char* name;
1279 vk::VkSamplerYcbcrRange value;
1280 };
1281 struct ChromaLocationNamePair
1282 {
1283 const char* name;
1284 vk::VkChromaLocation value;
1285 };
1286
1287 const vk::VkComponentMapping identitySwizzle =
1288 {
1289 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1290 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1291 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1292 vk::VK_COMPONENT_SWIZZLE_IDENTITY
1293 };
1294
1295 const RangeNamePair colorRanges[] =
1296 {
1297 { "itu_full", vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL },
1298 { "itu_narrow", vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW }
1299 };
1300
1301 const ChromaLocationNamePair chromaLocations[] =
1302 {
1303 { "cosited", vk::VK_CHROMA_LOCATION_COSITED_EVEN },
1304 { "midpoint", vk::VK_CHROMA_LOCATION_MIDPOINT }
1305 };
1306
1307 const struct
1308 {
1309 const char* const name;
1310 const vk::VkSamplerYcbcrModelConversion value;
1311 } colorModels[] =
1312 {
1313 { "rgb_identity", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY },
1314 { "ycbcr_identity", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY },
1315 { "ycbcr_709", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 },
1316 { "ycbcr_601", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 },
1317 { "ycbcr_2020", vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 }
1318 };
1319
1320 const struct
1321 {
1322 const char* name;
1323 vk::VkImageTiling value;
1324 } imageTilings[] =
1325 {
1326 { "tiling_linear", vk::VK_IMAGE_TILING_LINEAR },
1327 { "tiling_optimal", vk::VK_IMAGE_TILING_OPTIMAL }
1328 };
1329
1330 const deUint32 tilingNdx = 1;
1331 const vk::VkImageTiling tiling = imageTilings[tilingNdx].value;
1332 const char* tilingName = imageTilings[tilingNdx].name;
1333
1334 const vk::VkFormat testFormats[] =
1335 {
1336 // noChromaSubsampledFormats
1337 vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1338 vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1339 vk::VK_FORMAT_R5G6B5_UNORM_PACK16,
1340 vk::VK_FORMAT_B5G6R5_UNORM_PACK16,
1341 vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16,
1342 vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16,
1343 vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1344 vk::VK_FORMAT_R8G8B8_UNORM,
1345 vk::VK_FORMAT_B8G8R8_UNORM,
1346 vk::VK_FORMAT_R8G8B8A8_UNORM,
1347 vk::VK_FORMAT_B8G8R8A8_UNORM,
1348 vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1349 vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32,
1350 vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1351 vk::VK_FORMAT_R16G16B16_UNORM,
1352 vk::VK_FORMAT_R16G16B16A16_UNORM,
1353 vk::VK_FORMAT_R10X6_UNORM_PACK16,
1354 vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
1355 vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
1356 vk::VK_FORMAT_R12X4_UNORM_PACK16,
1357 vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
1358 vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
1359 vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
1360 vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
1361 vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
1362 vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
1363
1364 // xChromaSubsampledFormats
1365 vk::VK_FORMAT_G8B8G8R8_422_UNORM,
1366 vk::VK_FORMAT_B8G8R8G8_422_UNORM,
1367 vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
1368 vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
1369
1370 vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
1371 vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
1372 vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
1373 vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
1374 vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
1375 vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
1376 vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
1377 vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
1378 vk::VK_FORMAT_G16B16G16R16_422_UNORM,
1379 vk::VK_FORMAT_B16G16R16G16_422_UNORM,
1380 vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
1381 vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
1382
1383 // xyChromaSubsampledFormats
1384 vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
1385 vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
1386 vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
1387 vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
1388 vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
1389 vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
1390 vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
1391 vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
1392 };
1393
1394 for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(testFormats); formatNdx++)
1395 {
1396 const vk::VkFormat format (testFormats[formatNdx]);
1397 const std::string formatName (de::toLower(std::string(getFormatName(format)).substr(10)));
1398 de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str()));
1399
1400 for (size_t shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderNdx++)
1401 {
1402 const char* shaderTypeName = shaderTypes[shaderNdx].name;
1403 de::MovePtr<tcu::TestCaseGroup> shaderGroup (new tcu::TestCaseGroup(testCtx, shaderTypeName, "YCbCr conversion tests"));
1404
1405 for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++)
1406 {
1407 const char* const colorModelName (colorModels[modelNdx].name);
1408 const vk::VkSamplerYcbcrModelConversion colorModel (colorModels[modelNdx].value);
1409
1410 if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY && ycbcr::getYCbCrFormatChannelCount(format) < 3)
1411 continue;
1412
1413 de::MovePtr<tcu::TestCaseGroup> colorModelGroup (new tcu::TestCaseGroup(testCtx, colorModelName, "YCbCr conversion tests"));
1414
1415 for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++)
1416 {
1417 const char* const colorRangeName (colorRanges[rangeNdx].name);
1418 const vk::VkSamplerYcbcrRange colorRange (colorRanges[rangeNdx].value);
1419
1420 // Narrow range doesn't really work with formats that have less than 8 bits
1421 if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW)
1422 {
1423 const tcu::UVec4 bitDepth (ycbcr::getYCbCrBitDepth(format));
1424 if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8)
1425 continue;
1426 }
1427
1428 de::MovePtr<tcu::TestCaseGroup> colorRangeGroup (new tcu::TestCaseGroup(testCtx, colorRangeName, ("Tests for color range " + std::string(colorRangeName)).c_str()));
1429
1430 for (size_t chromaOffsetNdx = 0; chromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); chromaOffsetNdx++)
1431 {
1432 const char* const chromaOffsetName (chromaLocations[chromaOffsetNdx].name);
1433 const vk::VkChromaLocation chromaOffset (chromaLocations[chromaOffsetNdx].value);
1434
1435
1436 for (deUint32 disjointNdx = 0; disjointNdx < 2; ++disjointNdx)
1437 {
1438 bool disjoint = (disjointNdx == 1);
1439 const TestConfig config (shaderTypes[shaderNdx].type,
1440 format,
1441 tiling,
1442 vk::VK_FILTER_NEAREST,
1443 vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1444 vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1445 vk::VK_FILTER_NEAREST,
1446 chromaOffset,
1447 chromaOffset,
1448 false,
1449 disjoint,
1450 colorRange,
1451 colorModel,
1452 identitySwizzle);
1453
1454 addFunctionCaseWithPrograms(colorRangeGroup.get(),
1455 std::string(tilingName) + "_" + chromaOffsetName + (disjoint ? "_disjoint" : ""),
1456 "",
1457 testShaders,
1458 conversionTest,
1459 config);
1460 }
1461 }
1462
1463 colorModelGroup->addChild(colorRangeGroup.release());
1464 }
1465
1466 shaderGroup->addChild(colorModelGroup.release());
1467 }
1468
1469 formatGroup->addChild(shaderGroup.release());
1470
1471 }
1472 testGroup->addChild(formatGroup.release());
1473 }
1474
1475 return testGroup.release();
1476 }
1477
1478 } // ProtectedMem
1479 } // vkt
1480