Merge vk-gl-cts/vulkan-cts-1.1.4 into vk-gl-cts/vulkan-cts-1.1.5
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / fragment_ops / vktFragmentOperationsScissorMultiViewportTests.cpp
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 multi viewport tests
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktFragmentOperationsScissorMultiViewportTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktFragmentOperationsMakeUtil.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkTypeUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38
39 #include "tcuTestLog.hpp"
40 #include "tcuVector.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuTextureUtil.hpp"
43
44 #include "deUniquePtr.hpp"
45 #include "deMath.h"
46
47 namespace vkt
48 {
49 namespace FragmentOperations
50 {
51 using namespace vk;
52 using de::UniquePtr;
53 using de::MovePtr;
54 using tcu::Vec4;
55 using tcu::Vec2;
56 using tcu::IVec2;
57 using tcu::IVec4;
58
59 namespace
60 {
61
62 enum Constants
63 {
64         MIN_MAX_VIEWPORTS = 16,         //!< Minimum number of viewports for an implementation supporting multiViewport.
65 };
66
67 template<typename T>
68 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
69 {
70         return vec.size() * sizeof(vec[0]);
71 }
72
73 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage)
74 {
75         const VkImageCreateInfo imageParams =
76         {
77                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                    // VkStructureType                      sType;
78                 DE_NULL,                                                                                // const void*                          pNext;
79                 (VkImageCreateFlags)0,                                                  // VkImageCreateFlags           flags;
80                 VK_IMAGE_TYPE_2D,                                                               // VkImageType                          imageType;
81                 format,                                                                                 // VkFormat                                     format;
82                 makeExtent3D(size.x(), size.y(), 1),                    // VkExtent3D                           extent;
83                 1u,                                                                                             // deUint32                                     mipLevels;
84                 1u,                                                                                             // deUint32                                     arrayLayers;
85                 VK_SAMPLE_COUNT_1_BIT,                                                  // VkSampleCountFlagBits        samples;
86                 VK_IMAGE_TILING_OPTIMAL,                                                // VkImageTiling                        tiling;
87                 usage,                                                                                  // VkImageUsageFlags            usage;
88                 VK_SHARING_MODE_EXCLUSIVE,                                              // VkSharingMode                        sharingMode;
89                 0u,                                                                                             // deUint32                                     queueFamilyIndexCount;
90                 DE_NULL,                                                                                // const deUint32*                      pQueueFamilyIndices;
91                 VK_IMAGE_LAYOUT_UNDEFINED,                                              // VkImageLayout                        initialLayout;
92         };
93         return imageParams;
94 }
95
96 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&           vk,
97                                                                            const VkDevice                               device,
98                                                                            const VkPipelineLayout               pipelineLayout,
99                                                                            const VkRenderPass                   renderPass,
100                                                                            const VkShaderModule                 vertexModule,
101                                                                            const VkShaderModule                 geometryModule,
102                                                                            const VkShaderModule                 fragmentModule,
103                                                                            const IVec2                                  renderSize,
104                                                                            const int                                    numViewports,
105                                                                            const std::vector<IVec4>             scissors)
106 {
107         const VkViewport defaultViewport = makeViewport(renderSize);
108         const std::vector<VkViewport> viewports(numViewports, defaultViewport);
109
110         DE_ASSERT(numViewports == static_cast<int>(scissors.size()));
111
112         std::vector<VkRect2D> rectScissors;
113         rectScissors.reserve(numViewports);
114
115         for (std::vector<IVec4>::const_iterator it = scissors.begin(); it != scissors.end(); ++it)
116         {
117                 const VkRect2D rect =
118                 {
119                         makeOffset2D(it->x(), it->y()),
120                         makeExtent2D(static_cast<deUint32>(it->z()), static_cast<deUint32>(it->w())),
121                 };
122                 rectScissors.push_back(rect);
123         }
124
125         return vk::makeGraphicsPipeline(vk,                                                                     // const DeviceInterface&            vk
126                                                                         device,                                                         // const VkDevice                    device
127                                                                         pipelineLayout,                                         // const VkPipelineLayout            pipelineLayout
128                                                                         vertexModule,                                           // const VkShaderModule              vertexShaderModule
129                                                                         DE_NULL,                                                        // const VkShaderModule              tessellationControlModule
130                                                                         DE_NULL,                                                        // const VkShaderModule              tessellationEvalModule
131                                                                         geometryModule,                                         // const VkShaderModule              geometryShaderModule
132                                                                         fragmentModule,                                         // const VkShaderModule              fragmentShaderModule
133                                                                         renderPass,                                                     // const VkRenderPass                renderPass
134                                                                         viewports,                                                      // const std::vector<VkViewport>&    viewports
135                                                                         rectScissors,                                           // const std::vector<VkRect2D>&      scissors
136                                                                         VK_PRIMITIVE_TOPOLOGY_POINT_LIST);      // const VkPrimitiveTopology         topology
137 }
138
139 void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize size)
140 {
141         deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(size));
142         flushAlloc(vk, device, alloc);
143 }
144
145 void requireFeatureMultiViewport (const InstanceInterface& vki, const VkPhysicalDevice physDevice)
146 {
147         const VkPhysicalDeviceFeatures  features        = getPhysicalDeviceFeatures(vki, physDevice);
148         const VkPhysicalDeviceLimits    limits          = getPhysicalDeviceProperties(vki, physDevice).limits;
149
150         if (!features.geometryShader)
151                 TCU_THROW(NotSupportedError, "Required feature is not supported: geometryShader");
152
153         if (!features.multiViewport)
154                 TCU_THROW(NotSupportedError, "Required feature is not supported: multiViewport");
155
156         if (limits.maxViewports < MIN_MAX_VIEWPORTS)
157                 TCU_THROW(NotSupportedError, "Implementation doesn't support minimum required number of viewports");
158 }
159
160 std::vector<IVec4> generateScissors (const int numScissors, const IVec2& renderSize)
161 {
162         // Scissor rects will be arranged in a grid-like fashion.
163
164         const int numCols               = deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numScissors)));
165         const int numRows               = deCeilFloatToInt32(static_cast<float>(numScissors) / static_cast<float>(numCols));
166         const int rectWidth             = renderSize.x() / numCols;
167         const int rectHeight    = renderSize.y() / numRows;
168
169         std::vector<IVec4> scissors;
170         scissors.reserve(numScissors);
171
172         int x = 0;
173         int y = 0;
174
175         for (int scissorNdx = 0; scissorNdx < numScissors; ++scissorNdx)
176         {
177                 const bool nextRow = (scissorNdx != 0) && (scissorNdx % numCols == 0);
178                 if (nextRow)
179                 {
180                         x  = 0;
181                         y += rectHeight;
182                 }
183
184                 scissors.push_back(IVec4(x, y, rectWidth, rectHeight));
185
186                 x += rectWidth;
187         }
188
189         return scissors;
190 }
191
192 std::vector<Vec4> generateColors (const int numColors)
193 {
194         const Vec4 colors[] =
195         {
196                 Vec4(0.18f, 0.42f, 0.17f, 1.0f),
197                 Vec4(0.29f, 0.62f, 0.28f, 1.0f),
198                 Vec4(0.59f, 0.84f, 0.44f, 1.0f),
199                 Vec4(0.96f, 0.95f, 0.72f, 1.0f),
200                 Vec4(0.94f, 0.55f, 0.39f, 1.0f),
201                 Vec4(0.82f, 0.19f, 0.12f, 1.0f),
202                 Vec4(0.46f, 0.15f, 0.26f, 1.0f),
203                 Vec4(0.24f, 0.14f, 0.24f, 1.0f),
204                 Vec4(0.49f, 0.31f, 0.26f, 1.0f),
205                 Vec4(0.78f, 0.52f, 0.33f, 1.0f),
206                 Vec4(0.94f, 0.82f, 0.31f, 1.0f),
207                 Vec4(0.98f, 0.65f, 0.30f, 1.0f),
208                 Vec4(0.22f, 0.65f, 0.53f, 1.0f),
209                 Vec4(0.67f, 0.81f, 0.91f, 1.0f),
210                 Vec4(0.43f, 0.44f, 0.75f, 1.0f),
211                 Vec4(0.26f, 0.24f, 0.48f, 1.0f),
212         };
213
214         DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors));
215
216         return std::vector<Vec4>(colors, colors + numColors);
217 }
218
219 //! Renders a colorful grid of rectangles.
220 tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat      format,
221                                                                                   const IVec2&                          renderSize,
222                                                                                   const Vec4&                           clearColor,
223                                                                                   const std::vector<IVec4>&     scissors,
224                                                                                   const std::vector<Vec4>&      scissorColors)
225 {
226         DE_ASSERT(scissors.size() == scissorColors.size());
227
228         tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
229         tcu::clear(image.getAccess(), clearColor);
230
231         for (std::size_t i = 0; i < scissors.size(); ++i)
232         {
233                 tcu::clear(
234                         tcu::getSubregion(image.getAccess(), scissors[i].x(), scissors[i].y(), scissors[i].z(), scissors[i].w()),
235                         scissorColors[i]);
236         }
237
238         return image;
239 }
240
241 void initPrograms (SourceCollections& programCollection, const int numViewports)
242 {
243         DE_UNREF(numViewports);
244
245         // Vertex shader
246         {
247                 std::ostringstream src;
248                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
249                         << "\n"
250                         << "layout(location = 0) in  vec4 in_color;\n"
251                         << "layout(location = 0) out vec4 out_color;\n"
252                         << "\n"
253                         << "void main(void)\n"
254                         << "{\n"
255                         << "    out_color = in_color;\n"
256                         << "}\n";
257
258                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
259         }
260
261         // Geometry shader
262         {
263                 // Each input point generates a fullscreen quad.
264
265                 std::ostringstream src;
266                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
267                         << "\n"
268                         << "layout(points) in;\n"
269                         << "layout(triangle_strip, max_vertices=4) out;\n"
270                         << "\n"
271                         << "out gl_PerVertex {\n"
272                         << "    vec4 gl_Position;\n"
273                         << "};\n"
274                         << "\n"
275                         << "layout(location = 0) in  vec4 in_color[];\n"
276                         << "layout(location = 0) out vec4 out_color;\n"
277                         << "\n"
278                         << "void main(void)\n"
279                         << "{\n"
280                         << "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
281                         << "    gl_Position      = vec4(-1.0, -1.0, 0.0, 1.0);\n"
282                         << "    out_color        = in_color[0];\n"
283                         << "    EmitVertex();"
284                         << "\n"
285                         << "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
286                         << "    gl_Position      = vec4(-1.0, 1.0, 0.0, 1.0);\n"
287                         << "    out_color        = in_color[0];\n"
288                         << "    EmitVertex();"
289                         << "\n"
290                         << "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
291                         << "    gl_Position      = vec4(1.0, -1.0, 0.0, 1.0);\n"
292                         << "    out_color        = in_color[0];\n"
293                         << "    EmitVertex();"
294                         << "\n"
295                         << "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
296                         << "    gl_Position      = vec4(1.0, 1.0, 0.0, 1.0);\n"
297                         << "    out_color        = in_color[0];\n"
298                         << "    EmitVertex();"
299                         << "}\n";
300
301                 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
302         }
303
304         // Fragment shader
305         {
306                 std::ostringstream src;
307                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
308                         << "\n"
309                         << "layout(location = 0) in  vec4 in_color;\n"
310                         << "layout(location = 0) out vec4 out_color;\n"
311                         << "\n"
312                         << "void main(void)\n"
313                         << "{\n"
314                         << "    out_color = in_color;\n"
315                         << "}\n";
316
317                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
318         }
319 }
320
321 class ScissorRenderer
322 {
323 public:
324         ScissorRenderer (Context&                                       context,
325                                          const IVec2&                           renderSize,
326                                          const int                                      numViewports,
327                                          const std::vector<IVec4>&      scissors,
328                                          const VkFormat                         colorFormat,
329                                          const Vec4&                            clearColor,
330                                          const std::vector<Vec4>&       vertices)
331                 : m_renderSize                          (renderSize)
332                 , m_colorFormat                         (colorFormat)
333                 , m_colorSubresourceRange       (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
334                 , m_clearColor                          (clearColor)
335                 , m_numViewports                        (numViewports)
336                 , m_vertexBufferSize            (sizeInBytes(vertices))
337         {
338                 const DeviceInterface&          vk                                      = context.getDeviceInterface();
339                 const VkDevice                          device                          = context.getDevice();
340                 const deUint32                          queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
341                 Allocator&                                      allocator                       = context.getDefaultAllocator();
342
343                 m_colorImage            = makeImage                             (vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
344                 m_colorImageAlloc       = bindImage                             (vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
345                 m_colorAttachment       = makeImageView                 (vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
346
347                 m_vertexBuffer          = makeBuffer                    (vk, device, makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
348                 m_vertexBufferAlloc     = bindBuffer                    (vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
349
350                 {
351                         deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
352                         flushAlloc(vk, device, *m_vertexBufferAlloc);
353                 }
354
355                 m_vertexModule          = createShaderModule    (vk, device, context.getBinaryCollection().get("vert"), 0u);
356                 m_geometryModule        = createShaderModule    (vk, device, context.getBinaryCollection().get("geom"), 0u);
357                 m_fragmentModule        = createShaderModule    (vk, device, context.getBinaryCollection().get("frag"), 0u);
358                 m_renderPass            = makeRenderPass                (vk, device, m_colorFormat);
359                 m_framebuffer           = makeFramebuffer               (vk, device, *m_renderPass, m_colorAttachment.get(),
360                                                                                                          static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
361                 m_pipelineLayout        = makePipelineLayout    (vk, device);
362                 m_pipeline                      = makeGraphicsPipeline  (vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_geometryModule, *m_fragmentModule,
363                                                                                                          m_renderSize, m_numViewports, scissors);
364                 m_cmdPool                       = createCommandPool             (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
365                 m_cmdBuffer                     = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
366         }
367
368         void draw (Context& context, const VkBuffer colorBuffer) const
369         {
370                 const DeviceInterface&          vk                      = context.getDeviceInterface();
371                 const VkDevice                          device          = context.getDevice();
372                 const VkQueue                           queue           = context.getUniversalQueue();
373
374                 beginCommandBuffer(vk, *m_cmdBuffer);
375
376                 beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), m_clearColor);
377
378                 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
379                 {
380                         const VkDeviceSize vertexBufferOffset = 0ull;
381                         vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
382                 }
383                 vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_numViewports), 1u, 0u, 0u);    // one vertex per viewport
384                 endRenderPass(vk, *m_cmdBuffer);
385
386                 copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, m_renderSize);
387
388                 endCommandBuffer(vk, *m_cmdBuffer);
389                 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
390         }
391
392 private:
393         const IVec2                                             m_renderSize;
394         const VkFormat                                  m_colorFormat;
395         const VkImageSubresourceRange   m_colorSubresourceRange;
396         const Vec4                                              m_clearColor;
397         const int                                               m_numViewports;
398         const VkDeviceSize                              m_vertexBufferSize;
399
400         Move<VkImage>                                   m_colorImage;
401         MovePtr<Allocation>                             m_colorImageAlloc;
402         Move<VkImageView>                               m_colorAttachment;
403         Move<VkBuffer>                                  m_vertexBuffer;
404         MovePtr<Allocation>                             m_vertexBufferAlloc;
405         Move<VkShaderModule>                    m_vertexModule;
406         Move<VkShaderModule>                    m_geometryModule;
407         Move<VkShaderModule>                    m_fragmentModule;
408         Move<VkRenderPass>                              m_renderPass;
409         Move<VkFramebuffer>                             m_framebuffer;
410         Move<VkPipelineLayout>                  m_pipelineLayout;
411         Move<VkPipeline>                                m_pipeline;
412         Move<VkCommandPool>                             m_cmdPool;
413         Move<VkCommandBuffer>                   m_cmdBuffer;
414
415         // "deleted"
416                                                 ScissorRenderer (const ScissorRenderer&);
417         ScissorRenderer&        operator=               (const ScissorRenderer&);
418 };
419
420 tcu::TestStatus test (Context& context, const int numViewports)
421 {
422         requireFeatureMultiViewport(context.getInstanceInterface(), context.getPhysicalDevice());
423
424         const DeviceInterface&                  vk                                      = context.getDeviceInterface();
425         const VkDevice                                  device                          = context.getDevice();
426         Allocator&                                              allocator                       = context.getDefaultAllocator();
427
428         const IVec2                                             renderSize                      (128, 128);
429         const VkFormat                                  colorFormat                     = VK_FORMAT_R8G8B8A8_UNORM;
430         const Vec4                                              clearColor                      (0.5f, 0.5f, 0.5f, 1.0f);
431         const std::vector<Vec4>                 vertexColors            = generateColors(numViewports);
432         const std::vector<IVec4>                scissors                        = generateScissors(numViewports, renderSize);
433
434         const VkDeviceSize                              colorBufferSize         = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
435         const Unique<VkBuffer>                  colorBuffer                     (makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
436         const UniquePtr<Allocation>             colorBufferAlloc        (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
437
438         zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize);
439
440         {
441                 context.getTestContext().getLog()
442                         << tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
443                         << tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
444         }
445
446         // Draw
447         {
448                 const ScissorRenderer renderer (context, renderSize, numViewports, scissors, colorFormat, clearColor, vertexColors);
449                 renderer.draw(context, *colorBuffer);
450         }
451
452         // Log image
453         {
454                 invalidateAlloc(vk, device, *colorBufferAlloc);
455
456                 const tcu::ConstPixelBufferAccess       resultImage             (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferAlloc->getHostPtr());
457                 const tcu::TextureLevel                         referenceImage  = generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, scissors, vertexColors);
458
459                 // Images should now match.
460                 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
461                         return tcu::TestStatus::fail("Rendered image is not correct");
462         }
463
464         return tcu::TestStatus::pass("OK");
465 }
466
467 } // anonymous
468
469 tcu::TestCaseGroup* createScissorMultiViewportTests     (tcu::TestContext& testCtx)
470 {
471         MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "multi_viewport", ""));
472
473         for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports)
474                 addFunctionCaseWithPrograms(group.get(), "scissor_" + de::toString(numViewports), "", initPrograms, test, numViewports);
475
476         return group.release();
477 }
478
479 } // FragmentOperations
480 } // vkt