Add basic WSI rendering test
authorPyry Haulos <phaulos@google.com>
Mon, 11 Apr 2016 23:37:53 +0000 (16:37 -0700)
committerPyry Haulos <phaulos@google.com>
Tue, 12 Apr 2016 00:24:33 +0000 (17:24 -0700)
Bug: 27536551
Bug: 27641433
Change-Id: Icc74ea9c6d669ced21e536ee96f0dd04d5e47343

android/cts/master/com.drawelements.deqp.vk.xml
android/cts/master/vk-master.txt
external/vulkancts/framework/vulkan/vkBasicTypes.inl
external/vulkancts/framework/vulkan/vkWsiUtil.cpp
external/vulkancts/framework/vulkan/vkWsiUtil.hpp
external/vulkancts/gen_framework.py
external/vulkancts/modules/vulkan/wsi/vktWsiSwapchainTests.cpp

index 9c4e1d4..ea34bef 100644 (file)
                                                        <TestInstance/>
                                                </Test>
                                        </TestCase>
+                                       <TestCase name="render">
+                                               <Test name="basic">
+                                                       <TestInstance/>
+                                               </Test>
+                                       </TestCase>
                                </TestSuite>
                        </TestSuite>
                </TestSuite>
index 94fd6a8..8e09788 100644 (file)
@@ -81128,6 +81128,7 @@ dEQP-VK.wsi.android.swapchain.simulate_oom.pre_transform
 dEQP-VK.wsi.android.swapchain.simulate_oom.composite_alpha
 dEQP-VK.wsi.android.swapchain.simulate_oom.present_mode
 dEQP-VK.wsi.android.swapchain.simulate_oom.clipped
+dEQP-VK.wsi.android.swapchain.render.basic
 dEQP-VK.synchronization.fences
 dEQP-VK.synchronization.semaphores
 dEQP-VK.synchronization.events
index 5e5db01..a00b8e3 100644 (file)
@@ -9,6 +9,7 @@ enum { VK_MAX_MEMORY_TYPES                              = 32                                            };
 enum { VK_MAX_MEMORY_HEAPS                             = 16                                            };
 enum { VK_MAX_DESCRIPTION_SIZE                 = 256                                           };
 enum { VK_ATTACHMENT_UNUSED                            = (~0U)                                         };
+enum { VK_SUBPASS_EXTERNAL                             = (~0U)                                         };
 
 VK_DEFINE_HANDLE                                       (VkInstance,                            HANDLE_TYPE_INSTANCE);
 VK_DEFINE_HANDLE                                       (VkPhysicalDevice,                      HANDLE_TYPE_PHYSICAL_DEVICE);
index 6f0968d..d94610b 100644 (file)
@@ -310,5 +310,25 @@ std::vector<VkPresentModeKHR> getPhysicalDeviceSurfacePresentModes (const Instan
                return std::vector<VkPresentModeKHR>();
 }
 
+std::vector<VkImage> getSwapchainImages (const DeviceInterface&                        vkd,
+                                                                                VkDevice                                               device,
+                                                                                VkSwapchainKHR                                 swapchain)
+{
+       deUint32        numImages       = 0;
+
+       VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, DE_NULL));
+
+       if (numImages > 0)
+       {
+               std::vector<VkImage>    images  (numImages);
+
+               VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, &images[0]));
+
+               return images;
+       }
+       else
+               return std::vector<VkImage>();
+}
+
 } // wsi
 } // vk
index e7da7d7..bee82de 100644 (file)
@@ -94,6 +94,10 @@ std::vector<VkPresentModeKHR>        getPhysicalDeviceSurfacePresentModes    (const Instan
                                                                                                                                                 VkPhysicalDevice                               physicalDevice,
                                                                                                                                                 VkSurfaceKHR                                   surface);
 
+std::vector<VkImage>                   getSwapchainImages                                              (const DeviceInterface&                 vkd,
+                                                                                                                                                VkDevice                                               device,
+                                                                                                                                                VkSwapchainKHR                                 swapchain);
+
 } // wsi
 } // vk
 
index 4cf7263..e6d9e55 100644 (file)
@@ -113,6 +113,7 @@ DEFINITIONS                 = [
        "VK_MAX_MEMORY_HEAPS",
        "VK_MAX_DESCRIPTION_SIZE",
        "VK_ATTACHMENT_UNUSED",
+       "VK_SUBPASS_EXTERNAL"
 ]
 
 PLATFORM_TYPES         = [
index 5ddfa64..6935899 100644 (file)
@@ -48,6 +48,9 @@
 #include "deUniquePtr.hpp"
 #include "deStringUtil.hpp"
 #include "deArrayUtil.hpp"
+#include "deSharedPtr.hpp"
+
+#include <limits>
 
 namespace vkt
 {
@@ -671,12 +674,894 @@ void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters para
        }
 }
 
+VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type                                             wsiType,
+                                                                                                         const InstanceInterface&      vki,
+                                                                                                         VkPhysicalDevice                      physicalDevice,
+                                                                                                         VkSurfaceKHR                          surface,
+                                                                                                         const tcu::UVec2&                     desiredSize,
+                                                                                                         deUint32                                      desiredImageCount)
+{
+       const VkSurfaceCapabilitiesKHR          capabilities            = getPhysicalDeviceSurfaceCapabilities(vki,
+                                                                                                                                                                                                  physicalDevice,
+                                                                                                                                                                                                  surface);
+       const vector<VkSurfaceFormatKHR>        formats                         = getPhysicalDeviceSurfaceFormats(vki,
+                                                                                                                                                                                         physicalDevice,
+                                                                                                                                                                                         surface);
+       const PlatformProperties&                       platformProperties      = getPlatformProperties(wsiType);
+       const VkSwapchainCreateInfoKHR          parameters                      =
+       {
+               VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+               DE_NULL,
+               (VkSwapchainCreateFlagsKHR)0,
+               surface,
+               de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount),
+               formats[0].format,
+               formats[0].colorSpace,
+               (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
+                       ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
+               1u,                                                                     // imageArrayLayers
+               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+               VK_SHARING_MODE_EXCLUSIVE,
+               0u,
+               (const deUint32*)DE_NULL,
+               VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
+               VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+               VK_PRESENT_MODE_FIFO_KHR,
+               VK_FALSE,                                                       // clipped
+               (VkSwapchainKHR)0                                       // oldSwapchain
+       };
+
+       return parameters;
+}
+
+typedef de::SharedPtr<Unique<VkImageView> >            ImageViewSp;
+typedef de::SharedPtr<Unique<VkFramebuffer> >  FramebufferSp;
+
+class TriangleRenderer
+{
+public:
+                                                                       TriangleRenderer        (const DeviceInterface&         vkd,
+                                                                                                                const VkDevice                         device,
+                                                                                                                Allocator&                                     allocator,
+                                                                                                                const BinaryCollection&        binaryRegistry,
+                                                                                                                const vector<VkImage>          swapchainImages,
+                                                                                                                const VkFormat                         framebufferFormat,
+                                                                                                                const UVec2&                           renderSize);
+                                                                       ~TriangleRenderer       (void);
+
+       void                                                    recordFrame                     (VkCommandBuffer                        cmdBuffer,
+                                                                                                                deUint32                                       imageNdx,
+                                                                                                                deUint32                                       frameNdx) const;
+
+       static void                                             getPrograms                     (SourceCollections& dst);
+
+private:
+       static Move<VkRenderPass>               createRenderPass        (const DeviceInterface&         vkd,
+                                                                                                                const VkDevice                         device,
+                                                                                                                const VkFormat                         colorAttachmentFormat);
+       static Move<VkPipelineLayout>   createPipelineLayout(const DeviceInterface&             vkd,
+                                                                                                                VkDevice                                       device);
+       static Move<VkPipeline>                 createPipeline          (const DeviceInterface&         vkd,
+                                                                                                                const VkDevice                         device,
+                                                                                                                const VkRenderPass                     renderPass,
+                                                                                                                const VkPipelineLayout         pipelineLayout,
+                                                                                                                const BinaryCollection&        binaryCollection,
+                                                                                                                const UVec2&                           renderSize);
+
+       static Move<VkImageView>                createAttachmentView(const DeviceInterface&             vkd,
+                                                                                                                const VkDevice                         device,
+                                                                                                                const VkImage                          image,
+                                                                                                                const VkFormat                         format);
+       static Move<VkFramebuffer>              createFramebuffer       (const DeviceInterface&         vkd,
+                                                                                                                const VkDevice                         device,
+                                                                                                                const VkRenderPass                     renderPass,
+                                                                                                                const VkImageView                      colorAttachment,
+                                                                                                                const UVec2&                           renderSize);
+
+       static Move<VkBuffer>                   createBuffer            (const DeviceInterface&         vkd,
+                                                                                                                VkDevice                                       device,
+                                                                                                                VkDeviceSize                           size,
+                                                                                                                VkBufferUsageFlags                     usage);
+
+       const DeviceInterface&                  m_vkd;
+
+       const vector<VkImage>                   m_swapchainImages;
+       const tcu::UVec2                                m_renderSize;
+
+       const Unique<VkRenderPass>              m_renderPass;
+       const Unique<VkPipelineLayout>  m_pipelineLayout;
+       const Unique<VkPipeline>                m_pipeline;
+
+       const Unique<VkBuffer>                  m_vertexBuffer;
+       const UniquePtr<Allocation>             m_vertexBufferMemory;
+
+       vector<ImageViewSp>                             m_attachmentViews;
+       vector<FramebufferSp>                   m_framebuffers;
+};
+
+Move<VkRenderPass> TriangleRenderer::createRenderPass (const DeviceInterface&  vkd,
+                                                                                                          const VkDevice                       device,
+                                                                                                          const VkFormat                       colorAttachmentFormat)
+{
+       const VkAttachmentDescription   colorAttDesc            =
+       {
+               (VkAttachmentDescriptionFlags)0,
+               colorAttachmentFormat,
+               VK_SAMPLE_COUNT_1_BIT,
+               VK_ATTACHMENT_LOAD_OP_CLEAR,
+               VK_ATTACHMENT_STORE_OP_STORE,
+               VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+               VK_ATTACHMENT_STORE_OP_DONT_CARE,
+               VK_IMAGE_LAYOUT_UNDEFINED,
+               VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+       };
+       const VkAttachmentReference             colorAttRef                     =
+       {
+               0u,
+               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+       };
+       const VkSubpassDescription              subpassDesc                     =
+       {
+               (VkSubpassDescriptionFlags)0u,
+               VK_PIPELINE_BIND_POINT_GRAPHICS,
+               0u,                                                     // inputAttachmentCount
+               DE_NULL,                                        // pInputAttachments
+               1u,                                                     // colorAttachmentCount
+               &colorAttRef,                           // pColorAttachments
+               DE_NULL,                                        // pResolveAttachments
+               DE_NULL,                                        // depthStencilAttachment
+               0u,                                                     // preserveAttachmentCount
+               DE_NULL,                                        // pPreserveAttachments
+       };
+       const VkSubpassDependency               dependencies[]          =
+       {
+               {
+                       VK_SUBPASS_EXTERNAL,    // srcSubpass
+                       0u,                                             // dstSubpass
+                       VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+                       VK_ACCESS_MEMORY_READ_BIT,
+                       (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
+                        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
+                       VK_DEPENDENCY_BY_REGION_BIT
+               },
+               {
+                       0u,                                             // srcSubpass
+                       VK_SUBPASS_EXTERNAL,    // dstSubpass
+                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+                       VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                       (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
+                        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
+                       VK_ACCESS_MEMORY_READ_BIT,
+                       VK_DEPENDENCY_BY_REGION_BIT
+               },
+       };
+       const VkRenderPassCreateInfo    renderPassParams        =
+       {
+               VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+               DE_NULL,
+               (VkRenderPassCreateFlags)0,
+               1u,
+               &colorAttDesc,
+               1u,
+               &subpassDesc,
+               DE_LENGTH_OF_ARRAY(dependencies),
+               dependencies,
+       };
+
+       return vk::createRenderPass(vkd, device, &renderPassParams);
+}
+
+Move<VkPipelineLayout> TriangleRenderer::createPipelineLayout (const DeviceInterface&  vkd,
+                                                                                                                          const VkDevice                       device)
+{
+       const VkPushConstantRange                                               pushConstantRange               =
+       {
+               VK_SHADER_STAGE_VERTEX_BIT,
+               0u,                                                                                     // offset
+               (deUint32)sizeof(deUint32),                                     // size
+       };
+       const VkPipelineLayoutCreateInfo                                pipelineLayoutParams    =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+               DE_NULL,
+               (vk::VkPipelineLayoutCreateFlags)0,
+               0u,                                                                                     // setLayoutCount
+               DE_NULL,                                                                        // pSetLayouts
+               1u,
+               &pushConstantRange,
+       };
+
+       return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
+}
+
+Move<VkPipeline> TriangleRenderer::createPipeline (const DeviceInterface&      vkd,
+                                                                                                  const VkDevice                       device,
+                                                                                                  const VkRenderPass           renderPass,
+                                                                                                  const VkPipelineLayout       pipelineLayout,
+                                                                                                  const BinaryCollection&      binaryCollection,
+                                                                                                  const UVec2&                         renderSize)
+{
+       // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
+       //               and can be deleted immediately following that call.
+       const Unique<VkShaderModule>                                    vertShaderModule                (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
+       const Unique<VkShaderModule>                                    fragShaderModule                (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
+
+       const VkSpecializationInfo                                              emptyShaderSpecParams   =
+       {
+               0u,                                                                                     // mapEntryCount
+               DE_NULL,                                                                        // pMap
+               0,                                                                                      // dataSize
+               DE_NULL,                                                                        // pData
+       };
+       const VkPipelineShaderStageCreateInfo                   shaderStageParams[]             =
+       {
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+                       DE_NULL,
+                       (VkPipelineShaderStageCreateFlags)0,
+                       VK_SHADER_STAGE_VERTEX_BIT,
+                       *vertShaderModule,
+                       "main",
+                       &emptyShaderSpecParams,
+               },
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+                       DE_NULL,
+                       (VkPipelineShaderStageCreateFlags)0,
+                       VK_SHADER_STAGE_FRAGMENT_BIT,
+                       *fragShaderModule,
+                       "main",
+                       &emptyShaderSpecParams,
+               }
+       };
+       const VkPipelineDepthStencilStateCreateInfo             depthStencilParams              =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineDepthStencilStateCreateFlags)0,
+               DE_FALSE,                                                                       // depthTestEnable
+               DE_FALSE,                                                                       // depthWriteEnable
+               VK_COMPARE_OP_ALWAYS,                                           // depthCompareOp
+               DE_FALSE,                                                                       // depthBoundsTestEnable
+               DE_FALSE,                                                                       // stencilTestEnable
+               {
+                       VK_STENCIL_OP_KEEP,                                                     // failOp
+                       VK_STENCIL_OP_KEEP,                                                     // passOp
+                       VK_STENCIL_OP_KEEP,                                                     // depthFailOp
+                       VK_COMPARE_OP_ALWAYS,                                           // compareOp
+                       0u,                                                                                     // compareMask
+                       0u,                                                                                     // writeMask
+                       0u,                                                                                     // reference
+               },                                                                                      // front
+               {
+                       VK_STENCIL_OP_KEEP,                                                     // failOp
+                       VK_STENCIL_OP_KEEP,                                                     // passOp
+                       VK_STENCIL_OP_KEEP,                                                     // depthFailOp
+                       VK_COMPARE_OP_ALWAYS,                                           // compareOp
+                       0u,                                                                                     // compareMask
+                       0u,                                                                                     // writeMask
+                       0u,                                                                                     // reference
+               },                                                                                      // back
+               -1.0f,                                                                          // minDepthBounds
+               +1.0f,                                                                          // maxDepthBounds
+       };
+       const VkViewport                                                                viewport0                               =
+       {
+               0.0f,                                                                           // x
+               0.0f,                                                                           // y
+               (float)renderSize.x(),                                          // width
+               (float)renderSize.y(),                                          // height
+               0.0f,                                                                           // minDepth
+               1.0f,                                                                           // maxDepth
+       };
+       const VkRect2D                                                                  scissor0                                =
+       {
+               { 0u, 0u, },                                                            // offset
+               { renderSize.x(), renderSize.y() },                     // extent
+       };
+       const VkPipelineViewportStateCreateInfo                 viewportParams                  =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineViewportStateCreateFlags)0,
+               1u,
+               &viewport0,
+               1u,
+               &scissor0
+       };
+       const VkPipelineMultisampleStateCreateInfo              multisampleParams               =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineMultisampleStateCreateFlags)0,
+               VK_SAMPLE_COUNT_1_BIT,                                          // rasterizationSamples
+               VK_FALSE,                                                                       // sampleShadingEnable
+               0.0f,                                                                           // minSampleShading
+               (const VkSampleMask*)DE_NULL,                           // sampleMask
+               VK_FALSE,                                                                       // alphaToCoverageEnable
+               VK_FALSE,                                                                       // alphaToOneEnable
+       };
+       const VkPipelineRasterizationStateCreateInfo    rasterParams                    =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineRasterizationStateCreateFlags)0,
+               VK_TRUE,                                                                        // depthClampEnable
+               VK_FALSE,                                                                       // rasterizerDiscardEnable
+               VK_POLYGON_MODE_FILL,                                           // polygonMode
+               VK_CULL_MODE_NONE,                                                      // cullMode
+               VK_FRONT_FACE_COUNTER_CLOCKWISE,                        // frontFace
+               VK_FALSE,                                                                       // depthBiasEnable
+               0.0f,                                                                           // depthBiasConstantFactor
+               0.0f,                                                                           // depthBiasClamp
+               0.0f,                                                                           // depthBiasSlopeFactor
+               1.0f,                                                                           // lineWidth
+       };
+       const VkPipelineInputAssemblyStateCreateInfo    inputAssemblyParams             =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineInputAssemblyStateCreateFlags)0,
+               VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+               DE_FALSE,                                                                       // primitiveRestartEnable
+       };
+       const VkVertexInputBindingDescription                   vertexBinding0                  =
+       {
+               0u,                                                                                     // binding
+               (deUint32)sizeof(tcu::Vec4),                            // stride
+               VK_VERTEX_INPUT_RATE_VERTEX,                            // inputRate
+       };
+       const VkVertexInputAttributeDescription                 vertexAttrib0                   =
+       {
+               0u,                                                                                     // location
+               0u,                                                                                     // binding
+               VK_FORMAT_R32G32B32A32_SFLOAT,                          // format
+               0u,                                                                                     // offset
+       };
+       const VkPipelineVertexInputStateCreateInfo              vertexInputStateParams  =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineVertexInputStateCreateFlags)0,
+               1u,
+               &vertexBinding0,
+               1u,
+               &vertexAttrib0,
+       };
+       const VkPipelineColorBlendAttachmentState               attBlendParams0                 =
+       {
+               VK_FALSE,                                                                       // blendEnable
+               VK_BLEND_FACTOR_ONE,                                            // srcColorBlendFactor
+               VK_BLEND_FACTOR_ZERO,                                           // dstColorBlendFactor
+               VK_BLEND_OP_ADD,                                                        // colorBlendOp
+               VK_BLEND_FACTOR_ONE,                                            // srcAlphaBlendFactor
+               VK_BLEND_FACTOR_ZERO,                                           // dstAlphaBlendFactor
+               VK_BLEND_OP_ADD,                                                        // alphaBlendOp
+               (VK_COLOR_COMPONENT_R_BIT|
+                VK_COLOR_COMPONENT_G_BIT|
+                VK_COLOR_COMPONENT_B_BIT|
+                VK_COLOR_COMPONENT_A_BIT),                                     // colorWriteMask
+       };
+       const VkPipelineColorBlendStateCreateInfo               blendParams                             =
+       {
+               VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineColorBlendStateCreateFlags)0,
+               VK_FALSE,                                                                       // logicOpEnable
+               VK_LOGIC_OP_COPY,
+               1u,
+               &attBlendParams0,
+               { 0.0f, 0.0f, 0.0f, 0.0f },                                     // blendConstants[4]
+       };
+       const VkGraphicsPipelineCreateInfo                              pipelineParams                  =
+       {
+               VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+               DE_NULL,
+               (VkPipelineCreateFlags)0,
+               (deUint32)DE_LENGTH_OF_ARRAY(shaderStageParams),
+               shaderStageParams,
+               &vertexInputStateParams,
+               &inputAssemblyParams,
+               (const VkPipelineTessellationStateCreateInfo*)DE_NULL,
+               &viewportParams,
+               &rasterParams,
+               &multisampleParams,
+               &depthStencilParams,
+               &blendParams,
+               (const VkPipelineDynamicStateCreateInfo*)DE_NULL,
+               pipelineLayout,
+               renderPass,
+               0u,                                                                                     // subpass
+               DE_NULL,                                                                        // basePipelineHandle
+               0u,                                                                                     // basePipelineIndex
+       };
+
+       return vk::createGraphicsPipeline(vkd, device, (VkPipelineCache)0, &pipelineParams);
+}
+
+Move<VkImageView> TriangleRenderer::createAttachmentView (const DeviceInterface&       vkd,
+                                                                                                                 const VkDevice                        device,
+                                                                                                                 const VkImage                         image,
+                                                                                                                 const VkFormat                        format)
+{
+       const VkImageViewCreateInfo             viewParams      =
+       {
+               VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+               DE_NULL,
+               (VkImageViewCreateFlags)0,
+               image,
+               VK_IMAGE_VIEW_TYPE_2D,
+               format,
+               vk::makeComponentMappingRGBA(),
+               {
+                       VK_IMAGE_ASPECT_COLOR_BIT,
+                       0u,                                             // baseMipLevel
+                       1u,                                             // levelCount
+                       0u,                                             // baseArrayLayer
+                       1u,                                             // layerCount
+               },
+       };
+
+       return vk::createImageView(vkd, device, &viewParams);
+}
+
+Move<VkFramebuffer> TriangleRenderer::createFramebuffer        (const DeviceInterface&         vkd,
+                                                                                                                const VkDevice                         device,
+                                                                                                                const VkRenderPass                     renderPass,
+                                                                                                                const VkImageView                      colorAttachment,
+                                                                                                                const UVec2&                           renderSize)
+{
+       const VkFramebufferCreateInfo   framebufferParams       =
+       {
+               VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+               DE_NULL,
+               (VkFramebufferCreateFlags)0,
+               renderPass,
+               1u,
+               &colorAttachment,
+               renderSize.x(),
+               renderSize.y(),
+               1u,                                                     // layers
+       };
+
+       return vk::createFramebuffer(vkd, device, &framebufferParams);
+}
+
+Move<VkBuffer> TriangleRenderer::createBuffer (const DeviceInterface&  vkd,
+                                                                                          VkDevice                                     device,
+                                                                                          VkDeviceSize                         size,
+                                                                                          VkBufferUsageFlags           usage)
+{
+       const VkBufferCreateInfo        bufferParams    =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+               DE_NULL,
+               (VkBufferCreateFlags)0,
+               size,
+               usage,
+               VK_SHARING_MODE_EXCLUSIVE,
+               0,
+               DE_NULL
+       };
+
+       return vk::createBuffer(vkd, device, &bufferParams);
+}
+
+TriangleRenderer::TriangleRenderer (const DeviceInterface&     vkd,
+                                                                       const VkDevice                  device,
+                                                                       Allocator&                              allocator,
+                                                                       const BinaryCollection& binaryRegistry,
+                                                                       const vector<VkImage>   swapchainImages,
+                                                                       const VkFormat                  framebufferFormat,
+                                                                       const UVec2&                    renderSize)
+       : m_vkd                                 (vkd)
+       , m_swapchainImages             (swapchainImages)
+       , m_renderSize                  (renderSize)
+       , m_renderPass                  (createRenderPass(vkd, device, framebufferFormat))
+       , m_pipelineLayout              (createPipelineLayout(vkd, device))
+       , m_pipeline                    (createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
+       , m_vertexBuffer                (createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
+       , m_vertexBufferMemory  (allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
+                                                        MemoryRequirement::HostVisible))
+{
+       m_attachmentViews.resize(swapchainImages.size());
+       m_framebuffers.resize(swapchainImages.size());
+
+       for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
+       {
+               m_attachmentViews[imageNdx]     = ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
+               m_framebuffers[imageNdx]        = FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
+       }
+
+       VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
+
+       {
+               const VkMappedMemoryRange       memRange        =
+               {
+                       VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
+                       DE_NULL,
+                       m_vertexBufferMemory->getMemory(),
+                       m_vertexBufferMemory->getOffset(),
+                       VK_WHOLE_SIZE
+               };
+               const tcu::Vec4                         vertices[]      =
+               {
+                       tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
+                       tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
+                       tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
+               };
+               DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
+
+               deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
+               VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
+       }
+}
+
+TriangleRenderer::~TriangleRenderer (void)
+{
+}
+
+void TriangleRenderer::recordFrame (VkCommandBuffer    cmdBuffer,
+                                                                       deUint32                imageNdx,
+                                                                       deUint32                frameNdx) const
+{
+       const VkImage           curImage                = m_swapchainImages[imageNdx];
+       const VkFramebuffer     curFramebuffer  = **m_framebuffers[imageNdx];
+
+       {
+               const VkCommandBufferBeginInfo  cmdBufBeginParams       =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+                       DE_NULL,
+                       (VkCommandBufferUsageFlags)0,
+                       (const VkCommandBufferInheritanceInfo*)DE_NULL,
+               };
+               VK_CHECK(m_vkd.beginCommandBuffer(cmdBuffer, &cmdBufBeginParams));
+       }
+
+       {
+               const VkImageMemoryBarrier      fromPresentationBarrier =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+                       DE_NULL,
+                       VK_ACCESS_MEMORY_READ_BIT,
+                       (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
+                        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
+                       VK_IMAGE_LAYOUT_UNDEFINED,
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                       VK_QUEUE_FAMILY_IGNORED,
+                       VK_QUEUE_FAMILY_IGNORED,
+                       curImage,
+                       {
+                               VK_IMAGE_ASPECT_COLOR_BIT,
+                               0u,                                     // baseMipLevel
+                               1u,                                     // levelCount
+                               0u,                                     // baseArrayLayer
+                               1u,                                     // layerCount
+                       }
+               };
+               m_vkd.cmdPipelineBarrier(cmdBuffer,
+                                                                VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+                                                                VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+                                                                (VkDependencyFlags)0,
+                                                                0, (const VkMemoryBarrier*)DE_NULL,
+                                                                0, (const VkBufferMemoryBarrier*)DE_NULL,
+                                                                1, &fromPresentationBarrier);
+       }
+
+       {
+               const VkClearValue                      clearValue              = makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
+               const VkRenderPassBeginInfo     passBeginParams =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                       DE_NULL,
+                       *m_renderPass,
+                       curFramebuffer,
+                       {
+                               { 0, 0 },
+                               { (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() }
+                       },                                                                                                      // renderArea
+                       1u,                                                                                                     // clearValueCount
+                       &clearValue,                                                                            // pClearValues
+               };
+               m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
+       }
+
+       m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
+
+       {
+               const VkDeviceSize bindingOffset = 0;
+               m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
+       }
+
+       m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
+       m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
+       m_vkd.cmdEndRenderPass(cmdBuffer);
+
+       {
+               const VkImageMemoryBarrier      toPresentationBarrier   =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+                       DE_NULL,
+                       (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
+                        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
+                       VK_ACCESS_MEMORY_READ_BIT,
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                       VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+                       VK_QUEUE_FAMILY_IGNORED,
+                       VK_QUEUE_FAMILY_IGNORED,
+                       curImage,
+                       {
+                               VK_IMAGE_ASPECT_COLOR_BIT,
+                               0u,                                     // baseMipLevel
+                               1u,                                     // levelCount
+                               0u,                                     // baseArrayLayer
+                               1u,                                     // layerCount
+                       }
+               };
+               m_vkd.cmdPipelineBarrier(cmdBuffer,
+                                                                VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+                                                                VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                                                                (VkDependencyFlags)0,
+                                                                0, (const VkMemoryBarrier*)DE_NULL,
+                                                                0, (const VkBufferMemoryBarrier*)DE_NULL,
+                                                                1, &toPresentationBarrier);
+       }
+
+       VK_CHECK(m_vkd.endCommandBuffer(cmdBuffer));
+}
+
+void TriangleRenderer::getPrograms (SourceCollections& dst)
+{
+       dst.glslSources.add("tri-vert") << glu::VertexSource(
+               "#version 310 es\n"
+               "layout(location = 0) in highp vec4 a_position;\n"
+               "layout(push_constant) uniform FrameData\n"
+               "{\n"
+               "    highp uint frameNdx;\n"
+               "} frameData;\n"
+               "void main (void)\n"
+               "{\n"
+               "    highp float angle = float(frameData.frameNdx) / 100.0;\n"
+               "    highp float c     = cos(angle);\n"
+               "    highp float s     = sin(angle);\n"
+               "    highp mat4  t     = mat4( c, -s,  0,  0,\n"
+               "                              s,  c,  0,  0,\n"
+               "                              0,  0,  1,  0,\n"
+               "                              0,  0,  0,  1);\n"
+               "    gl_Position = t * a_position;\n"
+               "}\n");
+       dst.glslSources.add("tri-frag") << glu::FragmentSource(
+               "#version 310 es\n"
+               "layout(location = 0) out lowp vec4 o_color;\n"
+               "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
+}
+
+typedef de::SharedPtr<Unique<VkCommandBuffer> >        CommandBufferSp;
+typedef de::SharedPtr<Unique<VkFence> >                        FenceSp;
+typedef de::SharedPtr<Unique<VkSemaphore> >            SemaphoreSp;
+
+Move<VkFence> createFence (const DeviceInterface&      vkd,
+                                                  const VkDevice                       device)
+{
+       const VkFenceCreateInfo fenceParams     =
+       {
+               VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+               DE_NULL,
+               (VkFenceCreateFlags)0,
+       };
+       return vk::createFence(vkd, device, &fenceParams);
+}
+
+vector<FenceSp> createFences (const DeviceInterface&   vkd,
+                                                         const VkDevice                        device,
+                                                         size_t                                        numFences)
+{
+       vector<FenceSp> fences(numFences);
+
+       for (size_t ndx = 0; ndx < numFences; ++ndx)
+               fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
+
+       return fences;
+}
+
+Move<VkSemaphore> createSemaphore (const DeviceInterface&      vkd,
+                                                                  const VkDevice                       device)
+{
+       const VkSemaphoreCreateInfo     semaphoreParams =
+       {
+               VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+               DE_NULL,
+               (VkSemaphoreCreateFlags)0,
+       };
+       return vk::createSemaphore(vkd, device, &semaphoreParams);
+}
+
+vector<SemaphoreSp> createSemaphores (const DeviceInterface&   vkd,
+                                                                         const VkDevice                        device,
+                                                                         size_t                                        numSemaphores)
+{
+       vector<SemaphoreSp> semaphores(numSemaphores);
+
+       for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
+               semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
+
+       return semaphores;
+}
+
+Move<VkCommandPool> createCommandPool (const DeviceInterface&  vkd,
+                                                                          const VkDevice                       device,
+                                                                          VkCommandPoolCreateFlags     flags,
+                                                                          deUint32                                     queueFamilyIndex)
+{
+       const VkCommandPoolCreateInfo   commandPoolParams       =
+       {
+               VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+               DE_NULL,
+               flags,
+               queueFamilyIndex
+       };
+
+       return createCommandPool(vkd, device, &commandPoolParams);
+}
+
+vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&         vkd,
+                                                                                               const VkDevice                          device,
+                                                                                               const VkCommandPool                     commandPool,
+                                                                                               const VkCommandBufferLevel      level,
+                                                                                               const size_t                            numCommandBuffers)
+{
+       const VkCommandBufferAllocateInfo       allocInfo       =
+       {
+               VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+               DE_NULL,
+               commandPool,
+               level,
+               1u,
+       };
+
+       vector<CommandBufferSp>                         buffers         (numCommandBuffers);
+
+       for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
+               buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, &allocInfo)));
+
+       return buffers;
+}
+
+tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
+{
+       const tcu::UVec2                                desiredSize                                     (256, 256);
+       const InstanceHelper                    instHelper                                      (context, wsiType);
+       const NativeObjects                             native                                          (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
+       const Unique<VkSurfaceKHR>              surface                                         (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
+       const DeviceHelper                              devHelper                                       (context, instHelper.vki, *instHelper.instance, *surface);
+       const DeviceInterface&                  vkd                                                     = devHelper.vkd;
+       const VkDevice                                  device                                          = *devHelper.device;
+       const VkSwapchainCreateInfoKHR  swapchainInfo                           = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
+       const Unique<VkSwapchainKHR>    swapchain                                       (createSwapchainKHR(vkd, device, &swapchainInfo));
+       const vector<VkImage>                   swapchainImages                         = getSwapchainImages(vkd, device, *swapchain);
+
+       const TriangleRenderer                  renderer                                        (vkd,
+                                                                                                                                        device,
+                                                                                                                                        context.getDefaultAllocator(),
+                                                                                                                                        context.getBinaryCollection(),
+                                                                                                                                        swapchainImages,
+                                                                                                                                        swapchainInfo.imageFormat,
+                                                                                                                                        tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
+
+       const Unique<VkCommandPool>             commandPool                                     (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
+
+       const size_t                                    maxQueuedFrames                         = swapchainImages.size()*2;
+
+       // We need to keep hold of fences from vkAcquireNextImageKHR to actually
+       // limit number of frames we allow to be queued.
+       const vector<FenceSp>                   imageReadyFences                        (createFences(vkd, device, maxQueuedFrames));
+
+       // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
+       // the semaphore in same time as the fence we use to meter rendering.
+       const vector<SemaphoreSp>               imageReadySemaphores            (createSemaphores(vkd, device, maxQueuedFrames+1));
+
+       // For rest we simply need maxQueuedFrames as we will wait for image
+       // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
+       // previous uses must have completed.
+       const vector<SemaphoreSp>               renderingCompleteSemaphores     (createSemaphores(vkd, device, maxQueuedFrames));
+       const vector<CommandBufferSp>   commandBuffers                          (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
+
+       try
+       {
+               const deUint32  numFramesToRender       = 60*10;
+
+               for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
+               {
+                       const VkFence           imageReadyFence         = **imageReadyFences[frameNdx%imageReadyFences.size()];
+                       const VkSemaphore       imageReadySemaphore     = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
+                       deUint32                        imageNdx                        = ~0u;
+
+                       if (frameNdx >= maxQueuedFrames)
+                               VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
+
+                       VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
+
+                       {
+                               const VkResult  acquireResult   = vkd.acquireNextImageKHR(device,
+                                                                                                                                                 *swapchain,
+                                                                                                                                                 std::numeric_limits<deUint64>::max(),
+                                                                                                                                                 imageReadySemaphore,
+                                                                                                                                                 imageReadyFence,
+                                                                                                                                                 &imageNdx);
+
+                               if (acquireResult == VK_SUBOPTIMAL_KHR)
+                                       context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
+                               else
+                                       VK_CHECK(acquireResult);
+                       }
+
+                       TCU_CHECK((size_t)imageNdx < swapchainImages.size());
+
+                       {
+                               const VkSemaphore                       renderingCompleteSemaphore      = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
+                               const VkCommandBuffer           commandBuffer                           = **commandBuffers[frameNdx%commandBuffers.size()];
+                               const VkPipelineStageFlags      waitDstStage                            = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+                               const VkSubmitInfo                      submitInfo                                      =
+                               {
+                                       VK_STRUCTURE_TYPE_SUBMIT_INFO,
+                                       DE_NULL,
+                                       1u,
+                                       &imageReadySemaphore,
+                                       &waitDstStage,
+                                       1u,
+                                       &commandBuffer,
+                                       1u,
+                                       &renderingCompleteSemaphore
+                               };
+                               const VkPresentInfoKHR          presentInfo                                     =
+                               {
+                                       VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+                                       DE_NULL,
+                                       1u,
+                                       &renderingCompleteSemaphore,
+                                       1u,
+                                       &*swapchain,
+                                       &imageNdx,
+                                       (VkResult*)DE_NULL
+                               };
+
+                               renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
+                               VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
+                               VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
+                       }
+               }
+
+               VK_CHECK(vkd.deviceWaitIdle(device));
+       }
+       catch (...)
+       {
+               // Make sure device is idle before destroying resources
+               vkd.deviceWaitIdle(device);
+               throw;
+       }
+
+       return tcu::TestStatus::pass("Rendering tests suceeded");
+}
+
+void getBasicRenderPrograms (SourceCollections& dst, Type)
+{
+       TriangleRenderer::getPrograms(dst);
+}
+
+void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
+{
+       addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
+}
+
 } // anonymous
 
 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
 {
        addTestGroup(testGroup, "create",                       "Create VkSwapchain with various parameters",                                   populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
        addTestGroup(testGroup, "simulate_oom",         "Simulate OOM using callbacks during swapchain construction",   populateSwapchainGroup, GroupParameters(wsiType, createSwapchainSimulateOOMTest));
+       addTestGroup(testGroup, "render",                       "Rendering Tests",                                                                                              populateRenderGroup,    wsiType);
 }
 
 } // wsi