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