1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2014 The Android Open Source Project
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 Scissor tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktFragmentOperationsScissorTests.hpp"
26 #include "vktFragmentOperationsScissorMultiViewportTests.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29
30 #include "vkDefs.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38
39 #include "tcuTestLog.hpp"
40 #include "tcuVector.hpp"
41 #include "tcuImageCompare.hpp"
42
43 #include "deUniquePtr.hpp"
44 #include "deRandom.hpp"
45
46 namespace vkt
47 {
48 namespace FragmentOperations
49 {
50 using namespace vk;
51 using de::MovePtr;
52 using de::UniquePtr;
53 using tcu::IVec2;
54 using tcu::IVec4;
55 using tcu::Vec2;
56 using tcu::Vec4;
57
58 namespace
59 {
60
61 //! What primitives will be drawn by the test case.
62 enum TestPrimitive
63 {
64 TEST_PRIMITIVE_POINTS, //!< Many points.
65 TEST_PRIMITIVE_LINES, //!< Many short lines.
66 TEST_PRIMITIVE_TRIANGLES, //!< Many small triangles.
67 TEST_PRIMITIVE_BIG_LINE, //!< One line crossing the whole render area.
68 TEST_PRIMITIVE_BIG_TRIANGLE, //!< One triangle covering the whole render area.
69 };
70
71 struct VertexData
72 {
73 Vec4 position;
74 Vec4 color;
75 };
76
77 //! Parameters used by the test case.
78 struct CaseDef
79 {
80 Vec4
81 renderArea; //!< (ox, oy, w, h), where origin (0,0) is the top-left corner of the viewport. Width and height are in range [0, 1].
82 Vec4 scissorArea; //!< scissored area (ox, oy, w, h)
83 TestPrimitive primitive;
84 };
85
86 template <typename T>
sizeInBytes(const std::vector<T> & vec)87 inline VkDeviceSize sizeInBytes(const std::vector<T> &vec)
88 {
89 return vec.size() * sizeof(vec[0]);
90 }
91
makeImageCreateInfo(const VkFormat format,const IVec2 & size,VkImageUsageFlags usage)92 VkImageCreateInfo makeImageCreateInfo(const VkFormat format, const IVec2 &size, VkImageUsageFlags usage)
93 {
94 const VkImageCreateInfo imageParams = {
95 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
96 DE_NULL, // const void* pNext;
97 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
98 VK_IMAGE_TYPE_2D, // VkImageType imageType;
99 format, // VkFormat format;
100 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
101 1u, // uint32_t mipLevels;
102 1u, // uint32_t arrayLayers;
103 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
104 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
105 usage, // VkImageUsageFlags usage;
106 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
107 0u, // uint32_t queueFamilyIndexCount;
108 DE_NULL, // const uint32_t* pQueueFamilyIndices;
109 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
110 };
111 return imageParams;
112 }
113
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const IVec2 renderSize,const IVec4 scissorArea,const VkPrimitiveTopology topology)114 Move<VkPipeline> makeGraphicsPipeline(const DeviceInterface &vk, const VkDevice device,
115 const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass,
116 const VkShaderModule vertexModule, const VkShaderModule fragmentModule,
117 const IVec2 renderSize,
118 const IVec4 scissorArea, //!< (ox, oy, w, h)
119 const VkPrimitiveTopology topology)
120 {
121 const VkVertexInputBindingDescription vertexInputBindingDescription = {
122 0u, // uint32_t binding;
123 sizeof(VertexData), // uint32_t stride;
124 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
125 };
126
127 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
128 {
129 0u, // uint32_t location;
130 0u, // uint32_t binding;
131 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
132 0u, // uint32_t offset;
133 },
134 {
135 1u, // uint32_t location;
136 0u, // uint32_t binding;
137 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
138 sizeof(Vec4), // uint32_t offset;
139 },
140 };
141
142 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
143 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
144 DE_NULL, // const void* pNext;
145 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
146 1u, // uint32_t vertexBindingDescriptionCount;
147 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
148 DE_LENGTH_OF_ARRAY(
149 vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount;
150 vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
151 };
152
153 const VkRect2D scissor = {makeOffset2D(scissorArea.x(), scissorArea.y()),
154 makeExtent2D(scissorArea.z(), scissorArea.w())};
155
156 const std::vector<VkViewport> viewports(1, makeViewport(renderSize));
157 const std::vector<VkRect2D> scissors(1, scissor);
158
159 return vk::makeGraphicsPipeline(
160 vk, // const DeviceInterface& vk
161 device, // const VkDevice device
162 pipelineLayout, // const VkPipelineLayout pipelineLayout
163 vertexModule, // const VkShaderModule vertexShaderModule
164 DE_NULL, // const VkShaderModule tessellationControlModule
165 DE_NULL, // const VkShaderModule tessellationEvalModule
166 DE_NULL, // const VkShaderModule geometryShaderModule
167 fragmentModule, // const VkShaderModule fragmentShaderModule
168 renderPass, // const VkRenderPass renderPass
169 viewports, // const std::vector<VkViewport>& viewports
170 scissors, // const std::vector<VkRect2D>& scissors
171 topology, // const VkPrimitiveTopology topology
172 0u, // const uint32_t subpass
173 0u, // const uint32_t patchControlPoints
174 &vertexInputStateInfo); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
175 }
176
makeVertex(const float x,const float y,const Vec4 & color)177 inline VertexData makeVertex(const float x, const float y, const Vec4 &color)
178 {
179 const VertexData data = {Vec4(x, y, 0.0f, 1.0f), color};
180 return data;
181 }
182
genVertices(const TestPrimitive primitive,const Vec4 & renderArea,const Vec4 & primitiveColor)183 std::vector<VertexData> genVertices(const TestPrimitive primitive, const Vec4 &renderArea, const Vec4 &primitiveColor)
184 {
185 std::vector<VertexData> vertices;
186 de::Random rng(1234);
187
188 const float x0 = 2.0f * renderArea.x() - 1.0f;
189 const float y0 = 2.0f * renderArea.y() - 1.0f;
190 const float rx = 2.0f * renderArea.z();
191 const float ry = 2.0f * renderArea.w();
192 const float size = 0.2f;
193
194 switch (primitive)
195 {
196 case TEST_PRIMITIVE_POINTS:
197 for (int i = 0; i < 50; ++i)
198 {
199 const float x = x0 + rng.getFloat(0.0f, rx);
200 const float y = y0 + rng.getFloat(0.0f, ry);
201 vertices.push_back(makeVertex(x, y, primitiveColor));
202 }
203 break;
204
205 case TEST_PRIMITIVE_LINES:
206 for (int i = 0; i < 30; ++i)
207 {
208 const float x = x0 + rng.getFloat(0.0f, rx - size);
209 const float y = y0 + rng.getFloat(0.0f, ry - size);
210 vertices.push_back(makeVertex(x, y, primitiveColor));
211 vertices.push_back(makeVertex(x + size, y + size, primitiveColor));
212 }
213 break;
214
215 case TEST_PRIMITIVE_TRIANGLES:
216 for (int i = 0; i < 20; ++i)
217 {
218 const float x = x0 + rng.getFloat(0.0f, rx - size);
219 const float y = y0 + rng.getFloat(0.0f, ry - size);
220 vertices.push_back(makeVertex(x, y, primitiveColor));
221 vertices.push_back(makeVertex(x + size / 2.0f, y + size, primitiveColor));
222 vertices.push_back(makeVertex(x + size, y, primitiveColor));
223 }
224 break;
225
226 case TEST_PRIMITIVE_BIG_LINE:
227 vertices.push_back(makeVertex(x0, y0, primitiveColor));
228 vertices.push_back(makeVertex(x0 + rx, y0 + ry, primitiveColor));
229 break;
230
231 case TEST_PRIMITIVE_BIG_TRIANGLE:
232 vertices.push_back(makeVertex(x0, y0, primitiveColor));
233 vertices.push_back(makeVertex(x0 + rx / 2.0f, y0 + ry, primitiveColor));
234 vertices.push_back(makeVertex(x0 + rx, y0, primitiveColor));
235 break;
236 }
237
238 return vertices;
239 }
240
getTopology(const TestPrimitive primitive)241 VkPrimitiveTopology getTopology(const TestPrimitive primitive)
242 {
243 switch (primitive)
244 {
245 case TEST_PRIMITIVE_POINTS:
246 return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
247
248 case TEST_PRIMITIVE_LINES:
249 case TEST_PRIMITIVE_BIG_LINE:
250 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
251
252 case TEST_PRIMITIVE_TRIANGLES:
253 case TEST_PRIMITIVE_BIG_TRIANGLE:
254 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
255
256 default:
257 DE_ASSERT(0);
258 return VK_PRIMITIVE_TOPOLOGY_LAST;
259 }
260 }
261
262 //! Transform from normalized coords to framebuffer space.
getAreaRect(const Vec4 & area,const int width,const int height)263 inline IVec4 getAreaRect(const Vec4 &area, const int width, const int height)
264 {
265 return IVec4(static_cast<int32_t>(static_cast<float>(width) * area.x()),
266 static_cast<int32_t>(static_cast<float>(height) * area.y()),
267 static_cast<int32_t>(static_cast<float>(width) * area.z()),
268 static_cast<int32_t>(static_cast<float>(height) * area.w()));
269 }
270
applyScissor(tcu::PixelBufferAccess imageAccess,const Vec4 & floatScissorArea,const Vec4 & clearColor)271 void applyScissor(tcu::PixelBufferAccess imageAccess, const Vec4 &floatScissorArea, const Vec4 &clearColor)
272 {
273 const IVec4 scissorRect(getAreaRect(floatScissorArea, imageAccess.getWidth(), imageAccess.getHeight()));
274 const int sx0 = scissorRect.x();
275 const int sx1 = scissorRect.x() + scissorRect.z();
276 const int sy0 = scissorRect.y();
277 const int sy1 = scissorRect.y() + scissorRect.w();
278
279 for (int y = 0; y < imageAccess.getHeight(); ++y)
280 for (int x = 0; x < imageAccess.getWidth(); ++x)
281 {
282 // Fragments outside fail the scissor test.
283 if (x < sx0 || x >= sx1 || y < sy0 || y >= sy1)
284 imageAccess.setPixel(clearColor, x, y);
285 }
286 }
287
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)288 void initPrograms(SourceCollections &programCollection, const CaseDef caseDef)
289 {
290 DE_UNREF(caseDef);
291
292 // Vertex shader
293 {
294 const bool usePointSize = (caseDef.primitive == TEST_PRIMITIVE_POINTS);
295
296 std::ostringstream src;
297 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
298 << "\n"
299 << "layout(location = 0) in vec4 in_position;\n"
300 << "layout(location = 1) in vec4 in_color;\n"
301 << "layout(location = 0) out vec4 o_color;\n"
302 << "\n"
303 << "out gl_PerVertex {\n"
304 << " vec4 gl_Position;\n"
305 << (usePointSize ? " float gl_PointSize;\n" : "") << "};\n"
306 << "\n"
307 << "void main(void)\n"
308 << "{\n"
309 << " gl_Position = in_position;\n"
310 << (usePointSize ? " gl_PointSize = 1.0;\n" : "") << " o_color = in_color;\n"
311 << "}\n";
312
313 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
314 }
315
316 // Fragment shader
317 {
318 std::ostringstream src;
319 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
320 << "\n"
321 << "layout(location = 0) in vec4 in_color;\n"
322 << "layout(location = 0) out vec4 o_color;\n"
323 << "\n"
324 << "void main(void)\n"
325 << "{\n"
326 << " o_color = in_color;\n"
327 << "}\n";
328
329 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
330 }
331 }
332
333 class ScissorRenderer
334 {
335 public:
ScissorRenderer(Context & context,const CaseDef caseDef,const IVec2 & renderSize,const VkFormat colorFormat,const Vec4 & primitiveColor,const Vec4 & clearColor)336 ScissorRenderer(Context &context, const CaseDef caseDef, const IVec2 &renderSize, const VkFormat colorFormat,
337 const Vec4 &primitiveColor, const Vec4 &clearColor)
338 : m_renderSize(renderSize)
339 , m_colorFormat(colorFormat)
340 , m_colorSubresourceRange(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
341 , m_primitiveColor(primitiveColor)
342 , m_clearColor(clearColor)
343 , m_vertices(genVertices(caseDef.primitive, caseDef.renderArea, m_primitiveColor))
344 , m_vertexBufferSize(sizeInBytes(m_vertices))
345 , m_topology(getTopology(caseDef.primitive))
346 {
347 const DeviceInterface &vk = context.getDeviceInterface();
348 const VkDevice device = context.getDevice();
349 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
350 Allocator &allocator = context.getDefaultAllocator();
351
352 m_colorImage =
353 makeImage(vk, device,
354 makeImageCreateInfo(m_colorFormat, m_renderSize,
355 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
356 m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
357 m_colorAttachment =
358 makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
359
360 m_vertexBuffer = makeBuffer(vk, device, m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
361 m_vertexBufferAlloc = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
362
363 {
364 deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
365 flushAlloc(vk, device, *m_vertexBufferAlloc);
366 }
367
368 m_vertexModule = createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u);
369 m_fragmentModule = createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u);
370 m_renderPass = makeRenderPass(vk, device, m_colorFormat);
371 m_framebuffer =
372 makeFramebuffer(vk, device, *m_renderPass, m_colorAttachment.get(), static_cast<uint32_t>(m_renderSize.x()),
373 static_cast<uint32_t>(m_renderSize.y()));
374 m_pipelineLayout = makePipelineLayout(vk, device);
375 m_cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
376 m_cmdBuffer = allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
377 }
378
draw(Context & context,const Vec4 & scissorAreaFloat,const VkBuffer colorBuffer) const379 void draw(Context &context, const Vec4 &scissorAreaFloat, const VkBuffer colorBuffer) const
380 {
381 const DeviceInterface &vk = context.getDeviceInterface();
382 const VkDevice device = context.getDevice();
383 const VkQueue queue = context.getUniversalQueue();
384
385 // New pipeline, because we're modifying scissor (we don't use dynamic state).
386 const Unique<VkPipeline> pipeline(makeGraphicsPipeline(
387 vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule, m_renderSize,
388 getAreaRect(scissorAreaFloat, m_renderSize.x(), m_renderSize.y()), m_topology));
389
390 beginCommandBuffer(vk, *m_cmdBuffer);
391
392 beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer,
393 makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), m_clearColor);
394
395 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
396 {
397 const VkDeviceSize vertexBufferOffset = 0ull;
398 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
399 }
400
401 vk.cmdDraw(*m_cmdBuffer, static_cast<uint32_t>(m_vertices.size()), 1u, 0u, 0u);
402 endRenderPass(vk, *m_cmdBuffer);
403
404 copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, m_renderSize);
405
406 endCommandBuffer(vk, *m_cmdBuffer);
407 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
408 context.resetCommandPoolForVKSC(device, *m_cmdPool);
409 }
410
411 private:
412 const IVec2 m_renderSize;
413 const VkFormat m_colorFormat;
414 const VkImageSubresourceRange m_colorSubresourceRange;
415 const Vec4 m_primitiveColor;
416 const Vec4 m_clearColor;
417 const std::vector<VertexData> m_vertices;
418 const VkDeviceSize m_vertexBufferSize;
419 const VkPrimitiveTopology m_topology;
420
421 Move<VkImage> m_colorImage;
422 MovePtr<Allocation> m_colorImageAlloc;
423 Move<VkImageView> m_colorAttachment;
424 Move<VkBuffer> m_vertexBuffer;
425 MovePtr<Allocation> m_vertexBufferAlloc;
426 Move<VkShaderModule> m_vertexModule;
427 Move<VkShaderModule> m_fragmentModule;
428 Move<VkRenderPass> m_renderPass;
429 Move<VkFramebuffer> m_framebuffer;
430 Move<VkPipelineLayout> m_pipelineLayout;
431 Move<VkCommandPool> m_cmdPool;
432 Move<VkCommandBuffer> m_cmdBuffer;
433
434 // "deleted"
435 ScissorRenderer(const ScissorRenderer &);
436 ScissorRenderer &operator=(const ScissorRenderer &);
437 };
438
test(Context & context,const CaseDef caseDef)439 tcu::TestStatus test(Context &context, const CaseDef caseDef)
440 {
441 const DeviceInterface &vk = context.getDeviceInterface();
442 const VkDevice device = context.getDevice();
443 Allocator &allocator = context.getDefaultAllocator();
444
445 const IVec2 renderSize(128, 128);
446 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
447 const Vec4 scissorFullArea(0.0f, 0.0f, 1.0f, 1.0f);
448 const Vec4 primitiveColor(1.0f, 1.0f, 1.0f, 1.0f);
449 const Vec4 clearColor(0.5f, 0.5f, 1.0f, 1.0f);
450
451 const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
452 const Unique<VkBuffer> colorBufferFull(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
453 const UniquePtr<Allocation> colorBufferFullAlloc(
454 bindBuffer(vk, device, allocator, *colorBufferFull, MemoryRequirement::HostVisible));
455
456 const Unique<VkBuffer> colorBufferScissored(
457 makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
458 const UniquePtr<Allocation> colorBufferScissoredAlloc(
459 bindBuffer(vk, device, allocator, *colorBufferScissored, MemoryRequirement::HostVisible));
460
461 zeroBuffer(vk, device, *colorBufferFullAlloc, colorBufferSize);
462 zeroBuffer(vk, device, *colorBufferScissoredAlloc, colorBufferSize);
463
464 // Draw
465 {
466 const ScissorRenderer renderer(context, caseDef, renderSize, colorFormat, primitiveColor, clearColor);
467
468 renderer.draw(context, scissorFullArea, *colorBufferFull);
469 renderer.draw(context, caseDef.scissorArea, *colorBufferScissored);
470 }
471
472 // Log image
473 {
474 invalidateAlloc(vk, device, *colorBufferFullAlloc);
475 invalidateAlloc(vk, device, *colorBufferScissoredAlloc);
476
477 const tcu::ConstPixelBufferAccess resultImage(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u,
478 colorBufferScissoredAlloc->getHostPtr());
479 tcu::PixelBufferAccess referenceImage(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u,
480 colorBufferFullAlloc->getHostPtr());
481
482 // Apply scissor to the full image, so we can compare it with the result image.
483 applyScissor(referenceImage, caseDef.scissorArea, clearColor);
484
485 // Images should now match.
486 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage,
487 resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
488 return tcu::TestStatus::fail("Rendered image is not correct");
489 }
490
491 return tcu::TestStatus::pass("OK");
492 }
493
494 //! \note The ES 2.0 scissoring tests included color/depth/stencil clear cases, but these operations are not affected by scissor test in Vulkan.
495 //! Scissor is part of the pipeline state and pipeline only affects the drawing commands.
createTestsInGroup(tcu::TestCaseGroup * scissorGroup)496 void createTestsInGroup(tcu::TestCaseGroup *scissorGroup)
497 {
498 tcu::TestContext &testCtx = scissorGroup->getTestContext();
499
500 struct TestSpec
501 {
502 const char *name;
503 CaseDef caseDef;
504 };
505
506 const Vec4 areaFull(0.0f, 0.0f, 1.0f, 1.0f);
507 const Vec4 areaCropped(0.2f, 0.2f, 0.6f, 0.6f);
508 const Vec4 areaCroppedMore(0.4f, 0.4f, 0.2f, 0.2f);
509 const Vec4 areaLeftHalf(0.0f, 0.0f, 0.5f, 1.0f);
510 const Vec4 areaRightHalf(0.5f, 0.0f, 0.5f, 1.0f);
511
512 // Points
513 {
514 MovePtr<tcu::TestCaseGroup> primitiveGroup(new tcu::TestCaseGroup(testCtx, "points"));
515
516 const TestSpec cases[] = {
517 // Points fully inside the scissor area
518 {"inside", {areaFull, areaFull, TEST_PRIMITIVE_POINTS}},
519 // Points partially inside the scissor area
520 {"partially_inside", {areaFull, areaCropped, TEST_PRIMITIVE_POINTS}},
521 // Points fully outside the scissor area
522 {"outside", {areaLeftHalf, areaRightHalf, TEST_PRIMITIVE_POINTS}},
523 };
524
525 for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
526 addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, initPrograms, test, cases[i].caseDef);
527
528 scissorGroup->addChild(primitiveGroup.release());
529 }
530
531 // Lines
532 {
533 MovePtr<tcu::TestCaseGroup> primitiveGroup(new tcu::TestCaseGroup(testCtx, "lines"));
534
535 const TestSpec cases[] = {
536 // Lines fully inside the scissor area
537 {"inside", {areaFull, areaFull, TEST_PRIMITIVE_LINES}},
538 // Lines partially inside the scissor area
539 {"partially_inside", {areaFull, areaCropped, TEST_PRIMITIVE_LINES}},
540 // Lines fully outside the scissor area
541 {"outside", {areaLeftHalf, areaRightHalf, TEST_PRIMITIVE_LINES}},
542 // A line crossing the scissor area
543 {"crossing", {areaFull, areaCroppedMore, TEST_PRIMITIVE_BIG_LINE}},
544 };
545
546 for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
547 addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, initPrograms, test, cases[i].caseDef);
548
549 scissorGroup->addChild(primitiveGroup.release());
550 }
551
552 // Triangles
553 {
554 MovePtr<tcu::TestCaseGroup> primitiveGroup(new tcu::TestCaseGroup(testCtx, "triangles"));
555
556 const TestSpec cases[] = {
557 // Triangles fully inside the scissor area
558 {"inside", {areaFull, areaFull, TEST_PRIMITIVE_TRIANGLES}},
559 // Triangles partially inside the scissor area
560 {"partially_inside", {areaFull, areaCropped, TEST_PRIMITIVE_TRIANGLES}},
561 // Triangles fully outside the scissor area
562 {"outside", {areaLeftHalf, areaRightHalf, TEST_PRIMITIVE_TRIANGLES}},
563 // A triangle crossing the scissor area
564 {"crossing", {areaFull, areaCroppedMore, TEST_PRIMITIVE_BIG_TRIANGLE}},
565 };
566
567 for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
568 addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, initPrograms, test, cases[i].caseDef);
569
570 scissorGroup->addChild(primitiveGroup.release());
571 }
572
573 // Mulit-viewport scissor
574 {
575 scissorGroup->addChild(createScissorMultiViewportTests(testCtx));
576 }
577 }
578
579 } // namespace
580
createScissorTests(tcu::TestContext & testCtx)581 tcu::TestCaseGroup *createScissorTests(tcu::TestContext &testCtx)
582 {
583 return createTestGroup(testCtx, "scissor", createTestsInGroup);
584 }
585
586 } // namespace FragmentOperations
587 } // namespace vkt
588