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